Gin第四天---路由注册

7 篇文章 2 订阅
本文介绍了Gin框架中路由组的使用,通过路由组实现GET和POST请求的分离。接着讨论了路由的拆分,包括按包拆分、按文件拆分和按模块拆分为多个APP,以提高代码组织的清晰度和可维护性。通过对比Flask的路由注册,强调了解耦和模块化在项目中的重要性。
摘要由CSDN通过智能技术生成

Gin第四天

1. 路由组

当我们有许多相同的URL,但是需要它们处理不同的请求,这个时候就可以利用路由组来分别设置。

例如把GET请求的路由放在一个分组里,把POST请求的分组放在另一个。

package main

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

func main(){
   r:=gin.Default()
   v1:=r.Group("/get")
   {
      v1.GET("/login",login)
      v1.GET("/submit",submit)
   }

   v2:=r.Group("/post")
   {
      v2.POST("/login",login)
      v2.POST("/submit",submit)
   }
   r.Run()
}

func login(c *gin.Context){
   name:=c.DefaultQuery("name","shelgi")
   c.String(http.StatusOK,fmt.Sprintf("hello %s\n",name))
}

func submit(c *gin.Context){
   name:=c.DefaultQuery("name","shelgi")
   c.String(http.StatusOK,fmt.Sprintf("hello %s\n",name))
}

image-20211115131248201

image-20211115131331407

但如果我们用post请求去请求get操作对应的页面,就会返回404

image-20211115131518151

来看看Group到底干了什么,它是RouterGroup的一个方法,然后内部将传入的相对路径转换为绝对路径,并且把处理函数结合起来(下图二),返回一个路由组

image-20211115131654881

image-20211115132116999

可以看到这里对传入的处理函数有规模限制,这里面abortIndex从源码可以看到

const abortIndex int8=math.MaxInt8 / 2

也就是总共的处理函数不能超过63个

关于Gin的路由原理,涉及到前缀树和基数树,基数树就是前缀树压缩优化后的结果;Gin采用httprouter进行路由匹配,每个http方法对应都会生成一颗基数树,下面是树节点的结构

image-20211115134819500

里面包含了路径、索引、前节点、孩子节点、处理函数链……

感兴趣的可以去gin源码中的tree.go看看实现

2. 路由的拆分与注册

2.1 基本的路由注册

最基本的路由注册就是先写一个处理函数,然后再将这个处理函数与请求方法与路由路径绑定上,类似于下面的例子

package main

import (
   "github.com/gin-gonic/gin"
   "net/http"
)

func testhandler(c *gin.Context){
   c.JSON(http.StatusOK,gin.H{
      "test":"这是路由注册的测试",
   })
}

func main(){
   r:=gin.Default()
   r.GET("/test",testhandler)
   r.Run()
}

image-20211115140443027

2.2 路由拆分为包

当我们需要处理注册的路由数量过多时,全部写在一个文件里既不方便阅读修改,也不能很好的简化代码结构,为此我们可以把这部分代码拎出来单独作为一个包

创建一个routers的包,然后将路由注册部分全部放在这个包里

package routers

import (
   "github.com/gin-gonic/gin"
   "net/http"
)

func testhandler(c *gin.Context){
   c.JSON(http.StatusOK,gin.H{
      "test":"这是路由注册的测试",
   })
}

func SetupRouter() *gin.Engine{
   r:=gin.Default()
   r.GET("/test",testhandler)
   return r
}

然后在主函数中引入已经实例化路由注册后的引擎

package main

import (
   "Learn_Gin/Gin-day4/routers"
)

//从Routers包中引入路由

func main() {
   r := routers.SetupRouter()
   r.Run()
}

image-20211115141820768

2.3 路由拆分为多个文件

我们现在是把所有的路由注册全部写在SetupRouter中,但是如果我们的路由更多,同样会引起之前一样的问题,所以我们还可以继续分,分为更细致的模块化

在routers中创建两个路由,传入引擎实例作为参数,在模块中就实现了各个路由的注册

package routers

import (
   "github.com/gin-gonic/gin"
   "net/http"
)

func test1handler(c *gin.Context){
   c.JSON(http.StatusOK,gin.H{
      "test":"这是路由1注册的测试",
   })
}

func Test1(e *gin.Engine){
   e.GET("/test1",test1handler)
}
package routers

import (
   "github.com/gin-gonic/gin"
   "net/http"
)

func test2handler(c *gin.Context){
   c.JSON(http.StatusOK,gin.H{
      "test":"这是路由2注册的测试",
   })
}


func Test2(e *gin.Engine){
   e.GET("/test2",test2handler)
}

在主函数中只用调用这两个函数就可以啦

package main

import (
   "Learn_Gin/Gin-day4/routers"
   "github.com/gin-gonic/gin"
)

//多文件路由注册

func main(){
   r:=gin.Default()
   routers.Test1(r)
   routers.Test2(r)
   r.Run()
}

image-20211115143810869

image-20211115143824276

说到这里,来互相对比一下。拿我们熟悉的Flask作为对比,除了@app.route("/") 装饰器方式注册路由,还可以使用app.add_url_rule(rule="xxx",view_func=func)

这个和我们的r.GET(relativePath="/",handles)结构上其实是一样的,有的时候交叉对比学习,可以进行知识迁移,从而更简单的理解使用

2.4 路由拆分为多个APP

当我们的项目继续扩大,全部放在routers里面还是不能满足分模块的效果,我们就可以继续再分;每个不同的功能模块放在APP的不同模块下,然后在各自的模块中实现handler和Routers(路由注册),最终只需要在routers中将所有APP注册的路由全部整合在一起(一个切片中),然后初始化方法中用实例一个个遍历注册。在主函数中只需要直接初始化然后运行就可以了。

APP/demo/下

package demo

import (
   "github.com/gin-gonic/gin"
   "net/http"
)

func idHandler(c *gin.Context){
   c.JSON(http.StatusOK,gin.H{
      "id_test":"这是id的测试",
   })
}

func commentHandler(c *gin.Context){
   c.JSON(http.StatusOK,gin.H{
      "comment_test":"这是comment的测试",
   })
}
package demo

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

func Routers(e *gin.Engine) {
   e.GET("/id", idHandler)
   e.GET("/comment", commentHandler)
}

routers中合并注册整合,然后同意初始化

package routers

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

type Option func(*gin.Engine)

var options = []Option{}

// 注册app的路由配置
func Include(opts ...Option) {
   options = append(options, opts...)
}

// 初始化
func Init() *gin.Engine {
   r := gin.New()
   for _, opt := range options {
      opt(r)
   }
   return r
}

主函数中调用整合初始化方法,直接启动

package main

import (
   "Learn_Gin/Gin-day4/APP/demo"
   "Learn_Gin/Gin-day4/routers"
)

func main(){
   routers.Include(demo.Routers)
   r:=routers.Init()
   r.Run()
}

image-20211115160636825

总结

这部分主要就是在处理一件事,如何解耦,使各个模块之间更细分并且在项目方便使用。不论是从项目的目录结构还是从代码功能都能让人比较清晰直观的理解,这样的项目不仅利于开发,更利于后期的迭代更新、运营维护。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在使用Gin和Redis进行事务操作时,你可以通过以下步骤来实现: 1. 创建Redis连接:首先,你需要使用Go语言的Redis客户端库连接到Redis数据库。可以使用第三方库如`go-redis`或`redigo`来实现。创建一个Redis连接池,以便在需要时可以重用连接。 2. 创建Gin路由:使用Gin框架创建HTTP路由和处理程序。你可以定义不同的路由来处理各种请求。 3. 开启事务:在处理程序中,使用Redis的MULTI命令来开启一个事务。MULTI命令将后续的Redis命令添加到事务队列中,而不是立即执行它们。 4. 执行Redis命令:在事务中,使用Redis的各种命令(如SET、GET、INCR等)来执行你需要的操作。这些命令会被添加到事务队列中。 5. 执行事务:在事务中的所有命令都添加完成后,使用Redis的EXEC命令来执行整个事务。Redis会按照添加的顺序依次执行队列中的命令,并返回每个命令的结果。 6. 处理事务结果:根据EXEC命令的返回结果,你可以判断事务是否执行成功。如果成功,你可以继续处理其他业务逻辑。如果失败,你可以回滚事务或进行其他错误处理。 需要注意的是,在Redis事务中,一旦EXEC命令被调用,Redis会将所有命令作为一个原子操作执行。这意味着要么所有命令都成功执行,要么都不执行。如果在事务执行期间发生了错误,你可以使用Redis的DISCARD命令来放弃执行事务的结果,并回滚到事务开始之前的状态。 希望这些步骤能帮助你在Gin和Redis中实现事务操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shelgi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值