ai-engineering-init 1.4.3 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/.cursor/skills/bug-detective/SKILL.md +19 -19
  2. package/.cursor/skills/project-navigator/SKILL.md +164 -258
  3. package/README.md +20 -236
  4. package/bin/index.js +437 -7
  5. package/package.json +7 -1
  6. package/scripts/build-skills.js +180 -0
  7. package/src/platform-map.json +56 -0
  8. package/src/skills/add-skill/SKILL.md +488 -0
  9. package/src/skills/add-todo/SKILL.md +269 -0
  10. package/src/skills/api-development/SKILL.md +266 -0
  11. package/src/skills/architecture-design/SKILL.md +262 -0
  12. package/src/skills/backend-annotations/SKILL.md +302 -0
  13. package/src/skills/banana-image/CHANGELOG.md +37 -0
  14. package/src/skills/banana-image/README.md +146 -0
  15. package/src/skills/banana-image/SKILL.md +171 -0
  16. package/src/skills/banana-image/assets/logo.png +0 -0
  17. package/src/skills/banana-image/references/advanced-usage.md +189 -0
  18. package/src/skills/banana-image/scripts/apply_template.py +125 -0
  19. package/src/skills/banana-image/scripts/banana_image_exec.ts +412 -0
  20. package/src/skills/banana-image/scripts/batch_prep.py +82 -0
  21. package/src/skills/banana-image/scripts/package-lock.json +1437 -0
  22. package/src/skills/banana-image/scripts/package.json +18 -0
  23. package/src/skills/banana-image/scripts/requirements.txt +10 -0
  24. package/src/skills/banana-image/templates/poster.json +22 -0
  25. package/src/skills/banana-image/templates/product.json +17 -0
  26. package/src/skills/banana-image/templates/social.json +22 -0
  27. package/src/skills/banana-image/templates/thumbnail.json +17 -0
  28. package/src/skills/brainstorm/SKILL.md +216 -0
  29. package/src/skills/bug-detective/SKILL.md +256 -0
  30. package/src/skills/bug-detective/references/error-patterns.md +242 -0
  31. package/src/skills/check/SKILL.md +367 -0
  32. package/src/skills/code-patterns/SKILL.md +280 -0
  33. package/src/skills/code-patterns/references/leniu-code-patterns.md +87 -0
  34. package/src/skills/codex-code-review/SKILL.md +135 -0
  35. package/src/skills/collaborating-with-codex/SKILL.md +174 -0
  36. package/src/skills/collaborating-with-codex/scripts/codex_bridge.py +275 -0
  37. package/src/skills/collaborating-with-gemini/SKILL.md +194 -0
  38. package/src/skills/collaborating-with-gemini/scripts/gemini_bridge.py +275 -0
  39. package/src/skills/crud/SKILL.md +265 -0
  40. package/src/skills/crud-development/SKILL.md +409 -0
  41. package/src/skills/data-permission/SKILL.md +292 -0
  42. package/src/skills/data-permission/references/custom-data-scope.md +90 -0
  43. package/src/skills/database-ops/SKILL.md +407 -0
  44. package/src/skills/dev/SKILL.md +187 -0
  45. package/src/skills/error-handler/SKILL.md +371 -0
  46. package/src/skills/file-oss-management/SKILL.md +255 -0
  47. package/src/skills/file-oss-management/references/entities.md +105 -0
  48. package/src/skills/file-oss-management/references/service-impl.md +104 -0
  49. package/src/skills/git-workflow/SKILL.md +397 -0
  50. package/src/skills/init-docs/SKILL.md +194 -0
  51. package/src/skills/json-serialization/SKILL.md +357 -0
  52. package/src/skills/leniu-api-development/SKILL.md +319 -0
  53. package/src/skills/leniu-api-development/references/real-examples.md +273 -0
  54. package/src/skills/leniu-architecture-design/SKILL.md +383 -0
  55. package/src/skills/leniu-backend-annotations/SKILL.md +277 -0
  56. package/src/skills/leniu-brainstorm/SKILL.md +242 -0
  57. package/src/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
  58. package/src/skills/leniu-code-patterns/SKILL.md +411 -0
  59. package/src/skills/leniu-crud-development/SKILL.md +404 -0
  60. package/src/skills/leniu-crud-development/references/templates.md +597 -0
  61. package/src/skills/leniu-customization-location/SKILL.md +410 -0
  62. package/src/skills/leniu-data-permission/SKILL.md +341 -0
  63. package/src/skills/leniu-database-ops/SKILL.md +426 -0
  64. package/src/skills/leniu-error-handler/SKILL.md +462 -0
  65. package/src/skills/leniu-java-amount-handling/SKILL.md +461 -0
  66. package/src/skills/leniu-java-code-style/SKILL.md +510 -0
  67. package/src/skills/leniu-java-concurrent/SKILL.md +400 -0
  68. package/src/skills/leniu-java-entity/SKILL.md +237 -0
  69. package/src/skills/leniu-java-entity/references/templates.md +237 -0
  70. package/src/skills/leniu-java-export/SKILL.md +570 -0
  71. package/src/skills/leniu-java-logging/SKILL.md +229 -0
  72. package/src/skills/leniu-java-logging/references/data-mask.md +46 -0
  73. package/src/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
  74. package/src/skills/leniu-java-mq/SKILL.md +338 -0
  75. package/src/skills/leniu-java-mybatis/SKILL.md +267 -0
  76. package/src/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
  77. package/src/skills/leniu-java-report-query-param/SKILL.md +291 -0
  78. package/src/skills/leniu-java-task/SKILL.md +367 -0
  79. package/src/skills/leniu-java-total-line/SKILL.md +196 -0
  80. package/src/skills/leniu-marketing-price-rule-customizer/SKILL.md +301 -0
  81. package/src/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +285 -0
  82. package/src/skills/leniu-mealtime/SKILL.md +215 -0
  83. package/src/skills/leniu-redis-cache/SKILL.md +331 -0
  84. package/src/skills/leniu-report-customization/SKILL.md +335 -0
  85. package/src/skills/leniu-report-customization/references/table-fields.md +93 -0
  86. package/src/skills/leniu-report-standard-customization/SKILL.md +328 -0
  87. package/src/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
  88. package/src/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
  89. package/src/skills/leniu-security-guard/SKILL.md +306 -0
  90. package/src/skills/leniu-utils-toolkit/SKILL.md +380 -0
  91. package/src/skills/mysql-debug/SKILL.md +364 -0
  92. package/src/skills/next/SKILL.md +137 -0
  93. package/src/skills/openspec-apply-change/SKILL.md +165 -0
  94. package/src/skills/openspec-archive-change/SKILL.md +122 -0
  95. package/src/skills/openspec-bulk-archive-change/SKILL.md +254 -0
  96. package/src/skills/openspec-continue-change/SKILL.md +126 -0
  97. package/src/skills/openspec-explore/SKILL.md +299 -0
  98. package/src/skills/openspec-ff-change/SKILL.md +109 -0
  99. package/src/skills/openspec-new-change/SKILL.md +82 -0
  100. package/src/skills/openspec-onboard/SKILL.md +414 -0
  101. package/src/skills/openspec-sync-specs/SKILL.md +146 -0
  102. package/src/skills/openspec-verify-change/SKILL.md +176 -0
  103. package/src/skills/performance-doctor/SKILL.md +303 -0
  104. package/src/skills/progress/SKILL.md +193 -0
  105. package/src/skills/project-navigator/SKILL.md +211 -0
  106. package/src/skills/redis-cache/SKILL.md +333 -0
  107. package/src/skills/redis-cache/references/listeners.md +23 -0
  108. package/src/skills/scheduled-jobs/SKILL.md +314 -0
  109. package/src/skills/security-guard/SKILL.md +353 -0
  110. package/src/skills/security-guard/references/encrypt-config.md +103 -0
  111. package/src/skills/security-guard/references/sensitive-strategies.md +42 -0
  112. package/src/skills/sms-mail/SKILL.md +308 -0
  113. package/src/skills/sms-mail/references/mail-config.md +88 -0
  114. package/src/skills/sms-mail/references/sms-config.md +74 -0
  115. package/src/skills/social-login/SKILL.md +266 -0
  116. package/src/skills/social-login/references/provider-configs.md +118 -0
  117. package/src/skills/start/SKILL.md +154 -0
  118. package/src/skills/store-pc/SKILL.md +366 -0
  119. package/src/skills/sync/SKILL.md +149 -0
  120. package/src/skills/task-tracker/SKILL.md +307 -0
  121. package/src/skills/tech-decision/SKILL.md +393 -0
  122. package/src/skills/tenant-management/SKILL.md +288 -0
  123. package/src/skills/tenant-management/references/tenant-scenarios.md +91 -0
  124. package/src/skills/test-development/SKILL.md +301 -0
  125. package/src/skills/test-development/references/parameterized-examples.md +119 -0
  126. package/src/skills/ui-pc/SKILL.md +438 -0
  127. package/src/skills/update-status/SKILL.md +159 -0
  128. package/src/skills/utils-toolkit/SKILL.md +362 -0
  129. package/src/skills/utils-toolkit/references/redis-utils-api.md +56 -0
  130. package/src/skills/websocket-sse/SKILL.md +271 -0
  131. package/src/skills/workflow-engine/SKILL.md +321 -0
@@ -0,0 +1,211 @@
1
+ ---
2
+ name: project-navigator
3
+ description: |
4
+ 当需要了解项目结构、查找文件、定位代码时自动使用此 Skill。提供 leniu 云食堂项目的精确导航。
5
+
6
+ 触发场景:
7
+ - 询问某个功能/文件在哪里
8
+ - 新建模块时需要确认目录位置
9
+ - 查找参考代码(Controller/Service/Mapper/Entity 示例)
10
+ - 了解项目整体结构和模块划分
11
+ - 查找技能、命令、Hook 的位置
12
+
13
+ 触发词:项目结构、文件在哪、代码位置、目录结构、模块在哪、参考代码、怎么找、哪个文件、路径、在哪里
14
+ ---
15
+
16
+ # leniu 项目导航指南
17
+
18
+ ## 工程化配置项目
19
+
20
+ ```
21
+ ai-engineering-init/ # 当前工作目录(本仓库根目录)
22
+ ├── CLAUDE.md # 项目规范(核心约束必读)
23
+ ├── AGENTS.md # Agent 配置文档
24
+ ├── .claude/
25
+ │ ├── skills/ # 73 个技能模块
26
+ │ ├── commands/ # 10 个快速命令(/dev /crud /check 等)
27
+ │ ├── hooks/ # Hooks(skill-forced-eval.js 强制技能评估)
28
+ │ └── docs/ # 开发文档
29
+ └── .codex/skills/ # Codex CLI 技能同步目录
30
+ ```
31
+
32
+ ---
33
+
34
+ ## 后端 Java 项目
35
+
36
+ **根路径**:由用户在 `CLAUDE.md` 中配置,各安装者路径不同
37
+
38
+ ### 业务模块(25 个 core-* 模块)
39
+
40
+ | 模块 | 职责 |
41
+ |------|------|
42
+ | `core-order` | 订单管理 |
43
+ | `core-menu` | 菜品管理 |
44
+ | `core-marketing` | 营销(充值/优惠) |
45
+ | `core-report` | 报表统计 |
46
+ | `core-pay` | 支付 |
47
+ | `core-account` | 账号管理 |
48
+ | `core-merchant` | 商户配置 |
49
+ | `core-customer` | 用户/员工 |
50
+ | `core-device` | 设备管理 |
51
+ | `core-attendance` | 考勤 |
52
+ | `core-kitchen` / `core-backfield` | 后场厨房 |
53
+ | `core-drp` | 供应链 |
54
+ | `core-dorm` | 宿舍管理 |
55
+ | `core-notice` | 通知消息 |
56
+ | `core-open` | 开放接口 |
57
+ | `core-nutrition` | 营养管理 |
58
+ | `core-supermarket` | 超市 |
59
+ | `core-common` / `core-base` | 公共基础 |
60
+ | `core-auth` / `core-starter` | 认证/启动 |
61
+
62
+ ### 标准包结构(四层架构)
63
+
64
+ ```
65
+ net.xnzn.core.{module}/
66
+ ├── controller/
67
+ │ ├── web/ # Web 管理端(/api/v2/web/{module})
68
+ │ ├── mobile/ # 移动端(/api/v2/mobile/{module})
69
+ │ ├── android/ # 设备端(/api/v2/android/{module})
70
+ │ └── open/ # 开放接口(/api/v2/open/{module})
71
+ ├── business/impl/ # Business 层(跨 Service 编排)
72
+ ├── service/impl/ # Service 层(单表 CRUD、事务)
73
+ ├── mapper/ # Mapper + XML(同目录!非 resources/mapper/)
74
+ ├── model/ # Entity
75
+ ├── vo/ # 响应对象
76
+ ├── dto/ # 请求参数(含 Param)
77
+ ├── constants/ # 枚举、常量
78
+ ├── mq/ # 消息队列
79
+ └── task/ # 定时任务
80
+ ```
81
+
82
+ ### 参考代码位置
83
+
84
+ | 需要参考 | 路径 |
85
+ |---------|------|
86
+ | Controller 写法 | `core-order/.../order/web/controller/OrderInfoWebController.java` |
87
+ | Business 层写法 | `core-order/.../order/web/business/impl/OrderWebBusiness.java` |
88
+ | Service 写法 | `core-order/.../order/common/service/impl/OrderInfoService.java` |
89
+ | Entity 写法 | `core-order/.../order/common/model/OrderInfo.java` |
90
+ | 枚举写法 | `core-order/.../order/common/constants/OrderStateEnum.java` |
91
+ | 配置文件 | `core-base/src/main/resources/bootstrap.yml` |
92
+
93
+ ---
94
+
95
+ ## 前端项目
96
+
97
+ **根路径**:由用户在 `CLAUDE.md` 中配置,各安装者路径不同
98
+
99
+ ### src/ 核心目录
100
+
101
+ | 目录 | 说明 | 规模 |
102
+ |------|------|------|
103
+ | `api/` | 接口定义 | 63 个文件 |
104
+ | `leniuview/` | 业务模块页面 | 33 个模块 |
105
+ | `leniu-components/` | 业务组件库 | 12 个组件包 |
106
+ | `components/` | 通用组件 | ~87 个 |
107
+ | `store/` | Vuex 状态管理 | 30+ 个模块 |
108
+ | `utils/` | 工具函数 | 37 个文件 |
109
+
110
+ ### 常用前端文件
111
+
112
+ | 需要查找 | 路径 |
113
+ |---------|------|
114
+ | 主入口 | `src/main.js` |
115
+ | 权限路由守卫 | `src/permission.js` |
116
+ | 请求封装 | `src/utils/request.js` |
117
+ | Token/租户工具 | `src/utils/auth.js` |
118
+ | 全局工具 | `src/utils/index.js` |
119
+ | Vuex 根配置 | `src/store/index.js` |
120
+ | 构建配置 | `vue.config.js` |
121
+
122
+ ### 前端业务模块(leniuview 33 个)
123
+
124
+ ```
125
+ accountCenter、canteenBackcourt、cost、dashboard、dataScreen、
126
+ deviceMange、dormitory、marketing、menudish、orderCenter、
127
+ purchase、reportCenter、stock、supplyChain、attendance、
128
+ campus、approvalManage、noticeV2、personalV2 ...
129
+ ```
130
+
131
+ ---
132
+
133
+ ## 技能系统导航
134
+
135
+ **技能路径**:`.claude/skills/{技能名}/SKILL.md`
136
+
137
+ ### 按开发场景选择技能
138
+
139
+ | 场景 | 技能 |
140
+ |------|------|
141
+ | 新建 CRUD 模块 | `leniu-crud-development` |
142
+ | API 接口设计 | `leniu-api-development` |
143
+ | 建表/SQL | `leniu-database-ops` |
144
+ | Entity/VO/DTO | `leniu-java-entity` |
145
+ | MyBatis/Mapper | `leniu-java-mybatis` |
146
+ | 异常处理 | `leniu-error-handler` |
147
+ | 工具类使用 | `leniu-utils-toolkit` |
148
+ | 注解使用 | `leniu-backend-annotations` |
149
+ | 代码规范 | `leniu-code-patterns` |
150
+ | 数据权限/双库 | `leniu-data-permission` |
151
+ | 定制报表 | `leniu-report-customization` |
152
+ | 标准报表 | `leniu-report-standard-customization` |
153
+ | 金额处理 | `leniu-java-amount-handling` |
154
+ | 并发/异步 | `leniu-java-concurrent` |
155
+ | 导出功能 | `leniu-java-export` |
156
+ | 定时任务 | `leniu-java-task` |
157
+ | 消息队列 | `leniu-java-mq` |
158
+ | Redis 缓存 | `leniu-redis-cache` |
159
+ | 合计行查询 | `leniu-java-total-line` |
160
+ | 报表查询入参 | `leniu-java-report-query-param` |
161
+ | 营销计费规则 | `leniu-marketing-price-rule-customizer` |
162
+ | 营销充值规则 | `leniu-marketing-recharge-rule-customizer` |
163
+ | 餐次处理 | `leniu-mealtime` |
164
+ | 定制开发位置 | `leniu-customization-location` |
165
+ | Bug 排查 | `bug-detective`(数据问题自动联动 `mysql-debug`) |
166
+ | 数据库查询验证 | `mysql-debug` |
167
+ | Codex 代码审查 | `codex-code-review` |
168
+ | 前端组件/权限 | `ui-pc` |
169
+ | 前端 Vuex | `store-pc` |
170
+ | 方案设计 | `leniu-brainstorm` |
171
+ | 架构设计 | `leniu-architecture-design` |
172
+ | 安全认证 | `leniu-security-guard` |
173
+
174
+ ### 快速命令
175
+
176
+ | 命令 | 用途 |
177
+ |------|------|
178
+ | `/dev` | 开发新功能 |
179
+ | `/crud` | 快速生成 CRUD |
180
+ | `/check` | 代码规范检查 |
181
+ | `/start` | 项目快速了解 |
182
+ | `/progress` | 查看项目进度 |
183
+ | `/next` | 下一步建议 |
184
+ | `/add-todo` | 添加待办事项 |
185
+
186
+ ---
187
+
188
+ ## 常用搜索模式
189
+
190
+ ```bash
191
+ # 查找某模块的 Controller
192
+ Glob core-order/**/*Controller*.java
193
+
194
+ # 查找 Service 实现类
195
+ Glob core-order/**/impl/*Service*.java
196
+
197
+ # 查找 Mapper XML
198
+ Glob core-order/**/*Mapper.xml
199
+
200
+ # 查找 Entity
201
+ Glob core-order/**/model/*.java
202
+
203
+ # 查找某接口路由
204
+ Grep "/api/v2/web/order" --type java
205
+
206
+ # 查找前端某页面
207
+ Glob src/leniuview/**/index.vue
208
+
209
+ # 查找前端接口定义
210
+ Glob src/api/*.js
211
+ ```
@@ -0,0 +1,333 @@
1
+ ---
2
+ name: redis-cache
3
+ description: |
4
+ 当需要使用Redis缓存、分布式锁、限流等功能时自动使用此Skill。包含RedisUtils工具类、CacheUtils工具类、缓存注解使用规范、分布式锁实现、缓存key命名规范等。
5
+
6
+ 触发场景:
7
+ - 使用Redis缓存数据
8
+ - 配置Spring Cache缓存注解
9
+ - 实现分布式锁
10
+ - 实现接口限流
11
+ - Redis发布订阅
12
+ - 缓存key设计和命名
13
+ - 缓存清理和刷新
14
+
15
+ 触发词:Redis、缓存、Cache、@Cacheable、@CacheEvict、@CachePut、RedisUtils、CacheUtils、分布式锁、RLock、限流、RateLimiter、发布订阅、缓存key、缓存过期
16
+
17
+ 核心警告:
18
+ - @Cacheable返回值不能使用不可变集合(List.of()、Set.of()、Map.of())
19
+ - 分布式锁必须在finally中释放,且需注入RedissonClient(RedisUtils无getLock)
20
+ - keys()和deleteKeys()会忽略租户隔离
21
+ ---
22
+
23
+ # Redis 缓存开发指南
24
+
25
+ > 模块位置:`ruoyi-common/ruoyi-common-redis`
26
+
27
+ ## 快速索引
28
+
29
+ | 功能 | 工具类/注解 | 说明 |
30
+ |------|-------------|------|
31
+ | 对象缓存 | `RedisUtils.setCacheObject()` | 基于 Redisson |
32
+ | 集合缓存 | `RedisUtils.setCacheList/Set/Map()` | List/Set/Map 操作 |
33
+ | Spring Cache | `CacheUtils.get/put/evict()` | Spring Cache 封装 |
34
+ | 缓存注解 | `@Cacheable/@CachePut/@CacheEvict` | 声明式缓存 |
35
+ | 分布式锁 | `redissonClient.getLock()` | 需注入 RedissonClient |
36
+ | 限流控制 | `RedisUtils.rateLimiter()` | 基于 Redisson |
37
+ | 原子操作 | `RedisUtils.incrAtomicValue()` | 原子递增/递减 |
38
+ | 发布订阅 | `RedisUtils.publish/subscribe()` | 消息通信 |
39
+
40
+ ---
41
+
42
+ ## 一、RedisUtils 工具类
43
+
44
+ ```java
45
+ import org.dromara.common.redis.utils.RedisUtils;
46
+ ```
47
+
48
+ ### 1.1 基础缓存操作
49
+
50
+ ```java
51
+ RedisUtils.setCacheObject("user:123", userObj); // 永不过期
52
+ RedisUtils.setCacheObject("user:123", userObj, Duration.ofMinutes(30)); // 带过期时间
53
+ RedisUtils.setCacheObject("user:123", userObj, true); // 保留原有TTL(Redis 6.0+)
54
+ boolean ok = RedisUtils.setObjectIfAbsent("user:123", userObj, Duration.ofMinutes(30)); // 不存在时设置
55
+ boolean ok = RedisUtils.setObjectIfExists("user:123", userObj, Duration.ofMinutes(30)); // 存在时设置
56
+
57
+ User user = RedisUtils.getCacheObject("user:123"); // 获取
58
+ long ttl = RedisUtils.getTimeToLive("user:123"); // TTL毫秒(-1永不过期,-2不存在)
59
+ boolean deleted = RedisUtils.deleteObject("user:123"); // 删除
60
+ RedisUtils.deleteObject(Arrays.asList("user:123", "user:456")); // 批量删除
61
+ boolean exists = RedisUtils.isExistsObject("user:123"); // 是否存在
62
+ RedisUtils.expire("user:123", Duration.ofMinutes(30)); // 设置过期
63
+ ```
64
+
65
+ ### 1.2 集合操作
66
+
67
+ ```java
68
+ // List
69
+ RedisUtils.setCacheList("myList", dataList);
70
+ RedisUtils.addCacheList("myList", "item3");
71
+ List<String> result = RedisUtils.getCacheList("myList");
72
+ List<String> range = RedisUtils.getCacheListRange("myList", 0, 10);
73
+
74
+ // Set
75
+ RedisUtils.setCacheSet("mySet", dataSet);
76
+ boolean added = RedisUtils.addCacheSet("mySet", "value3");
77
+ Set<String> result = RedisUtils.getCacheSet("mySet");
78
+
79
+ // Map
80
+ RedisUtils.setCacheMap("myMap", dataMap);
81
+ RedisUtils.setCacheMapValue("myMap", "key3", "value3");
82
+ String value = RedisUtils.getCacheMapValue("myMap", "key1");
83
+ Map<String, Object> result = RedisUtils.getCacheMap("myMap");
84
+ Set<String> keys = RedisUtils.getCacheMapKeySet("myMap");
85
+ RedisUtils.delCacheMapValue("myMap", "key1");
86
+ RedisUtils.delMultiCacheMapValue("myMap", new HashSet<>(Arrays.asList("key1", "key2")));
87
+ Map<String, Object> values = RedisUtils.getMultiCacheMapValue("myMap", keySet);
88
+ ```
89
+
90
+ ### 1.3 发布订阅
91
+
92
+ ```java
93
+ RedisUtils.publish("notification:channel", messageObj);
94
+ RedisUtils.publish("notification:channel", messageObj, msg -> { log.info("已发布: {}", msg); });
95
+ RedisUtils.subscribe("notification:channel", MessageDTO.class, msg -> { /* 处理消息 */ });
96
+ ```
97
+
98
+ ### 1.4 限流控制
99
+
100
+ ```java
101
+ import org.redisson.api.RateType;
102
+
103
+ // 每10秒最多100个请求
104
+ long remaining = RedisUtils.rateLimiter("api:limit:user:123", RateType.OVERALL, 100, 10);
105
+ if (remaining == -1) {
106
+ throw new ServiceException("请求过于频繁");
107
+ }
108
+
109
+ // 带超时版本(5秒超时)
110
+ long remaining = RedisUtils.rateLimiter("api:limit:user:123", RateType.OVERALL, 100, 10, 5);
111
+ ```
112
+
113
+ ### 1.5 原子操作
114
+
115
+ ```java
116
+ RedisUtils.setAtomicValue("counter:view", 0L);
117
+ long value = RedisUtils.getAtomicValue("counter:view");
118
+ long newVal = RedisUtils.incrAtomicValue("counter:view");
119
+ long newVal = RedisUtils.decrAtomicValue("counter:view");
120
+ ```
121
+
122
+ ### 1.6 Key 操作
123
+
124
+ ```java
125
+ // ⚠️ keys() 和 deleteKeys() 会忽略租户隔离
126
+ Collection<String> keys = RedisUtils.keys("user:*");
127
+
128
+ KeysScanOptions options = KeysScanOptions.defaults().pattern("user:*").chunkSize(1000).limit(100);
129
+ Collection<String> keys = RedisUtils.keys(options);
130
+
131
+ RedisUtils.deleteKeys("temp:*");
132
+ Boolean exists = RedisUtils.hasKey("user:123");
133
+ ```
134
+
135
+ ### 1.7 监听机制
136
+
137
+ 详见 [references/listeners.md](references/listeners.md)
138
+
139
+ ---
140
+
141
+ ## 二、CacheUtils 工具类
142
+
143
+ ```java
144
+ import org.dromara.common.redis.utils.CacheUtils;
145
+
146
+ CacheUtils.put("userCache", "user:123", userObj); // 保存
147
+ User user = CacheUtils.get("userCache", "user:123"); // 获取
148
+ CacheUtils.evict("userCache", "user:123"); // 删除
149
+ CacheUtils.clear("userCache"); // 清空整组
150
+ ```
151
+
152
+ ---
153
+
154
+ ## 三、CacheNames 缓存名称常量
155
+
156
+ > 位置:`ruoyi-common/ruoyi-common-core/.../constant/CacheNames.java`
157
+
158
+ ### 命名格式
159
+
160
+ ```
161
+ cacheNames#ttl#maxIdleTime#maxSize#local
162
+ - ttl: 过期时间(0=不过期,默认0)
163
+ - maxIdleTime: 最大空闲时间(0=不检测,默认0)
164
+ - maxSize: 最大条数(0=无限,默认0)
165
+ - local: 本地缓存(1开启,0关闭,默认1)
166
+ ```
167
+
168
+ ```java
169
+ "test#60s" // 60秒过期
170
+ "test#0#60s" // 不过期,60秒空闲清理
171
+ "test#0#1m#1000" // 不过期,1分钟空闲,最大1000条
172
+ "test#1h#0#500#0" // 1小时过期,最大500条,关闭本地缓存
173
+ ```
174
+
175
+ ### 已定义常量
176
+
177
+ ```java
178
+ public interface CacheNames {
179
+ String DEMO_CACHE = "demo:cache#60s#10m#20";
180
+ String SYS_CONFIG = "sys_config";
181
+ String SYS_DICT = "sys_dict";
182
+ String SYS_DICT_TYPE = "sys_dict_type";
183
+ String SYS_TENANT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d";
184
+ String SYS_CLIENT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_client#30d";
185
+ String SYS_USER_NAME = "sys_user_name#30d";
186
+ String SYS_NICKNAME = "sys_nickname#30d";
187
+ String SYS_DEPT = "sys_dept#30d";
188
+ String SYS_OSS = "sys_oss#30d";
189
+ String SYS_ROLE_CUSTOM = "sys_role_custom#30d";
190
+ String SYS_DEPT_AND_CHILD = "sys_dept_and_child#30d";
191
+ String SYS_OSS_CONFIG = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss_config";
192
+ String ONLINE_TOKEN = "online_tokens";
193
+ }
194
+ ```
195
+
196
+ ---
197
+
198
+ ## 四、缓存注解使用规范
199
+
200
+ ### @Cacheable - 查询缓存
201
+
202
+ ```java
203
+ @Cacheable(cacheNames = CacheNames.SYS_DICT, key = "#dictType")
204
+ @Override
205
+ public List<SysDictDataVo> listDictDataByType(String dictType) {
206
+ if (StringUtils.isBlank(dictType)) {
207
+ return Collections.emptyList();
208
+ }
209
+ List<SysDictData> dictDataList = dictDataMapper.selectByType(dictType);
210
+ if (CollUtil.isEmpty(dictDataList)) {
211
+ return Collections.emptyList(); // 返回空列表防止缓存穿透
212
+ }
213
+ return MapstructUtils.convert(dictDataList, SysDictDataVo.class);
214
+ }
215
+ ```
216
+
217
+ ### @CachePut / @CacheEvict
218
+
219
+ ```java
220
+ @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType")
221
+ public List<SysDictDataVo> insertDictType(SysDictTypeBo bo) { ... }
222
+
223
+ @CacheEvict(cacheNames = CacheNames.SYS_DICT, key = "#dictType")
224
+ public void deleteDictType(String dictType) { ... }
225
+
226
+ @CacheEvict(cacheNames = CacheNames.SYS_DICT, allEntries = true)
227
+ public void clearAllDictCache() { ... }
228
+ ```
229
+
230
+ ### 返回值禁止使用不可变集合
231
+
232
+ ```java
233
+ // ❌ 禁止!@Cacheable 返回值序列化失败
234
+ return List.of(data1, data2);
235
+ return Set.of("admin", "user");
236
+ return Map.of("key1", "value1");
237
+
238
+ // ✅ 正确:使用可变集合
239
+ List<SysDictDataVo> result = new ArrayList<>();
240
+ result.add(data1);
241
+ return result;
242
+ ```
243
+
244
+ ---
245
+
246
+ ## 五、分布式锁
247
+
248
+ > RedisUtils **不提供** `getLock()`,需直接注入 `RedissonClient`。
249
+
250
+ ```java
251
+ @Service
252
+ @RequiredArgsConstructor
253
+ public class OrderServiceImpl implements IOrderService {
254
+
255
+ private final RedissonClient redissonClient;
256
+
257
+ public void submitOrder(OrderBo orderBo) {
258
+ String lockKey = "lock:submit:order:" + LoginHelper.getUserId();
259
+ RLock lock = redissonClient.getLock(lockKey);
260
+
261
+ try {
262
+ boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
263
+ if (!locked) {
264
+ throw new ServiceException("请勿重复提交订单");
265
+ }
266
+ try {
267
+ orderMapper.insert(orderBo);
268
+ } finally {
269
+ lock.unlock(); // 必须在 finally 中释放
270
+ }
271
+ } catch (InterruptedException e) {
272
+ Thread.currentThread().interrupt();
273
+ throw new ServiceException("订单提交被中断");
274
+ }
275
+ }
276
+ }
277
+ ```
278
+
279
+ ---
280
+
281
+ ## 六、缓存 Key 命名规范
282
+
283
+ ```
284
+ 格式:{业务模块}:{功能}:{具体标识}
285
+
286
+ 示例:
287
+ user:info:123 user:roles:123 user:permissions:123
288
+ dict:data:sys_user_sex order:info:20240101001 order:status:20240101001
289
+ lock:order:20240101001 lock:stock:123 lock:submit:order:456
290
+ limit:api:user:123 limit:sms:18888888888
291
+ ```
292
+
293
+ ---
294
+
295
+ ## 七、租户隔离注意
296
+
297
+ ```java
298
+ // ⚠️ keys() 和 deleteKeys() 会忽略租户隔离,需手动拼接
299
+ String tenantId = LoginHelper.getTenantId();
300
+ Collection<String> keys = RedisUtils.keys(tenantId + ":user:*");
301
+
302
+ // CacheUtils 会自动处理租户隔离
303
+ CacheUtils.clear(CacheNames.SYS_USER_NAME);
304
+ ```
305
+
306
+ ---
307
+
308
+ ## 八、注意事项速查
309
+
310
+ 1. **@Cacheable 返回值不能使用不可变集合**(List.of()、Set.of()、Map.of())
311
+ 2. **分布式锁必须在 finally 中释放**
312
+ 3. **keys() 和 deleteKeys() 会忽略租户隔离**
313
+ 4. **返回空列表而不是 null**,防止缓存穿透
314
+ 5. **设置随机过期时间偏移**,避免缓存雪崩
315
+ 6. **热点数据用分布式锁 + 双重检查**,防止缓存击穿
316
+
317
+ ---
318
+
319
+ ## 九、核心文件位置
320
+
321
+ | 文件 | 位置 |
322
+ |------|------|
323
+ | RedisUtils | `ruoyi-common/ruoyi-common-redis/.../utils/RedisUtils.java` |
324
+ | CacheUtils | `ruoyi-common/ruoyi-common-redis/.../utils/CacheUtils.java` |
325
+ | CacheNames | `ruoyi-common/ruoyi-common-core/.../constant/CacheNames.java` |
326
+ | GlobalConstants | `ruoyi-common/ruoyi-common-core/.../constant/GlobalConstants.java` |
327
+
328
+ ---
329
+
330
+ ## 多项目适配说明
331
+
332
+ - 如果需要 leniu-tengyun-core 项目的 Redis 开发规范,请使用 `leniu-redis-cache` skill
333
+ - leniu-tengyun-core 的 RedisUtil 工具类方法名与 RuoYi-Vue-Plus 的 RedisUtils 不同
@@ -0,0 +1,23 @@
1
+ # Redis 监听机制
2
+
3
+ ## 过期/删除监听器
4
+
5
+ ```java
6
+ import org.redisson.api.listener.ExpiredObjectListener;
7
+ import org.redisson.api.listener.DeletedObjectListener;
8
+
9
+ // 注册过期监听器(需要开启Redis的notify-keyspace-events配置)
10
+ RedisUtils.addObjectListener("user:123", (ExpiredObjectListener) name -> {
11
+ log.info("缓存已过期: {}", name);
12
+ });
13
+
14
+ // 注册删除监听器
15
+ RedisUtils.addObjectListener("user:123", (DeletedObjectListener) name -> {
16
+ log.info("缓存已删除: {}", name);
17
+ });
18
+
19
+ // 注册List/Set/Map监听器
20
+ RedisUtils.addListListener("myList", (ExpiredObjectListener) name -> { ... });
21
+ RedisUtils.addSetListener("mySet", (DeletedObjectListener) name -> { ... });
22
+ RedisUtils.addMapListener("myMap", (ExpiredObjectListener) name -> { ... });
23
+ ```