gin获取参数、文件上传、请求重定向、路由和路由组、中间件的使用

685 阅读4分钟
一、获取参数

1、Get通过query获取请求参数代码示例如下:

package main

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

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

 r.GET("/web", func(c *gin.Context) {
    name1:=c.Query("name") //获取Get请求中的name如果没有返回空字符串
 name2:=c.DefaultQuery("name","ze") //如果没有获取到name参数默认使用ze字符串
    name3,ok:=c.GetQuery("name")//获取参数,如果没有获取到参数ok为false,或则为true。
    if !ok{
       name3="pangu"
    }
    c.JSON(http.StatusOK,gin.H{
       "name":name3   ,
    })
 })
 r.Run(":9999")
}

2、获取Form表单参数代码示例如下:

func main() {
	//Default返回一个默认的路由引擎
	r := gin.Default()
	r.POST("/user/search", func(c *gin.Context) {
		// DefaultPostForm取不到值时会返回指定的默认值
		//username := c.DefaultPostForm("username", "pangu")
		username := c.PostForm("username")
		address := c.PostForm("address")
		//输出json结果给调用方
		c.JSON(http.StatusOK, gin.H{
			"message":  "ok",
			"username": username,
			"address":  address,
		})
	})
	r.Run(":9999")
}

3、获取JSON参数代码示例如下:

func main() {
    //Default返回一个默认的路由引擎
	r := gin.Default()
        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)
})
        r.Run(":9999")
}

4、获取path参数代码示例如下:

func main() {
	//Default返回一个默认的路由引擎
	r := gin.Default()
	r.GET("/user/search/:username/:address", func(c *gin.Context) {
		username := c.Param("username")
		address := c.Param("address")
		//输出json结果给调用方
		c.JSON(http.StatusOK, gin.H{
			"message":  "ok",
			"username": username,
			"address":  address,
		})
	})

	r.Run(":9999")
}

5、基于请求的Content-Type识别请求数据类型和利用反射机制自动提取请求中的参数并且把值绑定在指定的结构体对象.ShouldBind()强大的功能,代码示例如下:

// Binding from JSON
type Login struct {
	User     string `form:"user" json:"user" binding:"required"`
	Password string `form:"password" json:"password" binding:"required"`
}

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

	// 绑定JSON的示例 ({"user": "ze", "password": "123456"})
	router.POST("/loginJSON", func(c *gin.Context) {
		var login Login

		if err := c.ShouldBind(&login); err == nil {
			fmt.Printf("login info:%#v\n", login)
			c.JSON(http.StatusOK, gin.H{
				"user":     login.User,
				"password": login.Password,
			})
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
	})

	// 绑定form表单示例 (user=ze&password=123456)
	router.POST("/loginForm", func(c *gin.Context) {
		var login Login
		// ShouldBind()会根据请求的Content-Type自行选择绑定器
		if err := c.ShouldBind(&login); err == nil {
			c.JSON(http.StatusOK, gin.H{
				"user":     login.User,
				"password": login.Password,
			})
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
	})

	// 绑定QueryString示例 (/loginQuery?user=ze&password=123456)
	router.GET("/loginForm", func(c *gin.Context) {
		var login Login
		// ShouldBind()会根据请求的Content-Type自行选择绑定器
		if err := c.ShouldBind(&login); err == nil {
			c.JSON(http.StatusOK, gin.H{
				"user":     login.User,
				"password": login.Password,
			})
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
	})

	// Listen and serve on 0.0.0.0:9999
	router.Run(":9999")
}
二、文件上传

1、文件的上传代码示例如下:

func main() {
	r := gin.Default()
	// 处理multipart forms提交文件时默认的内存限制是32 MiB
	// 可以通过下面的方式修改
	// r.MaxMultipartMemory = 8 << 20  // 8 MiB
	r.POST("/upload", func(c *gin.Context) {
		// 单个文件
		file, err := c.FormFile("f1")
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{
				"message": err.Error(),
			})
			return
		}

		log.Println(file.Filename)
		dst := fmt.Sprintf("C:/tmp/%s", file.Filename)
		// 上传文件到指定的目录
		c.SaveUploadedFile(file, dst)
		c.JSON(http.StatusOK, gin.H{
			"message": fmt.Sprintf("'%s' success!", file.Filename),
		})
	})
	r.Run(":9999")
}
三、请求重定向

1、HTTP 重定向, 内部、外部重定向均支持,代码示例如下:

r.GET("/test", func(c *gin.Context) {
	c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com/")
})

2、路由重定向

r.GET("/a", func(c *gin.Context) {
    // 指定重定向的URL
    c.Request.URL.Path = "/b"
    r.HandleContext(c)
})
r.GET("/b", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"hello": "world"})
})
四、路由和路由组

1、普通路由,代码示例如下

r.GET("/b", func(c *gin.Context) {
  c.JSON(http.StatusOK, gin.H{"hello": "world"})
})

2、匹配所有请求方法的路由,只要是/test路由都可以匹配该方法,代码示例方法如下:

r.Any("/test", func(c *gin.Context) {...})

3、处理没有找到路由的特殊路由,代码示例如下:

r.NoRoute(func(c *gin.Context) {
		c.HTML(http.StatusNotFound, "views/404.html", nil)
	})

4、路由组的使用: 我们可以将拥有共同URL前缀的路由划分为一个路由组。可以使用一对{}包裹同组的路由,方便代码清晰,代码示例如下:

func main() {
	r := gin.Default()
	userGroup := r.Group("/user")
	{
		userGroup.GET("/index", func(c *gin.Context) {...})
		userGroup.GET("/login", func(c *gin.Context) {...})
		userGroup.POST("/login", func(c *gin.Context) {...})

	}
	shopGroup := r.Group("/shop")
	{
		shopGroup.GET("/index", func(c *gin.Context) {...})
		shopGroup.GET("/cart", func(c *gin.Context) {...})
		shopGroup.POST("/checkout", func(c *gin.Context) {...})
	}
	r.Run(":9999")
}

2、嵌套路由组,代码示例如下

shopGroup := r.Group("/shop")
	{
		shopGroup.GET("/index", func(c *gin.Context) {...})
		shopGroup.GET("/cart", func(c *gin.Context) {...})
		shopGroup.POST("/checkout", func(c *gin.Context) {...})
		// 嵌套路由组
		xx := shopGroup.Group("/xxx")
		xx.GET("/oo", func(c *gin.Context) {...})
	}
五、中间件的使用

1、gin中的中间件必须是gin.HandlerFunc,代码示例如下:

func m1(c *gin.Context){
   fmt.Println("m1 in...")
   // 计时
   start := time.Now()
   //go funcXX(c.Copy())  // 在funcXX中只能使用c的拷贝
   c.Next()  // 调用后续的处理函数
   //c.Abort() // 阻止调用后续的处理函数
   cost := time.Since(start)
   fmt.Printf("cost:%v\n", cost)
   fmt.Println("m1 out...")
}

中间件整体代码的的示例:

package main

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

func main() {
   r:=gin.Default()
   fmt.Print(*r)
   r.Use(m1,m2,authMiddleware(true))
   r.GET("/index",indexHandler)
   //下面是路由组相关设置中间件函数
   ////为该组注册对应的中间件1
   //test1:=r.Group("/test1",authMiddleware(true))
   //{
   //test1.GET("/xx1", func(c *gin.Context) {
   // c.JSON(http.StatusOK,gin.H{
   //    "msg":"xx1",
   // })
   //})
   //}
   ////为该组注册对应的中间件2
   //test2:=r.Group("/test2")
   //test2.Use(authMiddleware(true))
   //{
   // test2.GET("/xx2", func(c *gin.Context) {
   //    c.JSON(http.StatusOK,gin.H{
   //       "msg":"xx1",
   //    })
   // })
   //}
   r.Run(":9999")

}

func indexHandler(c *gin.Context){
   fmt.Printf("index")
   name,ok:=c.Get("name")//从上下文中取值(跨中间件取值)
   if !ok{
      name="pangu"
   }else{
      c.JSON(http.StatusOK,gin.H{"msg":name})
   }

}
func m1(c *gin.Context){
   fmt.Println("m1 in...")
   // 计时
   start := time.Now()
   //go funcXX(c.Copy())  // 在funcXX中只能使用c的拷贝
   c.Next()  // 调用后续的处理函数
   //c.Abort() // 阻止调用后续的处理函数
   cost := time.Since(start)
   fmt.Printf("cost:%v\n", cost)
   fmt.Println("m1 out...")
}

func m2(c *gin.Context){
   fmt.Println("m2 in...")
   c.Set("name", "q1mi")  // 在上下文c中设置值
   //c.Abort()  // 阻止调用后续的处理函数
   //return
   fmt.Println("m2 out...")
}

func authMiddleware(doCheck bool) gin.HandlerFunc{
   return func(c *gin.Context) {
      if doCheck{
         // 存放具体的逻辑
         // 是否登录的判断
         // if 是登录用户
         c.Abort()
      }else{
         c.Abort()

      }
   }


}