gin 框架介绍和使用
1 安装使用
- 下载安装
 
$ go get -u github.com/gin-gonic/gin
- 使用事例
 
package main
import (
	"github.com/gin-gonic/gin"
)
func main() {
	GinObj := gin.Default() // 创建默认的路由引擎
	GinObj.GET("/book", get) // get方法,第一个参数是url,第二个参数是调用的函数
	GinObj.GET("/struct", structFunc)
  GinObj.Run() // 启动http服务,默认是0.0.0.0:8080启动服务;可以跟字符串参数,自定义启动服务的端口:":9090"
}
func get(c *gin.Context) {
	c.JSON(200, gin.H{
		"message": "get book",
	}) // 返回json数据,第一个参数是状态码,第二个参数是空接口类型,也就是任意数据类型
}
func structFunc(c *gin.Context) {
	var user struct{
		Name string
		Age int
	}
	user.Name = "lynn"
	user.Age = 18
	c.JSON(200, "user")
}
2 API restful
以请求方法,表示不同的处理逻辑,且url都用名词,结果是json格式数据
gin遵循api restful规范:
	路由引擎对象的方法:.GET查询数据,对应get请求、POST创建数据,对应post方法、PUT更新数据,put方法、DELETE删除数据,delete方法
package main
import (
	"github.com/gin-gonic/gin"
)
func main() {
	GinObj := gin.Default()
	GinObj.GET("/book", get) // get请求,查询
	GinObj.POST("/book", get) // post请求,创建
	GinObj.PUT("/book", get) // put请求,修改。提交所有数据
	GinObj.PATCH("/book", get) // patch请求,修改。只提交修改的数据
	GinObj.DELETE("/book", get) // delete请求,删除数据
  GinObj.Run() // 可以指定端口,例子: ":9090"
}
func get(c *gin.Context) {
	responseData := map[string]string{
		"message": "success",
	}
	c.JSON(200, responseData) // 200是状态码,第二个参数是返回值
}
3 获取参数
01 通过url传参
get请求时,在url之后以?name=lynn&age=18这种格式传参数
package main
import (
	"github.com/gin-gonic/gin"
)
func main() {
	GinObj := gin.Default()
	GinObj.GET("/book", get)
	GinObj.Run()
}
func get(c *gin.Context) {
	name := c.Query("name") // 没传值时,结果为空字符串
  age := c.DefaultQuery("age", "18") // 没传值时,结果为: "18"
	responseData := map[string]interface{}{
		"message": "success",
	}
	c.JSON(200, responseData)
}
注意:
	Query:只能有一个参数,要接收数据的key值,key不存在时,默认为空字符串
	DefaultQuery:有两个参数,第一个时要接收数据的key值,第二个是key不存在时,默认的值。注意key存在,value为空字符串时不默认
02 form表单参数
通过form表单提交数据时,post、patch等
package main
import (
	"fmt"
	"github.com/gin-gonic/gin"
)
var responseData = map[string]interface{}{
	"message": "success",
}
func main() {
	GinObj := gin.Default()
	GinObj.POST("/book", post)
	GinObj.Run()
}
func post(c *gin.Context) {
	name := c.PostForm("name")
	age := c.DefaultPostForm("age", "90") //
	responseData["name"] = name
	responseData["age"] = age
	fmt.Println(name)
	fmt.Println(age)
	c.JSON(200, responseData)
}
注意:
	PostForm:只能有一个参数,要接收数据的key值,key不存在时,默认为空字符串
	DefaultPostForm:有两个参数,第一个时要接收数据的key值,第二个是key不存在时,默认的值。注意key存在,value为空字符串时不默认
03 json数据
前后端分离的项目,一般是json数据
package main
import (
	"encoding/json"
	"github.com/gin-gonic/gin"
)
var responseData = map[string]interface{}{
	"message": "success",
}
func main() {
	GinObj := gin.Default()
	GinObj.POST("/book", post)
	GinObj.Run()
}
}
func post(c *gin.Context) {
	data, _ := c.GetRawData()
	var b map[string]interface{}
	_ = json.Unmarshal(data, &b) // 如果是map记得用指针,因为map是值类型
	responseData["data"] = b
	c.JSON(200, responseData)
}
04 url路径传参
通过URL路径传递参数,一般用法/book/1:查询第一本书的数据
 main
import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
)
var responseData = map[string]interface{}{
	"message": "success",
}
func main() {
	GinObj := gin.Default()
  GinObj.GET("/book/:name/:age/:bookId", get) // 可以是多个:名字,用/分割,所有参数都要传,否则404
	GinObj.POST("/book", post)
	GinObj.Run()
}
func get(c *gin.Context) {
	bookId := c.Param("bookId") // 获取url路径传的数据
	params := c.Params // 获取所有的url路径传的数据
	value, ok := params.Get("name") // value是数据,ok是是否有数据
	fmt.Println(value, ok)
	responseData["id"] = bookId
	c.JSON(200, responseData)
}
注意:
	url路径传参,是在路径后边,且可以传多个,在定义的路径后边用:变量名格式接收,多个时,用/分割
 所有的参数必填,一般不要超过两个
4 文件上传
- 
01 单文件上传
 - 
02 多文件上传
 
5 重定向
- Redirect
 
内部外部都支持
重定向url既可以是完整的:https://www.baidu.com;也可以是内部的,且不以http开头的url都认为是内部的
package main
import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
)
func main() {
	GinObj := gin.Default()
	GinObj.GET("/book", getRedirect)
	GinObj.Run()
}
func getRedirect(gc *gin.Context) {
	gc.Redirect(302, "https://www.baidu.com") // 重定向到百度首页
}
注意:
	gc.Redirect(): 第一个参数是数字状态码,第二个是全路径
6 路由
- 自定义
404时,页面 
package main
import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
)
func main() {
	GinObj := gin.Default()
	GinObj.NoRoute(noPage) // 没有匹配到路由时,调用该函数
	GinObj.Run()
}
func noPage(gc *gin.Context) {
	gc.JSON(200, "404页面")
}
01 路由组
方便管理,将拥有共同前缀的url划分为一个路由组。一般同一个组的路由,用{}包起来
package main
import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
)
var responseData = map[string]interface{}{
	"message": "success",
}
func main() {
	GinObj := gin.Default()
	GinObj.NoRoute(noPage)
	bookGroup := GinObj.Group("/book") // book路由组,都以/book为前缀
	{
		bookUserGroup := bookGroup.Group("/user") // 路由组嵌套,相当于/book/user
    bookUserGroup.GET("/:id", book) // 相当于路由是:/book/user/:id
	}
	GinObj.Run()
}
func book(gc *gin.Context) {
	id := gc.Param("id")
	responseData["id"] = id
	gc.JSON(200, responseData)
}
注意:
 路由组一般最多嵌套一层,建议路由组不嵌套
7 中间件
处理请求的过程中加入自定义的钩子函数,也就是中间件
01 定义中间件
中间件必须是gin.HandelFunc类型
func StaCost() gin.HandlerFunc { // StaCost是一个中间件,返回值必须是gin.HandlerFunc类型
	return MiddlewareFunc
}
func MiddlewareFunc(request *gin.Context) {
	start := time.Now()
	request.Set("message", "这是一个中间件") // 给初始的路由对象添加数据,值可以是任意类型
  data, ok := request.Get("message") // 从路由对象中获取数据,第一个数据,第二个是布尔值
	request.Next() // 继续往下运行
	//gc.Abort() // 不再往下运行
	cost := time.Since(start)
	fmt.Println(cost)
}
02 注册中间件
1 全局注册
所有的请求(url)都要经过中间件才能进入业务逻辑
package main 
import (
	"fmt"
	"github.com/gin-gonic/gin"
	"time"
)
func main() {
  request := gin.New() // 实例化一个空的路由对象
	request.Use(StaCost())  // 全局注册使用该中间件
	request.Run()
  
}
func StaCost() gin.HandlerFunc {
	return middlewareFunc
}
func middlewareFunc(request *gin.Context) {
	start := time.Now()
	request.Set("message", "这是一个中间件")
	fmt.Println(request.Get("message"))
	request.Next()
	//gc.Abort()
	cost := time.Since(start)
	fmt.Println(cost)
}
注意:
	gin.New()实例化一个新的没有任何中间件的路由对象
	gin.Default()实例化的路由对象,包含两个中间件Logger  Recovery
Logger:中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release。Recovery:中间件会recover任何panic。如果有panic的话,会写入500响应码。
2 单个路由注册
只有请求该路由时,才进入该中间件,一个路由可以注册多个中间件
package main 
import (
	"fmt"
	"github.com/gin-gonic/gin"
	"time"
)
func main() {
  request := gin.New() // 实例化一个空的路由对象
  request.GET("/id", m1(), m2(), ShopCart) //  只有请求该路由时该路由,可以注册多个中间件,执行顺序从左到右
	request.Run() 
}
func m1() gin.HandlerFunc {
	return MiddlewareFunc
}
func MiddlewareFunc(request *gin.Context) {
	request.Set("message", "这是一个中间件")
	fmt.Println(request.Get("message"))
	fmt.Println("我是第一个中间件")
	request.Next()
}
func m2() gin.HandlerFunc {
	return MiddlewareFunc1
}
func MiddlewareFunc1(request *gin.Context) {
	request.Set("message1", "这是第二个中间件")
	fmt.Println(request.Get("message1"))
	fmt.Println("我是第二个中间件")
	request.Next()
}
func ShopCart(request *gin.Context) {
	request.JSON(200, "shop ok")
}
注意:
 多个中间件时,把优先级高的放在左边
3 路由组注册
只要请求是该路由组,就进入该中间件,可以有多个中间件
第一种:
package main 
import (
	"fmt"
	"github.com/gin-gonic/gin"
	"time"
)
func main() {
  request := gin.New() // 实例化一个空的路由对象
  group := request.Group("/shop", m1(), m2())  //  只要请求该路由组就进入该中间件,可以注册多个中间件,执行顺序从左到右
  {
  group.GET("/id", ShopCart) 
  }
	request.Run() 
}
func m1() gin.HandlerFunc {
	return MiddlewareFunc
}
func MiddlewareFunc(request *gin.Context) {
	request.Set("message", "这是一个中间件")
	fmt.Println(request.Get("message"))
	fmt.Println("我是第一个中间件")
	request.Next()
}
func m2() gin.HandlerFunc {
	return MiddlewareFunc1
}
func MiddlewareFunc1(request *gin.Context) {
	request.Set("message1", "这是第二个中间件")
	fmt.Println(request.Get("message1"))
	fmt.Println("我是第二个中间件")
	request.Next()
}
func ShopCart(request *gin.Context) {
	request.JSON(200, "shop ok")
}
第二种:
package main 
import (
	"fmt"
	"github.com/gin-gonic/gin"
	"time"
)
func main() {
  request := gin.New() // 实例化一个空的路由对象
  group := request.Group("/shop")  
  group.Use(m1(), m2())  // 只要请求该路由组就进入该中间件,可以注册多个中间件,执行顺序从左到右
  {
  group.GET("/id", ShopCart) 
  }
	request.Run() 
}
func m1() gin.HandlerFunc {
	return MiddlewareFunc
}
func MiddlewareFunc(request *gin.Context) {
	request.Set("message", "这是一个中间件")
	fmt.Println(request.Get("message"))
	fmt.Println("我是第一个中间件")
	request.Next()
}
func m2() gin.HandlerFunc {
	return MiddlewareFunc1
}
func MiddlewareFunc1(request *gin.Context) {
	request.Set("message1", "这是第二个中间件")
	fmt.Println(request.Get("message1"))
	fmt.Println("我是第二个中间件")
	request.Next()
}
func ShopCart(request *gin.Context) {
	request.JSON(200, "shop ok")
}
一个中间件可以被多个路由或者路由组注册,同时一个路由或者路由组也可以注册多个中间件
03 其他
当在中间件或handler中启动新的goroutine时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy())。
8 运行多个服务
多端口启动服务

                
            
        
浙公网安备 33010602011771号