ai-engineering-init 1.4.3 → 1.5.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.
- package/.cursor/skills/bug-detective/SKILL.md +19 -19
- package/.cursor/skills/project-navigator/SKILL.md +164 -258
- package/package.json +7 -1
- package/scripts/build-skills.js +180 -0
- package/src/platform-map.json +56 -0
- package/src/skills/add-skill/SKILL.md +488 -0
- package/src/skills/add-todo/SKILL.md +269 -0
- package/src/skills/api-development/SKILL.md +266 -0
- package/src/skills/architecture-design/SKILL.md +262 -0
- package/src/skills/backend-annotations/SKILL.md +302 -0
- package/src/skills/banana-image/CHANGELOG.md +37 -0
- package/src/skills/banana-image/README.md +146 -0
- package/src/skills/banana-image/SKILL.md +171 -0
- package/src/skills/banana-image/assets/logo.png +0 -0
- package/src/skills/banana-image/references/advanced-usage.md +189 -0
- package/src/skills/banana-image/scripts/apply_template.py +125 -0
- package/src/skills/banana-image/scripts/banana_image_exec.ts +412 -0
- package/src/skills/banana-image/scripts/batch_prep.py +82 -0
- package/src/skills/banana-image/scripts/package-lock.json +1437 -0
- package/src/skills/banana-image/scripts/package.json +18 -0
- package/src/skills/banana-image/scripts/requirements.txt +10 -0
- package/src/skills/banana-image/templates/poster.json +22 -0
- package/src/skills/banana-image/templates/product.json +17 -0
- package/src/skills/banana-image/templates/social.json +22 -0
- package/src/skills/banana-image/templates/thumbnail.json +17 -0
- package/src/skills/brainstorm/SKILL.md +216 -0
- package/src/skills/bug-detective/SKILL.md +256 -0
- package/src/skills/bug-detective/references/error-patterns.md +242 -0
- package/src/skills/check/SKILL.md +367 -0
- package/src/skills/code-patterns/SKILL.md +280 -0
- package/src/skills/code-patterns/references/leniu-code-patterns.md +87 -0
- package/src/skills/codex-code-review/SKILL.md +135 -0
- package/src/skills/collaborating-with-codex/SKILL.md +174 -0
- package/src/skills/collaborating-with-codex/scripts/codex_bridge.py +275 -0
- package/src/skills/collaborating-with-gemini/SKILL.md +194 -0
- package/src/skills/collaborating-with-gemini/scripts/gemini_bridge.py +275 -0
- package/src/skills/crud/SKILL.md +265 -0
- package/src/skills/crud-development/SKILL.md +409 -0
- package/src/skills/data-permission/SKILL.md +292 -0
- package/src/skills/data-permission/references/custom-data-scope.md +90 -0
- package/src/skills/database-ops/SKILL.md +407 -0
- package/src/skills/dev/SKILL.md +187 -0
- package/src/skills/error-handler/SKILL.md +371 -0
- package/src/skills/file-oss-management/SKILL.md +255 -0
- package/src/skills/file-oss-management/references/entities.md +105 -0
- package/src/skills/file-oss-management/references/service-impl.md +104 -0
- package/src/skills/git-workflow/SKILL.md +397 -0
- package/src/skills/init-docs/SKILL.md +194 -0
- package/src/skills/json-serialization/SKILL.md +357 -0
- package/src/skills/leniu-api-development/SKILL.md +319 -0
- package/src/skills/leniu-api-development/references/real-examples.md +273 -0
- package/src/skills/leniu-architecture-design/SKILL.md +383 -0
- package/src/skills/leniu-backend-annotations/SKILL.md +277 -0
- package/src/skills/leniu-brainstorm/SKILL.md +242 -0
- package/src/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
- package/src/skills/leniu-code-patterns/SKILL.md +411 -0
- package/src/skills/leniu-crud-development/SKILL.md +404 -0
- package/src/skills/leniu-crud-development/references/templates.md +597 -0
- package/src/skills/leniu-customization-location/SKILL.md +410 -0
- package/src/skills/leniu-data-permission/SKILL.md +341 -0
- package/src/skills/leniu-database-ops/SKILL.md +426 -0
- package/src/skills/leniu-error-handler/SKILL.md +462 -0
- package/src/skills/leniu-java-amount-handling/SKILL.md +461 -0
- package/src/skills/leniu-java-code-style/SKILL.md +510 -0
- package/src/skills/leniu-java-concurrent/SKILL.md +400 -0
- package/src/skills/leniu-java-entity/SKILL.md +237 -0
- package/src/skills/leniu-java-entity/references/templates.md +237 -0
- package/src/skills/leniu-java-export/SKILL.md +570 -0
- package/src/skills/leniu-java-logging/SKILL.md +229 -0
- package/src/skills/leniu-java-logging/references/data-mask.md +46 -0
- package/src/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
- package/src/skills/leniu-java-mq/SKILL.md +338 -0
- package/src/skills/leniu-java-mybatis/SKILL.md +267 -0
- package/src/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
- package/src/skills/leniu-java-report-query-param/SKILL.md +291 -0
- package/src/skills/leniu-java-task/SKILL.md +367 -0
- package/src/skills/leniu-java-total-line/SKILL.md +196 -0
- package/src/skills/leniu-marketing-price-rule-customizer/SKILL.md +301 -0
- package/src/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +285 -0
- package/src/skills/leniu-mealtime/SKILL.md +215 -0
- package/src/skills/leniu-redis-cache/SKILL.md +331 -0
- package/src/skills/leniu-report-customization/SKILL.md +335 -0
- package/src/skills/leniu-report-customization/references/table-fields.md +93 -0
- package/src/skills/leniu-report-standard-customization/SKILL.md +328 -0
- package/src/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
- package/src/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
- package/src/skills/leniu-security-guard/SKILL.md +306 -0
- package/src/skills/leniu-utils-toolkit/SKILL.md +380 -0
- package/src/skills/mysql-debug/SKILL.md +364 -0
- package/src/skills/next/SKILL.md +137 -0
- package/src/skills/openspec-apply-change/SKILL.md +165 -0
- package/src/skills/openspec-archive-change/SKILL.md +122 -0
- package/src/skills/openspec-bulk-archive-change/SKILL.md +254 -0
- package/src/skills/openspec-continue-change/SKILL.md +126 -0
- package/src/skills/openspec-explore/SKILL.md +299 -0
- package/src/skills/openspec-ff-change/SKILL.md +109 -0
- package/src/skills/openspec-new-change/SKILL.md +82 -0
- package/src/skills/openspec-onboard/SKILL.md +414 -0
- package/src/skills/openspec-sync-specs/SKILL.md +146 -0
- package/src/skills/openspec-verify-change/SKILL.md +176 -0
- package/src/skills/performance-doctor/SKILL.md +303 -0
- package/src/skills/progress/SKILL.md +193 -0
- package/src/skills/project-navigator/SKILL.md +211 -0
- package/src/skills/redis-cache/SKILL.md +333 -0
- package/src/skills/redis-cache/references/listeners.md +23 -0
- package/src/skills/scheduled-jobs/SKILL.md +314 -0
- package/src/skills/security-guard/SKILL.md +353 -0
- package/src/skills/security-guard/references/encrypt-config.md +103 -0
- package/src/skills/security-guard/references/sensitive-strategies.md +42 -0
- package/src/skills/sms-mail/SKILL.md +308 -0
- package/src/skills/sms-mail/references/mail-config.md +88 -0
- package/src/skills/sms-mail/references/sms-config.md +74 -0
- package/src/skills/social-login/SKILL.md +266 -0
- package/src/skills/social-login/references/provider-configs.md +118 -0
- package/src/skills/start/SKILL.md +154 -0
- package/src/skills/store-pc/SKILL.md +366 -0
- package/src/skills/sync/SKILL.md +149 -0
- package/src/skills/task-tracker/SKILL.md +307 -0
- package/src/skills/tech-decision/SKILL.md +393 -0
- package/src/skills/tenant-management/SKILL.md +288 -0
- package/src/skills/tenant-management/references/tenant-scenarios.md +91 -0
- package/src/skills/test-development/SKILL.md +301 -0
- package/src/skills/test-development/references/parameterized-examples.md +119 -0
- package/src/skills/ui-pc/SKILL.md +438 -0
- package/src/skills/update-status/SKILL.md +159 -0
- package/src/skills/utils-toolkit/SKILL.md +362 -0
- package/src/skills/utils-toolkit/references/redis-utils-api.md +56 -0
- package/src/skills/websocket-sse/SKILL.md +271 -0
- package/src/skills/workflow-engine/SKILL.md +321 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: architecture-design
|
|
3
|
+
description: |
|
|
4
|
+
系统架构设计、模块划分、代码重构、技术栈选型。核心内容:三层架构规范、业务模块划分、表设计规范、技术栈优先级决策。
|
|
5
|
+
|
|
6
|
+
触发场景:
|
|
7
|
+
- 系统整体架构设计
|
|
8
|
+
- 新业务模块的模块划分与结构规划
|
|
9
|
+
- 代码分层与重构策略
|
|
10
|
+
- 依赖关系梳理与解耦
|
|
11
|
+
- 架构演进路径建议
|
|
12
|
+
- 领域边界划分与包结构设计
|
|
13
|
+
- 技术栈选型与方案决策
|
|
14
|
+
|
|
15
|
+
触发词:架构设计、模块划分、三层架构、分层、领域划分、重构、解耦、依赖管理、系统设计、代码组织、技术栈、架构演进
|
|
16
|
+
|
|
17
|
+
注意:
|
|
18
|
+
1. 具体技术对比(Redis vs 本地缓存)-> 使用 tech-decision
|
|
19
|
+
2. 开发具体 CRUD 模块 -> 使用 crud-development
|
|
20
|
+
3. 数据库建表与字典配置 -> 使用 database-ops
|
|
21
|
+
4. 本项目是纯后端项目(无前端代码)
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# 架构设计指南
|
|
25
|
+
|
|
26
|
+
## 核心技术栈
|
|
27
|
+
|
|
28
|
+
| 层级 | 技术栈 | 版本 |
|
|
29
|
+
|------|--------|------|
|
|
30
|
+
| 后端框架 | Spring Boot | 3.5.9 |
|
|
31
|
+
| 开发语言 | Java | 17 |
|
|
32
|
+
| ORM | MyBatis-Plus | 3.5.16 |
|
|
33
|
+
| 安全 | Sa-Token | 1.44.0 |
|
|
34
|
+
| 数据库 | MySQL | 8.0+ |
|
|
35
|
+
| 缓存 | Redis + Redisson | 3.52.0 |
|
|
36
|
+
| 文档 | SpringDoc | 2.8.15 |
|
|
37
|
+
| 工具库 | Hutool | 5.8.43 |
|
|
38
|
+
| 对象转换 | Mapstruct-Plus | 1.5.0 |
|
|
39
|
+
|
|
40
|
+
## 已集成技术栈(按优先级)
|
|
41
|
+
|
|
42
|
+
### 高优先级(优先选择)
|
|
43
|
+
|
|
44
|
+
| 技术 | 使用场景 |
|
|
45
|
+
|------|---------|
|
|
46
|
+
| Redis + Redisson | 缓存、分布式锁、延迟队列、布隆过滤器 |
|
|
47
|
+
| WebSocket | 实时推送、在线聊天、消息通知 |
|
|
48
|
+
| Sa-Token | 权限控制、登录认证、单点登录 |
|
|
49
|
+
| Lock4j | 分布式锁(基于 Redisson) |
|
|
50
|
+
| SnailJob | 分布式定时任务、复杂调度 |
|
|
51
|
+
|
|
52
|
+
### 中优先级(按需使用)
|
|
53
|
+
|
|
54
|
+
| 技术 | 使用场景 |
|
|
55
|
+
|------|---------|
|
|
56
|
+
| SSE | 服务端单向推送 |
|
|
57
|
+
| FastExcel | Excel 导入导出 |
|
|
58
|
+
| SMS4j | 多平台短信发送 |
|
|
59
|
+
| JustAuth | 第三方 OAuth 登录(30+ 平台) |
|
|
60
|
+
| AWS S3 | 对象存储(兼容 MinIO) |
|
|
61
|
+
| MailSender | 邮件发送 |
|
|
62
|
+
| Redis Streams | 轻量级消息队列 |
|
|
63
|
+
|
|
64
|
+
### 已集成扩展能力
|
|
65
|
+
|
|
66
|
+
数据加密、数据脱敏、防重复提交、国际化翻译、审计日志、接口限流
|
|
67
|
+
|
|
68
|
+
### 需自行扩展
|
|
69
|
+
|
|
70
|
+
| 技术 | 使用场景 |
|
|
71
|
+
|------|---------|
|
|
72
|
+
| RocketMQ | 高吞吐消息队列、分布式事务 |
|
|
73
|
+
| MQTT | 物联网设备通信 |
|
|
74
|
+
| LangChain4j | AI 大模型集成 |
|
|
75
|
+
|
|
76
|
+
### 技术选型决策树
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
需要实时通信?
|
|
80
|
+
+-- 是 -> WebSocket(首选)
|
|
81
|
+
+-- 否 -> 需要消息队列?
|
|
82
|
+
+-- 是 -> Redis Streams(优先) / RocketMQ(高吞吐,自行引入)
|
|
83
|
+
+-- 否 -> 需要定时任务?
|
|
84
|
+
+-- 是 -> SnailJob(分布式) / @Scheduled(简单场景)
|
|
85
|
+
+-- 否 -> 需要缓存?
|
|
86
|
+
+-- 是 -> Redis + Redisson
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 三层架构(Controller -> Service -> Mapper)
|
|
92
|
+
|
|
93
|
+
**没有独立的 DAO 层。** Service 直接调用 Mapper,`buildQueryWrapper()` 在 Service 实现类中。
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
Controller 层:接收 HTTP 请求、参数校验、返回 R<T>
|
|
97
|
+
|
|
|
98
|
+
Service 层:业务逻辑、事务管理、buildQueryWrapper()、直接注入 Mapper
|
|
99
|
+
|
|
|
100
|
+
Mapper 层:extends BaseMapperPlus<Entity, Vo>,ORM 映射
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 模块划分与表前缀
|
|
106
|
+
|
|
107
|
+
**包名必须是 `org.dromara.*`**
|
|
108
|
+
|
|
109
|
+
### 标准模块
|
|
110
|
+
|
|
111
|
+
| 模块 | 目录 | 包路径 | 表前缀 |
|
|
112
|
+
|------|------|--------|--------|
|
|
113
|
+
| 系统管理 | `ruoyi-modules/ruoyi-system/` | `org.dromara.system` | `sys_` |
|
|
114
|
+
| 演示模块 | `ruoyi-modules/ruoyi-demo/` | `org.dromara.demo` | `test_` |
|
|
115
|
+
| 工作流 | `ruoyi-modules/ruoyi-workflow/` | `org.dromara.workflow` | `flow_` |
|
|
116
|
+
|
|
117
|
+
### 扩展模块命名
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
ruoyi-modules/ruoyi-{业务}/ -> org.dromara.{业务} -> {前缀}_
|
|
121
|
+
例:ruoyi-mall/ -> org.dromara.mall -> m_
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 关键规则
|
|
125
|
+
|
|
126
|
+
```java
|
|
127
|
+
// 1. 表前缀与模块一一对应
|
|
128
|
+
// OK: sys_user -> ruoyi-system NG: sys_user -> ruoyi-demo
|
|
129
|
+
|
|
130
|
+
// 2. 所有业务表继承 TenantEntity
|
|
131
|
+
public class Order extends TenantEntity {
|
|
132
|
+
@TableId(value = "id") // 雪花ID,依赖全局配置,不指定 type
|
|
133
|
+
private Long id;
|
|
134
|
+
|
|
135
|
+
@TableLogic
|
|
136
|
+
private Long delFlag; // 逻辑删除
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 3. 主键使用雪花 ID(全局配置 idType: ASSIGN_ID)
|
|
140
|
+
@TableId(value = "id") // OK
|
|
141
|
+
@TableId(value = "id", type = IdType.ASSIGN_ID) // NG: 冗余
|
|
142
|
+
// SQL 中禁止 AUTO_INCREMENT
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 模块内部结构(以 TestDemo 为例)
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/
|
|
151
|
+
+-- controller/
|
|
152
|
+
| +-- TestDemoController.java # @RestController
|
|
153
|
+
+-- service/
|
|
154
|
+
| +-- ITestDemoService.java # 接口
|
|
155
|
+
| +-- impl/
|
|
156
|
+
| +-- TestDemoServiceImpl.java # 实现(含 buildQueryWrapper)
|
|
157
|
+
+-- mapper/
|
|
158
|
+
| +-- TestDemoMapper.java # extends BaseMapperPlus<TestDemo, TestDemoVo>
|
|
159
|
+
+-- domain/
|
|
160
|
+
+-- TestDemo.java # extends TenantEntity
|
|
161
|
+
+-- bo/
|
|
162
|
+
| +-- TestDemoBo.java # @AutoMapper
|
|
163
|
+
+-- vo/
|
|
164
|
+
+-- TestDemoVo.java
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Service 实现核心模式
|
|
168
|
+
|
|
169
|
+
```java
|
|
170
|
+
@Service
|
|
171
|
+
public class TestDemoServiceImpl implements ITestDemoService {
|
|
172
|
+
private final TestDemoMapper baseMapper; // 直接注入 Mapper
|
|
173
|
+
|
|
174
|
+
private LambdaQueryWrapper<TestDemo> buildQueryWrapper(TestDemoBo bo) {
|
|
175
|
+
Map<String, Object> params = bo.getParams();
|
|
176
|
+
LambdaQueryWrapper<TestDemo> lqw = Wrappers.lambdaQuery();
|
|
177
|
+
lqw.eq(bo.getDeptId() != null, TestDemo::getDeptId, bo.getDeptId());
|
|
178
|
+
lqw.like(StringUtils.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey());
|
|
179
|
+
lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
|
|
180
|
+
TestDemo::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
|
|
181
|
+
return lqw;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
@Override
|
|
185
|
+
public TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo, PageQuery pageQuery) {
|
|
186
|
+
LambdaQueryWrapper<TestDemo> lqw = buildQueryWrapper(bo);
|
|
187
|
+
Page<TestDemoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
|
188
|
+
return TableDataInfo.build(result);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## 建表模板(MySQL)
|
|
196
|
+
|
|
197
|
+
```sql
|
|
198
|
+
CREATE TABLE xxx_table (
|
|
199
|
+
id BIGINT(20) NOT NULL COMMENT '主键ID',
|
|
200
|
+
tenant_id VARCHAR(20) DEFAULT '000000' COMMENT '租户ID',
|
|
201
|
+
-- 业务字段
|
|
202
|
+
xxx_name VARCHAR(100) NOT NULL COMMENT '名称',
|
|
203
|
+
status CHAR(1) DEFAULT '0' COMMENT '状态',
|
|
204
|
+
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
|
205
|
+
-- 审计字段(TenantEntity 提供)
|
|
206
|
+
create_dept BIGINT(20) DEFAULT NULL COMMENT '创建部门',
|
|
207
|
+
create_by BIGINT(20) DEFAULT NULL COMMENT '创建人',
|
|
208
|
+
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
|
209
|
+
update_by BIGINT(20) DEFAULT NULL COMMENT '更新人',
|
|
210
|
+
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
|
211
|
+
del_flag CHAR(1) DEFAULT '0' COMMENT '删除标志(0正常 1已删除)',
|
|
212
|
+
PRIMARY KEY (id),
|
|
213
|
+
INDEX idx_tenant_id (tenant_id)
|
|
214
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='xxx表';
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**建表必须**:tenant_id、审计字段、del_flag、雪花ID(无 AUTO_INCREMENT)、表前缀对应模块。
|
|
218
|
+
|
|
219
|
+
多数据库 SQL 位置:`script/sql/` 下的 `ry_vue_5.X.sql`(MySQL)、`oracle/`、`postgres/`、`sqlserver/`
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 技术选型决策速查
|
|
224
|
+
|
|
225
|
+
| 场景 | 推荐方案 |
|
|
226
|
+
|------|---------|
|
|
227
|
+
| 简单异步通知 | 同步调用即可 |
|
|
228
|
+
| 解耦场景消息队列 | Redis Streams |
|
|
229
|
+
| 高并发削峰 | RocketMQ(自行引入) |
|
|
230
|
+
| 单机定时任务 | `@Scheduled` |
|
|
231
|
+
| 分布式定时任务 | SnailJob |
|
|
232
|
+
| 实时双向通信 | WebSocket |
|
|
233
|
+
| 服务端单向推送 | SSE |
|
|
234
|
+
| IoT 设备通信 | MQTT(自行集成) |
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 新模块设计检查清单
|
|
239
|
+
|
|
240
|
+
- [ ] 包路径:`org.dromara.{模块名}`
|
|
241
|
+
- [ ] 表前缀与模块对应
|
|
242
|
+
- [ ] 主键雪花ID、含 tenant_id、审计字段、del_flag
|
|
243
|
+
- [ ] 三层完整:Controller / Service(含 buildQueryWrapper) / Mapper(extends BaseMapperPlus)
|
|
244
|
+
- [ ] 对象转换:`MapstructUtils.convert()`
|
|
245
|
+
- [ ] 异常处理:`ServiceException`
|
|
246
|
+
- [ ] 权限注解:`@SaCheckPermission("{模块}:{实体}:{操作}")`
|
|
247
|
+
- [ ] 缓存优先 Redis、实时通信优先 WebSocket、导出用 FastExcel
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## 多项目适配对照
|
|
252
|
+
|
|
253
|
+
| 特征 | RuoYi-Vue-Plus | leniu-tengyun-core |
|
|
254
|
+
|------|----------------|-------------------|
|
|
255
|
+
| 包名前缀 | `org.dromara.*` | `net.xnzn.core.*` |
|
|
256
|
+
| JDK | 17 | 21 |
|
|
257
|
+
| 请求封装 | 直接 BO | `LeRequest<T>` |
|
|
258
|
+
| 响应封装 | `R<T>`, `TableDataInfo<T>` | `Page<T>`, `void` |
|
|
259
|
+
| 异常类 | `ServiceException` | `LeException` |
|
|
260
|
+
| 国际化 | `MessageUtils.message()` | `I18n.getMessage()` |
|
|
261
|
+
| 权限注解 | `@SaCheckPermission` | `@RequiresAuthentication` |
|
|
262
|
+
| 分页 | `PageQuery`, `TableDataInfo` | `PageDTO`, `Page<VO>` |
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: backend-annotations
|
|
3
|
+
description: |
|
|
4
|
+
后端高级注解使用指南。包含 @RateLimiter、@RepeatSubmit、@Sensitive、@EncryptField、@ApiEncrypt、@DataPermission 等注解的用法。
|
|
5
|
+
|
|
6
|
+
触发场景:
|
|
7
|
+
- 配置接口限流(@RateLimiter)
|
|
8
|
+
- 配置防重复提交(@RepeatSubmit)
|
|
9
|
+
- 配置数据脱敏(@Sensitive)
|
|
10
|
+
- 配置字段加密(@EncryptField)
|
|
11
|
+
- 配置接口加密(@ApiEncrypt)
|
|
12
|
+
- 配置数据权限注解(@DataPermission)
|
|
13
|
+
|
|
14
|
+
触发词:注解、@RateLimiter、@RepeatSubmit、@Sensitive、@EncryptField、@ApiEncrypt、@DataPermission、@DataColumn、限流、防重复、脱敏、加密、数据权限注解
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# 后端高级注解指南
|
|
18
|
+
|
|
19
|
+
> RuoYi-Vue-Plus 三层架构,包名 `org.dromara.*`
|
|
20
|
+
|
|
21
|
+
## 注解总览
|
|
22
|
+
|
|
23
|
+
| 注解 | 机制 | 作用层 | 依赖 |
|
|
24
|
+
|------|------|--------|------|
|
|
25
|
+
| `@RateLimiter` | AOP | Controller 方法 | Redis |
|
|
26
|
+
| `@RepeatSubmit` | AOP | Controller 方法 | Redis + Token |
|
|
27
|
+
| `@Sensitive` | Jackson 序列化器 | VO 字段 | 无 |
|
|
28
|
+
| `@EncryptField` | MyBatis 拦截器 | Entity 字段 | 无 |
|
|
29
|
+
| `@ApiEncrypt` | 拦截器 | Controller 方法 | 无 |
|
|
30
|
+
| `@DataPermission` | AOP | Mapper 接口 | MyBatis |
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 1. @RateLimiter - 接口限流
|
|
35
|
+
|
|
36
|
+
**导入**:`org.dromara.common.ratelimiter.annotation.RateLimiter`
|
|
37
|
+
|
|
38
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
39
|
+
|------|------|--------|------|
|
|
40
|
+
| `key` | String | "" | 限流key,支持SpEL |
|
|
41
|
+
| `time` | int | 60 | 时间窗口(秒) |
|
|
42
|
+
| `count` | int | 100 | 最大请求次数 |
|
|
43
|
+
| `limitType` | LimitType | DEFAULT | DEFAULT/IP/CLUSTER |
|
|
44
|
+
| `message` | String | 国际化key | 错误提示 |
|
|
45
|
+
|
|
46
|
+
```java
|
|
47
|
+
// 全局限流:60秒100次
|
|
48
|
+
@RateLimiter(time = 60, count = 100)
|
|
49
|
+
@GetMapping("/list")
|
|
50
|
+
public R<List<XxxVo>> list() { }
|
|
51
|
+
|
|
52
|
+
// IP限流:每个IP每分钟10次(登录、验证码)
|
|
53
|
+
@RateLimiter(time = 60, count = 10, limitType = LimitType.IP)
|
|
54
|
+
@PostMapping("/login")
|
|
55
|
+
public R<String> login() { }
|
|
56
|
+
|
|
57
|
+
// 动态key:基于用户ID限流
|
|
58
|
+
@RateLimiter(key = "#userId", time = 60, count = 5)
|
|
59
|
+
@PostMapping("/submit")
|
|
60
|
+
public R<Void> submit(Long userId) { }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 2. @RepeatSubmit - 防重复提交
|
|
66
|
+
|
|
67
|
+
**导入**:`org.dromara.common.idempotent.annotation.RepeatSubmit`
|
|
68
|
+
|
|
69
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
70
|
+
|------|------|--------|------|
|
|
71
|
+
| `interval` | int | 5000 | 间隔时间(毫秒) |
|
|
72
|
+
| `timeUnit` | TimeUnit | MILLISECONDS | 时间单位 |
|
|
73
|
+
| `message` | String | 国际化key | 错误提示 |
|
|
74
|
+
|
|
75
|
+
```java
|
|
76
|
+
// 默认5秒
|
|
77
|
+
@RepeatSubmit()
|
|
78
|
+
@PostMapping()
|
|
79
|
+
public R<Long> add(@RequestBody OrderBo bo) { }
|
|
80
|
+
|
|
81
|
+
// 10秒间隔 + 自定义提示
|
|
82
|
+
@RepeatSubmit(interval = 10, timeUnit = TimeUnit.SECONDS, message = "请勿重复提交")
|
|
83
|
+
@PostMapping("/pay")
|
|
84
|
+
public R<Void> pay(@RequestBody PayBo bo) { }
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**原理**:`MD5(token + ":" + 序列化参数)` -> Redis 设置/检查 -> 成功保留key防重复 -> 异常删除key允许重试。
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 3. @Sensitive - 数据脱敏
|
|
92
|
+
|
|
93
|
+
**导入**:`org.dromara.common.sensitive.annotation.Sensitive`
|
|
94
|
+
|
|
95
|
+
### 脱敏策略
|
|
96
|
+
|
|
97
|
+
| 策略 | 效果 | 策略 | 效果 |
|
|
98
|
+
|------|------|------|------|
|
|
99
|
+
| `ID_CARD` | 110\*\*\*5431 | `PHONE` | 176\*\*\*\*5371 |
|
|
100
|
+
| `EMAIL` | t\*\*@example.com | `BANK_CARD` | 6222\*\*\*2853 |
|
|
101
|
+
| `CHINESE_NAME` | 张\* | `ADDRESS` | 北京市朝阳区\*\*\*\* |
|
|
102
|
+
| `PASSWORD` | \*\*\*\*\*\* | `IPV4` | 192.\*.\*.\* |
|
|
103
|
+
| `FIRST_MASK` | a\*\*\*\*\* | `CLEAR` | "" |
|
|
104
|
+
|
|
105
|
+
```java
|
|
106
|
+
public class UserVo {
|
|
107
|
+
// 所有人看脱敏数据
|
|
108
|
+
@Sensitive(strategy = SensitiveStrategy.PHONE)
|
|
109
|
+
private String phone;
|
|
110
|
+
|
|
111
|
+
// admin 角色可查看原数据
|
|
112
|
+
@Sensitive(strategy = SensitiveStrategy.ID_CARD, roleKey = {"admin"})
|
|
113
|
+
private String idCard;
|
|
114
|
+
|
|
115
|
+
// 需要权限才能看原数据
|
|
116
|
+
@Sensitive(strategy = SensitiveStrategy.EMAIL, perms = {"system:user:detail"})
|
|
117
|
+
private String email;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**权限逻辑**:roleKey 和 perms 都为空 = 全部脱敏;满足任一 roleKey **或** 任一 perms = 可查看原数据(OR 关系)。
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 4. @EncryptField - 字段加密
|
|
126
|
+
|
|
127
|
+
**导入**:`org.dromara.common.encrypt.annotation.EncryptField`
|
|
128
|
+
|
|
129
|
+
| 算法 | 说明 | 算法 | 说明 |
|
|
130
|
+
|------|------|------|------|
|
|
131
|
+
| `BASE64` | 编码(低安全) | `AES` | 对称加密(推荐) |
|
|
132
|
+
| `RSA` | 非对称(高安全) | `SM2` | 国密非对称 |
|
|
133
|
+
| `SM4` | 国密对称 | | |
|
|
134
|
+
|
|
135
|
+
```java
|
|
136
|
+
@Data
|
|
137
|
+
@TableName("test_demo")
|
|
138
|
+
public class TestDemo extends BaseEntity {
|
|
139
|
+
// AES 加密(使用 yml 全局秘钥)
|
|
140
|
+
@EncryptField(algorithm = AlgorithmType.AES)
|
|
141
|
+
private String phone;
|
|
142
|
+
|
|
143
|
+
// RSA 加密(指定公私钥)
|
|
144
|
+
@EncryptField(algorithm = AlgorithmType.RSA,
|
|
145
|
+
privateKey = "MIICdQ...", publicKey = "MFkwEw...")
|
|
146
|
+
private String idCard;
|
|
147
|
+
|
|
148
|
+
// 使用 yml 默认配置
|
|
149
|
+
@EncryptField
|
|
150
|
+
private String secretField;
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**配置**:
|
|
155
|
+
|
|
156
|
+
```yaml
|
|
157
|
+
mybatis-encryptor:
|
|
158
|
+
enable: false
|
|
159
|
+
algorithm: BASE64 # 默认算法
|
|
160
|
+
encode: BASE64 # 编码方式:BASE64 | HEX
|
|
161
|
+
password: your-secret-16 # AES/SM4 秘钥(16字符)
|
|
162
|
+
publicKey: MFwwDQ... # RSA/SM2 公钥
|
|
163
|
+
privateKey: MIIBVAIBADANBg... # RSA/SM2 私钥
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## 5. @ApiEncrypt - 接口加密
|
|
169
|
+
|
|
170
|
+
**导入**:`org.dromara.common.encrypt.annotation.ApiEncrypt`
|
|
171
|
+
|
|
172
|
+
```java
|
|
173
|
+
// 加密响应数据
|
|
174
|
+
@ApiEncrypt(response = true)
|
|
175
|
+
@GetMapping("/{id}")
|
|
176
|
+
public R<UserVo> getUser(@PathVariable Long id) { }
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
180
|
+
|------|------|--------|------|
|
|
181
|
+
| `response` | boolean | false | 是否加密响应 |
|
|
182
|
+
|
|
183
|
+
**配置**:
|
|
184
|
+
|
|
185
|
+
```yaml
|
|
186
|
+
api-decrypt:
|
|
187
|
+
enabled: true
|
|
188
|
+
headerFlag: encrypt-key
|
|
189
|
+
publicKey: MFwwDQ... # 响应加密公钥
|
|
190
|
+
privateKey: MIIBVAIBADANBg... # 请求解密私钥
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## 6. @DataPermission - 数据权限
|
|
196
|
+
|
|
197
|
+
**导入**:`org.dromara.common.mybatis.annotation.DataPermission`、`@DataColumn`
|
|
198
|
+
|
|
199
|
+
```java
|
|
200
|
+
public interface OrderMapper extends BaseMapperPlus<Order, OrderVo> {
|
|
201
|
+
|
|
202
|
+
// 按部门+创建人隔离
|
|
203
|
+
@DataPermission({
|
|
204
|
+
@DataColumn(key = "deptName", value = "dept_id"),
|
|
205
|
+
@DataColumn(key = "userName", value = "create_by")
|
|
206
|
+
})
|
|
207
|
+
default Page<OrderVo> selectPageOrderList(Page<Order> page, Wrapper<Order> wrapper) {
|
|
208
|
+
return this.selectVoPage(page, wrapper);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// 使用表别名
|
|
212
|
+
@DataPermission({
|
|
213
|
+
@DataColumn(key = "deptName", value = "d.dept_id"),
|
|
214
|
+
@DataColumn(key = "userName", value = "u.create_by")
|
|
215
|
+
})
|
|
216
|
+
List<OrderVo> selectWithJoin(@Param(Constants.WRAPPER) Wrapper<Order> wrapper);
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**@DataColumn 参数**:
|
|
221
|
+
|
|
222
|
+
| 参数 | 默认值 | 说明 |
|
|
223
|
+
|------|--------|------|
|
|
224
|
+
| `key` | "deptName" | 占位符关键字 |
|
|
225
|
+
| `value` | "dept_id" | 替换的字段名 |
|
|
226
|
+
| `permission` | "" | 拥有此权限则不过滤 |
|
|
227
|
+
|
|
228
|
+
**权限范围**:全部数据 / 本部门 / 本部门及以下 / 仅本人 / 自定义。
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## 七、组合使用
|
|
233
|
+
|
|
234
|
+
```java
|
|
235
|
+
// 接口防护:限流 + 防重复 + 日志
|
|
236
|
+
@RateLimiter(time = 60, count = 10, limitType = LimitType.IP)
|
|
237
|
+
@RepeatSubmit(interval = 10, timeUnit = TimeUnit.SECONDS)
|
|
238
|
+
@Log(title = "订单", businessType = BusinessType.INSERT)
|
|
239
|
+
@PostMapping()
|
|
240
|
+
public R<Long> addOrder(@Validated @RequestBody OrderBo bo) { }
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
```java
|
|
244
|
+
// 数据保护分层:Entity 加密存储 + VO 脱敏展示
|
|
245
|
+
@TableName("sys_user")
|
|
246
|
+
public class SysUser extends TenantEntity {
|
|
247
|
+
@EncryptField(algorithm = AlgorithmType.AES)
|
|
248
|
+
private String phone; // 存储时加密
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
public class UserVo {
|
|
252
|
+
@Sensitive(strategy = SensitiveStrategy.PHONE)
|
|
253
|
+
private String phone; // 序列化时脱敏
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## 八、常见错误
|
|
260
|
+
|
|
261
|
+
```java
|
|
262
|
+
// ❌ @RateLimiter 用在 Service 方法上(无效,只能 Controller)
|
|
263
|
+
@Service
|
|
264
|
+
public class XxxService {
|
|
265
|
+
@RateLimiter(...) // 无效!
|
|
266
|
+
public void doSomething() { }
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ❌ @DataPermission 未配置 @DataColumn
|
|
270
|
+
@DataPermission // 空注解无效!
|
|
271
|
+
public interface UserMapper { }
|
|
272
|
+
|
|
273
|
+
// ❌ @Sensitive 用在 Entity 上(应在 VO 上)
|
|
274
|
+
// ❌ @EncryptField 用在 VO 上(应在 Entity 上)
|
|
275
|
+
|
|
276
|
+
// ✅ @DataPermission 支持类级别 + 方法级别(方法覆盖类)
|
|
277
|
+
@DataPermission({ @DataColumn(key = "deptName", value = "dept_id") })
|
|
278
|
+
public interface UserMapper {
|
|
279
|
+
@DataPermission({ /* 方法级覆盖 */ })
|
|
280
|
+
List<UserVo> selectList();
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## 九、参考实现
|
|
287
|
+
|
|
288
|
+
| 类型 | 位置 |
|
|
289
|
+
|------|------|
|
|
290
|
+
| 限流示例 | `org.dromara.demo.controller.RedisRateLimiterController` |
|
|
291
|
+
| 脱敏示例 | `org.dromara.demo.controller.TestSensitiveController` |
|
|
292
|
+
| 加密示例 | `org.dromara.demo.domain.TestDemo` |
|
|
293
|
+
| 数据权限 | `org.dromara.system.mapper.SysUserMapper` |
|
|
294
|
+
|
|
295
|
+
**配置位置**:
|
|
296
|
+
|
|
297
|
+
```
|
|
298
|
+
application.yml:
|
|
299
|
+
mybatis-encryptor.* → @EncryptField 全局配置
|
|
300
|
+
api-decrypt.* → @ApiEncrypt 全局配置
|
|
301
|
+
spring.data.redis.* → @RateLimiter/@RepeatSubmit 依赖
|
|
302
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0] - 2025-12-22
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial release of Banana Image skill
|
|
13
|
+
- **Dual model support**: Flash (fast) and Pro (4K high-quality)
|
|
14
|
+
- **Image generation** with customizable parameters:
|
|
15
|
+
- Aspect ratios: 1:1, 16:9, 9:16, 4:3, 3:4, 4:5, 5:4, 2:3, 3:2, 21:9
|
|
16
|
+
- Resolutions: 1K, 2K, 4K (Pro model only for 4K)
|
|
17
|
+
- Negative prompts for content exclusion
|
|
18
|
+
- Batch generation (1-4 images)
|
|
19
|
+
- **Image editing mode** - modify existing images with text prompts
|
|
20
|
+
- **Proxy support** via undici for corporate network environments
|
|
21
|
+
- **Google Search grounding** for Pro model
|
|
22
|
+
- **Template system** with predefined configurations:
|
|
23
|
+
- Product photography
|
|
24
|
+
- Social media posts
|
|
25
|
+
- Posters
|
|
26
|
+
- Thumbnails
|
|
27
|
+
- CLI interface with comprehensive options
|
|
28
|
+
- JSON output format for easy integration
|
|
29
|
+
- Claude Code skill integration
|
|
30
|
+
|
|
31
|
+
### Technical Details
|
|
32
|
+
|
|
33
|
+
- Models:
|
|
34
|
+
- Flash: `gemini-2.5-flash-image`
|
|
35
|
+
- Pro: `gemini-3-pro-image-preview`
|
|
36
|
+
- Default output: `./images` directory
|
|
37
|
+
- Supported input formats: PNG, JPG, JPEG, GIF, WebP
|