Gin-封装自动路由

O.0

  • 思路
  • 一、API
  • 二、控制层
  • 三、自动路由核心
  • 四、分组路由外加中间件使用

思路

由于Java转Go直接使用的goframe框架,然学习Gin时觉得一个接口一个路由太麻烦,于是有了...1、在请求结构体中采用标签的形式,直接给出路由和请求方式
2、在控制层引用xxxReq开头的结构体作为入参(此时API结构体就与方法形成了联系)
3、通过反射获取控制层的所有方法,通过每个方法拿到结构体,并获取到标签信息,随后进行路由绑定以上就是大致思路,中途也加入了路由分组、中间件设置等反正也支持数据自动绑定到结构体中(Req),也能直接返回结构体数据(Res)等

在这里插入图片描述

一、API

label.go 文件

// Package common
// @Author 铁憨憨[cory] 2024/9/5 15:35:00
package commontype (MetaCory = Meta // Meta is alias of frequently-used type gmeta.Meta.
)type Meta struct{}

userApi.go 文件

// Package api
// @Author 铁憨憨[cory] 2024/9/5 15:23:00
package apiimport ("cory_chat_room/api/common""mime/multipart"
)type UserReq struct {common.MetaCory `path:"/getUserMenus" method:"get" tags:"用户管理"  summary:"获取用户菜单"`Name            string `json:"name" form:"name" `Age             int    `json:"age" form:"age" `Flag            bool   `json:"flag" form:"flag" `
}type UserRes struct {Text string `json:"text" form:"text" `
}type UserListReq struct {common.MetaCory `path:"/getUserMenus" method:"post" tags:"用户管理"  summary:"获取用户菜单"`Name            string                `json:"name" form:"name" `Age             int                   `json:"age" form:"age" `Flag            bool                  `json:"flag" form:"flag" `File            *multipart.FileHeader `json:"file" form:"file" `
}type UserListRes struct {Text string `json:"text" form:"text" `
}

二、控制层

postController.go 文件

// Package controllers
// @Author 铁憨憨[cory] 2024/9/5 14:58:00
package controllersimport ("cory_chat_room/api""fmt""github.com/gin-gonic/gin"
)var Product = new(productController)type productController struct {
}func (uc *productController) GetProducts(c *gin.Context, req *api.UserReq) (res *api.UserRes, err error) {a := new(api.UserRes)a.Text = "风、风、大风"// 处理获取用户的逻辑fmt.Println("----", req.Name)fmt.Println("----", req.Age)fmt.Println("----", req.Flag)return a, err
}

userController.go 文件
这块其实我想通过init调用方法来实现路由注册,但是有依赖注入就放弃了

// Package controllers
// @Author 铁憨憨[cory] 2024/9/6 16:58:00
package controllersimport ("cory_chat_room/api""fmt""github.com/gin-gonic/gin"
)var User = new(userController)type userController struct {
}//func init() {
//	routers.TwoGroup(User)
//}func (uc *userController) GetUserList(c *gin.Context, req *api.UserListReq) (res *api.UserListRes, err error) {a := new(api.UserListRes)a.Text = "人民有信仰,民族有希望,国家有力量。"// 处理获取用户的逻辑fmt.Println("----", req.Name)fmt.Println("----", req.Age)fmt.Println("----", req.Flag)fmt.Println("----", req.File.Filename)return a, err
}

三、自动路由核心

package routersimport ("github.com/gin-gonic/gin""reflect""strings"
)// @Title controllerRoutingPacket
// @Description 根据控制器名称进行路由分组(也可单独为某一个路由设置中间件)
// @Author 铁憨憨[cory] 2024-09-06 16:29:19
// @Param userGroup 分组
// @Param controller 控制层
// @Param middlewares 中间件
func controllerRoutingPacket(userGroup *gin.RouterGroup, controller interface{}, middlewares ...gin.HandlerFunc) {//如若没有分组,那么就以"/"做根分组if userGroup == nil {userGroup = allRouter.Group("/")}controllerName := lowerFirst(reflect.TypeOf(controller).Elem().Name()) //通过反射获取控制层名称userGroup = userGroup.Group(controllerName)AutoBindRoutes(userGroup, controller, middlewares...)
}// @Title lowerFirst
// @Description 将字符串首字母小写,且带/
// @Author 铁憨憨[cory] 2024-09-06 16:18:57
// @Param str
// @Return string
func lowerFirst(str string) string {if len(str) > 0 {firstChar := strings.ToLower(string(str[0]))return firstChar + str[1:]}return "/" + str
}// @Title AutoBindRoutes
// @Description 自动路由绑定函数,支持传入路由分组和中间件
// @Author 铁憨憨[cory] 2024-09-06 16:20:44
// @Param group		分组
// @Param controller	控制层
// @Param middlewares	中间件
func AutoBindRoutes(group *gin.RouterGroup, controller interface{}, middlewares ...gin.HandlerFunc) {ctrlType := reflect.TypeOf(controller)ctrlValue := reflect.ValueOf(controller)for i := 0; i < ctrlType.NumMethod(); i++ {method := ctrlType.Method(i)// 检查方法的参数数量if method.Type.NumIn() != 3 {continue // 必须有 3 个参数:*gin.Context, req}// 检查第一个参数是否是 *gin.Contextif method.Type.In(1) != reflect.TypeOf(&gin.Context{}) {continue}// 检查第二个参数是否是以 "Req" 结尾的结构体指针reqType := method.Type.In(2)if reqType.Kind() != reflect.Ptr || !strings.HasSuffix(reqType.Elem().Name(), "Req") {continue}// 提取路由信息routePath, httpMethod := extractRouteInfo(reqType.Elem())if routePath == "" || httpMethod == "" {continue}// 注册路由到指定的分组,并追加中间件group.Handle(httpMethod, routePath, append(middlewares, func(c *gin.Context) {// 创建一个新的请求结构体实例reqInstance := reflect.New(reqType.Elem()).Interface()// 绑定请求数据,无论请求方法if err := c.ShouldBind(reqInstance); err != nil {c.JSON(400, gin.H{"error": "Invalid request", "details": err.Error()})return}// 调用控制器方法results := method.Func.Call([]reflect.Value{ctrlValue, reflect.ValueOf(c), reflect.ValueOf(reqInstance),})// 处理返回值if len(results) == 2 && results[1].IsNil() {c.JSON(200, results[0].Interface())} else {c.JSON(500, gin.H{"error": "Internal server error"})}})...)}
}// @Title extractRouteInfo
// @Description 提取路由信息的辅助函数(目前主要提取路由和请求方式)
// @Author 铁憨憨[cory] 2024-09-06 16:21:06
// @Param reqType
// @Return string
// @Return string
func extractRouteInfo(reqType reflect.Type) (string, string) {field := reqType.Field(0) // 假设路由信息总是在第一个字段中path := field.Tag.Get("path")method := field.Tag.Get("method")return path, strings.ToUpper(method)
}

四、分组路由外加中间件使用

authMiddleware.go 中间件

// Package middlewares
// @Description: 中间件
package middlewaresimport ("fmt""github.com/gin-gonic/gin""time"
)// LoggingMiddleware 记录请求路径和处理时间
func LoggingMiddleware() gin.HandlerFunc {return func(c *gin.Context) {startTime := time.Now()// 继续执行其他中间件或处理请求c.Next()// 计算处理时间duration := time.Since(startTime)fmt.Printf("------------Request: %s, Duration: %v\n", c.Request.URL.Path, duration)fmt.Printf("------------Request: %s, Duration: %v\n", c.Request.URL.Path, duration)fmt.Printf("------------Request: %s, Duration: %v\n", c.Request.URL.Path, duration)}
}

routingPacket.go 路由分组

// Package controllers
// @Author 铁憨憨[cory] 2024/9/6 15:35:00
package routersimport ("cory_chat_room/controllers""cory_chat_room/middlewares""github.com/gin-gonic/gin"
)var (allRouter *gin.Engine //gin
)func RouterInit() {allRouter = gin.Default()OneGroup("/api/v1")TwoGroup("/api/v2")err := allRouter.Run(":8080")if err != nil {return}
}func OneGroup(routerPath string) {oneGroup := allRouter.Group(routerPath)oneGroup.Use(middlewares.LoggingMiddleware())controllerRoutingPacket(oneGroup, controllers.Product)
}func TwoGroup(routerPath string) {TwoGroup := allRouter.Group(routerPath)controllerRoutingPacket(TwoGroup, controllers.User)
}

也可直接在controllerRoutingPacket加中间件,此时就是具体的路由的中间件了

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/422118.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QXml 使用方法

VS2019 QT 编译工具链问题解决 使用winqtdeploy.exe 打包环境就可以正常运行&#xff0c;缺少某一个运行库引起的 简易使用python脚本编译运行 Python3 中的 slots 和 QT 中的 slots 宏定义重复, 放在不同的文件中进行调用可以避免 还是比较习惯从源码包引入&#xff08;方便定…

【区块链通用服务平台及组件】信息数据流转验真技术研究项目 | FISCO BCOS应用案例

在日常工作中&#xff0c;相关系统每天会产生大量数据&#xff0c;系统之间有多种模式数据交互方式&#xff0c;数据监管工作量巨大&#xff0c;急需 数据追溯定位工具来辅助监管&#xff1b;数据在生产过程中经常会出现采集、提交、修改、删除等操作&#xff0c;需要对数据变更…

Vue(9)——.sync修饰符、ref和$refs、$nextTick

.sync 作用:可以实现子组件与父组件数据的双向绑定&#xff0c;简化代码。 特点&#xff1a;prop属性名&#xff0c;可以自定义&#xff0c;非固定位value 场景&#xff1a;封装弹框类的基础组件&#xff0c;visible属性 true显示&#xff0c;false隐藏 本质&#xff1a;就是 …

鸿蒙界面开发——组件(7):组件导航 页面路由

组件导航 (Navigation)(推荐) Navigation() Navigation(pathInfos: NavPathStack)Navigation是路由容器组件&#xff0c;一般作为首页的根容器&#xff0c;包括单栏(Stack)、分栏(Split)和自适应(Auto)三种显示模式。Navigation组件适用于模块内和跨模块的路由切换&#xff0c…

2024年金九银十最新版Java面试题及答案整理(持续更新)

2024年金九银十到了&#xff0c;发现网上很多Java面试题都没有答案&#xff0c;所以花了很长时间搜集整理出来了这套Java面试题大全~这套互联网 Java 工程师面试题包括了&#xff1a;MyBatis、ZK、Dubbo、EL、Redis、MySQL、并发编程、Java面试、Spring、微服务、Linux、Spring…

文件加密最简单的方法有哪些?十个电脑文件加密方法【超详细】

在当今数字化和信息化的时代&#xff0c;数据已成为企业最重要的资产之一。内部数据外泄不仅可能导致商业秘密的丧失&#xff0c;还可能对企业的声誉和财务健康造成严重影响。为了有效防止内部数据外泄&#xff0c;企业需要实施综合的防泄密解决方案。以下是十大最佳防泄密解决…

内网安全-横向移动【3】

1.域横向移动-内网服务-Exchange探针 Exchange是一个电子右键服务组件&#xff0c;由微软公司开发。它不仅是一个邮件系统&#xff0c;还是一个消息与协作系统。Exchange可以用来构建企业、学校的邮件系统&#xff0c;同时也是一个协作平台&#xff0c;可以基于此开发工作流、…

19:I2C一:程序模拟I2C通信时序

I2C 1、什么是I2C2、I2C的通信时序2.1&#xff1a;起始信号2.2&#xff1a;停止信号2.3&#xff1a;主机向从机发送一个字节数据2.4&#xff1a;主机向从机读取一个字节数据2.5&#xff1a;主机接收应答2.6&#xff1a;主机发送应答 3、程序模拟I2C的通信时序3.1&#xff1a;指…

NX1872三维电气布线

电气部件审核与定义

Windows系统介绍

文章目录 1、Windows启动过程1.1 启动过程BIOS1.2 启动过程MBR1.3 启动过程 GPT1.4 启动过程BootMgr1.5 启动过程Winload.exe1.6 启动过程1.7 explorer.exe 2、Windows重要进程及组件2.1 注册表Services注册表服务管理器Services.mscsc.exe计划任务taskschd.msc计划任务schtask…

区块链学习笔记1--比特币

区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。 从狭义上来说&#xff1a;区块链是一种按照时间顺序将数据区块以顺序相连的方式组合成的一种链式数据结构&#xff0c;并以密码学的方式保证的不可篡改和不可伪造的分布式账本。 意思就是…

第67期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

组播 2024 9 11

PIM&#xff08;Protocol Independent Multicast&#xff09;是一种常用的组播路由协议&#xff0c;其独立于底层的单播路由协议&#xff0c;能够在多种网络环境中有效地实现多播路由功能。PIM主要有两种模式&#xff1a;PIM Sparse Mode (PIM-SM) 和 PIM Dense Mode (PIM-DM)&…

DDoS对策是什么?详细解说DDoS攻击难以防御的理由和对策方法

攻击规模逐年增加的DDoS攻击。据相关调查介绍&#xff0c;2023年最大的攻击甚至达到了700Gbps。 为了抑制DDoS攻击的危害&#xff0c;采取适当的对策是很重要的。 特别是在网站显示花费时间或频繁出现504错误的情况下&#xff0c;可能已经受到了DDoS攻击&#xff0c;需要尽早采…

Spring面试

一、对Spring的理解 &#xff08;一&#xff09;Spring的发展史 &#xff08;二&#xff09;Spring的体系结构 &#xff08;三&#xff09;Spring相关组件 1.Spring和SpringMVC的关系 2.Spring和SpringBoot的关系 3.Spring和SpringCloud的关系 4.Spring和SpringSecurity的…

C语言基础——⑩③数据结构——②栈和队列

一、栈(Stack) 1、基本概念 栈是一种逻辑结构&#xff0c;是特殊的线性表。特殊在&#xff1a; 只能在固定的一端操作 只要满足上述条件&#xff0c;那么这种特殊的线性表就会呈现一种“后进先出”的逻辑&#xff0c;这种逻辑就被称为栈。栈 在生活中到处可见&#xff0c;比…

为什么企业需要数据目录?

想象一下&#xff0c;如果在没有目录系统的庞大图书馆里寻找一本特定的书&#xff0c;你可能会耗费无数个小时搜索&#xff0c;但最终却一无所获。 同理&#xff0c;企业的数据如果没有一个组织良好、易于搜索的系统&#xff0c;也无法充分发挥其潜力。企业数据目录能够简化这一…

Kafka 基础与架构理解

目录 前言 Kafka 基础概念 消息队列简介&#xff1a;Kafka 与传统消息队列&#xff08;如 RabbitMQ、ActiveMQ&#xff09;的对比 Kafka 的组件 Kafka 的工作原理&#xff1a;消息的生产、分发、消费流程 Kafka 系统架构 Kafka 的分布式架构设计 Leader-Follower 机制与…

进击J6:ResNeXt-50实战

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 一、实验目的&#xff1a; 阅读ResNeXt论文&#xff0c;了解作者的构建思路对比之前介绍的ResNet50V2、DenseNet算法使用ResNeXt-50算法完成猴痘病识别 二、实…

jmeter之仅一次控制器

仅一次控制器作用&#xff1a; 不管线程组设置多少次循环&#xff0c;它下面的组件都只会执行一次 Tips&#xff1a;很多情况下需要登录才能访问其他接口&#xff0c;比如&#xff1a;商品列表、添加商品到购物车、购物车列表等&#xff0c;在多场景下&#xff0c;登录只需要…