开源、免费、轻量级 Gin 前后分离快速开发基础框架,基于主流技术,集成了 JWT 认证、权限控制、数据库操作等功能,帮助开发者快速搭建一个支持多租户的后台管理系统。
本项目由Gfast团队(奇讯科技)开发,如果您愿意为GinFast贡献代码或提供建议以及商业合作,请加微信:qixun007(备注:ginfast)
项目为前后端分离,前端地址:
github地址:https://github.com/qxkjsoft/ginfast-ui
账号:demo 密码:123456
- 🔐 JWT 认证:基于 JWT 的用户认证系统,支持 Token 刷新机制
- 🛡️ 权限控制:集成 Casbin 权限管理框架,支持 RBAC 权限模型
- 🗄️ 数据库支持:支持 MySQL、SQL Server、PostgreSQL 数据库
- 🔧 配置管理:基于 YAML 的配置文件管理
- 📝 日志系统:集成 Zap 日志框架,支持日志切割和归档
- 🌐 跨域支持:内置 CORS 中间件
- 🚀 性能监控:集成 pprof 性能分析工具
- 💾 缓存支持:支持 Redis 和内存缓存
- 🔢 验证码支持:集成图形验证码功能,支持登录安全验证
- 📋 完整的后台管理:包含用户管理、角色管理、菜单管理、部门管理、字典管理、API管理等模块
- 🔗 菜单与API权限关联:支持菜单与API权限的动态关联管理
- 🏗️ 分层架构:采用Controller-Service-Model分层架构,代码结构清晰
- 📚 API文档:集成 Swagger API 文档,自动生成接口文档
- 🏢 多租户架构:支持完整的租户管理、用户租户关联、数据隔离等功能
- 🔒 数据隔离:基于GORM钩子函数实现自动租户数据隔离,确保各租户数据安全
- 👥 租户用户管理:支持用户与租户的灵活关联,一个用户可关联多个租户
- 🤖 代码生成:强大的代码生成器,支持根据数据库表一键生成完整的后端和前端代码,包括模型、控制器、服务和视图层
- 🔌 插件管理:完整的插件管理系统,支持插件打包、导入、导出、卸载等功能,支持版本管理和依赖检查
- ⏰ 任务调度:基于Cron表达式的任务调度系统,支持多种执行策略、阻塞策略、超时控制和自动重试机制
- Web 框架:Gin
- ORM 框架:GORM
- 认证授权:JWT (golang-jwt/jwt/v5)
- 权限控制:Casbin
- 日志系统:Zap + Lumberjack
- 配置管理:Viper
- 数据库:MySQL、SQL Server、PostgreSQL(多数据库支持)
- 缓存:Redis、内存缓存
- 验证码:Captcha (dchest/captcha)
- 参数验证:Gookit Validate
- 密码加密:Bcrypt
- 性能监控:Pprof
- API文档:Swagger (swaggo)
- 代码生成:Go text/template(支持后端和前端代码生成)
- 任务调度:robfig/cron(基于Cron表达式的任务调度)
ginfast-tenant/
├── app/ # 应用核心代码
│ ├── controllers/ # 控制器层
│ │ ├── auth.go # 认证控制器
│ │ ├── codegen.go # 代码生成控制器
│ │ ├── common.go # 通用控制器基类
│ │ ├── user.go # 用户控制器
│ │ ├── sysapi.go # 系统API管理控制器
│ │ ├── sysdepartment.go # 部门管理控制器
│ │ ├── sysdict.go # 字典管理控制器
│ │ ├── sysdictitem.go # 字典项管理控制器
│ │ ├── sysgen.go # 代码生成配置控制器
│ │ ├── sysmenu.go # 菜单管理控制器
│ │ ├── sysrole.go # 角色管理控制器
│ │ ├── systenant.go # 租户管理控制器
│ │ ├── sysusertenant.go # 用户租户关联控制器
│ │ ├── sysjobs.go # 任务调度管理控制器
│ │ ├── sysjobresults.go # 任务执行结果控制器
│ │ └── pluginsmanager.go # 插件管理控制器
│ ├── global/ # 全局变量和接口
│ │ ├── app/ # 全局应用接口
│ │ ├── consts/ # 常量定义
│ │ └── myerrors/ # 错误定义
│ ├── middleware/ # 中间件
│ │ ├── captcha.go # 验证码中间件
│ │ ├── casbin.go # 权限控制中间件
│ │ ├── cors.go # 跨域中间件
│ │ ├── jwt.go # JWT 认证中间件
│ │ └── requestaborted.go # 请求中断处理中间件
│ ├── models/ # 数据模型
│ │ ├── base.go # 基础模型
│ │ ├── codegen.go # 代码生成模型
│ │ ├── user.go # 用户模型
│ │ ├── sysapi.go # 系统API模型
│ │ ├── sysapiparam.go # 系统API参数模型
│ │ ├── sysdepartment.go # 部门模型
│ │ ├── sysdict.go # 字典模型
│ │ ├── sysdictitem.go # 字典项模型
│ │ ├── sysgen.go # 代码生成配置模型
│ │ ├── sysgenfield.go # 代码生成字段模型
│ │ ├── sysmenu.go # 菜单模型
│ │ ├── sysmenuapi.go # 菜单API关联模型
│ │ ├── sysrole.go # 角色模型
│ │ ├── systenants.go # 租户模型
│ │ ├── sysusertenant.go # 用户租户关联模型
│ │ ├── pluginexport.go # 插件导出配置模型
│ │ └── *param.go # 各种参数模型
│ ├── routes/ # 路由配置
│ │ └── routes.go # 路由定义
│ ├── scheduler/ # 任务调度模块
│ │ ├── register.go # 执行器注册和任务加载
│ │ ├── result_handler.go # 任务结果处理器
│ │ └── executors/ # 任务执行器
│ ├── service/ # 服务层
│ │ ├── casbinservice.go # 权限服务
│ │ ├── codegenservice.go # 代码生成服务
│ │ ├── sysgenservice.go # 代码生成配置服务
│ │ ├── sysmenu.go # 菜单服务
│ │ ├── userservice.go # 用户服务
│ │ ├── pluginsmanagerservice.go # 插件管理服务
│ │ └── zaphooks.go # 日志钩子
│ └── utils/ # 工具类
│ ├── cachehelper/ # 缓存助手
│ ├── casbinhelper/ # 权限助手
│ ├── common/ # 通用工具
│ ├── ginhelper/ # Gin助手
│ ├── gormhelper/ # GORM助手
│ ├── passwordhelper/ # 密码助手
│ ├── response/ # 响应助手
│ ├── tenanthelper/ # 租户助手
│ ├── tokenhelper/ # Token助手
│ └── ymlconfig/ # 配置助手
├── bootstrap/ # 应用初始化
│ └── init.go # 初始化配置
├── config/ # 配置文件
│ └── config.yml # 主配置文件
├── docs/ # 文档
│ ├── swagger/ # Swagger API 文档
│ └── catalog.md # 项目目录说明
├── gen/ # 代码生成模板
│ └── templates/ # 代码生成器使用的模板文件
├── plugins/ # 插件目录
│ ├── example/ # 示例插件
│ └── exampleinit.go # 插件初始化文件
├── resource/ # 资源文件
│ ├── database/ # 数据库脚本
│ │ └── gin-fast-tenant.sql # 数据库初始化脚本
│ ├── logs/ # 日志文件目录
│ └── public/ # 静态资源
├── scripts/ # 脚本文件
│ ├── swagger.sh # Swagger文档生成脚本(Linux/Mac)
│ └── swagger.bat # Swagger文档生成脚本(Windows)
├── main.go # 应用入口
└── go.mod # 依赖管理
- Go 1.25+
- MySQL 5.7+ 或其他支持的数据库
- Redis (可选,用于缓存)
- 克隆项目
git clone https://github.com/qxkjsoft/ginfast.git
cd ginfast- 安装依赖
go mod tidy-
配置数据库
- 修改
config/config.yml中的数据库配置 - 导入数据库脚本
resource/database/gin-fast.sql
- 修改
-
启动应用
go run main.go应用将在 http://localhost:8080 启动。
本项目集成了 Swagger API 文档,可以自动生成接口文档。
启动应用后,可以通过以下URL访问API文档:
- Swagger UI: http://localhost:8080/swagger/index.html
- Swagger JSON: http://localhost:8080/swagger/doc.json
# 进入项目根目录
cd gin-fast
# 运行脚本生成文档
./scripts/swagger.sh# 进入项目根目录
cd gin-fast
# 运行脚本生成文档
scripts\swagger.bat如果系统中未安装 swag 命令行工具,需要先安装:
go install github.com/swaggo/swag/cmd/swag@latest然后生成文档:
swag init -g main.go -o docs/swagger主要配置项位于 config/config.yml 文件中:
Server:
AppDebug: true # 调试模式
CacheType: "redis" # 缓存类型:memory 或 redis
HttpServer:
Port: ":8080" # 服务端口
AllowCrossDomain: true # 是否允许跨域
ServerRootPath: "/public" # 静态资源路由路径
ServerRoot: "./resource/public" # 静态资源根目录Database:
Type: "mysql" # 数据库类型
Host: "127.0.0.1" # 数据库主机
Port: 3306 # 数据库端口
Username: "root" # 数据库用户名
Password: "password" # 数据库密码
Database: "gin_fast" # 数据库名
Charset: "utf8mb4" # 字符集
ParseTime: true # 解析时间
Loc: "Local" # 时区本项目基于标准的多租户架构设计,支持数据隔离和租户管理功能:
-
租户管理 (Tenant Management)
- 租户创建、更新、删除和查询
- 租户状态管理(启用/停用)
- 租户域名绑定
-
用户租户关联 (User-Tenant Association)
- 用户与租户的多对多关系管理
- 支持用户关联多个租户
- 默认租户设置
- 批量关联和取消关联操作
-
数据隔离 (Data Isolation)
- 基于GORM钩子函数自动实现数据隔离
- 通过TenantID字段实现行级数据隔离
- JWT中间件自动注入租户信息
Tenant- 租户模型,包含租户基本信息SysUserTenant- 用户租户关联模型,管理用户与租户的关系
TenantController- 租户管理控制器SysUserTenantController- 用户租户关联控制器
tenanthelper- 租户助手函数,提供租户数据隔离作用域gormhelper/hook.go- GORM钩子函数,自动设置TenantID字段jwt.go- JWT认证中间件,提取并验证租户信息
-
数据隔离
- 所有需要进行租户隔离的模型都必须包含
TenantID uint字段 - GORM钩子函数会自动为创建和更新操作设置TenantID
- 查询时会自动应用租户数据隔离作用域
- 所有需要进行租户隔离的模型都必须包含
-
JWT认证与租户信息
- JWT Token中包含租户信息
- 通过
tenanthelper.TenantScope(c)可以获取当前用户的租户数据作用域
-
跨租户操作
- 特殊管理接口可以绕过租户隔离,但需要谨慎使用
- 用户租户关联控制器提供了不进行租户过滤的用户和角色查询接口
本项目集成了强大的代码生成器,支持根据数据库表自动生成完整的后端和前端代码。
-
后端代码生成
- 自动生成Go数据模型(Model)
- 生成RESTful API控制器(Controller)
- 生成业务逻辑服务层(Service)
- 生成路由配置(Routes)
- 支持参数验证模型生成
-
前端代码生成
- 生成Vue 3组件及API接口调用(API)
- 生成Pinia状态管理模块(Store)
- 生成完整的CRUD页面视图(View)
- 自动适配表单校验和表格展示规则
-
智能特性
- 支持多数据库类型(MySQL、PostgreSQL、SQL Server)
- 自动识别数据库字段注释生成代码文档
- 支持字段级别的显示控制(列表展示、表单展示、查询展示)
- 自动处理时间字段、主键字段等特殊字段
- 支持代码预览,可在生成前查看效果
- 支持覆盖现有文件选项
- 集成菜单和API权限自动注册
GET /api/codegen/databases
获取当前连接的数据库服务器中的所有数据库列表
GET /api/codegen/tables?database=<database_name>
根据数据库名称获取该数据库中的所有表名和表注释
GET /api/codegen/columns?database=<database_name>&table=<table_name>
获取指定表的所有字段信息(包括字段名、类型、注释、是否主键等)
POST /api/codegen/generate
根据代码生成配置ID实际生成后端和前端代码文件
请求体示例:
{
"genId": 1
}GET /api/codegen/preview?genId=<gen_id>
预览即将生成的代码内容,不实际创建文件
-
配置代码生成
- 在后台管理系统中配置代码生成任务(选择数据库、表、输出模块名等)
- 配置字段显示规则(是否在列表、表单、查询中显示)
- 设置字段的自定义名称、表单类型、字典关联等
-
预览生成代码
- 调用预览接口查看生成的代码效果
- 确认代码无误后再执行生成
-
执行代码生成
- 调用生成接口执行代码生成
- 系统将自动生成后端代码到
app/controllers、app/models、app/service等目录 - 前端代码生成到指定的前端项目目录
-
集成生成的代码
- 自动注册菜单和API权限
- 自动生成的代码遵循项目规范,可直接使用
- 如需修改,建议在生成后进行微调
-
字段设计规范
- 为所有需要隔离的字段添加
TenantID字段 - 为表和字段添加有意义的注释,便于代码文档生成
- 使用标准的数据类型(VARCHAR、INT、DATETIME等)
- 为所有需要隔离的字段添加
-
生成配置规范
- 选择有意义的模块名和文件名
- 根据业务需求配置字段的显示规则
- 为不同的字段类型选择合适的表单组件(日期选择器、下拉框等)
-
生成后处理
- 检查生成的代码是否符合项目规范
- 根据实际业务需求调整校验规则
- 添加必要的业务逻辑实现
- 在前端添加特定的交互和样式
代码生成配置保存在 SysGen 和 SysGenField 数据库表中,包含以下主要信息:
| 字段 | 说明 | 示例 |
|---|---|---|
| dbType | 数据库类型 | mysql、postgresql、sqlserver |
| database | 数据库名 | gin-fast |
| name | 表名 | sys_user |
| moduleName | 模块名 | user |
| fileName | 文件名 | user |
| describe | 功能描述 | 用户管理 |
| isCover | 是否覆盖现有文件 | true/false |
| packageName | 包名 | models、controllers 等 |
为确保API文档的完整性和一致性,请遵循以下Swagger注释规范:
- 每个控制器结构体添加概要说明:
// UserController 用户控制器
// @Summary 用户管理API
// @Description 用户管理相关接口
// @Tags 用户管理
// @Accept json
// @Produce json
// @Router /users [get]
type UserController struct {
Common
}- 每个控制器方法添加详细注释:
// List 用户列表
// @Summary 用户列表
// @Description 获取用户列表,支持分页和过滤
// @Tags 用户管理
// @Accept json
// @Produce json
// @Param pageNum query int false "页码" default(1)
// @Param pageSize query int false "每页数量" default(10)
// @Success 200 {object} map[string]interface{} "成功返回用户列表"
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
// @Router /users/list [get]
// @Security ApiKeyAuth
func (uc *UserController) List(c *gin.Context) {
// 方法实现
}- 为数据模型添加注释:
// User 用户模型
// @Description 用户信息
type User struct {
// 字段定义
}- 为请求参数和响应结构体添加注释:
// LoginRequest 登录请求结构
// @Description 登录请求参数
type LoginRequest struct {
Username string `validate:"required" message:"用户名不能为空"`
Password string `validate:"required" message:"密码不能为空"`
}本项目使用 JWT 进行身份认证,API 请求需要在请求头中添加 Authorization 字段:
Authorization: Bearer <access_token>
本项目提供完整的插件管理系统,支持插件的上传、下载、安装和卸载,同时集成了强大的插件导出功能,允许开发者将插件打包为可重新分发的压缩包。
所有插件管理接口需要JWT认证,路由前缀为 /api/pluginsmanager
GET /api/pluginsmanager/exports
获取plugins文件夹下所有插件的导出配置信息(plugin_export.json)。
响应示例:
{
"code": 0,
"msg": "ok",
"data": {
"list": [
{
"name": "example",
"version": "1.0.0",
"description": "示例插件",
"author": "author_name",
"email": "author@example.com",
"url": "https://example.com",
"folderName": "example",
"dependencies": {},
"exportDirs": [],
"exportDirsFrontend": [],
"menus": [],
"databaseTable": []
}
]
}
}POST /api/pluginsmanager/export
将指定插件打包成压缩包进行下载。压缩包包含:
- 后端代码文件(ginfastback目录)
- 前端代码文件(ginfastfront目录)
- plugin.json 插件配置文件
- menus.json 菜单数据(如果有)
- database.sql 数据库脚本(如果有)
请求体:
{
"folderName": "example"
}响应: 返回压缩包文件(Content-Type: application/zip)
POST /api/pluginsmanager/import
从上传的压缩包导入插件。支持以下功能:
- 检查导入的插件文件和数据库是否存在
- 导入菜单配置
- 导入数据库脚本
- 覆盖现有文件
请求参数(multipart/form-data):
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
| file | file | 是 | 插件压缩包文件 |
| checkExist | int | 否 | 仅检查文件和数据库是否存在 (0:否, 1:是) |
| overwriteDB | int | 否 | 是否覆盖数据库 (0:否, 1:是) |
| importMenu | int | 否 | 是否导入菜单 (0:否, 1:是) |
| overwriteFiles | int | 否 | 是否覆盖文件 (0:否, 1:是) |
| userId | int | 否 | 用户ID(默认使用当前登录用户) |
响应示例(检查存在):
{
"code": 1,
"msg": "以下项已存在,请核查",
"data": {
"existingPaths": [
"plugins/example"
],
"existingTables": [
"plugin_example"
]
}
}DELETE /api/pluginsmanager/uninstall?folderName=example
卸载指定插件,包括:
- 删除菜单
- 删除文件
- 删除数据库表
参数:
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
| folderName | string | 是 | 插件文件夹名称 |
每个插件必须在根目录包含 plugin_export.json 文件,定义插件的导出配置。
plugin_export.json 格式示例:
{
"name": "example",
"version": "1.0.0",
"description": "示例插件说明",
"author": "插件作者",
"email": "author@example.com",
"url": "https://github.com/example",
"dependencies": {
"ginfast": ">=1.0.0"
},
"exportDirs": [
"plugins/example/controllers",
"plugins/example/models",
"plugins/example/service",
"plugins/example/routes"
],
"exportDirsFrontend": [
"src/modules/example"
],
"menus": [
{
"path": "/example",
"type": 0
}
],
"databaseTable": [
"plugin_example",
"plugin_example_detail"
]
}配置项说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| name | string | 插件唯一标识名称 |
| version | string | 插件版本号(支持语义化版本) |
| description | string | 插件描述 |
| author | string | 插件作者名称 |
| string | 作者邮箱 | |
| url | string | 插件主页或代码仓库URL |
| dependencies | object | 插件依赖(键为插件名,值为版本要求) |
| exportDirs | array | 后端代码目录列表(相对路径) |
| exportDirsFrontend | array | 前端代码目录列表(相对于gen.dir) |
| menus | array | 菜单配置列表 |
| databaseTable | array | 数据库表名列表 |
- 读取配置 - 系统读取插件的 plugin_export.json 配置
- 验证路径 - 验证exportDirs和exportDirsFrontend中指定的所有路径是否存在
- 收集文件 - 收集所有需要导出的后端和前端文件
- 生成菜单数据 - 如果配置了menus,从sys_menu表查询相关菜单并生成树形结构的menus.json
- 生成数据库脚本 - 如果配置了databaseTable,导出这些表的CREATE和INSERT语句为database.sql
- 创建压缩包 - 将所有文件和数据打包成ZIP文件
- 流式传输 - 使用流式传输直接返回压缩包,无需保存到磁盘
- 解析压缩包 - 从上传的压缩包中读取plugin.json配置
- 版本检查 - 验证插件版本和依赖是否兼容
- 存在性检查 - 如果checkExist=true,检查文件和数据库是否已存在
- 导入数据库 - 如果overwriteDB=true,执行database.sql脚本
- 导入菜单 - 如果importMenu=true,导入menus.json中的菜单数据
- 提取文件 - 如果overwriteFiles=true,解压并覆盖文件
- 返回结果 - 返回导入是否成功或列出已存在的冲突项
系统支持以下版本表示法:
1.0.0- 精确版本>=1.0.0- 大于等于指定版本>1.0.0- 大于指定版本^1.0.0- 兼容版本(与1.0.0兼容)~1.0.0- 大约版本
在config.yml中配置前端项目路径:
gen:
dir: "../ginfast-ui" # 前端项目根目录相对路径本项目支持插件化开发,允许开发者在不影响核心代码的情况下扩展功能。插件遵循与主应用相同的架构模式和规范。
插件统一放在 plugins/ 目录下,每个插件应具有以下标准结构:
plugins/
├── {plugin_name}/
│ ├── controllers/ # 插件控制器
│ ├── models/ # 插件数据模型和参数验证
│ ├── routes/ # 插件路由注册
└── {plugin_name}init.go # 插件初始化文件
-
创建插件目录结构 在
plugins/目录下创建插件文件夹,例如plugins/example/ -
编写数据模型 在
plugins/{plugin_name}/models/目录下创建模型文件:- 继承
models.BaseModel基础模型 - 实现标准的 CRUD 方法(Create, Update, Delete, GetByID等)
- 创建对应的参数验证模型(如 CreateRequest, UpdateRequest等)
- 注意添加TenantID字段以支持多租户数据隔离
示例:
// plugins/example/models/example.go type Example struct { models.BaseModel TenantID uint `gorm:"column:tenant_id;default:0;comment:租户ID" json:"tenantID"` // 添加租户ID字段 Name string `gorm:"type:varchar(255);comment:名称" json:"name"` Description string `gorm:"type:varchar(255);comment:描述" json:"description"` CreatedBy uint `gorm:"type:int(11);comment:创建者ID" json:"createdBy"` } // 实现标准方法 func (m *Example) GetByID(id uint) error { return app.DB().First(m, id).Error } func (m *Example) Create() error { return app.DB().Create(m).Error }
- 继承
-
编写控制器 在
plugins/{plugin_name}/controllers/目录下创建控制器文件:- 继承
controllers.Common结构体以复用响应方法 - 实现标准的 RESTful API 方法(Create, Update, Delete, GetByID, List等)
- 使用参数验证模型进行输入验证
- 使用统一的错误处理和响应格式
示例:
// plugins/example/controllers/example.go type ExampleController struct { controllers.Common } func (ec *ExampleController) Create(c *gin.Context) { var req models.CreateRequest if err := req.Validate(c); err != nil { ec.FailAndAbort(c, err.Error(), err) } // 业务逻辑处理 example := models.NewExample() example.Name = req.Name // ... if err := example.Create(); err != nil { ec.FailAndAbort(c, "创建示例失败", err) } ec.Success(c, gin.H{"id": example.ID}) }
- 继承
-
注册路由 在
plugins/{plugin_name}/routes/routes.go中注册插件路由:- 使用统一的路由前缀
/api/plugins/{plugin_name} - 应用必要的中间件(如 JWT 认证、Casbin 权限验证)
- 注册控制器方法到对应路由
示例:
// plugins/example/routes/routes.go func RegisterRoutes(engine *gin.Engine) { example := engine.Group("/api/plugins/example") example.Use(middleware.JWTAuthMiddleware()) example.Use(middleware.CasbinMiddleware()) { example.POST("/add", exampleControllers.Create) example.PUT("/edit", exampleControllers.Update) // ... } }
- 使用统一的路由前缀
-
插件初始化 创建
plugins/{plugin_name}/{plugin_name}init.go文件,在init()函数中注册插件路由:- 使用
ginhelper.RegisterPluginRoutes注册路由 - 记录插件初始化日志
示例:
// plugins/example/exampleinit.go func init() { ginhelper.RegisterPluginRoutes(func(engine *gin.Engine) { routes.RegisterRoutes(engine) }) app.ZapLog.Info("示例插件初始化完成") }
- 使用
-
参数验证 在
plugins/{plugin_name}/models/中创建参数验证模型:- 继承
models.Validator和models.BasePaging(分页查询时) - 实现
Validate方法进行参数验证 - 实现
Handle方法处理查询条件
示例:
// plugins/example/models/exampleparam.go type CreateRequest struct { models.Validator Name string `json:"name" binding:"required"` Description string `json:"description" binding:"required"` } func (r *CreateRequest) Validate(c *gin.Context) error { return r.Validator.Check(c, r) }
- 继承
为了充分利用插件管理系统的功能,编写plugin_export.json时的建议:
- version字段 - 使用语义化版本号(如1.0.0),便于版本管理和兼容性检查
- dependencies字段 - 明确声明插件依赖的其他插件及最低版本要求
- exportDirs字段 - 列举所有需要导出的后端目录,确保完整性
- exportDirsFrontend字段 - 列举所有需要导出的前端目录(相对于gen.dir配置)
- menus字段 - 如果插件有菜单,配置相关菜单的path和type便于自动导出
- databaseTable字段 - 列举所有插件相关的数据库表名,便于导出和导入
-
命名规范
- 插件目录名应使用小写字母和下划线命名
- 控制器、模型、路由文件名应与功能对应,使用小写字母和下划线
- 结构体和方法名遵循 Go 语言命名规范
-
接口一致性
- 插件控制器必须继承
controllers.Common结构体 - 插件模型应继承
models.BaseModel基础模型 - 使用统一的错误处理和响应格式
- 插件控制器必须继承
-
路由规范
- 插件路由必须以
/api/plugins/{plugin_name}为前缀 - 必须应用 JWT 认证中间件确保安全性
- 根据需要应用 Casbin 权限验证中间件
- 插件路由必须以
-
日志记录
- 使用
app.ZapLog记录插件相关日志 - 在关键操作和初始化时添加日志记录
- 使用
-
数据库操作
- 使用
app.DB()获取数据库连接 - 遵循 GORM 的操作规范
- 注意处理数据库错误
- 添加TenantID字段以支持多租户数据隔离
- 使用
-
导出配置
- 在插件根目录创建plugin_export.json文件
- 完整列举所有需要导出的目录和数据库表
- 配置菜单和依赖信息便于自动化导入导出
本项目集成了强大的任务调度系统,基于Cron表达式实现定时任务的调度和管理,支持多种执行策略、阻塞策略、超时控制和自动重试机制。
- ⏰ Cron表达式支持:支持秒级Cron表达式,灵活配置任务执行时间
- 🔄 执行策略:支持重复执行和单次执行两种策略
- 🚫 阻塞策略:提供丢弃、覆盖、并行三种阻塞处理策略
- ⏱️ 超时控制:支持任务执行超时自动终止
- 🔁 重试机制:支持任务失败后自动重试,可配置重试次数和间隔
- 📊 结果记录:任务执行结果自动保存到数据库,便于追踪和分析
- 📝 日志记录:独立的调度器日志系统,按日期轮转
- 🔌 执行器扩展:支持自定义执行器,灵活实现各种业务逻辑
| 状态 | 常量 | 值 | 说明 |
|---|---|---|---|
| 启用 | StatusEnabled |
1 | 任务将被调度执行 |
| 禁用 | StatusDisabled |
0 | 任务不会被调度 |
| 策略 | 常量 | 值 | 说明 |
|---|---|---|---|
| 重复执行 | PolicyRepeat |
1 | 按照Cron表达式重复执行 |
| 单次执行 | PolicyOnce |
0 | 仅执行一次后自动禁用 |
当任务执行时间超过调度间隔时,可配置以下阻塞策略:
| 策略 | 常量 | 值 | 说明 |
|---|---|---|---|
| 丢弃 | BlockDiscard |
0 | 如果任务正在执行,跳过本次执行 |
| 并行 | BlockParallel |
1 | 允许多个实例并行执行(受ParallelNum限制) |
在 config/config.yml 中配置任务调度器:
# 任务调度器配置
scheduler:
# 日志配置
log:
dir: "/resource/logs/scheduler" # 日志目录
level: "info" # 日志级别: debug, info, warn, error, fatal
# 任务结果通道缓冲大小
job_results_buffer_size: 1000 # 任务结果通道缓冲大小,默认1000任务信息存储在 sys_jobs 表中,主要字段包括:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | string | 任务ID(主键) |
| group | string | 任务分组名称 |
| name | string | 任务名称 |
| description | string | 任务描述 |
| executor_name | string | 执行器名称 |
| execution_policy | int | 执行策略(0:单次 1:重复) |
| status | int | 任务状态(0:禁用 1:启用) |
| cron_expression | string | Cron表达式 |
| parameters | string | 任务参数(JSON格式) |
| blocking_policy | int | 阻塞策略(0:丢弃 1:并行) |
| timeout | int64 | 超时时间(纳秒) |
| max_retry | int | 最大重试次数 |
| retry_interval | int64 | 重试间隔(纳秒) |
| parallel_num | int | 并行数 |
支持6位Cron表达式(秒 分 时 日 月 周):
格式: 秒 分 时 日 月 周
示例: 0/5 * * * * * (每5秒执行一次)
0 0 2 * * * (每天凌晨2点执行)
0 0 0 * * 1 (每周一凌晨执行)
0 0 12 1 * * (每月1号中午12点执行)
所有任务管理接口需要JWT认证,路由前缀为 /api/sysjobs
| 接口 | 方法 | 说明 |
|---|---|---|
| /api/sysjobs/add | POST | 创建任务 |
| /api/sysjobs/edit | PUT | 更新任务 |
| /api/sysjobs/delete | DELETE | 删除任务 |
| /api/sysjobs/getByID | GET | 根据ID获取任务 |
| /api/sysjobs/list | GET | 获取任务列表(分页) |
| /api/sysjobs/enable | PUT | 启用任务 |
| /api/sysjobs/disable | PUT | 禁用任务 |
| /api/sysjobs/executeNow | POST | 立即执行任务 |
路由前缀为 /api/sysjobresults
| 接口 | 方法 | 说明 |
|---|---|---|
| /api/sysjobresults/list | GET | 获取任务执行结果列表(分页) |
| /api/sysjobresults/getByID | GET | 根据ID获取执行结果 |
执行器是任务的具体执行逻辑实现,需要实现 Executor 接口:
type Executor interface {
// Execute 执行任务
Execute(ctx context.Context, job *Job) error
// Name 返回执行器名称
Name() string
}package executors
import (
"context"
"log"
"gin-fast/app/utils/schedulerhelper"
)
// MyExecutor 自定义执行器
type MyExecutor struct{}
func (e *MyExecutor) Execute(ctx context.Context, job *schedulerhelper.Job) error {
log.Printf("执行任务: %s, 参数: %v", job.Name, job.Parameters)
// 实现您的业务逻辑
// ...
return nil
}
func (e *MyExecutor) Name() string {
return "my-executor"
}在 app/scheduler/register.go 中注册执行器:
func RegisterExecutors() {
// 注册演示执行器
app.JobScheduler.RegisterExecutor(&executors.DemoExecutor{})
// 注册自定义执行器
app.JobScheduler.RegisterExecutor(&executors.MyExecutor{})
}-
应用启动
- 在
bootstrap/init.go中初始化任务调度器 - 调用
RegisterExecutors()注册所有执行器 - 调用
LoadJobsFromDB()从数据库加载启用的任务
- 在
-
任务调度
- 调度器根据Cron表达式触发任务执行
- 根据阻塞策略决定是否执行任务
- 执行器执行任务逻辑
- 任务结果通过结果通道返回
-
结果处理
StartResultHandler()监听任务结果- 将执行结果保存到
sys_job_results表 - 记录执行状态、耗时、错误信息等
任务执行结果存储在 sys_job_results 表中,主要字段包括:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | uint | 结果ID(主键) |
| job_id | string | 关联的任务ID |
| job_name | string | 任务名称 |
| executor_name | string | 执行器名称 |
| status | string | 执行状态(success/failed/timeout) |
| error_message | string | 错误信息 |
| duration | int64 | 执行耗时(纳秒) |
| executed_at | time.Time | 执行时间 |
-
执行器设计
- 执行器应保持幂等性,避免重复执行导致数据问题
- 使用上下文超时控制,防止任务长时间阻塞
- 合理处理错误,记录详细的日志信息
-
任务配置
- 根据业务特点选择合适的阻塞策略
- 设置合理的超时时间,避免长时间占用资源
- 配置适当的重试次数和间隔
-
监控和日志
- 定期查看任务执行结果,及时发现异常
- 通过调度器日志追踪任务执行过程
- 对失败任务进行分析和优化
插件也可以定义自己的任务执行器,参考 plugins/example/scheduler/ 目录:
// plugins/example/scheduler/executors/example_executor.go
package executors
type ExampleExecutor struct{}
func (e *ExampleExecutor) Execute(ctx context.Context, job *schedulerhelper.Job) error {
// 插件任务逻辑
return nil
}
func (e *ExampleExecutor) Name() string {
return "example-executor"
}
// plugins/example/scheduler/register.go
package scheduler
import (
"gin-fast/app/global/app"
"gin-fast/plugins/example/scheduler/executors"
)
func init() {
// 注册插件执行器
app.JobScheduler.RegisterExecutor(&executors.ExampleExecutor{})
}go build -o gin-fast ../gin-fast- 构建 Docker 镜像
docker build -t gin-fast .- 运行容器
docker run -p 8080:8080 gin-fast1、GIN-FAST仅限自己学习使用,一切商业行为与GIN-FAST无关。
2、用户不得利用GIN-FAST从事非法行为,用户应当合法合规的使用,发现用户在使用产品时有任何的非法行为,GIN-FAST有权配合有关机关进行调查或向政府部门举报,GIN-FAST不承担用户因非法行为造成的任何法律责任,一切法律责任由用户自行承担,如因用户使用造成第三方损害的,用户应当依法予以赔偿。
3、所有与使用GIN-FAST相关的资源直接风险均由用户承担。
如果二维码过期,请添加微信 qixun007 邀请您进群(备注:ginfast)
QQ群:967593545
