这是一套基于 GORM v2 的企业级后台管理系统常用模型代码。按照国内主流后台框架(如 RuoYi、Gin-Vue-Admin)的最佳实践设计,包含完整的 GORM 标签、列名映射、注释、JSON 序列化及软删除支持。

为方便阅读与直接复制,代码已按业务模块拆分,并附带了工程结构建议与运行时组件说明。

📦 基础工程结构建议

models/
├── base.go          # 公共基础模型
├── sys_auth.go      # 用户、部门、岗位、菜单、角色
├── sys_dict_config.go # 字典、参数
├── sys_log_notice.go  # 通知、操作日志、登录日志
├── sys_job.go         # 定时任务及日志
└── sys_gen.go         # 代码生成元数据

1. 公共基础模型 (base.go)

package models

import (
	"time"
	"gorm.io/gorm"
)

// BaseModel 公共字段,建议嵌入到所有模型中
type BaseModel struct {
	ID        uint           `gorm:"primaryKey;autoIncrement;comment:主键ID" json:"id"`
	CreateBy  string         `gorm:"size:64;comment:创建者" json:"createBy"`
	CreateTime time.Time     `gorm:"autoCreateTime;comment:创建时间" json:"createTime"`
	UpdateBy  string         `gorm:"size:64;comment:更新者" json:"updateBy"`
	UpdateTime time.Time     `gorm:"autoUpdateTime;comment:更新时间" json:"updateTime"`
	Remark    string         `gorm:"size:500;comment:备注" json:"remark"`
	DeletedAt gorm.DeletedAt `gorm:"index;comment:软删除标记" json:"-"`
}

2. 核心权限模型 (sys_auth.go)

package models

import "gorm.io/gorm"

// SysUser 用户管理表
type SysUser struct {
	BaseModel
	DeptID       uint   `gorm:"column:dept_id;comment:所属部门ID" json:"deptId"`
	UserName     string `gorm:"column:user_name;size:30;not null;comment:用户账号" json:"userName"`
	NickName     string `gorm:"column:nick_name;size:30;not null;comment:用户昵称" json:"nickName"`
	UserType     string `gorm:"column:user_type;size:2;default:'00';comment:用户类型(00系统用户)" json:"userType"`
	Email        string `gorm:"column:email;size:50;default:'';comment:用户邮箱" json:"email"`
	Phonenumber  string `gorm:"column:phonenumber;size:11;default:'';comment:手机号码" json:"phonenumber"`
	Sex          string `gorm:"column:sex;size:1;default:'0';comment:性别(0男 1女 2未知)" json:"sex"`
	Avatar       string `gorm:"column:avatar;size:100;default:'';comment:头像地址" json:"avatar"`
	Password     string `gorm:"column:password;size:100;not null;comment:密码" json:"-"`
	Status       string `gorm:"column:status;size:1;default:'0';comment:帐号状态(0正常 1停用)" json:"status"`
	DelFlag      string `gorm:"column:del_flag;size:1;default:'0';comment:删除标志(0代表存在 2代表删除)" json:"-"`
	LoginIP      string `gorm:"column:login_ip;size:128;default:'';comment:最后登录IP" json:"loginIP"`
	LoginDate    string `gorm:"column:login_date;comment:最后登录时间" json:"loginDate"`
	PostID       string `gorm:"column:post_ids;type:varchar(255);default:'';comment:岗位ID组(逗号分隔)" json:"postIds"`
}
func (SysUser) TableName() string { return "sys_user" }

// SysDept 部门管理表 (树形结构)
type SysDept struct {
	BaseModel
	ParentID   uint   `gorm:"column:parent_id;default:0;comment:父部门ID" json:"parentId"`
	Ancestors  string `gorm:"column:ancestors;size:50;default:'';comment:祖级列表" json:"ancestors"`
	DeptName   string `gorm:"column:dept_name;size:30;not null;comment:部门名称" json:"deptName"`
	OrderNum   int    `gorm:"column:order_num;default:0;comment:显示顺序" json:"orderNum"`
	Leader     string `gorm:"column:leader;size:20;comment:负责人" json:"leader"`
	Phone      string `gorm:"column:phone;size:11;comment:联系电话" json:"phone"`
	Email      string `gorm:"column:email;size:50;comment:邮箱" json:"email"`
	Status     string `gorm:"column:status;size:1;default:'0';comment:部门状态(0正常 1停用)" json:"status"`
}
func (SysDept) TableName() string { return "sys_dept" }

// SysPost 岗位管理表
type SysPost struct {
	BaseModel
	PostCode string `gorm:"column:post_code;size:64;not null;comment:岗位编码" json:"postCode"`
	PostName string `gorm:"column:post_name;size:50;not null;comment:岗位名称" json:"postName"`
	PostSort int    `gorm:"column:post_sort;default:0;comment:显示顺序" json:"postSort"`
	Status   string `gorm:"column:status;size:1;default:'0';comment:状态(0正常 1停用)" json:"status"`
}
func (SysPost) TableName() string { return "sys_post" }

// SysMenu 菜单管理表
type SysMenu struct {
	MenuID       uint   `gorm:"primaryKey;autoIncrement;column:menu_id;comment:菜单ID" json:"menuId"`
	MenuName     string `gorm:"column:menu_name;size:50;not null;comment:菜单名称" json:"menuName"`
	ParentID     uint   `gorm:"column:parent_id;default:0;comment:父菜单ID" json:"parentId"`
	OrderNum     int    `gorm:"column:order_num;default:0;comment:显示顺序" json:"orderNum"`
	Path         string `gorm:"column:path;size:200;default:'';comment:路由地址" json:"path"`
	Component    string `gorm:"column:component;size:255;comment:组件路径" json:"component"`
	Query        string `gorm:"column:query;size:255;default:'';comment:路由参数" json:"query"`
	RouteName    string `gorm:"column:route_name;size:50;default:'';comment:路由名称" json:"routeName"`
	IsFrame      int    `gorm:"column:is_frame;default:1;comment:是否为外链(0是 1否)" json:"isFrame"`
	IsCache      int    `gorm:"column:is_cache;default:0;comment:是否缓存(0缓存 1不缓存)" json:"isCache"`
	MenuType     string `gorm:"column:menu_type;size:1;default:'M';comment:菜单类型(M目录 C菜单 F按钮)" json:"menuType"`
	Visible      string `gorm:"column:visible;size:1;default:'0';comment:菜单状态(0显示 1隐藏)" json:"visible"`
	Status       string `gorm:"column:status;size:1;default:'0';comment:菜单状态(0正常 1停用)" json:"status"`
	Perms        string `gorm:"column:perms;size:100;comment:权限标识" json:"perms"`
	Icon         string `gorm:"column:icon;size:100;default:'#';comment:菜单图标" json:"icon"`
	BaseModel `gorm:"embedded"` // 使用嵌套避免重复ID
}
func (SysMenu) TableName() string { return "sys_menu" }

// SysRole 角色管理表 (含数据权限)
type SysRole struct {
	BaseModel
	RoleName            string `gorm:"column:role_name;size:30;not null;comment:角色名称" json:"roleName"`
	RoleKey             string `gorm:"column:role_key;size:100;not null;comment:角色权限字符串" json:"roleKey"`
	RoleSort            int    `gorm:"column:role_sort;default:0;comment:显示顺序" json:"roleSort"`
	DataScope           string `gorm:"column:data_scope;size:1;default:'1';comment:数据范围(1全部数据权限 2自定 3本部门 4本部门及以下 5仅本人)" json:"dataScope"`
	MenuCheckStrictly   int    `gorm:"column:menu_check_strictly;default:1;comment:菜单树选择项是否关联显示" json:"menuCheckStrictly"`
	DeptCheckStrictly   int    `gorm:"column:dept_check_strictly;default:1;comment:部门树选择项是否关联显示" json:"deptCheckStrictly"`
	Status              string `gorm:"column:status;size:1;default:'0';comment:角色状态(0正常 1停用)" json:"status"`
}
func (SysRole) TableName() string { return "sys_role" }

// 关联表提示(GORM 多对多自动管理)
type SysUserRole struct {
	UserID uint `gorm:"primaryKey;column:user_id"`
	RoleID uint `gorm:"primaryKey;column:role_id"`
}
func (SysUserRole) TableName() string { return "sys_user_role" }

type SysRoleMenu struct {
	RoleID uint `gorm:"primaryKey;column:role_id"`
	MenuID uint `gorm:"primaryKey;column:menu_id"`
}
func (SysRoleMenu) TableName() string { return "sys_role_menu" }

type SysRoleDept struct {
	RoleID uint `gorm:"primaryKey;column:role_id"`
	DeptID uint `gorm:"primaryKey;column:dept_id"`
}
func (SysRoleDept) TableName() string { return "sys_role_dept" }

3. 字典与参数模型 (sys_dict_config.go)

package models

// SysDictType 字典类型表
type SysDictType struct {
	BaseModel
	DictName string `gorm:"column:dict_name;size:100;default:'';comment:字典名称" json:"dictName"`
	DictType string `gorm:"column:dict_type;size:100;uniqueIndex;not null;comment:字典类型" json:"dictType"`
	Status   string `gorm:"column:status;size:1;default:'0';comment:状态(0正常 1停用)" json:"status"`
}
func (SysDictType) TableName() string { return "sys_dict_type" }

// SysDictData 字典数据表
type SysDictData struct {
	BaseModel
	DictSort  int    `gorm:"column:dict_sort;default:0;comment:字典排序" json:"dictSort"`
	DictLabel string `gorm:"column:dict_label;size:100;comment:字典标签" json:"dictLabel"`
	DictValue string `gorm:"column:dict_value;size:100;comment:字典键值" json:"dictValue"`
	DictType  string `gorm:"column:dict_type;size:100;index;comment:字典类型" json:"dictType"`
	CSSClass  string `gorm:"column:css_class;size:100;comment:样式属性" json:"cssClass"`
	ListClass string `gorm:"column:list_class;size:100;comment:表格回显样式" json:"listClass"`
	IsDefault string `gorm:"column:is_default;size:1;default:'N';comment:是否默认(Y是 N否)" json:"isDefault"`
	Status    string `gorm:"column:status;size:1;default:'0';comment:状态(0正常 1停用)" json:"status"`
}
func (SysDictData) TableName() string { return "sys_dict_data" }

// SysConfig 参数管理表
type SysConfig struct {
	BaseModel
	ConfigName  string `gorm:"column:config_name;size:100;default:'';comment:参数名称" json:"configName"`
	ConfigKey   string `gorm:"column:config_key;size:100;uniqueIndex;comment:参数键名" json:"configKey"`
	ConfigValue string `gorm:"column:config_value;size:500;default:'';comment:参数键值" json:"configValue"`
	ConfigType  string `gorm:"column:config_type;size:1;default:'N';comment:系统内置(Y是 N否)" json:"configType"`
}
func (SysConfig) TableName() string { return "sys_config" }

4. 通知公告与日志模型 (sys_log_notice.go)

package models

import "time"

// SysNotice 通知公告表
type SysNotice struct {
	NoticeID     uint   `gorm:"primaryKey;autoIncrement;column:notice_id;comment:公告ID" json:"noticeId"`
	NoticeTitle  string `gorm:"column:notice_title;size:50;not null;comment:公告标题" json:"noticeTitle"`
	NoticeType   string `gorm:"column:notice_type;size:1;comment:公告类型(1通知 2公告)" json:"noticeType"`
	NoticeContent string `gorm:"column:notice_content;type:longtext;comment:公告内容" json:"noticeContent"`
	Status       string `gorm:"column:status;size:1;default:'0';comment:公告状态(0正常 1关闭)" json:"status"`
	BaseModel    `gorm:"embedded"`
}
func (SysNotice) TableName() string { return "sys_notice" }

// SysOperLog 操作日志表
type SysOperLog struct {
	OperID         uint      `gorm:"primaryKey;autoIncrement;column:oper_id;comment:日志主键" json:"operId"`
	Title          string    `gorm:"column:title;size:50;default:'';comment:模块标题" json:"title"`
	BusinessType   string    `gorm:"column:business_type;size:20;default:'0';comment:业务类型(0其它 1新增 2修改 3删除)" json:"businessType"`
	Method         string    `gorm:"column:method;size:100;default:'';comment:方法名称" json:"method"`
	RequestMethod  string    `gorm:"column:request_method;size:10;default:'';comment:请求方式" json:"requestMethod"`
	OperatorType   string    `gorm:"column:operator_type;size:1;default:'0';comment:操作类别" json:"operatorType"`
	OperName       string    `gorm:"column:oper_name;size:50;default:'';comment:操作人员" json:"operName"`
	DeptName       string    `gorm:"column:dept_name;size:50;default:'';comment:部门名称" json:"deptName"`
	OperURL        string    `gorm:"column:oper_url;size:255;default:'';comment:请求URL" json:"operUrl"`
	OperIP         string    `gorm:"column:oper_ip;size:128;default:'';comment:主机地址" json:"operIp"`
	OperLocation   string    `gorm:"column:oper_location;size:255;default:'';comment:操作地点" json:"operLocation"`
	OperParam      string    `gorm:"column:oper_param;type:longtext;default:'';comment:请求参数" json:"operParam"`
	JSONResult     string    `gorm:"column:json_result;type:longtext;default:'';comment:返回参数" json:"jsonResult"`
	Status         string    `gorm:"column:status;size:1;default:'0';comment:操作状态(0正常 1异常)" json:"status"`
	ErrorMsg       string    `gorm:"column:error_msg;size:2000;default:'';comment:错误消息" json:"errorMsg"`
	OperTime       time.Time `gorm:"column:oper_time;comment:操作时间" json:"operTime"`
}
func (SysOperLog) TableName() string { return "sys_oper_log" }

// SysLogininfor 登录日志表
type SysLogininfor struct {
	InfoID        uint      `gorm:"primaryKey;autoIncrement;column:info_id;comment:访问ID" json:"infoId"`
	UserName      string    `gorm:"column:user_name;size:50;default:'';comment:用户账号" json:"userName"`
	Ipaddr        string    `gorm:"column:ipaddr;size:128;default:'';comment:登录IP地址" json:"ipaddr"`
	LoginLocation string    `gorm:"column:login_location;size:255;default:'';comment:登录地点" json:"loginLocation"`
	Browser       string    `gorm:"column:browser;size:50;default:'';comment:浏览器类型" json:"browser"`
	OS            string    `gorm:"column:os;size:50;default:'';comment:操作系统" json:"os"`
	Status        string    `gorm:"column:status;size:1;default:'0';comment:登录状态(0成功 1失败)" json:"status"`
	Msg           string    `gorm:"column:msg;size:255;default:'';comment:提示消息" json:"msg"`
	LoginTime     time.Time `gorm:"column:login_time;comment:访问时间" json:"loginTime"`
}
func (SysLogininfor) TableName() string { return "sys_logininfor" }

5. 定时任务模型 (sys_job.go)

package models

import "time"

// SysJob 定时任务调度表
type SysJob struct {
	JobID         uint   `gorm:"primaryKey;autoIncrement;column:job_id;comment:任务ID" json:"jobId"`
	JobName       string `gorm:"column:job_name;size:64;default:'';comment:任务名称" json:"jobName"`
	JobGroup      string `gorm:"column:job_group;size:64;default:'DEFAULT';comment:任务组名" json:"jobGroup"`
	InvokeTarget  string `gorm:"column:invoke_target;size:500;not null;comment:调用目标字符串" json:"invokeTarget"`
	CronExpression string `gorm:"column:cron_expression;size:255;default:'';comment:cron执行表达式" json:"cronExpression"`
	MisfirePolicy string `gorm:"column:misfire_policy;size:20;default:'3';comment:计划执行错误策略(1立即执行 2执行一次 3放弃执行)" json:"misfirePolicy"`
	Concurrent    string `gorm:"column:concurrent;size:1;default:'1';comment:是否并发执行(0允许 1禁止)" json:"concurrent"`
	Status        string `gorm:"column:status;size:1;default:'0';comment:状态(0正常 1暂停)" json:"status"`
	BaseModel     `gorm:"embedded"`
}
func (SysJob) TableName() string { return "sys_job" }

// SysJobLog 定时任务调度日志表
type SysJobLog struct {
	JobLogID     uint      `gorm:"primaryKey;autoIncrement;column:job_log_id;comment:任务日志ID" json:"jobLogId"`
	JobName      string    `gorm:"column:job_name;size:64;comment:任务名称" json:"jobName"`
	JobGroup     string    `gorm:"column:job_group;size:64;comment:任务组名" json:"jobGroup"`
	InvokeTarget string    `gorm:"column:invoke_target;size:500;comment:调用目标字符串" json:"invokeTarget"`
	JobMessage   string    `gorm:"column:job_message;size:500;comment:日志信息" json:"jobMessage"`
	Status       string    `gorm:"column:status;size:1;default:'0';comment:执行状态(0正常 1失败)" json:"status"`
	ExceptionInfo string   `gorm:"column:exception_info;type:longtext;default:'';comment:异常信息" json:"exceptionInfo"`
	StartTime    time.Time `gorm:"column:start_time;comment:开始时间" json:"startTime"`
	StopTime     time.Time `gorm:"column:stop_time;comment:停止时间" json:"stopTime"`
}
func (SysJobLog) TableName() string { return "sys_job_log" }

6. 代码生成元数据模型 (sys_gen.go)

package models

// SysGenTable 代码生成表定义
type SysGenTable struct {
	TableID         uint   `gorm:"primaryKey;autoIncrement;column:table_id;comment:编号" json:"tableId"`
	TableName       string `gorm:"column:table_name;size:200;default:'';comment:表名称" json:"tableName"`
	TableComment    string `gorm:"column:table_comment;size:500;default:'';comment:表描述" json:"tableComment"`
	SubTableName    string `gorm:"column:sub_table_name;size:64;comment:关联子表的表名" json:"subTableName"`
	SubTableFKName  string `gorm:"column:sub_table_fk_name;size:64;comment:子表关联的外键列" json:"subTableFKName"`
	ClassName       string `gorm:"column:class_name;size:100;default:'';comment:实体类名称" json:"className"`
	TplCategory     string `gorm:"column:tpl_category;size:200;default:'crud';comment:使用的模板" json:"tplCategory"`
	PackageName     string `gorm:"column:package_name;size:100;comment:生成包路径" json:"packageName"`
	ModuleName      string `gorm:"column:module_name;size:30;comment:生成模块名" json:"moduleName"`
	BusinessName    string `gorm:"column:business_name;size:30;comment:生成业务名" json:"businessName"`
	FunctionName    string `gorm:"column:function_name;size:50;comment:生成功能名" json:"functionName"`
	FunctionAuthor  string `gorm:"column:function_author;size:50;comment:生成功能作者" json:"functionAuthor"`
	GenType         string `gorm:"column:gen_type;size:1;default:'0';comment:生成代码方式(0zip压缩包 1自定义路径)" json:"genType"`
	GenPath         string `gorm:"column:gen_path;size:200;comment:生成路径" json:"genPath"`
	Options         string `gorm:"column:options;type:longtext;comment:其它生成选项" json:"options"`
	BaseModel       `gorm:"embedded"`
}
func (SysGenTable) TableName() string { return "sys_gen_table" }

// SysGenColumn 代码生成业务字段
type SysGenColumn struct {
	ColumnID     uint   `gorm:"primaryKey;autoIncrement;column:column_id;comment:编号" json:"columnId"`
	TableID      uint   `gorm:"column:table_id;index:idx_table;comment:归属表编号" json:"tableId"`
	ColumnName   string `gorm:"column:column_name;size:200;comment:列名称" json:"columnName"`
	ColumnComment string `gorm:"column:column_comment;size:500;comment:列描述" json:"columnComment"`
	ColumnType   string `gorm:"column:column_type;size:100;comment:列类型" json:"columnType"`
	GoType       string `gorm:"column:go_type;size:500;comment:Go类型" json:"goType"`
	GoField      string `gorm:"column:go_field;size:200;comment:Go字段名" json:"goField"`
	DictType     string `gorm:"column:dict_type;size:200;comment:字典类型" json:"dictType"`
	IsPK         string `gorm:"column:is_pk;size:1;default:'N';comment:是否主键(1是)" json:"isPk"`
	IsIncrement  string `gorm:"column:is_increment;size:1;default:'N';comment:是否自增(1是)" json:"isIncrement"`
	IsRequired   string `gorm:"column:is_required;size:1;default:'N';comment:是否必填(1是)" json:"isRequired"`
	IsInsert     string `gorm:"column:is_insert;size:1;default:'N';comment:是否插入字段(1是)" json:"isInsert"`
	IsEdit       string `gorm:"column:is_edit;size:1;default:'N';comment:是否编辑字段(1是)" json:"isEdit"`
	IsList       string `gorm:"column:is_list;size:1;default:'Y';comment:是否列表字段(1是)" json:"isList"`
	IsQuery      string `gorm:"column:is_query;size:1;default:'Y';comment:是否查询字段(1是)" json:"isQuery"`
	QueryType    string `gorm:"column:query_type;size:200;default:'EQ';comment:查询方式(EQ等于/NE不等于/GT大于/LT小于/LIKE/BEWEEN)" json:"queryType"`
	HTMLType     string `gorm:"column:html_type;size:200;comment:显示类型(input/textarea/select/checkbox/radio/editor)" json:"htmlType"`
}
func (SysGenColumn) TableName() string { return "sys_gen_column" }

💡 针对您需求中非持久化模块的说明

功能模块 实现建议 是否需建表
在线用户 基于 Redis 存储 Token 信息(Key: access_tokens:{uuid}),查询时遍历或分页获取,退出/踢出直接 DEL
系统接口 使用 swag init 自动生成 Swagger 文档,路由扫描依赖 gin-swagger 中间件,无需单独表
服务监控 调用 github.com/shirou/gopsutil/v3 实时读取 CPU/内存/磁盘,前端轮询或 WebSocket 推送
缓存监控 直接连接 Redis 实例,通过 INFO, DBSIZE, CLIENT LIST 命令获取指标,支持 FLUSHDB 清理
在线构建器 纯前端实现(如 Formily、BPMN.js),拖拽结果通常以 JSON 字符串存在业务表或 localStorage,无需专属系统表

🛠 GORM 使用最佳实践

  1. 自动迁移:启动时调用 db.AutoMigrate(&models.SysUser{}, &models.SysDept{}...) 即可同步表结构。
  2. 关联预加载
    db.Preload("Roles").Preload("Dept").First(&user, id)
    
  3. 索引优化:日志类表(SysOperLogSysLogininforSysJobLog)数据量极大,建议按 CreateTimeOperTime 进行 按月/季度分表,或定期归档到冷数据库。
  4. 数据权限实现:在 GORM 插件层或全局中间件中拦截 Where 条件,根据当前用户的 Role.DataScope 动态注入 dept_id IN (...) 过滤条件,避免在业务代码中硬编码。

如需配套的 Service/Dao 层 封装、权限中间件或 Swagger 路由配置代码,可提供具体技术栈版本(如 Gin/Echo + GORM v2),我将继续补充。


这套核心权限模型遵循经典的 RBAC(基于角色的访问控制)+ 数据权限 架构。在关系型数据库与 GORM 的语境下,实体间的对应关系可分为 一对一/多对一一对多多对多 以及 自关联树形 四类。

以下是详细的关系映射、GORM 实现方式及业务含义:

📊 核心关系总览表

实体 A 实体 B 关系类型 物理存储/外键 GORM 映射方式 业务含义
SysDept SysUser 一对多 (1 Dept → N Users) sys_user.dept_id BelongsTo / HasMany 一个部门包含多名员工
SysUser SysRole 多对多 (N Users ↔ N Roles) sys_user_role 中间表 Many2Many 用户可兼任多个角色
SysUser SysPost 多对多 (逻辑) sys_user.post_ids (逗号分隔) 手动 Split 或自定义 Join 员工可担任多个岗位(简化设计)
SysRole SysMenu 多对多 (N Roles ↔ N Menus) sys_role_menu 中间表 Many2Many 角色分配菜单/按钮操作权限
SysRole SysDept 多对多 (N Roles ↔ N Depts) sys_role_dept 中间表 Many2Many 角色数据范围(可见哪些部门的数据)
SysMenu SysMenu 自关联一对多 (树形) sys_menu.parent_id HasMany / BelongsTo 菜单多级嵌套(目录→菜单→按钮)
SysDept SysDept 自关联一对多 (树形) sys_dept.parent_id + ancestors HasMany / BelongsTo 组织架构树(公司→部门→小组)

🔍 详细关系拆解与 GORM 实现

1. 用户 部门:多对一 / 一对多
  • 关系:一个用户只能属于一个主部门,一个部门下有多名用户。
  • GORM 定义示例
    // SysUser 侧(多对一)
    type SysUser struct {
        DeptID uint   `gorm:"column:dept_id;comment:所属部门ID"`
        Dept   SysDept `gorm:"foreignKey:DeptID;references:ID;comment:关联部门"`
    }
    // SysDept 侧(一对多)
    type SysDept struct {
        Users []SysUser `gorm:"foreignKey:DeptID;references:ID;comment:部门成员"`
    }
    
  • 业务用法:查询用户时预加载部门信息 db.Preload("Dept").First(&user);统计部门人数直接 db.Model(&SysDept{}).Association("Users").Count()
2. 用户 角色:多对多(标准 RBAC)
  • 关系:用户可拥有多个角色,角色可分配给多个用户。通过 sys_user_role 解耦。
  • GORM 定义示例
    type SysUser struct {
        // ...
        Roles []SysRole `gorm:"many2many:sys_user_role;joinForeignKey:UserID;joinReferences:RoleID"`
    }
    type SysRole struct {
        // ...
        Users []SysUser `gorm:"many2many:sys_user_role;joinForeignKey:RoleID;joinReferences:UserID"`
    }
    
  • 业务用法:GORM 自动管理中间表。登录时获取用户权限链:db.Preload("Roles").First(&user) → 遍历角色获取菜单权限。

注意,RuoYi模型为用户N-1角色,简化了业务逻辑(规则更清晰)

3. 用户 岗位:多对多(非规范化设计)
  • 关系:逻辑上是多对多,但模型中使用了 post_ids string(如 "1,3,5")。
  • 设计考量:企业后台中岗位变动频率低,且前端多为多选下拉框。使用逗号分隔可避免频繁 JOIN,提升列表查询性能。若需强一致性,可改为标准中间表 sys_user_post
  • GORM 处理:不直接定义关联,业务层用 strings.Split(postIds, ",") 转换,或通过自定义 Hook 序列化/反序列化。
4. 角色 菜单:多对多(功能权限)
  • 关系:决定角色能访问哪些路由、显示哪些按钮。通过 sys_role_menu 维护。
  • GORM 定义:同用户角色,使用 Many2Many:sys_role_menu
  • 业务用法:权限拦截中间件会读取 sys_role_menu 生成 perms 列表(如 ["system:user:add", "system:user:edit"]),前端通过 v-hasPermi 指令控制按钮显隐。
5. 角色 部门:多对多(数据权限)
  • 关系:控制角色能查看哪些部门产生的数据。由 SysRole.DataScope 字段配合 sys_role_dept 实现。
  • DataScope 策略
    含义 SQL 过滤逻辑
    1 全部数据 不追加条件
    2 自定义部门 WHERE dept_id IN (SELECT dept_id FROM sys_role_dept WHERE role_id=?)
    3 本部门数据 WHERE dept_id = 当前用户dept_id
    4 本部门及以下 WHERE dept_id IN (SELECT id FROM sys_dept WHERE ancestors LIKE '%当前用户dept_id,%')
    5 仅本人数据 WHERE create_by = 当前用户username
  • GORM 实现:通常封装为 GORM 插件或全局 Where 拦截器,根据 DataScope 动态注入 WHERE 子句,实现行级数据隔离
6. 菜单 & 部门:自关联树形结构
  • 关系:自身引用自身形成层级树。
  • 关键字段
    • parent_id:指向父节点 ID,根节点为 0
    • ancestors(部门特有):祖级链路,如 0,100,101。用于避免递归查询,直接 LIKE '0,100,%' 即可查出所有子孙节点。
  • GORM 查询树
    // 方式1:递归加载(适合小数据量)
    db.Preload("Children").Where("parent_id = 0").Find(&menus)
    
    // 方式2:一次性查平铺 + 内存组装树(推荐,性能高)
    var allDepts []SysDept
    db.Find(&allDepts)
    tree := BuildTree(allDepts, 0) // 自定义函数递归组装
    

🧩 权限校验完整数据流向示例

当一个用户请求 POST /api/system/user 时:

  1. 身份认证:解析 Token → 获取 UserID
  2. 功能权限UserIDsys_user_rolesys_role_menu → 匹配 perms: "system:user:add" → 放行请求
  3. 数据权限:拦截器读取当前角色 DataScope=2(自定义)→ 查 sys_role_dept 获取允许的 DeptID 列表 → 自动在业务 SQL 追加 WHERE dept_id IN (101,102)
  4. 结果返回:仅返回该角色权限范围内的数据,越权请求返回 403 Forbidden

💡 架构建议

  1. 避免 N+1 查询:权限树、用户列表等高频场景,优先使用单次查询 + 内存构建树,而非 GORM 递归 Preload
  2. 中间表显式声明:虽然 GORM 支持隐式多对多,但显式定义 SysUserRole 等结构体便于后续扩展字段(如 create_time, assign_by)。
  3. 数据权限插件化:建议封装 GORM Callback,在 gorm:query 阶段自动拼接数据权限 WHERE 条件,业务代码无需关心过滤逻辑。

如需我提供 GORM 数据权限拦截插件代码树形结构内存组装算法权限中间件完整实现,可告知具体需求。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐