• gin中间件&控制器&model


    中间件#

    Gin 框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。

    通俗的讲:中间件就是匹配路由前和匹配路由完成后执行的一系列操作

    路由中间件#

    Gin 中的中间件必须是一个 gin.HandlerFunc 类型,配置路由的时候可以传递多个 func 回调函数,最后一个 func 回调函数前面触发的方法都可以称为中间件

    // 请求方式的源码参数,... 可以传入多个func(context *gin.Context)
    // 可以在func(context *gin.Context)之前传入自定义的一些处理方法
    (relativePath string, handlers ...HandlerFunc)
    
    定义和使用路由中间件#
    写法一#
    // 定义一个中间件要执行的方法
    func MiddlewareFunc() {
    	fmt.Println("中间件方法")
    
    }
    
    func ApiRoutersInit(router *gin.Engine) {
    
    	apiRouter := router.Group("api")
    	{
    		apiRouter.GET("list",
    			func(context *gin.Context) {
    				// 请求前执行中间件方法
    				MiddlewareFunc()
    			},
    			// 执行请求
    			func(context *gin.Context) {
    				context.String(http.StatusOK, "ok")
    
    			})
    
    	}
    }
    
    
    写法二#
    // 定义一个中间件要执行的方法
    func MiddlewareFunc(context *gin.Context) {
    	fmt.Println("中间件方法")
    
    }
    
    func ApiRoutersInit(router *gin.Engine) {
    
    	apiRouter := router.Group("api")
    	{	
    		// 写法二
    		apiRouter.GET("list", MiddlewareFunc,func(context *gin.Context) {
    				context.String(http.StatusOK, "ok")
    
    			})
    
    	}
    }
    
    
    ctx.Next()#

    中间件里面加上 ctx.Next()可以让我们在路由匹配完成后执行一些操作

    func MiddlewareFunc(context *gin.Context) {
    	
    	fmt.Println("请求执行前")
      // 调用该请求的剩余处理程序
    	context.Next() 
      // 执行后面的func(context *gin.Context)方法
      // 每调用一次	context.Next() ,向后执行一个func(context *gin.Context)
      
      // 执行完之后再执行打印
    	fmt.Println("请求执行完成")
    
    
    }
    
    ctx.Abort#

    Abort 是终止的意思, ctx.Abort() 表示终止调用该请求的剩余处理程序

    func MiddlewareFunc(context *gin.Context) {
    	fmt.Println("aaa")
    	// 终止该请求的剩余处理程序 
    	context.Abort()
    	fmt.Println("这里继续打印")
      
      
    
    
    }
    

    全局中间件#

    func main() {
    	router := gin.Default()
    
    	// 在匹配路由之前配置全局中间件
    
    	// 使用Use配置全局中间件,参数就是中间件方法,可以传入多个,
    	router.Use(MiddlewareFunc1,MiddlewareFunc2)
    
    	router.GET("/", func(context *gin.Context) {
    		context.String(http.StatusOK, "ok")
    
    	})
    
    	// 将默认引擎传给其他文件定义的接收引擎的方法
    	api.ApiRoutersInit(router)
    	router.Run()
    
    }
    
    

    路由分组中间件#

    方法一#
    func ApiRoutersInit(router *gin.Engine) {
    	// 在路由分组的Group后配置中间件
    	apiRouter := router.Group("api",MiddlewareFunc)
    	{
    		apiRouter.GET("list",
    			// 执行请求
    			func(context *gin.Context) {
    				context.String(http.StatusOK, "ok")
    
    			})
    
    	}
    }
    
    
    方法二#
    func ApiRoutersInit(router *gin.Engine) {
    	apiRouter := router.Group("api")
    	// 调用group对象 配置中间件
    	apiRouter.Use(MiddlewareFunc)
    	{
    		apiRouter.GET("list",
    			// 执行请求
    			func(context *gin.Context) {
    				context.String(http.StatusOK, "ok")
    
    			})
    
    	}
    }
    
    

    中间件和对应控制器共享数据#

    // 中间件
    
    func MiddlewareFunc(context *gin.Context) {
    	// 通过Set设置一个数据 k,v
    	context.Set("name", "li")
    
    }
    
    // 控制器
    func (a ApiController) ApiSetInfo(context *gin.Context) {
      // 通过.Get(key) 获取值,获取到的是一个any类型的值和是否异常的bool
    	username, _ := context.Get("name")
    	// 通过类型断言获取string类型的name
    	name, _ := username.(string)
    	context.String(http.StatusOK, name)
    }
    
    

    中间件注意事项#

    gin默认中间件#

    gin.Default()默认使用了 Logger 和 Recovery 中间件,其中:

    • Logger 中间件将日志写入 gin.DefaultWriter,即使配置了 GIN_MODE=release。

    • Recovery 中间件会 recover 任何 panic。如果有 panic 的话,会写入 500 响应码。

    如果不想使用上面两个默认的中间件,可以使用 gin.New()新建一个没有任何默认中间件的路由

    中间件中使用协程#

    当在中间件或 handler 中启动新的 goroutine 时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy())

    func MiddlewareFunc(context *gin.Context) {
    	c := context.Copy()
    
    	go func() {
    		fmt.Println("url是", c.Request.URL)
    	}()
    
    	go func() {
    		fmt.Println("body是", c.Request.Body)
    	}()
    
    }
    	// 不需要wait等待协程完成,因为主程序main.go会一直执行
    
    

    model#

    如果我们的应用非常简单的话,我们可以在 Controller 里面处理常见的业务逻辑。但是如果我们有一个功能想在多个控制器、或者多个模板里面复用的话,那么我们就可以把公共的功能单独抽取出来作为一个模块(Model)。 Model 是逐步抽象的过程,一般我们会在 Model里面封装一些公共的方法让不同 Controller 使用,也可以在 Model 中实现和数据库的交互

    自定义一个models包,把通用的一些功能抽离来封装好,供其他地方调用,简单说models的概念就是封装一些公共方法

    /*
    
    */
    package models
    
    import "time"
    
    // 将时间戳转换为日期
    func UnixToTime(timestamp int) string {
    	t := time.Unix(int64(timestamp), 0)
    	return t.Format("2006-01-02 15:04:05")
    }
    
    
  • 相关阅读:
    JAVA注解
    【微服务】安装docker以及可视化界面
    uniapp项目,使用HbuilderX建立eslint规范
    在RockyLinux 9.3环境中采用RPM模式部署Oracle 19C
    TorchScript学习使用
    YOLO-World:实时开放词汇目标检测
    C++函数内联详解
    如何选择最适合你的LLM优化方法:全面微调、PEFT、提示工程和RAG对比分析
    Python正则表达式
    根据SpringBoot Guides完成进行示例学习(详细步骤)
  • 原文地址:https://www.cnblogs.com/Mickey-7/p/18036593