GinGin custom controller and middleware

Article directory

    • Gin custom controller
      • controller layering
      • controller inheritance
    • Gin middleware
      • routing middleware
      • c.Next() calls the remaining handlers for the request
      • A route configures the execution order of multiple middleware
      • global middleware
      • Configure middleware in route grouping
      • Data sharing between middleware and corresponding controllers
      • Middleware Considerations

Gin custom controller

Controller layering

When the project is relatively large, it is necessary to group the controllers

Create a new controller in the root directory of the project, and create a new admin user … folder in the controller

Create a new indexController.go userController.go file in the admin file

indexController.go

package admin

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

type IndexController struct {<!-- -->
}

func (con IndexController) Index(c *gin.Context) {<!-- -->
c.String(200, "background page")
}

userController.go

package admin

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

type UserController struct {<!-- -->
}

func (con UserController) Index(c *gin.Context) {<!-- -->
c.String(200, "User List")
}
func (con UserController) Add(c *gin.Context) {<!-- -->
c.String(200, "User List---add")
}
func (con UserController) Edit(c *gin.Context) {<!-- -->
c.String(200, "User List---edit")
}

under the routes folder

Configure the corresponding route-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)

}
}

Controller Inheritance

1. Create a new 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, "Success")

}
func (con BaseController) error(c *gin.Context) {<!-- -->
c.String(200, "Failed")
}

2. userController inherits baseController

package admin

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

type UserController struct {<!-- -->
BaseController
}

func (con UserController) Index(c *gin.Context) {<!-- -->
//c.String(200, "User List")
con. success(c)
}
func (con UserController) Add(c *gin.Context) {<!-- -->
c.String(200, "User List---add")
}
func (con UserController) Edit(c *gin.Context) {<!-- -->
c.String(200, "User List---edit")
}

Gin middleware

Middleware is a series of operations performed before matching routes and after matching routes

Routing middleware

The middleware in Gin must be a gin.HandlerFunc type. When configuring the route, you can pass multiple func callback functions. The functions triggered before the last func callback function can be called middleware.

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, "Homepage")
})
r.GET("/news", InitMessage, func(c *gin.Context) {<!-- -->
c.String(200, "News")
})

r.Run()
}

c.Next() calls the remaining handlers for the request

Adding c.Next() to the middleware allows us to perform some operations after the route matching is completed

Count the execution time of a request

package main

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

func InitMessage(c *gin.Context) {<!-- -->
fmt.Println("111")
start := time. Now(). Nanosecond()
// call the remaining handlers for the request
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, "Homepage")
})
r.GET("/news", InitMessage, func(c *gin.Context) {<!-- -->
c.String(200, "News")
})

r.Run()
}

A route configures the execution order of multiple middleware

When there are multiple middleware in a request, what is the execution order?

Various messages can be printed to the console to determine the order in which programs are executed.

package main

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

func InitMiddlewareOne(c *gin.Context) {<!-- -->
fmt.Println("1")
// call the remaining handlers for the request
c. Next()
fmt.Println("2")

}

func InitMiddlewareTwo(c *gin.Context) {<!-- -->
fmt.Println("3")
// call the remaining handlers for the request
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("Homepage...")
c.String(200, "Homepage")
})
r.GET("/news", InitMiddlewareOne, InitMiddlewareTwo, func(c *gin.Context) {<!-- -->
c.String(200, "News")
})

r.Run()
}


Console content:

1
3
front page...
4
2

Global middleware

You can use r.Use(middleware name) to define global middleware

package main

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

func InitMiddleware(c *gin.Context) {<!-- -->
fmt.Println("1")
// call the remaining handlers for the request
c. Next()
fmt.Println("2")

}

func main() {<!-- -->
r := gin. Default()
r.LoadHTMLGlob("templates/*")
r.Static("/static", "./static")
// define global middleware
r.Use(InitMiddleware)
r.GET("/", func(c *gin.Context) {<!-- -->
fmt.Println("Homepage...")
c.String(200, "Homepage")
})
r.GET("/news", func(c *gin.Context) {<!-- -->
c.String(200, "News")
})

r.Run()
}

Configure middleware in routing group

Create a new middlewares folder in the project root directory and create a new middleware

package middlewares

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

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

Routing files in the routes file use middleware

package routes

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

func AdminRoutesInit(r *gin.Engine) {<!-- -->
// use middleware
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)

}
}

Share data between middleware and corresponding controller

Set value in middleware

package middlewares

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

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

Get the value in the controller

package admin

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

type UserController struct {<!-- -->
BaseController
}

func (con UserController) Index(c *gin.Context) {<!-- -->
//c.String(200, "User List")
//con. success(c)
username, _ := c. Get("username")
v, ok := username.(string)
if ok {<!-- -->
c. String(200, v)
} else {<!-- -->
c.String(200, "Failed to get user")
}
fmt.Println("username==>", username)
}
func (con UserController) Add(c *gin.Context) {<!-- -->
c.String(200, "User List---add")
}
func (con UserController) Edit(c *gin.Context) {<!-- -->
c.String(200, "User List---edit")
}

Middleware Considerations

1. gin.Default() uses Logger and Recovery middleware by default, among which:

  • Logger middleware writes logs to gin.DefaultWriter even if GIN_MODE=release is configured.
  • Recovery middleware will recover any panic. If there is a panic, a 500 response code will be written.

If you don’t want to use the above two default middleware, you can use gin.New() to create a new route without any default middleware. Generally, gin.Default() is recommended.

2. When starting a new goroutine in middleware or handler, the original context (c *gin.Context) cannot be used, its read-only copy (c.Copy()) must be used

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)
        // use the copy you created here
        fmt.Println("Done! in path " + cCp.Request.URL.Path)
    }()
    c.String(200, "Homepage")
})