【Gin】Gin 自定义控制器与中间件


作者的 Gin 框架学习是根据 B站视频 Gin教程_Golang框架Gin入门实战教程 来学习的,对大地老师的评价不吹不捧,很喜欢其讲课风格,而且这个视频特别适合小白学习,强烈推荐。

Gin 自定义控制器

控制器分层

当项目比较大的时候有必要对控制器进行分组

在项目根目录下新建 controller ,在 controller 中新建 admin user … 文件夹

在 admin 文件当中新建 indexController.go userController.go文件

indexController.go

package admin

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

type IndexController struct {
}

func (con IndexController) Index(c *gin.Context) {
	c.String(200, "后台页面")
}

userController.go

package admin

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

type UserController struct {
}

func (con UserController) Index(c *gin.Context) {
	c.String(200, "用户列表")
}
func (con UserController) Add(c *gin.Context) {
	c.String(200, "用户列表---add")
}
func (con UserController) Edit(c *gin.Context) {
	c.String(200, "用户列表---edit")
}

routes 文件夹下

配置对应的路由—adminRoutes.go

package routes

import (
	"Gin_demo/controllers/admin"
	"github.com/gin-gonic/gin"
)

func AdminRoutesInit(r *gin.Engine) {
	adminRoutes := r.Group("/admin")
	{
		adminRoutes.GET("/", admin.IndexController{}.Index)
        
        adminRoutes.GET("/user", admin.UserController{}.Index)

		adminRoutes.GET("/user/add", admin.UserController{}.Add)

		adminRoutes.GET("/user/edit", admin.UserController{}.Edit)

	}
}

控制器的继承

1、新建 controller/admin/baseController.go

package admin

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

type BaseController struct {
}

func (con BaseController) success(c *gin.Context) {
	c.String(200, "成功")

}
func (con BaseController) error(c *gin.Context) {
	c.String(200, "失败")
}

2、userController 继承 baseController

package admin

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

type UserController struct {
	BaseController
}

func (con UserController) Index(c *gin.Context) {
	//c.String(200, "用户列表")
	con.success(c)
}
func (con UserController) Add(c *gin.Context) {
	c.String(200, "用户列表---add")
}
func (con UserController) Edit(c *gin.Context) {
	c.String(200, "用户列表---edit")
}

Gin 中间件

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

路由中间件

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

package main

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

func InitMessage(c *gin.Context) {
	fmt.Println("111")
}

func main() {
	r := gin.Default()
	r.LoadHTMLGlob("templates/*")
	r.Static("/static", "./static")
	r.GET("/", InitMessage, func(c *gin.Context) {
		c.String(200, "首页")
	})
	r.GET("/news", InitMessage, func(c *gin.Context) {
		c.String(200, "新闻")
	})

	r.Run()
}

c.Next() 调用该请求的剩余处理程序

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

统计一个请求的执行时间

package main

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

func InitMessage(c *gin.Context) {
	fmt.Println("111")
	start := time.Now().Nanosecond()
	// 调用该请求的剩余处理程序
	c.Next()
	end := time.Now().Nanosecond()
	fmt.Println(end - start)
}

func main() {
	r := gin.Default()
	r.LoadHTMLGlob("templates/*")
	r.Static("/static", "./static")
	r.GET("/", InitMessage, func(c *gin.Context) {
		c.String(200, "首页")
	})
	r.GET("/news", InitMessage, func(c *gin.Context) {
		c.String(200, "新闻")
	})

	r.Run()
}

一个路由配置多个中间件的执行顺序

当一个请求中存在多个中间件,其执行顺序又是如何呢?

可以在控制台中打印不同的信息来确定程序的执行顺序。

package main

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

func InitMiddlewareOne(c *gin.Context) {
	fmt.Println("1")
	// 调用该请求的剩余处理程序
	c.Next()
	fmt.Println("2")

}

func InitMiddlewareTwo(c *gin.Context) {
	fmt.Println("3")
	// 调用该请求的剩余处理程序
	c.Next()
	fmt.Println("4")

}
func main() {
	r := gin.Default()
	r.LoadHTMLGlob("templates/*")
	r.Static("/static", "./static")
	r.GET("/", InitMiddlewareOne, InitMiddlewareTwo, func(c *gin.Context) {
		fmt.Println("首页...")
		c.String(200, "首页")
	})
	r.GET("/news", InitMiddlewareOne, InitMiddlewareTwo, func(c *gin.Context) {
		c.String(200, "新闻")
	})

	r.Run()
}


控制台内容:

1
3
首页...
4
2

全局中间件

可以使用r.Use(中间件名称)来定义全局中间件

package main

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

func InitMiddleware(c *gin.Context) {
	fmt.Println("1")
	// 调用该请求的剩余处理程序
	c.Next()
	fmt.Println("2")

}

func main() {
	r := gin.Default()
	r.LoadHTMLGlob("templates/*")
	r.Static("/static", "./static")
	// 定义全局中间件
	r.Use(InitMiddleware)
	r.GET("/", func(c *gin.Context) {
		fmt.Println("首页...")
		c.String(200, "首页")
	})
	r.GET("/news", func(c *gin.Context) {
		c.String(200, "新闻")
	})

	r.Run()
}

在路由分组中配置中间件

在项目根目录下新建 middlewares 文件夹,并新建中间件

package middlewares

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

func InitMiddleware(c *gin.Context) {
	fmt.Println(time.Now())
	fmt.Println(c.Request.URL)
}

在 routes 文件中的路由文件使用中间件

package routes

import (
	"Gin_demo/controllers/admin"
	"Gin_demo/middlewares"
	"github.com/gin-gonic/gin"
)

func AdminRoutesInit(r *gin.Engine) {
	// 使用中间件
	adminRoutes := r.Group("/admin", middlewares.InitMiddleware)
	{
		adminRoutes.GET("/", admin.IndexController{}.Index)

		adminRoutes.GET("/user", admin.UserController{}.Index)

		adminRoutes.GET("/user/add", admin.UserController{}.Add)

		adminRoutes.GET("/user/edit", admin.UserController{}.Edit)

		adminRoutes.GET("/article", admin.ArticleController{}.Index)

		adminRoutes.GET("/article/add", admin.ArticleController{}.Add)

		adminRoutes.GET("/article/edit", admin.ArticleController{}.Edit)

	}
}

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

在中间件当中设置值

package middlewares

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

func InitMiddleware(c *gin.Context) {
	c.Set("username", "zhangsan")
}

在控制器当中获取值

package admin

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

type UserController struct {
	BaseController
}

func (con UserController) Index(c *gin.Context) {
	//c.String(200, "用户列表")
	//con.success(c)
	username, _ := c.Get("username")
	v, ok := username.(string)
	if ok {
		c.String(200, v)
	} else {
		c.String(200, "获取用户失败")
	}
	fmt.Println("username==>", username)
}
func (con UserController) Add(c *gin.Context) {
	c.String(200, "用户列表---add")
}
func (con UserController) Edit(c *gin.Context) {
	c.String(200, "用户列表---edit")
}

中间件注意事项

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

  • Logger 中间件将日志写入 gin.DefaultWriter,即使配置了 GIN_MODE=release。
  • Recovery 中间件会 recover 任何 panic 。如果有 panic 的话,会写入 500 响应码。

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

2、当在中间件或 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, "首页")
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值