# gin-base **Repository Path**: xmlgrg/gin-base ## Basic Information - **Project Name**: gin-base - **Description**: 基于Golang语言框架Go Gin开发的轻量级框架,设计灵感基于laravel、thinphp,项目架构目录层次分明,初学者的福音,后端使用JWT、中间件、缓存、验证器、事件、路由、redis、命令行工具等、前端基于vue-next-admin typescrip改js使用vue3+element-plus+element-plus-table+vite 支持多语言,开发简单易于上手,方便扩展。 - **Primary Language**: Go - **License**: GPL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 3 - **Created**: 2025-07-09 - **Last Updated**: 2025-07-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 中文 | [English](readme.md) # 郑重提示 本文档由`大师兄`整理编写邮箱25076778@qq.com,严禁转载。 禁止将本项目用于含病毒、木马、色情、赌博、诈骗、违禁用品、假冒产品、虚假信息、数字货币、金融等违法违规业务 当前项目仅供个人学习测试,禁止一切线上商用行为,禁止一切违法使用!!! ## 项目地址 - Github: https://github.com/dsxwk/gin-base.git - Gitee: https://gitee.com/dsxwk/gin-base.git ## Gin框架介绍 Gin是一个用Go语言编写的Web框架。它具有简单、快速、高效等特点,被广泛应用于Go语言的Web开发中。 Gin框架的特性包括: - 快速:Gin框架基于标准库`net/http`,使用`goroutine`和`channel`实现异步处理,提高性能。 - 简单:Gin框架提供了一系列的API和中间件,使得开发人员可以快速构建Web应用程序。 - 高效:Gin框架使用`sync.Pool`来缓存对象,减少内存分配和释放,提高性能。 Golang Gin 是一个轻量级且高效的 Golang Web 框架。它具有高性能、易用性和灵活性等特点,被广泛应用于各种 Web 应用程序的开发。 ## 项目截图 ![img.png](./img.png) ![img_1.png](./img_1.png) ![img_2.png](./img_2.png) ![img_3.png](./img_3.png) ![img_4.png](./img_4.png) ## Gin-Base项目介绍 - 命令行生成 - - 模型 - - 控制器 - - 服务 - - 验证器 - - 中间件 - - 路由 - 验证器 - - 自定义验证场景 - 中间件 - - 跨域 - - 多语言 - - JWT - - 日志 - 缓存 - - 内存缓存 - - redis缓存 - - 磁盘缓存 - 事件 - - sql事件监听 - - http事件监听 - 日志 - - 错误信息记录 - - 堆栈信息记录 - - sql语句记录 - - http请求记录 - 多语言 - - 目前只有登录相关模块有案例,只支持中英文,如需其他模块或语言自行扩展 - Air - Swagger - 测试用例 - ... ## 后端使用技术 - Gin - Gorm - Jwt - Mysql - Middleware - Validator - Cache - Event - Swagger ## 前端使用技术 - vue-next-admin - Vue3 - Vite - Element-Plus - Element-Plus-Table - ... ### 感谢vue-next-admin提供的前端模版 项目地址: https://gitee.com/lyt-top/vue-next-admin ## go-base目录结构 ```bash ├── app # 应用程序代码 │ ├── controller # 控制期 │ ├── model # 模型 │ ├── service # 服务 │ ├── validate # 验证器 │ ├── middleware # 中间件 ├── cli # 命令行 ├── common # 公共模块 │ ├── base # 基类 │ ├── extend # 扩展 │ ├──├── cache # 缓存 │ ├──├── context # 上下文 │ ├──├── i18n # 多语言 │ ├──├──├── locales # 翻译文件 │ ├── global # 全局变量 │ ├── template # 模版 ├── config # 配置文件 ├── database # 数据库测试文件 ├── docs # 文档 ├── helper # 工具类 ├── resource # 静态资源 ├── routers # 路由 ├── storage # 存储 │ ├── cache # 磁盘缓存 │ ├── logs # 日志 ├── tests # 测试用例 ├── vendor # 依赖包 ├── web # Web服务 ``` ## web目录结构 ## 目录结构 ```bash ├── api # 请求接口 ├── components # 组件 ├── dict # 字典 ├── directive # 指令 ├── layouts # 布局 ├── public # 公共资源 ├── router # 路由 ├── static # 静态资源 ├── stores # 缓存 ├── them # 主题 ├── docs # 文档 ├── types # ts ├── utils # 工具助手类 │ ├── error # 全局错误处理 ├── views # 视图文件 ``` ## 使用 ### 运行前后端 ```bash # 后端运行 端口8080 接口地址:127.0.0.1:8080/api/v1/... cd path/gin-base go env -w GO111MODULE=on go env -w GOPROXY=https://goproxy.cn,direct go get -u go mod tidy go mod vendor go run main.go # OR air ``` ```bash # 前端运行 端口3000 访问地址:127.0.0.1:3000 cd path/gin-base/web npm install npm run dev ``` ### 命令行生成 ```bash # 命令 make: # 生成模型 # --table= --camel=true|false(true:生成驼峰字段,false:生成下划线字段) --file= go run ./cli/main.go make:model --table=user --camel=true --file=admin/test # 生成控制器 # --file= --func= --method= --router= --desc=<方法注释> go run ./cli/main.go make:controller --file=v1/test --func=List --method=get --router=/v1/list --desc=测试 # 生成服务 # --file= --func= --desc=<方法注释> go run ./cli/main.go make:service --file=admin/test --func=List --desc=测试 # 生成验证器 # --file= --desc=<方法注释> go run ./cli/main.go make:validate --file=test --desc=测试 # 生成中间件 # --file= --desc=<方法注释> go run ./cli/main.go make:middleware --file=admin/test --desc=测试 # 生成路由 # --fileName= go run ./cli/main.go make=router --file=admin/test ``` ### 生成模型结构示例 ```go // Code generated by gorm.io/gen. DO NOT EDIT. // Code generated by gorm.io/gen. DO NOT EDIT. // Code generated by gorm.io/gen. DO NOT EDIT. package model import ( "gorm.io/gorm" ) const TableNameArticle = "article" // Article mapped from table
type Article struct { ID int64 `gorm:"column:id;type:int(10) unsigned;primaryKey;autoIncrement:true;comment:ID" json:"id"` // ID UID int64 `gorm:"column:uid;type:int(11);not null;comment:用户id" json:"uid"` // 用户id User *User `json:"user" gorm:"foreignkey:uid;references:id"` // 关联用户 Title string `gorm:"column:title;type:varchar(50);not null;comment:标题" json:"title"` // 标题 Content string `gorm:"column:content;type:varchar(255);not null;comment:内容" json:"content"` // 内容 CategoryID int64 `gorm:"column:category_id;type:int(11);not null;comment:分类id" json:"categoryId"` // 分类id DataSource int64 `gorm:"column:data_source;type:int(11);not null;comment:数据来源 1=文章库 2=自建" json:"dataSource"` // 数据来源 1=文章库 2=自建 IsPublish int64 `gorm:"column:is_publish;type:int(11);not null;comment:是否发布 1=已发布 2=未发布" json:"IsPublish"` // 是否发布 1=已发布 2=未发布 Category *Category `json:"category" gorm:"foreignkey:category_id;references:id"` // 关联分类 Tag JsonString `gorm:"column:tag;type:json;comment:标签" json:"tag"` // 标签 CreatedAt *JsonTime `gorm:"column:created_at;type:datetime;comment:创建时间" json:"createdAt"` // 创建时间 UpdatedAt *JsonTime `gorm:"column:updated_at;type:datetime;comment:更新时间" json:"updatedAt"` // 更新时间 DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:datetime;comment:删除时间" json:"deletedAt"` // 删除时间 } // TableName Article's table name func (*Article) TableName() string { return TableNameArticle } ``` ## 设置器和获取器 ```go type Meta struct { Title string `gorm:"column:title;type:json;comment:菜单名称" json:"title"` Icon string `gorm:"column:icon;type:json;comment:菜单图标" json:"icon"` IsHide bool `gorm:"column:isHide;type:json;comment:是否隐藏" json:"isHide"` IsKeepAlive bool `gorm:"column:isKeepAlive;type:json;comment:是否缓存" json:"isKeepAlive"` IsAffix bool `gorm:"column:isAffix;type:json;comment:是否固定" json:"isAffix"` IsLink string `gorm:"column:isLink;type:json;comment:外链/内嵌时链接地址" json:"isLink"` // 外链/内嵌时链接地址(http:xxx.com),开启外链条件,`1、isLink: 链接地址不为空` IsIframe bool `gorm:"column:isIframe;type:json;comment:是否内嵌" json:"isIframe"` // 是否内嵌,开启条件,`1、isIframe:true 2、isLink:链接地址不为空` Roles []int64 `gorm:"column:roles;type:json;comment:菜单角色" json:"roles"` // 权限标识,取角色管理 } func (m Meta) Value() (driver.Value, error) { return json.Marshal(m) } // 实现 sql.Scanner 接口(用于从数据库读取) func (m *Meta) Scan(value interface{}) error { if value == nil { *m = Meta{} return nil } var data []byte switch v := value.(type) { case string: data = []byte(v) case []byte: data = v default: return fmt.Errorf("cannot scan type %T into Meta", value) } return json.Unmarshal(data, m) } ``` ## 模型动态筛选 ### 结构体筛选 ```go package validate ... // UserSearchQuery 用户搜索 query type UserSearchQuery struct { Username string `form:"username" validate:"required" label:"用户名"` FullName string `form:"fullName" validate:"required" label:"姓名"` Nickname string `form:"nickname" validate:"required" label:"昵称"` Gender int64 `form:"gender" validate:"required|int" label:"性别"` // json字段 如user是数据库的json字段, user = {gender:1,age:18} UserGender string `form:"user.gender" validate:"required" label:"性别"` } // UserSearchBody 用户搜索 body type UserSearchBody struct { Username string `json:"username" validate:"required" label:"用户名"` FullName string `json:"fullName" validate:"required" label:"姓名"` Nickname string `json:"nickname" validate:"required" label:"昵称"` Gender int `json:"gender" validate:"required|int" label:"性别"` // json字段 如user是数据库的json字段, user = {gender:1,age:18} UserGender string `json:"user.gender" validate:"required" label:"性别"` } ... package service import ( "gin-base/app/model" ) ... var ( models []model.user ) data := global.DB.Scopes(model.Search(search)).Find(&models) fmt.Printf("data:%v",data) ... ``` ### map筛选 建议复杂筛选使用post放body请求, get需自行组装前端数据 ```json // operator: >,<, >=, <=, =, !=, in, not in, between, not between, is null, is not null, like, not like, left like, right like // 前端请求 // __search: { // "field": {"operator": ">", "value": 10}, // "field": {"operator": "<", "value": 10}, // "field": {"operator": ">=", "value": 10}, // "field": {"operator": "<=", "value": 10}, // "field": {"operator": "=", "value": 10}, // "field": {"operator": "!=", "value": 10}, // "field": {"operator": "in", "value": [1,2,3]}, // "field": {"operator": "not in", "value": [1,2,3]}, // "field": {"operator": "between", "value": [1,2]}, // "field": {"operator": "not between", "value": [1,2]}, // "field": {"operator": "is null"}, // "field": {"operator": "is not null"}, // "field": {"operator": "like", "value": "admin"}, // "field": {"operator": "left like", "value": "test"}, // "field": {"operator": "right like", "value": "138"}, // "or": [ // "field": {"operator": ">", "value": 10}, // "field": {"operator": "<", "value": 10}, // "field": {"operator": ">=", "value": 10}, // ... // ] // "and": [ // "field": {"operator": ">", "value": 10}, // "field": {"operator": "<", "value": 10}, // "field": {"operator": ">=", "value": 10}, // ... // ] // "jsonField.field": {"operator": ">", "value": 10}, // ... // } __search: { "username": { "operator": "like", "value": "admin" }, "fullName": { "operator": "=", "value": "张三" }, "nickname": { "operator": "=", "value": "昵称" }, "gender": { "operator": "=", "value": 1 }, // json字段 如user是数据库的json字段 user = {gender:1,age:18} "user.age": { "operator": ">", "value": 18 } } ``` ```go package service ... var ( search map[string]interface{} models []model.user ) ... data := global.DB.Scopes(model.SearchMap(search)).Find(&models) fmt.Printf("data:%v",data) ... ``` ## 缓存使用 支持内存、磁盘和redis缓存需要在yaml当中指定 ```yaml # 缓存 cache: type: "redis" # memory|disk|redis redis: address: "127.0.0.1:6379" password: "" # 密码为空则不需要 db: 1 ``` ### 缓存调用示例 ```go package service import ( "gin-base/common/base" "gin-base/common/global" "time" ) type CacheService struct { base.BaseService } // SetCache 设置缓存 // @param key string // @param value interface{} // @param expire time.Duration // @return: bool, error func (s *CacheService) SetCache(key string, value interface{}, expire time.Duration) (bool, error) { err := global.Cache.SetCache(key, value, expire) if err != nil { return false, err } return true, nil } // GetCache 获取缓存 // @param: key string // @return: interface{}, bool func (s *CacheService) GetCache(key string) (interface{}, bool) { res, ok := global.Cache.GetCache(key) if ok { return res, ok } return false, ok } // DeleteCache 删除缓存 // @param: key string // @return: bool, error func (s *CacheService) DeleteCache(key string) (bool, error) { err := global.Cache.DeleteCache(key) if err != nil { return false, err } return true, nil } ``` ## 事件使用 ### 发布事件 注:以登录为例只需要在你想要传递数据的地方加入发布事件 ```go package service import ( "errors" "gin-base/app/model" "gin-base/common/base" "gin-base/common/global" "gin-base/config" "gin-base/helper" "gorm.io/gorm" ) type LoginService struct { base.BaseService } // Login 登录 // @param username string // @param password string // @return m model.User, error func (s *LoginService) Login(username string, password string) (m model.User, err error) { if err = global.DB.Where("username = ?", username).First(&m).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return userModel, errors.New("登录账号错误") } } check := helper.BcryptCheck(password, m.Password) if !check { return m, errors.New("登录密码错误") } if m.Status != 1 { return m, errors.New("账号已被禁用") } // 发布事件 global.Event.Publish(config.Event{ Name: "userLogin", Data: map[string]interface{}{ "username": username, "password": password, }, }) return m, nil } ``` ### 收到事件 ```go package main import ( "fmt" "gin-base/app/middleware" "gin-base/common/global" "gin-base/config" "gin-base/routers" "github.com/gin-gonic/gin" "net/http" "time" ) //go:generate go env -w GO111MODULE=on //go:generate go env -w GOPROXY=https://goproxy.cn,direct //go:generate go get -u //go:generate go mod tidy //go:generate go mod download //go:generate go mod vendor func main() { // 运行环境模式 debug模式, test测试模式, release生产模式, 默认是debug,根据当前配置文件读取 gin.SetMode(global.Config.Service.Mode) router := gin.Default() router.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "code": 0, "message": "pong", "data": []string{}, }) }) // 静态文件 router.StaticFS("/resource", http.Dir("./resource")) // 设置 HTTP 请求处理文件上传时可以使用的最大内存为 90MB router.MaxMultipartMemory = 90 << 20 // 设置跨域 if global.Config.Cors.Enabled { router.Use(middleware.Cors{}.Handle()) } // 全局日志中间件 router.Use(middleware.Logger{}.Handle()) // 注册所有事件 global.Event.RegisterAllEvent(onEventReceived) // 加载路由 routers.LoadRouters(router) err := router.Run(`:` + global.Config.Env.Port) if err != nil { fmt.Println("启动服务失败,错误信息为:", err) } } // onEventReceived 接收事件 func onEventReceived(event config.Event, timestamp time.Time) { // todo 处理事件 fmt.Printf("Event received at %s: name: %s, data: %v\n", timestamp.Format(time.RFC3339), event.Name, event.Data) } ``` ## 多语言 ```go package v1 import ( "gin-base/app/middleware" "gin-base/app/service" "gin-base/app/validate" "gin-base/common/base" "gin-base/common/extend/i18n" "gin-base/common/global" "github.com/gin-gonic/gin" ) // Login 登录 // @Tags 登录相关 // @Summary 登录 // @Description 用户登录 // @Accept json // @Produce json // @Param data body validate.Login true "登录参数" // @Router /api/v1/login [post] // @Success 200 {object} global.Response{global.Success} "成功返回" Example({"code":0,"msg":"Success","data":[]}) // @Failure 400 {object} global.Response{global.ArgsError} "参数错误" Example({"code":400,"msg":"参数错误","data":[]}) // @Failure 500 {object} global.Response{global.SystemError} "系统错误" Example({"code":500,"msg":"系统错误","data":[]}) func (s *LoginController) Login(c *gin.Context) { var ( loginService service.LoginService loginValidate validate.Login jwt middleware.Jwt ) err := c.ShouldBind(&loginValidate) if err != nil { s.ApiResponse(c, global.SystemError, err.Error()) return } // 验证 err = validate.Login{}.GetValidate(c, loginValidate, "login") if err != nil { s.ApiResponse(c, global.ArgsError, err.Error()) return } // 验证码校验 b := s.verify(loginValidate.CaptchaID, loginValidate.Code) if !b { s.ApiResponse(c, global.ArgsError, i18n.T(c, "login.codeErr", nil)) return } userModel, err := loginService.Login(loginValidate.Username, loginValidate.Password) if err != nil { s.ApiResponse(c, global.ArgsError, err.Error()) return } token, rToken, tExpire, rExpire, err := jwt.WithRefresh(userModel.ID, 2*60*60, 2*24*60*60) if err != nil { s.ApiResponse(c, global.ArgsError, err.Error()) return } s.ApiResponse(c, global.Success, i18n.T(c, "login.codeErr", map[string]interface{}{ "name": userModel.Username, }), map[string]interface{}{ "token": map[string]interface{}{ "accessToken": token, "refreshToken": rToken, "expire": tExpire, "refreshExpire": rExpire, }, "user": userModel, }) } ``` ## air使用 ### 更新代码无需重启将自动重启更新 ```shell E:\www\dsx\gin-base> air __ _ ___ / /\ | | | |_) /_/--\ |_| |_| \_ v1.60.0, built with Go go1.23.1 watching . watching app watching app\controller watching app\controller\v1 watching app\middleware watching app\model watching app\service watching app\validate watching cli watching common watching common\global watching common\template watching config watching database watching helper watching log watching resource watching resource\images watching routers !exclude tmp !exclude vendor building... !exclude .git !exclude .git running... [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode) [GIN-debug] GET /ping --> main.main.func1 (3 handlers) [GIN-debug] GET /resource/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (3 handlers) [GIN-debug] HEAD /resource/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (3 handlers) [GIN-debug] POST /api/v1/login --> gin-base/app/controller/v1.(*LoginController).Login-fm (4 handlers) [GIN-debug] GET /api/v1/user/ --> gin-base/app/controller/v1.(*UserController).List-fm (5 handlers) [GIN-debug] POST /api/v1/user/ --> gin-base/app/controller/v1.(*UserController).Create-fm (5 handlers) [GIN-debug] PUT /api/v1/user/:id --> gin-base/app/controller/v1.(*UserController).Update-fm (5 handlers) [GIN-debug] GET /api/v1/user/:id --> gin-base/app/controller/v1.(*UserController).Detail-fm (5 handlers) [GIN-debug] DELETE /api/v1/user/:id --> gin-base/app/controller/v1.(*UserController).Delete-fm (5 handlers) [GIN-debug] GET /api/v1/article/ --> gin-base/app/controller/v1.(*ArticleController).List-fm (5 handlers) [GIN-debug] POST /api/v1/article/ --> gin-base/app/controller/v1.(*ArticleController).Create-fm (5 handlers) [GIN-debug] PUT /api/v1/article/:id --> gin-base/app/controller/v1.(*ArticleController).Update-fm (5 handlers) [GIN-debug] GET /api/v1/article/:id --> gin-base/app/controller/v1.(*ArticleController).Detail-fm (5 handlers) [GIN-debug] DELETE /api/v1/article/:id --> gin-base/app/controller/v1.(*ArticleController).Delete-fm (5 handlers) [GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value. Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details. [GIN-debug] Listening and serving HTTP on :8080 ``` ## 登录接口 ```http POST /api/v1/login HTTP/1.1 Host: :8080 Content-Type: application/json Content-Length: 56 { "username": "admin", "password": "123456" } ``` ## jwt验证header,获取文章列表示例 ```http GET /api/v1/article?page=1&pageSize=1 HTTP/1.1 Host: :8080 token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwibmFtZSI6IkFkbWluIiwiaWF0IjoxNjc0NjYzMjM5LCJleHAiOjE2NzQ2NjYzMzl9.8W45GJQqV656 ``` ## 控制器示例 ```go package v1 import ( "encoding/json" "gin-base/app/model" "gin-base/app/service" "gin-base/app/validate" "gin-base/common/base" "gin-base/common/global" "github.com/gin-gonic/gin" "strconv" ) type ArticleController struct { base.BaseController } // List 列表 // @Tags 文章管理 // @Summary 列表 // @Description 文章列表 // @Param token header string true "认证Token" // @Param page query string true "页码" // @Param pageSize query string true "分页大小" // @Success 200 {object} global.Response{global.Success} "成功返回" Example({"code":0,"msg":"Success","data":[]}) // @Failure 400 {object} global.Response{global.ArgsError} "参数错误" Example({"code":400,"msg":"参数错误","data":[]}) // @Failure 500 {object} global.Response{global.SystemError} "系统错误" Example({"code":500,"msg":"系统错误","data":[]}) // @Router /api/v1/article [get] func (s *ArticleController) List(c *gin.Context) { var ( articleService service.ArticleService articleValidate validate.Article ) err := c.ShouldBindQuery(&articleValidate) if err != nil { s.ApiResponse(c, global.SystemError, err.Error()) return } // 验证 err = validate.Article{}.GetValidate(articleValidate, "list") if err != nil { s.ApiResponse(c, global.ArgsError, err.Error()) return } pageData, err := articleService.List(articleValidate) if err != nil { s.ApiResponse(c, global.SystemError, err.Error()) return } s.ApiResponse(c, global.Success, "获取成功", pageData) } ``` ## 验证器以及验证场景 ```go package validate import ( "errors" validator "github.com/gookit/validate" ) // Article 文章请求验证 type Article struct { Page int `form:"page" validate:"required|int|gt:0" label:"页码"` PageSize int `form:"pageSize" validate:"required|int|gt:0" label:"每页数量"` ID int64 `json:"id" validate:"required" label:"ID"` Title string `json:"title" validate:"required" label:"标题"` Content string `json:"content" validate:"required" label:"内容"` } // GetValidate 请求验证 func (s Article) GetValidate(data Article, scene string) error { v := validator.Struct(data, scene) if !v.Validate(scene) { return errors.New(v.Errors.One()) } return nil } // ConfigValidation 配置验证 // - 定义验证场景 // - 也可以添加验证设置 func (a Article) ConfigValidation(v *validator.Validation) { v.WithScenes(validator.SValues{ "list": []string{"Page", "PageSize"}, "create": []string{"Title", "Content"}, "update": []string{"ID", "Title", "Content"}, "detail": []string{"ID"}, "delete": []string{"ID"}, }) } // Messages 您可以自定义验证器错误消息 func (s Article) Messages() map[string]string { return validator.MS{ "required": "字段 {field} 必填", "int": "字段 {field} 必须为整数", "Page.gt": "字段 {field} 需大于 0", "PageSize.gt": "字段 {field} 需大于 0", } } // Translates 你可以自定义字段翻译 func (s Article) Translates() map[string]string { return validator.MS{ "Page": "页码", "PageSize": "每页数量", "ID": "ID", "Title": "标题", "Content": "内容", } } ``` ## 路由注册 ```go package routers import ( "gin-base/app/controller/v1" "github.com/gin-gonic/gin" ) // UserRouter 用户路由 type UserRouter struct{} // RegisterRoutes 实现 Router 接口 func (r UserRouter) RegisterRoutes(routerGroup *gin.RouterGroup) { var ( controller v1.UserController ) // 列表 routerGroup.GET("/user", controller.List) // 创建 routerGroup.POST("/user", controller.Create) // 更新 routerGroup.PUT("/user/:id", controller.Update) // 删除 routerGroup.DELETE("/user/:id", controller.Delete) // 详情 routerGroup.GET("/user/:id", controller.Detail) } ``` ## 缓存 ```go package cache import ( "fmt" "time" ) // Test 缓存测试 func Test() { // 设置缓存 global.Cache.SetCache("test", "test", 10*time.Second) // 获取缓存 res := global.Cache.GetCache("test") // 删除缓存 global.Cache.DelCache("test") fmt.Printf("%v\n", res) } ``` ## Swagger 文档生成 ```bash # 快速生成文档命令 go install github.com/swaggo/swag/cmd/swag@latest swag init -g main.go --exclude cli,app/service ``` ![img.png](./img.png) ## 测试用例 ```bash go test -v ./tests/ ```