| name | expert-ruoyi |
| description | 若依(RuoYi)框架开发专家,精通项目搭建、代码生成和架构优化。当用户涉及若依框架开发、权限配置或菜单路由配置时自动触发。支持中文触发:若依框架、RuoYi、SpringBoot后台、权限配置。 |
若依框架开发专家
1. 技能概述
1.1 核心能力
核心能力:
- 项目搭建: SpringBoot + MyBatis + Shiro/Security
- 代码生成: CRUD代码自动生成
- 权限管理: 菜单权限、按钮权限、数据权限
- 动态路由: 基于sys_menu表的动态路由
- 最佳实践: 若依框架开发规范
适用场景:
- 新功能开发遇到权限问题
- 菜单配置后页面404
- 代码生成器使用
- 权限注解不生效
- 数据范围过滤异常
1.2 与其他技能协作
| 协作技能 | 协作方式 | 传入数据 | 期望输出 |
|---|
| pdd-implement-feature | Consultation | 若依技术问题 | 解决方案 |
| pdd-code-reviewer | Reference | 发现若依问题 | 框架最佳实践 |
| software-engineer | Delegation | 代码实现任务 | 符合规范的代码 |
2. 快速诊断模式
2.1 问题分类索引
问题类型:
路由问题:
- 页面404
- 菜单不显示
- 路由404
权限问题:
- 权限注解不生效
- 按钮不显示
- 数据范围错误
代码生成问题:
- 生成代码报错
- 生成后需要调整
配置问题:
- 数据库配置
- Redis缓存
- 会话管理
2.2 路由问题诊断
问题: 点击菜单后页面404
诊断流程:
1. 检查 sys_menu 表配置
SELECT * FROM sys_menu WHERE menu_name = 'XXX';
2. 检查 component 路径
- 路径相对于 src/views
- 文件必须存在
3. 检查 visible 字段
- '0' = 显示菜单
- '1' = 隐藏菜单
4. 检查父菜单是否存在
SELECT * FROM sys_menu WHERE menu_id = parent_id;
5. 检查角色权限分配
SELECT * FROM sys_role_menu WHERE menu_id = menu_id;
2.3 权限问题诊断
问题: @PreAuthorize 注解不生效
诊断流程:
1. 检查注解是否正确
@PreAuthorize("@ss.hasPermi('xxx:xxx:xxx')")
2. 检查 sys_menu 表中权限标识符
- perms 字段必须与注解中一致
3. 检查角色菜单分配
SELECT * FROM sys_role_menu WHERE menu_id IN
(SELECT menu_id FROM sys_menu WHERE perms = 'xxx:xxx:xxx');
4. 检查用户角色
SELECT * FROM sys_user_role WHERE user_id = user_id;
5. 清除Redis缓存
FLUSHDB
3. 核心配置规范
3.1 菜单配置规范
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, menu_type, visible, perms, icon)
VALUES ('资产管理', 0, 1, 'asset', NULL, 'M', '0', NULL, 'asset');
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, menu_type, visible, perms, icon)
VALUES ('资产列表', parent_id, 1, 'list', 'asset/index', 'C', '0', 'asset:list:list', 'list');
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, menu_type, visible, perms)
VALUES ('资产新增', parent_id, 10, 'add', 'asset/form', 'C', '1', 'asset:list:add');
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, menu_type, visible, perms)
VALUES ('资产新增按钮', menu_id, 1, '', '', 'F', '0', 'asset:list:add');
3.2 权限注解规范
@RestController
@RequestMapping("/asset/list")
public class AssetListController {
@PreAuthorize("@ss.hasPermi('asset:list:list')")
@GetMapping
public AjaxResult list() { }
@PreAuthorize("@ss.hasPermi('asset:list:add')")
@PostMapping
public AjaxResult add() { }
@PreAuthorize("@ss.hasPermi('asset:list:edit')")
@PutMapping
public AjaxResult edit() { }
@PreAuthorize("@ss.hasPermi('asset:list:remove')")
@DeleteMapping
public AjaxResult remove() { }
@PreAuthorize("@ss.hasPermi('asset:list:export')")
@GetMapping("/export")
public void export() { }
}
3.3 数据权限规范
public interface IAssetService {
@DataScope(deptAlias = "d", userAlias = "u")
List<Asset> selectAssetList(Asset asset);
}
<select id="selectAssetList" resultMap="AssetResult">
SELECT a.*, d.dept_name
FROM asset a
LEFT JOIN sys_dept d ON a.dept_id = d.dept_id
LEFT JOIN sys_user u ON a.create_by = u.user_name
WHERE a.del_flag = '0'
${params.dataScope}
</select>
4. 代码生成器使用
4.1 生成后必须调整项
| 调整项 | 原因 | 优先级 |
|---|
| 添加 @Validated 注解 | 参数校验 | P0 |
| 添加 @DataScope 注解 | 数据权限 | P0 |
| 添加 @Xss 注解 | XSS防护 | P0 |
| 配置 sys_menu 表 | 菜单路由 | P0 |
| 分配角色菜单权限 | 权限生效 | P0 |
| 清除Redis缓存 | 刷新权限缓存 | P0 |
4.2 代码调整示例
@PostMapping
public AjaxResult add(Asset asset) {
return AjaxResult.success(assetService.insertAsset(asset));
}
@PreAuthorize("@ss.hasPermi('asset:list:add')")
@Log(title = "资产管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody Asset asset) {
return AjaxResult.success(assetService.insertAsset(asset));
}
@Excel(name = "资产名称")
@Xss
private String assetName;
@DataScope(deptAlias = "d", userAlias = "u")
List<Asset> selectAssetList(Asset asset);
5. 常见问题解决方案
5.1 页面404问题
问题: 点击菜单后页面404
排查步骤:
SELECT * FROM sys_menu WHERE menu_name LIKE '%XXX%';
SELECT * FROM sys_menu WHERE menu_id = parent_id;
SELECT * FROM sys_role_menu WHERE menu_id = menu_id;
解决方案:
- 确认 sys_menu 表中 component 路径正确
- 确认 Vue 文件存在于正确位置
- 确认菜单已分配给用户角色
- 清除Redis缓存
- 重新登录
5.2 权限注解不生效
问题: @PreAuthorize 注解不生效,所有用户都能访问
排查步骤:
SELECT perms FROM sys_menu WHERE menu_name = 'XXX';
SELECT r.role_name, m.menu_name
FROM sys_role_menu rm
JOIN sys_menu m ON rm.menu_id = m.menu_id
WHERE m.perms = 'xxx:xxx:xxx';
SELECT u.user_name, r.role_name
FROM sys_user_role ur
JOIN sys_role r ON ur.role_id = r.role_id
WHERE ur.user_id = user_id;
解决方案:
- 确认注解中的权限标识符与 sys_menu.perms 一致
- 确认角色已分配对应菜单权限
- 确认用户已分配对应角色
- 清除Redis缓存
- 重新登录获取最新权限
5.3 数据范围过滤不生效
问题: 用户能看到不属于自己部门的数据
排查步骤:
SELECT u.user_name, d.dept_name, d.dept_id
FROM sys_user u
JOIN sys_dept d ON u.dept_id = d.dept_id
WHERE u.user_id = user_id;
解决方案:
- 确认 @DataScope 注解配置正确
- 确认 Mapper XML 中表别名正确
- 确认 sys_user 表中 dept_id 正确
- 重新登录获取新的会话信息
5.4 按钮权限不显示
问题: 用户有权限但按钮不显示
排查步骤:
<el-button v-hasPermi="['asset:list:add']">
新增
</el-button>
解决方案:
- 确认前端按钮使用了 v-hasPermi 指令
- 确认权限标识符完全一致
- 确认按钮对应的菜单权限已分配
- 清除浏览器缓存
- 重新登录
6. 最佳实践清单
6.1 开发检查清单
新增功能检查项:
- [ ] sys_menu 表配置完整 (目录/菜单/按钮)
- [ ] component 路径正确
- [ ] 权限标识符唯一且规范
- [ ] 角色菜单权限已分配
- [ ] @PreAuthorize 注解配置正确
- [ ] @DataScope 注解配置正确 (如需要)
- [ ] @Validated 参数校验添加
- [ ] @Xss 文本字段防护添加
- [ ] @Log 操作日志添加
- [ ] Redis缓存已清除
- [ ] 用户重新登录
6.2 API命名规范
export function listAsset(query) {
return request({ url: '/asset/list', method: 'get', params: query });
}
export function getAsset(assetId) {
return request({ url: '/asset/' + assetId, method: 'get' });
}
export function addAsset(data) {
return request({ url: '/asset', method: 'post', data });
}
export function updateAsset(data) {
return request({ url: '/asset', method: 'put', data });
}
export function delAsset(assetId) {
return request({ url: '/asset/' + assetId, method: 'delete' });
}
export function exportAsset(query) {
return request({ url: '/asset/export', method: 'get', params: query });
}
7. Guardrails
7.1 必须遵守
7.2 避免事项
- ❌ 硬编码权限标识符
- ❌ 跳过菜单配置直接访问页面
- ❌ 前端验证替代后端验证
- ❌ 忘记清除Redis缓存
7.5 若依Spec模板参考
当pdd-generate-spec为若依项目生成开发规格时,expert-ruoyi应提供以下模板参考:
7.5.1 若依Spec必须包含的章节
| 章节 | 内容 | 若依特有要求 |
|---|
| 数据模型 | 实体类定义 | 必须包含BaseEntity继承、@Data/@TableName注解 |
| 接口设计 | Controller/Service/Mapper | 必须包含@PreAuthorize权限注解、@Log操作日志 |
| 菜单配置 | sys_menu INSERT语句 | 必须包含目录(M)+菜单(C)+按钮(F)三层配置 |
| 权限矩阵 | 权限标识符列表 | 格式:模块:功能:操作(如asset:list:add) |
| 数据权限 | @DataScope配置 | 必须指定deptAlias和userAlias |
| 前端API | request封装 | 必须遵循listXxx/getXxx/addXxx/updateXxx/delXxx命名 |
7.5.2 若依Spec模板片段
## 数据模型
### {EntityName} 实体
- 继承: BaseEntity
- 注解: @Data, @TableName("{table_name}")
- 字段:
| 字段名 | 类型 | 注解 | 说明 |
|--------|------|------|------|
| {fieldName} | {type} | @Excel(name="{label}") | {desc} |
## 接口设计
### {EntityName}Controller
- 路径: @RequestMapping("/{module}/{feature}")
- 权限前缀: {module}:{feature}
| 方法 | 路径 | 权限标识 | 注解 |
|------|------|---------|------|
| list | GET / | {module}:{feature}:list | @PreAuthorize |
| getInfo | GET /{id} | {module}:{feature}:query | @PreAuthorize |
| add | POST / | {module}:{feature}:add | @PreAuthorize + @Log |
| edit | PUT / | {module}:{feature}:edit | @PreAuthorize + @Log |
| remove | DELETE /{ids} | {module}:{feature}:remove | @PreAuthorize + @Log |
## 菜单配置SQL
-- 目录(M)
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, menu_type, visible, perms, icon)
VALUES ('{菜单名}', 0, {排序}, '{path}', NULL, 'M', '0', NULL, '{icon}');
-- 菜单(C) - 列表页
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, menu_type, visible, perms)
VALUES ('{菜单名}列表', {parent_id}, 1, '{path}', '{module}/{feature}/index', 'C', '0', '{module}:{feature}:list');
-- 按钮(F) - 新增/修改/删除/导出
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, menu_type, visible, perms)
VALUES ('{菜单名}新增', {menu_id}, 1, '', '', 'F', '0', '{module}:{feature}:add');
7.6 若依Bug模式库
完整模式定义: config/bug-patterns.yaml (categories.ruoyi)
expert-ruoyi在提供解决方案时,必须主动检查并避免以下已知Bug模式:
| 模式编号 | 模式名称 | 典型表现 | 预防措施 |
|---|
| PATTERN-R001 | 权限注解缺失 | Controller方法缺少@PreAuthorize | 每个接口方法必须配置权限注解 |
| PATTERN-R002 | 菜单配置不完整 | 新增页面404/按钮不显示 | 所有页面(含隐藏页)必须配置sys_menu |
| PATTERN-R003 | 数据权限未配置 | 用户看到跨部门数据 | Service方法添加@DataScope注解 |
| PATTERN-R004 | Redis缓存未清除 | 权限修改后不生效 | 修改权限/菜单后必须清除Redis |
| PATTERN-R005 | 参数校验缺失 | @RequestBody参数无@Validated | 所有@RequestBody参数添加@Validated |
| PATTERN-R006 | XSS防护缺失 | 文本字段未添加@Xss | 所有String类型文本字段添加@Xss |
| PATTERN-R007 | 操作日志缺失 | 增删改操作无@Log | 所有CUD操作添加@Log注解 |
| PATTERN-R008 | API路径拼接断层 | 前端请求404 | 前端API路径=类级@RequestMapping+方法级@XXXMapping |
| PATTERN-R009 | 附件入参类型错误 | 参数解析异常 | 通用上传后用List接收URL,不用MultipartFile |
| PATTERN-R010 | 状态流转审批日志遗漏 | 审批历史缺记录 | 状态变更方法加@Transactional并同步插入审批记录 |
| PATTERN-R011 | 状态字典映射不完整 | 状态显示英文原文 | 新增状态值时全局搜索所有映射方法并同步 |
| PATTERN-R012 | MyBatis多参数@Param缺失 | 参数绑定异常 | 多参数Mapper方法每个参数加@Param |
检查原则: 每次提供若依相关建议时,必须对照以上12个模式逐一检查,确保建议的代码不会触犯已知模式。新增模式时只需修改 config/bug-patterns.yaml,无需修改此文件。
7.7 前后端契约规范 / Frontend-Backend Contract Standards
🇨🇳
7.7.1 API 路径拼接规则
- 前端 API 路径 = Controller 类
@RequestMapping + 方法 @XXXMapping
- 编写前端 API 前,必须检查后端 Controller 类上的完整路径
- 防止:PATTERN-R008(API路径404)
request({ url: '/review/manage/detail/' + id })
request({ url: '/evaluation/approval/review/manage/detail/' + id })
7.7.2 附件处理标准模式
- 模式A(直传): 后端接收
MultipartFile,适用于单文件简单上传
- 模式B(先传后存): 前端先调
/common/upload 获取 URL,业务接口统一接收 List<String>
- 若依项目中,业务表单附件必须默认使用模式B
- 防止:PATTERN-R009(参数类型不匹配)
7.7.3 响应数据解析约定
- 后端返回嵌套结构时,前端取值路径必须与后端一致
- 修改后端返回结构后,必须同步检查所有前端取值路径
- 防止:response.data 解析错误
🇺🇸
7.7.1 API Path Concatenation Rule
- Frontend API path = Controller class
@RequestMapping + method @XXXMapping
- Before writing frontend API, must check the complete path on the backend Controller class
- Prevents: PATTERN-R008 (API path 404)
7.7.2 File Upload Standard Pattern
- Pattern A (Direct): Backend receives
MultipartFile, for simple single-file uploads
- Pattern B (Upload-then-Save): Frontend calls
/common/upload to get URL first, business API receives List<String>
- In RuoYi projects, business form attachments must default to Pattern B
- Prevents: PATTERN-R009 (parameter type mismatch)
7.7.3 Response Data Parsing Convention
- When backend returns nested structures, frontend value paths must match backend
- After modifying backend return structure, must sync-check all frontend value paths
7.8 页面生命周期规范 / Page Lifecycle Standards
🇨🇳
7.8.1 列表页 → 详情页 → 返回列表的标准流程
- 列表页使用
this.$router.push() 跳转到详情/处理页
- 详情页提交成功后:
- 调用
this.$store.dispatch('tagsView/delView', this.$route) 关闭标签
- 调用
this.$router.back() 返回列表
- 列表页必须实现
activated() 钩子,在 keep-alive 激活时刷新数据
activated() {
this.getList();
}
this.$store.dispatch('tagsView/delView', this.$route).then(() => {
this.$router.back();
});
7.8.2 状态字典管理
- 禁止在单个 Vue 组件中硬编码
getStatusLabel / getNodeLabel 等大段映射
- 必须抽离到
src/utils/constants.js 或使用若依字典管理 dict.type.xxx
- 防止:PATTERN-R011(状态映射不完整/横向不一致)
🇺🇸
7.8.1 List → Detail → Back to List Standard Flow
- List page uses
this.$router.push() to navigate to detail/process page
- After detail page submission succeeds:
- Call
this.$store.dispatch('tagsView/delView', this.$route) to close tag
- Call
this.$router.back() to return to list
- List page must implement
activated() hook to refresh data on keep-alive activation
7.8.2 Status Dictionary Management
- Forbidden to hardcode
getStatusLabel / getNodeLabel mappings in individual Vue components
- Must extract to
src/utils/constants.js or use RuoYi dictionary management dict.type.xxx
- Prevents: PATTERN-R011 (incomplete/inconsistent status mapping)
7.9 状态流转规范 / State Transition Standards
🇨🇳
7.9.1 审批日志强制记录
- 任何涉及
status 字段变更的操作,必须在同一事务中记录审批日志
- 使用
@Transactional 确保原子性
- 防止:PATTERN-R010(审批历史遗漏)
7.9.2 状态判断优先查表
- 禁止通过推断/计算获取实体状态,必须直接查询数据库字段
- 防止:状态推断偏差导致的业务逻辑错误
if (project.getApprovalRecords().size() >= requiredApprovals) {
}
String status = projectMapper.selectStatusById(id);
if ("approved".equals(status)) { ... }
🇺🇸
7.9.1 Mandatory Approval Log Recording
- Any operation involving
status field changes must record approval logs in the same transaction
- Use
@Transactional to ensure atomicity
- Prevents: PATTERN-R010 (missing approval history)
7.9.2 Status Lookup Over Inference
- Forbidden to infer entity status through calculation; must directly query database field
- Prevents: business logic errors caused by status inference bias
8. 本地开发指南
本项目有特定的开发规范和历史经验,请在提供建议时优先参考:
8.1 项目规则文件
| 文件 | 路径 | 内容 |
|---|
| 项目规则 | .trae/rules/project_rules.md | 目录结构、命名规范、开发规范、API命名规范 |
| 经验教训 | .trae/rules/lessons.md | 历史问题和解决方案,包含若依框架特定问题 |
8.2 本地开发文档
| 文档 | 路径 | 内容 |
|---|
| 若依框架样式修改方案 | docs/plans/若依框架样式修改方案.md | 样式调整、主题配置、品牌一致性 |
8.3 历史问题参考
在 .trae/rules/lessons.md 中记录了以下若依框架相关问题:
-
菜单路由配置问题 (2026-03-08)
- 问题:新增页面404
- 原因:未在 sys_menu 表配置路由
- 解决:所有页面(包括隐藏页)都需要配置
-
API方法命名规范问题 (2026-03-08)
- 问题:前后端命名不一致
- 原因:未先定义规范
- 解决:设计文档先行,代码实现跟随
-
FP-ZCCZ1-001 Code Review实践 (2026-03-08)
- 问题:缺少参数校验、XSS防护、数据权限
- 解决:添加 @Validated、@Xss、@DataScope 注解
8.4 项目特定检查项
项目特定检查项:
- [ ] 检查 lessons.md 中是否有相关问题的解决方案
- [ ] 遵循 project_rules.md 中的命名规范
- [ ] 参考现有代码的实现模式
- [ ] 确认数据库配置:mysql6.sqlpub.com:3311/asset_ruoyi
9. 外部参考文档
10. 版本历史
| 版本 | 日期 | 变更内容 |
|---|
| 3.2 | 2026-04-28 | 新增§7.7前后端契约规范、§7.8页面生命周期规范、§7.9状态流转规范;Bug模式库表扩充至12个(+R008~R012) |
| 3.1 | 2026-03-22 | 添加本地开发指南和文档引用 |
| 3.0 | 2026-03-21 | 标准化结构,添加诊断模式,增强协作指导 |
| 2.0 | 早期 | 完善问题解决方案 |
| 1.0 | 早期 | 初始版本 |