
Gin中的中间件必须是一个gin.HandlerFunc类型配置路由的时候可以传递多个func回调函数最后一个func回调函数前面触发的方法都可以称为中间件。package main import ( fmt github.com/gin-gonic/gin ) func initMiddleware(ctx *gin.Context) { fmt.Println(我是一个中间件) } func main() { r : gin.Default() r.GET(/, initMiddleware, func(ctx *gin.Context) { ctx.String(200, 首页--中间件演示) }) r.GET(/news, initMiddleware, func(ctx *gin.Context) { ctx.String(200, 新闻页面--中间件演示) }) r.Run(:8080) }1、ctx.Next()调用该请求的剩余处理程序中间件里面加上ctx.Next()可以让我们在路由匹配完成后执行一些操作。比如我们统计一个请求的执行时间。package main import ( fmt time github.com/gin-gonic/gin ) func initMiddleware(ctx *gin.Context) { fmt.Println(1-执行中中间件) start : time.Now().UnixNano() // 调用该请求的剩余处理程序 ctx.Next() fmt.Println(3-程序执行完成 计算时间) // 计算耗时 Go 语言中的 Since()函数保留时间值并用于评估与实际时间的差异 end : time.Now().UnixNano() fmt.Println(end - start) } func main() { r : gin.Default() r.GET(/, initMiddleware, func(ctx *gin.Context) { fmt.Println(2-执行首页返回数据) ctx.String(200, 首页--中间件演示) }) r.GET(/news, initMiddleware, func(ctx *gin.Context) { ctx.String(200, 新闻页面--中间件演示) }) r.Run(:8080) } // 1-执行中中间件 》2-执行首页返回数据 》3-程序执行完成 计算时间2、一个路由配置多个中间件的执行顺序先进后出func initMiddlewareOne(ctx *gin.Context) { fmt.Println(initMiddlewareOne--1-执行中中间件) // 调用该请求的剩余处理程序 ctx.Next() fmt.Println(initMiddlewareOne--2-执行中中间件) } func initMiddlewareTwo(ctx *gin.Context) { fmt.Println(initMiddlewareTwo--1-执行中中间件) // 调用该请求的剩余处理程序 ctx.Next() fmt.Println(initMiddlewareTwo--2-执行中中间件) } func main() { r : gin.Default() r.GET(/, initMiddlewareOne, initMiddlewareTwo, func(ctx *gin.Context) { fmt.Println(执行路由里面的程序) 湖北众猿腾网络科技有限公司 ctx.String(200, 首页--中间件演示) }) r.Run(:8080) } 控制台打印内容 initMiddlewareOne--1-执行中中间件 initMiddlewareTwo--1-执行中中间件 执行路由里面的程序 initMiddlewareTwo--2-执行中中间件 initMiddlewareOne--2-执行中中间件3、c.Abort()--了解Abort是终止的意思c.Abort()表示终止调用该请求的剩余处理程序package main import ( fmt github.com/gin-gonic/gin ) func initMiddlewareOne(ctx *gin.Context) { fmt.Println(initMiddlewareOne--1-执行中中间件) // 调用该请求的剩余处理程序 ctx.Next() fmt.Println(initMiddlewareOne--2-执行中中间件) } func initMiddlewareTwo(ctx *gin.Context) { fmt.Println(initMiddlewareTwo--1-执行中中间件) // 终止调用该请求的剩余处理程序 ctx.Abort() fmt.Println(initMiddlewareTwo--2-执行中中间件) } func main() { r : gin.Default() r.GET(/, initMiddlewareOne, initMiddlewareTwo, func(ctx *gin.Context) { fmt.Println(执行路由里面的程序) ctx.String(200, 首页--中间件演示) }) r.Run(:8080) } 控制台打印内容 initMiddlewareOne--1-执行中间件 initMiddlewareTwo--1-执行中间件 initMiddlewareTwo--2-执行中间件 initMiddlewareOne--2-执行中间件4、全局中间件package main import ( fmt github.com/gin-gonic/gin ) func initMiddleware(ctx *gin.Context) { fmt.Println(全局中间件 通过 r.Use 配置) // 调用该请求的剩余处理程序 ctx.Next() } func main() { r : gin.Default() r.Use(initMiddleware) r.GET(/, func(ctx *gin.Context) { ctx.String(200, 首页--中间件演示) }) r.GET(/news, func(ctx *gin.Context) { ctx.String(200, 新闻页面--中间件演示) }) r.Run(:8080) }5、在路由分组中配置中间件1、为路由组注册中间件有以下两种写法写法1shopGroup : r.Group(/shop, StatCost()) { shopGroup.GET(/index, func(c *gin.Context) {...}) ... }写法2shopGroup : r.Group(/shop) shopGroup.Use(StatCost()) { shopGroup.GET(/index, func(c *gin.Context) {...}) ... }2、分组路由AdminRoutes.go中配置中间件package routes import ( fmt gin_demo/controller/admin net/http github.com/gin-gonic/gin ) func initMiddleware(ctx *gin.Context) { fmt.Println(路由分组中间件) // 调用该请求的剩余处理程序 ctx.Next() } func AdminRoutesInit(router *gin.Engine) { adminRouter : router.Group(/admin, initMiddleware) { adminRouter.GET(/user, admin.UserController{}.Index) adminRouter.GET(/user/add, admin.UserController{}.Add) adminRouter.GET(/news, func(c *gin.Context) { c.String(http.StatusOK, news) }) } }6、中间件和对应控制器之间共享数据设置值ctx.Set(username, 张三)获取值username, _ : ctx.Get(username)中间件设置值func InitAdminMiddleware(ctx *gin.Context) { fmt.Println(路由分组中间件) // 可以通过 ctx.Set 在请求上下文中设置值后续的处理函数能够取到该值 ctx.Set(username, 张三) // 调用该请求的剩余处理程序 ctx.Next() }控制器获取值func (c UserController) Index(ctx *gin.Context) { username, _ : ctx.Get(username) fmt.Println(username) ctx.String(http.StatusOK, 这是用户首页 111) }7、中间件注意事项gin默认中间件gin.Default()默认使用了Logger和Recovery中间件其中• Logger 中间件将日志写入gin.DefaultWriter即使配置了GIN_MODErelease。• Recovery 中间件会recover任何panic。如果有panic的话会写入500响应码。如果不想使用上面两个默认的中间件可以使用gin.New()新建一个没有任何默认中间件的路由。gin中间件中使用goroutine当在中间件或handler中启动新的goroutine时不能使用原始的上下文c *gin.Context必须使用其只读副本c.Copy()r.GET(/, func(c *gin.Context) { cCp : c.Copy() go func() { // simulate a long task with time.Sleep(). 5 seconds time.Sleep(5 * time.Second) // 这里使用你创建的副本 fmt.Println(Done! in path cCp.Request.URL.Path) }() c.String(200, 首页) })8、Gin中自定义Model1、关于Model如果我们的应用非常简单的话我们可以在Controller里面处理常见的业务逻辑。但是如果我们有一个功能想在多个控制器、或者多个模板里面复用的话那么我们就可以把公共的功能单独抽取出来作为一个模块Model。Model是逐步抽象的过程一般我们会在Model里面封装一些公共的方法让不同Controller使用也可以在Model中实现和数据库打交道2、Model里面封装公共的方法新建models/ tools.gopackage models import ( crypto/md5 fmt time ) // 时间戳间戳转换成日期 func UnixToDate(timestamp int) string { t : time.Unix(int64(timestamp), 0) return t.Format(2006-01-02 15:04:05) } // 日期转换成时间戳 2020-05-02 15:04:05 func DateToUnix(str string) int64 { template : 2006-01-02 15:04:05 t, err : time.ParseInLocation(template, str, time.Local) if err ! nil { return 0 } return t.Unix() } func GetUnix() int64 { return time.Now().Unix() } func GetDate() string { template : 2006-01-02 15:04:05 return time.Now().Format(template) } func GetDay() string { template : 20060102 return time.Now().Format(template) } func Md5(str string) string { data : []byte(str) return fmt.Sprintf(%x\n, md5.Sum(data)) }3、控制器中调用Modelpackage controllers import ( gin_demo/models ) day : models.GetDay()4、调用Model注册全局模板函数models/tools.go//时间戳间戳转换成日期func UnixToDate(timestamp int64) string { t : time.Unix(timestamp, 0) return t.Format(2006-01-02 15:04:05) }main.go//注册全局模板函数 注意顺序注册模板函数需要在加载模板上面r : gin.Default() r.SetFuncMap(template.FuncMap{ unixToDate: models.UnixToDate, })控制器func (c UserController) Add(ctx *gin.Context) { ctx.HTML(http.StatusOK, admin/user/add.html, gin.H{ now: models.GetUnix(), }) }模板h2{{.now | unixToDate}}/h29、Golang Md5加密打开golang包对应的网站https://pkg.go.dev/搜索md5方法一data : []byte(123456) has : md5.Sum(data) md5str : fmt.Sprintf(%x, has) fmt.Println(md5str)方法二湖北众猿腾网络科技有限公司h : md5.New() io.WriteString(h, 123456) fmt.Printf(%x\n, h.Sum(nil))