Gin 路由 Router


路由是用来管理访问接口
gin 路由 使用 httprouter库 性能好 功能够用
请求方法
Gin 路由支持 GET POST PUT DELETE PATCH HEAD OPTIONS 一个 Any 函数  支持这7个方法请求
router.GET("/", func(context *gin.Context) {//Get 请求路由
    context.String(http.StatusOK, "get method")
})
router.POST("/", func(context *gin.Context) {//Post 请求路由
    context.String(http.StatusOK, "post method")
})
router.PUT("/", func(context *gin.Context) {//Put 请求路由
    context.String(http.StatusOK, "put method")
})
router.DELETE("/", func(context *gin.Context) {//Delete 请求路由
    context.String(http.StatusOK, "delete method")
})
router.PATCH("/", func(context *gin.Context) {//Patch 请求路由
    context.String(http.StatusOK, "patch method")
})
router.HEAD("/", func(context *gin.Context) {//Head 请求路由
    context.String(http.StatusOK, "head method")
})
router.OPTIONS("/", func(context *gin.Context) {//Options 请求路由
    context.String(http.StatusOK, "options method")
})
单元测试
func TestIndexPostRouter(t *testing.T) {
    r := initRouter.SetupRouter()
    w := httptest.NewRecorder()
    req, _ := http.NewRequest(http.MethodPost, "/", nil)
    r.ServeHTTP(w, req)
    assert.Equal(t, http.StatusOK, w.Code)
    assert.Equal(t, "post method", w.Body.String())
}
将公共逻辑抽取出来
func ginRouteMethod(context *gin.Context) {
 context.String(http.StatusOK, ""+strings.ToLower(context.Request.Method)+" method")
}
通过 context.Request.Method 将请求的方法提取出来  将其转化为小写 此时就可以改造 路由了 将原有的路由中的函数去掉换成 新的函数
router.GET("/", ginRouteMethod)
router.POST("/", ginRouteMethod)
router.PUT("/", ginRouteMethod)
router.DELETE("/", ginRouteMethod)
router.PATCH("/", ginRouteMethod)
router.HEAD("/", ginRouteMethod)
router.OPTIONS("/", ginRouteMethod)

Handler 处理器

路由需要传入两个参数 一个为路径
另一个为路由执行的方法 叫做处理器 Handler 是可变长参数 可以传入多个 handler 形成一条 handler chain  
handler 函数要求 该函数需要传入  Gin.Context 指针 通过该指针进行值 处理
Handler 函数可以对前端返回 字符串 Json Html 等多种格式或形式文件

获取路由路径中参数

从路由中获取参数 router.GET("/user/:name",handler.Save)
/: 该符号 表示后面的字符串为 占位符 用于将传值  此时 路由为 /user/{name}
把所有的 Handler 都写到一个文件夹中 会臃肿不堪
所以新建一个 handler文件夹 下建立 userHandler.go 文件
package handler
import (
"github.com/gin-gonic/gin"
"net/http"
)
func UserSave(context *gin.Context) {
username := context.Param("name")
context.String(http.StatusOK, "用户已经保存")
}用 context.Param 获取路由路径参数
user_test.go 文件
func TestUserSave(t *testing.T) {
    username := "lisi"
    router := initRouter.SetupRouter()
    w := httptest.NewRecorder()
    req, _ := http.NewRequest(http.MethodGet, "/user/"+username, nil)
    router.ServeHTTP(w, req)
    assert.Equal(t, http.StatusOK, w.Code)
    assert.Equal(t, "用户"+username+"已经保存", w.Body.String())
}浏览器中输入 localhost:8080/user/lisi 页面显示 用户lisi已经保存
针对不同的路由 Gin 不同的获取参数的方法  形如 /user?name=lisi&age=18
添加一个 Handler 做为处理 在 userHandler.go 文件 中添加
//通过 query 方法进行获取参数
func UserSaveByQuery(context *gin.Context) {
    username := context.Query("name")
    age := context.Query("age")
    context.String(http.StatusOK, "用户:"+username+",年龄:"+age+"已经保存")
}

路由

router.GET("/user", handler.UserSaveByQuery)
单元测试
func TestUserSaveQuery(t *testing.T) {
    username := "lisi"
    age := 18
    router := initRouter.SetupRouter()
    w := httptest.NewRecorder()
    req, _ := http.NewRequest(http.MethodGet, "/user?name="+username+"&age="+strconv.Itoa(age), nil)
    router.ServeHTTP(w, req)
    assert.Equal(t, http.StatusOK, w.Code)
    assert.Equal(t, "用户:"+username+",年龄:"+strconv.Itoa(age)+"已经保存", w.Body.String())
}
浏览器访问 localhost:8080/user?name=lisi 页面上打印 用户:lisi,年龄:18已经保存  
可以通过 context.DefaultQuery 方法  赋 该值默认值
age := context.DefaultQuery("age", "20")
单元测试
func TestUserSaveWithNotAge(t *testing.T) {
    username := "lisi"
    router := initRouter.SetupRouter()
    w := httptest.NewRecorder()
    req, _ := http.NewRequest(http.MethodGet, "/user?name="+username, nil)
    router.ServeHTTP(w, req)
    assert.Equal(t, http.StatusOK, w.Code)
    assert.Equal(t, "用户:"+username+",年龄:20已经保存", w.Body.String())
}浏览器访问 /user?name=lisi 可以看到浏览器上显示 用户:lisi,年龄:20已经保存  
QueryArray 获取数组和 QueryMap 获取 map

路由分组

SetupRouter 方法时 里面的路由基本可以分为两大类 / 和 /user
如果功能的添加 会出现大量的路由 所以 需要对路由进行管理  Gin提供了路由分组
先把 / 的路由写到一起 运行 index_test.go 单元测试
index := router.Group("/"){
    index.GET("", ginRouteMethod)
    index.POST("", ginRouteMethod)
    index.PUT("", ginRouteMethod)
    index.DELETE("", ginRouteMethod)
    index.PATCH("", ginRouteMethod)
    index.HEAD("", ginRouteMethod)
    index.OPTIONS("", ginRouteMethod)
}通过 router.Group 返回一个新的分组路由 通过新的分组路由把之前的路由进行简单的修改 当然分组里面仍旧可以嵌套分组
Any 函数可以通过任何请求 此时可以把 index 里面所有的请求替换为 Any
index := router.Group("/"){
    index.Any("", ginRouteMethod)
}
把 user 分组 分组不仅仅是将相同逻辑的代码放到一起 而且可以提供相同的路由前缀 修改后的路由仍旧和之前一致
运行单元测试 user_test.go 单元测试可以完全通过
userRouter := router.Group("/user"){
    userRouter.GET("/:name", handler.UserSave)
    userRouter.GET("", handler.UserSaveByQuery)
}