更多文章 狂点

经过上一章节的介绍,搭建一个简单的 Gin web 项目非常容易,同时也引入了一些新的概念,比如说:路由 Router。

路由是一个非常重要的概念,所有的接口都要有路由来进行管理。

请求方法

Gin 的路由支持 GET , POST , PUT , DELETE , PATCH , HEAD , OPTIONS 请求,同时还有一个 Any 函数,可以同时支持以上的所有请求。

将上一章节的代码添加其他请求方式的路由,并编写单元测试。

// 省略其他代码

// 添加 Get 请求路由

router.GET("/", func(context *gin.Context) {

context.String(http.StatusOK, "hello gin get method")

})

// 添加 Post 请求路由

router.POST("/", func(context *gin.Context) {

context.String(http.StatusOK, "hello gin post method")

})

// 添加 Put 请求路由

router.PUT("/", func(context *gin.Context) {

context.String(http.StatusOK, "hello gin put method")

})

// 添加 Delete 请求路由

router.DELETE("/", func(context *gin.Context) {

context.String(http.StatusOK, "hello gin delete method")

})

// 添加 Patch 请求路由

router.PATCH("/", func(context *gin.Context) {

context.String(http.StatusOK, "hello gin patch method")

})

// 添加 Head 请求路由

router.HEAD("/", func(context *gin.Context) {

context.String(http.StatusOK, "hello gin head method")

})

// 添加 Options 请求路由

router.OPTIONS("/", func(context *gin.Context) {

context.String(http.StatusOK, "hello gin options method")

})

// 省略其他代码

单元测试,只展示一个 Post 请求函数,基本与 Get 请求一致,其他代码详见文末 Github 地址。

// router("/") post 测试

func TestIndexPostRouter(t *testing.T) {

router := initRouter.SetupRouter()

w := httptest.NewRecorder()

req, _ := http.NewRequest(http.MethodPost, "/", nil)

router.ServeHTTP(w, req)

assert.Equal(t, http.StatusOK, w.Code)

assert.Equal(t, "hello gin post method", w.Body.String())

}

此时运行单元测试,所有测试完美通过。

但是也有一个问题,所有的请求对应的路由内函数基本一样,只是有细微的差别,但是我们却每个路由里都完完整整的写了一遍,所以我们要将公共逻辑抽取出来。

func retHelloGinAndMethod(context *gin.Context) {

context.String(http.StatusOK, "hello gin "+strings.ToLower(context.Request.Method)+" method")

}

我们将方法的公共部分抽取出来,并通过 context.Request.Method 将请求的方法提取出来 ,并将其转化为小写。此时就可以改造我们的路由了,将原有的路由中的函数去掉换成我们所编写的新的函数。

// 添加 Get 请求路由

router.GET("/", retHelloGinAndMethod)

// 添加 Post 请求路由

router.POST("/", retHelloGinAndMethod)

// 添加 Put 请求路由

router.PUT("/", retHelloGinAndMethod)

// 添加 Delete 请求路由

router.DELETE("/", retHelloGinAndMethod)

// 添加 Patch 请求路由

router.PATCH("/", retHelloGinAndMethod)

// 添加 Head 请求路由

router.HEAD("/", retHelloGinAndMethod)

// 添加 Options 请求路由

router.OPTIONS("/", retHelloGinAndMethod)

此时运行单元测试,仍旧是完美通过。

Handler 处理器

经过上面简单的例子的演示和操作,现在我们大概可以了解到路由需要传入两个参数,一个为路径,另一个为路由执行的方法,我们叫做它处理器 Handler ,而且,该参数是可变长参数。也就是说,可以传入多个 handler,形成一条 handler chain 。

同时对 handler 该函数有着一些要求,该函数需要传入一个 Gin.Context 指针,同时要通过该指针进行值得处理。

Handler 函数可以对前端返回 字符串,Json,Html 等多种格式或形式文件,之后我们会慢慢逐一介绍。

获取路由路径中参数

知道了路由支持的方法和对应的处理器,那么接下来就应该了解如何从路由中获取参数。

编写一个新的路由,如下:

//省略其他代码

// 添加 user

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 中添加下面的方法。

// 通过 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("/")

{

// 添加 Get 请求路由

index.GET("", retHelloGinAndMethod)

// 添加 Post 请求路由

index.POST("", retHelloGinAndMethod)

// 添加 Put 请求路由

index.PUT("", retHelloGinAndMethod)

// 添加 Delete 请求路由

index.DELETE("", retHelloGinAndMethod)

// 添加 Patch 请求路由

index.PATCH("", retHelloGinAndMethod)

// 添加 Head 请求路由

index.HEAD("", retHelloGinAndMethod)

// 添加 Options 请求路由

index.OPTIONS("", retHelloGinAndMethod)

}

通过 router.Group 返回一个新的分组路由,通过新的分组路由把之前的路由进行简单的修改。当然分组里面仍旧可以嵌套分组。

之前在请求方法中说到有一个 Any 函数可以通过任何请求,此时我们就可以把 index 里面所有的请求替换为 Any

index := router.Group("/")

{

index.Any("", retHelloGinAndMethod)

}

运行单元测试,测试都可以通过。

此时也发现了单元测试的好处,虽说之前花费了时间和经历编写了单元测试,但是日后的功能上修改,只需要进行运行单元测试就可以知道我们的功能是否正确,在后期的功能测试上大大减少了经历和时间。

同样我们把 user 也进行分组,分组不仅仅是将相同逻辑的代码放到一起,而且可以提供相同的路由前缀,修改后的路由仍旧和之前一致。运行单元测试 user_test.go ,单元测试可以完全通过,证明我们的代码没有问题。

userRouter := router.Group("/user")

{

userRouter.GET("/:name", handler.UserSave)

userRouter.GET("", handler.UserSaveByQuery)

}

总结

通过简单的路由的使用,基本明白了路由在 Gin 中的地位,也对一些常见的使用方式有了一些直观的认识。

本章节代码

gin路由打开html页面,Gin(二):使用路由相关推荐

  1. 纯前端实现一键生成二维码,打开新页面展示二维码

    如何实现这个需求呢首先我们需要生成二维码,而且要打开一个新的页面展示,那么我们需要img标签来展示图片的载体,那么生成图片src必不可少的.无论我们的项目是spa,还是多页面应用,我们这里都要用bas ...

  2. vuejs中如何实现三级路由并刷新页面时保持当前路由激活状态

    虽互不曾谋面,但希望能和您成为笔尖下的朋友 以读书,技术,生活为主,偶尔撒点鸡汤 不作,不敷衍,意在真诚吐露,用心分享 点击左上方,可关注本刊 标星公众号(ID:itclanCoder) 如果不知道如 ...

  3. vue缓存页面【二】

    keep-alive是vue内置的一个组件,可以使被它包含的组件处于保留状态,或避免被重新渲染. 用法: 运行结果描述: input输入框内,路由切换输入框内部的内容不会发生改变. 在keep-ali ...

  4. gin context和官方context_gin 源码阅读(二) 路由和路由组

    " 上一篇讲的是gin 框架的启动原理,今天来讲一下 gin 路由的实现. 1 用法 还是老样子,先从使用方式开始: func main() { r := gin.Default() r.G ...

  5. html在父窗口中打开新页面跳转,路由跳转、打开新窗口、跳转到新页面

    基础不扎实,温故知新下 方案一: getDescribe(id) { // 直接调用$router.push 实现携带参数的跳转 this.$router.push({ path: `/describ ...

  6. 【gin学习笔记】05 gin的中间件和路由分组

    本文学习视频https://www.bilibili.com/video/BV18C4y1p7Fe/?spm_id_from=333.788 什么是路由分组 对router创建group就是分组,同一 ...

  7. vue 路由跳转并打开新页面

    let id ='123'; const {href} = this.$router.resolve( { path: '/home/test',query: {id: id}} ) window.o ...

  8. 若依 vue前端 动态设置路由path不同参数 在页面容器里打开新页面(新路由),面包屑和标签页标题根据参数动态改变,面包屑多级标题,侧边栏对应菜单亮起

    前言 因为是在vue源码的基础上进行修改,所以,就没有复制代码在文章上,采取的是截图对比源码和我修改的代码片段.要麻烦你们自己手敲了. 先来看看效果: 场景:在费用配置列表中,点击每一项的配置,都会在 ...

  9. golang gin框架源码分析(二)---- 渐入佳境 摸索Engine ServeHTTP访问前缀树真正原理

    文章目录 全系列总结博客链接 前引 golang gin框架源码分析(二)---- 渐入佳境 摸索Engine ServeHTTP访问前缀树真正远原理 1.再列示例代码 从示例代码入手 2.r.Run ...

最新文章

  1. 屏幕为什么要正负压供电_负压变换器的设计
  2. python将scikit-learn自带数据集转换为pandas dataframe格式
  3. fatal error LNK1169: 找到一个或多个多重定义的符号
  4. 使用接口改变已经装箱的值类型的字段
  5. SQL Server数据库设置自动备份策略
  6. 最近幻影的两个ARP欺骗工具 挺不错的
  7. 轻雨物联网解决方案:农业物联网的市场前景分析
  8. Git:改变世界的一次代码提交
  9. 吴恩达机器学习【第五天】逻辑回归模型
  10. android逐行写入读取_Android外部存储-读取,写入,保存文件
  11. IE无法浏览网页的常见原因及解决方法(转)
  12. that、this、these、those的区别
  13. 基于vue+百度地图的多车实时运动及轨迹追踪实现(上帝视角篇)
  14. [第一篇] 桌面快捷方式小箭头的取消与恢复
  15. (一)JMeter性能测试,完整入门篇:性能测试操作步骤
  16. js-xlsx 读取Excel解析
  17. 计算机专业用什么轴的键盘,机械键盘的哪个轴适合办公室使用
  18. java人品计算器,‎App Store 上的“围棋死活大全”
  19. android 带刻度的滑动条_Android实现滑动刻度尺效果
  20. 软碟通安装linux系统,使用U盘作为载体使用UltraISO软碟通安装Centos6.4

热门文章

  1. R语言应用calibrate包的textxy函数向R原生绘图结果中添加文本标签:添加多个文本标签、改变文本标签的字体、改变文本标签的字体颜色
  2. R语言包_rCharts
  3. java SE环境变量配置
  4. 基因组组装----k-mer
  5. 大数据,正在到来的数据革命——涂子沛
  6. 二十四、哈希表的原理分析及代码实现
  7. qu.la网站上的小说爬取
  8. linux apache配置目录大小写,linux apache 配置URL地址栏大小写不敏感配置
  9. matlab动力学方程,机器人动力学方程(二):拉格朗日法
  10. 引入三方库_关于使用第三方库、代码复用的一些思考