In the last article we modified the routing group
package routes
//routes/routes.go
import (
"github.com/gin-gonic/gin"
"myGin/controller"
)
func Load(r *gin.Engine) {
router := newRouter(r)
router.Group("/api".func(api group) {
api.Group("/user".func(user group) {
user.Registered(GET, "/info", controller.Index)
user.Registered(GET, "/order", controller.Index)
user.Registered(GET, "/money", controller.Index)
})
})
}
Copy the code
But there’s a problem with writing this, we can’t use middleware, we need to fix it to support middleware and the middleware context is our actual context.
Start by defining HandlerFunc as a middleware function in the context
package context
//context/context.go
import (
"github.com/gin-gonic/gin"
"strings"
)
type Context struct {
*gin.Context
}
type HandlerFunc func(*Context)
func (c *Context) Domain(a) string {
return c.Request.Host[:strings.Index(c.Request.Host, ":")]}Copy the code
Then modify router.go and add middleware parameters
package routes
////routes/router.go
import (
"github.com/gin-gonic/gin"
"myGin/context"
"myGin/response"
)
type router struct {
engine *gin.Engine
}
type group struct {
engine *gin.Engine
path string
middlewares []context.HandlerFunc
}
type method int
const (
GET method = 0x000000
POST method = 0x000001
PUT method = 0x000002
DELETE method = 0x000003
ANY method = 0x000004
)
func newRouter(engine *gin.Engine) *router {
return &router{
engine: engine,
}
}
func (r *router) Group(path string, callback func(group).middlewares.context.HandlerFunc) {
callback(group{
engine: r.engine,
path: path,
middlewares: middlewares,
})
}
func (g group) Group(path string, callback func(group).middlewares.context.HandlerFunc) {
// Note that the parent middleware comes first
g.middlewares = append(g.middlewares, middlewares...)
g.path += path
callback(g)
}
func (g group) Registered(method method, url string, action func(*context.Context) *response.Response.middlewares.context.HandlerFunc) {
// Parent middleware + current action middleware +action
var handlers = make([]gin.HandlerFunc, len(g.middlewares)+len(middlewares)+1)
// Add the current action's middleware
g.middlewares = append(g.middlewares, middlewares...)
// Convert the middleware to gin.HandlerFunc
for key, middleware := range g.middlewares {
temp := middleware
handlers[key] = func(c *gin.Context) {
temp(&context.Context{Context: c})
}
}
/ / add the action
handlers[len(g.middlewares)] = convert(action)
finalUrl := g.path + url
switch method {
case GET:
g.engine.GET(finalUrl, handlers...)
case POST:
g.engine.GET(finalUrl, handlers...)
case PUT:
g.engine.PUT(finalUrl, handlers...)
case DELETE:
g.engine.DELETE(finalUrl, handlers...)
caseANY: g.engine.Any(finalUrl, handlers...) }}func convert(f func(*context.Context) *response.Response) gin.HandlerFunc {
return func(c *gin.Context) {
resp := f(&context.Context{Context: c})
data := resp.GetData()
switch item := data.(type) {
case string:
c.String(200, item)
case gin.H:
c.JSON(200, item)
}
}
}
Copy the code
The implementation principle is to continuously add parent middleware through callback, count all middleware quantity in Registered, and add route to GIN after conversion.
Let’s test it out
Create the Middleware directory in your project and create middleware.go
package middleware
//middleware/middleware.go
import (
"fmt"
"myGin/context"
)
func M1(c *context.Context) {
fmt.Println("I am 1")}func M2(c *context.Context) {
fmt.Println("I'm a 2")}func M3(c *context.Context) {
fmt.Println("I'm a 3")}Copy the code
package routes
//routes/routes.go
import (
"github.com/gin-gonic/gin"
"myGin/controller"
"myGin/middleware"
)
func Load(r *gin.Engine) {
router := newRouter(r)
router.Group("/api".func(api group) {
api.Group("/user".func(user group) {
user.Registered(GET, "/info", controller.Index, middleware.M3)
user.Registered(GET, "/order", controller.Index)
user.Registered(GET, "/money", controller.Index)
}, middleware.M2)
}, middleware.M1)
}
Copy the code
Run browser, console print
In general, Web frameworks come with some global middleware, such as global error capture middleware, which we continue to encapsulate
Start by creating an error-catching middleware
package exception
import (
"fmt"
"myGin/context"
"runtime/debug"
)
func Exception(c *context.Context) {
defer func(a) {
if r := recover(a); r ! =nil {
msg := fmt.Sprint(r) + "\n" + string(debug.Stack())
c.String(500, msg)
c.Abort()
}
}()
c.Next()
}
Copy the code
Create a kernel under the project and create the kernel.go file
package kernel
import (
"myGin/context"
"myGin/middleware/exception"
)
// Middleware Global Middleware
var Middleware []context.HandlerFunc
func Load(a) {
Middleware = []context.HandlerFunc{
exception.Exception,
}
}
Copy the code
Load the global middleware in main.go
package main
import (
"github.com/gin-gonic/gin"
"myGin/kernel"
"myGin/routes"
)
func main(a) {
r := gin.Default()
// Load global variables
kernel.Load()
routes.Load(r)
r.Run()
}
Copy the code
Let’s change routes.go
package routes
//routes/routes.go
import (
"github.com/gin-gonic/gin"
"myGin/controller"
"myGin/kernel"
)
func config(router group) {
router.Group("/api".func(api group) {
api.Group("/user".func(user group) {
user.Registered(GET, "/info", controller.Index)
user.Registered(GET, "/order", controller.Index)
user.Registered(GET, "/money", controller.Index)
})
})
}
func Load(r *gin.Engine) {
router := newRouter(r)
router.Group("".func(g group) {
config(g)
}, kernel.Middleware...) // Load global middleware
}
Copy the code
The main idea is to use an empty route to load a global middleware to this empty route
Modify index controller to simulate an error
package controller
//controller/Index.go
import (
"myGin/context"
"myGin/response"
)
func Index(context *context.Context) *response.Response {
panic("Pretending to be wrong")
return response.Resp().String(context.Domain())
}
Copy the code
Accessing the browser
Source code address: github.com/PeterYangs/…