首页 > 其他分享 >gin教程

gin教程

时间:2022-11-03 21:36:15浏览次数:54  
标签:教程 http func GET Context gin name

介绍

  • Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,具有快速灵活,容错方便等特点
  • 对于golang而言,web框架的依赖要远比Python,Java之类的要小。自身的net/http足够简单,性能也非常不错
  • 借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范

安装

go get -u github.com/gin-gonic/gin

第一个gin程序

package main

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    // 1.创建路由
   r := gin.Default()
   // 2.绑定路由规则,执行的函数
   // gin.Context,封装了request和response
   r.GET("/", func(c *gin.Context) {
      c.String(http.StatusOK, "hello World!")
   })
   // 3.监听端口,默认在8080
   // Run("里面不指定端口号默认为8080") 
   r.Run(":8000")
}

路由

package main

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/", func(c *gin.Context) {
        c.String(http.StatusOK, "hello word")
    })
    r.POST("/xxxpost",getting)
    r.PUT("/xxxput")
    //监听端口默认为8080
    r.Run(":8000")
}

路由重定向

路由重定向,使用HandleContext

r.GET("/test", func(c *gin.Context) {
    // 指定重定向的URL
    c.Request.URL.Path = "/test2"
    r.HandleContext(c)
})
r.GET("/test2", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"hello": "world"})
})

返回数据渲染

JSON渲染

func main() {
	r := gin.Default()

	// gin.H 是map[string]interface{}的缩写
	r.GET("/someJSON", func(c *gin.Context) {
		// 方式一:自己拼接JSON
		c.JSON(http.StatusOK, gin.H{"message": "Hello world!"})
	})
	r.GET("/moreJSON", func(c *gin.Context) {
		// 方法二:使用结构体
		var msg struct {
			Name    string `json:"user"`
			Message string
			Age     int
		}
		msg.Name = "小王子"
		msg.Message = "Hello world!"
		msg.Age = 18
		c.JSON(http.StatusOK, msg)
	})
	r.Run(":8080")
}

XML渲染

注意需要使用具名的结构体类型。

func main() {
	r := gin.Default()
	// gin.H 是map[string]interface{}的缩写
	r.GET("/someXML", func(c *gin.Context) {
		// 方式一:自己拼接JSON
		c.XML(http.StatusOK, gin.H{"message": "Hello world!"})
	})
	r.GET("/moreXML", func(c *gin.Context) {
		// 方法二:使用结构体
		type MessageRecord struct {
			Name    string
			Message string
			Age     int
		}
		var msg MessageRecord
		msg.Name = "小王子"
		msg.Message = "Hello world!"
		msg.Age = 18
		c.XML(http.StatusOK, msg)
	})
	r.Run(":8080")
}

YMAL渲染

r.GET("/someYAML", func(c *gin.Context) {
	c.YAML(http.StatusOK, gin.H{"message": "ok", "status": http.StatusOK})
})

protobuf渲染

r.GET("/someProtoBuf", func(c *gin.Context) {
	reps := []int64{int64(1), int64(2)}
	label := "test"
	// protobuf 的具体定义写在 testdata/protoexample 文件中。
	data := &protoexample.Test{
		Label: &label,
		Reps:  reps,
	}
	// 请注意,数据在响应中变为二进制数据
	// 将输出被 protoexample.Test protobuf 序列化了的数据
	c.ProtoBuf(http.StatusOK, data)
})

获取参数

获取json参数

当前端请求的数据通过JSON提交时,例如向/json发送一个POST请求,则获取请求参数的方式如下:

r.POST("/json", func(c *gin.Context) {
	// 注意:下面为了举例子方便,暂时忽略了错误处理
	b, _ := c.GetRawData()  // 从c.Request.Body读取请求数据
	// 定义map或结构体
	var m map[string]interface{}
	// 反序列化
	_ = json.Unmarshal(b, &m)

	c.JSON(http.StatusOK, m)
})

请求参数

使用Param获取

 r.GET("/user/:name/*action", func(c *gin.Context) {
        name := c.Param("name")  // 使用Param获取
        action := c.Param("action")
package main

import (
    "net/http"
    "strings"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/user/:name/*action", func(c *gin.Context) {
        name := c.Param("name")
        action := c.Param("action")
        //截取/
        action = strings.Trim(action, "/")
        c.String(http.StatusOK, name+" is "+action)
    })
    //默认为监听8080端口
    r.Run(":8000")
}

url参数

  • URL参数可以通过DefaultQuery()或Query()方法获取
  • DefaultQuery()若参数不村则,返回默认值,Query()若不存在,返回空串
  • API ? name=zs
	r.GET("/", func(c *gin.Context) {
		name := c.Query("name")
		age := c.DefaultQuery("age", "18")
		c.JSON(http.StatusOK, gin.H{
			"msg":  "ok",
			"name": name,
			"age":  age,
		})
	})

表单参数

r.POST("/post", func(c *gin.Context) {
		username := c.PostForm("username")
		password := c.PostForm("password")
		c.JSON(200, gin.H{
			"username": username,
			"password": password,
		})
	})

上传文件

单个文件

	r.POST("/upload", func(c *gin.Context) {
		_, header, err := c.Request.FormFile("file")
		if err != nil {
			panic(err.Error())
		}
		c.SaveUploadedFile(header, "./media/"+header.Filename)  //保存文件
		c.JSON(200, gin.H{
			"msg":  "上传成功",
			"file": header.Filename,
		})
	})
r.POST("/upload2", func(c *gin.Context) {
		fileHeader, err := c.FormFile("file")
		if err != nil {
			panic(err.Error())
		}
		c.SaveUploadedFile(fileHeader, "./media/"+fileHeader.Filename)
		c.JSON(200, gin.H{
			"msg":  "上传成功",
			"file": fileHeader.Filename,
		})
	})

特定文件

	r.POST("/upload", func(c *gin.Context) {
		_, header, err := c.Request.FormFile("file")
		if err != nil {
			panic(err.Error())
		}
		c.SaveUploadedFile(header, "./media/"+header.Filename)
		if header.Size > 1024*1024 {
			panic("文件太大")
		} else if header.Header.Get("Content-Type") != "image/png" {
			panic("只能上传image/png")
		} else {
			c.JSON(200, gin.H{
				"msg":  "上传成功",
				"file": header.Filename,
			})
		}

	})

多个文件

 r.MaxMultipartMemory = 8 << 20
   r.POST("/upload", func(c *gin.Context) {
      form, err := c.MultipartForm()
      if err != nil {
         c.String(http.StatusBadRequest, fmt.Sprintf("get err %s", err.Error()))
      }
      // 获取所有图片
      files := form.File["files"]
      // 遍历所有图片
      for _, file := range files {
         // 逐个存
         if err := c.SaveUploadedFile(file, file.Filename); err != nil {
            c.String(http.StatusBadRequest, fmt.Sprintf("upload err %s", err.Error()))
            return
         }
      }
      c.String(200, fmt.Sprintf("upload ok %d files", len(files)))
   })

routes group

  • routes group是为了管理一些相同的URL
  • 我们可以将拥有共同URL前缀的路由划分为一个路由组。习惯性一对{}包裹同组的路由,这只是为了看着清晰,你用不用{}包裹功能上没什么区别。
// gin的helloWorld

func main() {
   // 1.创建路由
   // 默认使用了2个中间件Logger(), Recovery()
   r := gin.Default()
   // 路由组1 ,处理GET请求
   v1 := r.Group("/v1")
   // {} 是书写规范
   {
      v1.GET("/login", login)
      v1.GET("submit", submit)
   }
   v2 := r.Group("/v2")
   {
      v2.POST("/login", login)
      v2.POST("/submit", submit)
   }
   r.Run(":8000")
}

func login(c *gin.Context) {
   name := c.DefaultQuery("name", "jack")
   c.String(200, fmt.Sprintf("hello %s\n", name))
}

func submit(c *gin.Context) {
   name := c.DefaultQuery("name", "lily")
   c.String(200, fmt.Sprintf("hello %s\n", name))
}

404页面

package main

import (
    "fmt"
    "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/user", func(c *gin.Context) {
        //指定默认值
        //http://localhost:8080/user 才会打印出来默认的值
        name := c.DefaultQuery("name", "枯藤")
        c.String(http.StatusOK, fmt.Sprintf("hello %s", name))2020-08-05 09:22:11 星期三
    })
    r.NoRoute(func(c *gin.Context) {
        c.String(http.StatusNotFound, "404 not found2222")
    })
    r.Run()

中间件

注册中间件必须返回gin.HandlerFunc类型

func(c *gin.Context) { .... }的类型极为gin.HandlerFunc

// 调用该请求的剩余处理程序
c.Next()  // 通过
c.Set("name", "小王子") // 可以通过c.Set在请求上下文中设置值,后续的处理函数能够取到该值
// 不调用该请求的剩余处理程序
c.Abort() // 不通过

全局中间件

Use注册全局中间件

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
)

func Middleware() gin.HandlerFunc {
    // 逻辑
    // 操作数据库 ...
	return func(c *gin.Context) {
		fmt.Println("gin全局中间件")
		c.Next()
	}
}
func main() {
	r := gin.Default()
	r.Use(Middleware())
	r.GET("/", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "hello word",
		})
	})
	r.Run()
}

注册局部中间件

方式1

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
)

func Middleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		fmt.Println("gin全局中间件")
		c.Next()
	}
}
func main() {
	r := gin.Default()
	r.Use(Middleware())
	r.GET("/",Middleware(), func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "hello word",
		})
	})
	r.Run()
}

方式2

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
)

func main() {
	r := gin.Default()
	r.GET("/", func(c *gin.Context) {
		fmt.Println("gin局部中间件")
		c.Next()
	}, func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "hello word",
		})
	})
	r.Run()
}

为路由组注册中间件

func Middleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		fmt.Println("gin为路由组注册中间件")
		c.Next()
	}
}

shopGroup := r.Group("/shop", Middleware())
{
    shopGroup.GET("/index", func(c *gin.Context) {...})
    ...
}

运行多个服务

我们可以在多个端口启动服务,例如:

package main

import (
	"log"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"golang.org/x/sync/errgroup"
)

var (
	g errgroup.Group
)

func router01() http.Handler {
	e := gin.New()
	e.Use(gin.Recovery())
	e.GET("/", func(c *gin.Context) {
		c.JSON(
			http.StatusOK,
			gin.H{
				"code":  http.StatusOK,
				"error": "Welcome server 01",
			},
		)
	})

	return e
}

func router02() http.Handler {
	e := gin.New()
	e.Use(gin.Recovery())
	e.GET("/", func(c *gin.Context) {
		c.JSON(
			http.StatusOK,
			gin.H{
				"code":  http.StatusOK,
				"error": "Welcome server 02",
			},
		)
	})

	return e
}

func main() {
	server01 := &http.Server{
		Addr:         ":8080",
		Handler:      router01(),
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	server02 := &http.Server{
		Addr:         ":8081",
		Handler:      router02(),
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}
   // 借助errgroup.Group或者自行开启两个goroutine分别启动两个服务
	g.Go(func() error {
		return server01.ListenAndServe()
	})

	g.Go(func() error {
		return server02.ListenAndServe()
	})

	if err := g.Wait(); err != nil {
		log.Fatal(err)
	}
}

标签:教程,http,func,GET,Context,gin,name
From: https://www.cnblogs.com/yangyucai/p/16855895.html

相关文章

  • Atcoder Beginner Contest 271(A~G)
    省流:赛时F假了。赛时A转进制;B简单vector。C简单贪心模拟,大概就是能走就走,不能走就先不走(较大)或者存起来(较小),最后走存起来的。挂了3发,自闭了。D第一眼看成了......
  • nginx反向代理,实现地址栏域名不变,session不失效
    首先找到nginx.conf部分server{listen80;server_namewww.taekwondo-china.com;location/{#所有以/开头的地址,实际上就是所有请求p......
  • dockerNginx代理本地目录
    dockerNginx代理本地目录ssl_certificatecert/5900588_test.zk.limengkai.work.pem;ssl_certificate_keycert/5900588_test.zk.limengkai.work.key;dockerrun-tdi......
  • go-gin集成jwt认证
    今天趁热打铁,把cookie/session/jwt集成go-gin框架的认证方式,一鼓作气全code一遍,lifeisshort,showyouthecode.示例目录结构:项目入口:packagemainimport( "gin......
  • Redis Desktop Manager(Redis可视化工具)安装及使用教程
    1、https://blog.csdn.net/m0_55070913/article/details/123677891RedisDesktopManager(Redis可视化工具)安装及使用教程2、一、工具/材料官网下载:https://redisdesk......
  • IOS APP开发:苹果app从开发到上架教程详解
     不少人认为按照目前市场占有率,app开发还是以安卓为主,但不可忽视的是, iosapp开发的用户基础还是很庞大的,用户需求也很稳定,市场挖掘潜力还是很客观,进行苹果app开发还是......
  • nginx
    一、实现原理异步,非阻塞,使用了epoll和大量的底层代码优化。nginx采用linux的epoll模型,epoll模型基于事件驱动机制,可以监控多个事件是否准备完毕,如果可以,就放入epoll队列......
  • Java实现ip属地功能开发教程 | ip2region2.x使用总结
    ip属地功能开发-ip2region2.x使用总结一、前言如今许多软件如B站、微博、抖音等都加上IP归属地防止恶意评论,境外用户显示的是国家,国内的用户显示的省份。兴致一起,我便......
  • 基于iTOP-RK3568开发板-驱动教程更新20节
    迅为基于iTOP-RK3568开发板进行讲解,本次为第四期,主要讲解高级字符设备进阶,共计20讲。第一期主要讲解驱动基础第二期主要讲解字符设备基础第三期主要讲解并发与竞争​​​​......
  • 传奇开服教程:传奇开服在哪些网站打广告?传奇发布站打广告技巧
    ​开传奇sf,成本最高的就是广告费用了,为了让服人气更高,主播和发布站相信你们都已经尝试了,上人效果如何你们比我更清楚,为什么别的GM开的服人气那么高,而你的服玩家屈指可数呢?今......