@nebula-skills/nebula-code-standards 0.1.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/README.md +45 -0
- package/bin/cli.cjs +50 -0
- package/package.json +45 -0
- package/scripts/postinstall.cjs +18 -0
- package/skill/SKILL.md +133 -0
- package/skill/backend-standards.md +611 -0
- package/skill/boot-components-catalog.md +546 -0
- package/skill/db-standards.md +232 -0
- package/skill/framework-standards.md +610 -0
- package/skill/frontend-standards.md +310 -0
- package/skill/full-crud-example.md +608 -0
- package/skill/init-new-project.md +842 -0
- package/skill/microapp-guide.md +510 -0
- package/skill/pitfalls-checklist.md +188 -0
- package/skill/rpc-api-reference.md +313 -0
- package/skill/upgrade-decision.md +151 -0
- package/skill/workspace-overview.md +194 -0
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
# nebula-boot 组件能力目录
|
|
2
|
+
|
|
3
|
+
> 写代码前先来此查表。如果 boot 已经封装了某能力,**禁止** 在业务项目自己造轮子。如果 boot 没有,请走 [[upgrade-decision]] 判断「下沉到 boot」还是「业务自实现」。
|
|
4
|
+
|
|
5
|
+
> 本目录是规则文档,**不需要去本地源码** 验证。当 API 签名有疑问时,去 Nexus 内网仓库(`http://10.10.1.130:8081/repository/nebula-public/`)翻 jar 包或问 nebula-boot 维护者。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## A. Framework 层(14 个模块)
|
|
10
|
+
|
|
11
|
+
framework 层是**纯 Java + Spring 集成契约**,不带 `@AutoConfiguration`。每个模块导出工具类、注解、SPI 接口。
|
|
12
|
+
|
|
13
|
+
### A.1 nebula-framework-core — 基础工具
|
|
14
|
+
|
|
15
|
+
| 工具 | 一句话用法 |
|
|
16
|
+
|------|----------|
|
|
17
|
+
| `JsonUtils` | `JsonUtils.toJsonString(obj)` / `JsonUtils.parseObject(json, Class)` / `JsonUtils.parseArray(json, Class)` / `JsonUtils.getObjectMapper()` |
|
|
18
|
+
| `AesUtils` / `RsaUtils` / `DigestUtils` | 对称/非对称加密、MD5/SHA 摘要 |
|
|
19
|
+
| `DateUtils` / `DatePattern` | 日期工具与格式常量 |
|
|
20
|
+
| `MDCUtils` | SLF4J MDC 取值/设置(traceId 等) |
|
|
21
|
+
| `IdUtils` | Snowflake ID 生成(注意:跨服务业务号请用 system `IdGenRpcService`,不要拿 IdUtils 当业务号) |
|
|
22
|
+
| `SpelExpressionUtils` | SpEL 表达式解析(支持方法参数、静态方法) |
|
|
23
|
+
| `AssertUtils` | 参数断言 |
|
|
24
|
+
| `StringUtils` / `CollectionUtils` / `MapUtils` | 集合 / 字符串工具 |
|
|
25
|
+
| `BeanConvertUtils` / `BaseMapperConfig` | MapStruct 全局配置入口 |
|
|
26
|
+
| `PageParam` / `PageResult<T>` | 分页入参 / 分页响应 |
|
|
27
|
+
| `R<T>` | HTTP 统一响应包装:`R.ok(data)` / `R.fail(code, msg)` |
|
|
28
|
+
| `BusinessException` / `SystemException` / `GlobalErrorCode` | 业务异常 / 系统异常 / 错误码 |
|
|
29
|
+
|
|
30
|
+
**配置类入口:** `JacksonConfig`(Spring 注入即生效,已配置 LocalDateTime/null/日期格式)
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
### A.2 nebula-framework-trace — 链路追踪
|
|
35
|
+
|
|
36
|
+
| 入口 | 用法 |
|
|
37
|
+
|------|------|
|
|
38
|
+
| `TraceContextHolder` | `TraceContextHolder.getTraceId()` / `TraceContextHolder.runWithContext(ctx, lambda)` |
|
|
39
|
+
| `TraceContext` | 数据模型:traceId / spanId / parentSpanId / startTime |
|
|
40
|
+
| `TraceIdGenerator`(SPI) | 自定义 TraceId 生成策略 |
|
|
41
|
+
| `TracePropagator` / `TraceHeaders` | 在 HTTP Header / MDC 间传播 |
|
|
42
|
+
| `ScheduledTraceAspect` | `@Scheduled` 任务自动生成 TraceId(已默认装配) |
|
|
43
|
+
| `TraceTaskDecorator` | **线程池任务包装器,自建线程池必须包它**,否则丢 traceId |
|
|
44
|
+
|
|
45
|
+
**关键代码:**
|
|
46
|
+
```java
|
|
47
|
+
String traceId = TraceContextHolder.getTraceId(); // 取当前 TraceId
|
|
48
|
+
TraceContextHolder.runWithContext(ctx, () -> bizService.call()); // 函数式切换
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**所属模块:** `nebula-framework-trace`,包 `com.huida.nebula.framework.trace`
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### A.3 nebula-framework-tenant — 多租户
|
|
56
|
+
|
|
57
|
+
| 入口 | 用法 |
|
|
58
|
+
|------|------|
|
|
59
|
+
| `TenantContextHolder` | `getTenantId()` / `getTenantCode()` / `runAsTenant(t, lambda)` / `runWithoutTenant(lambda)` |
|
|
60
|
+
| `TenantInfo` | 数据模型:tenantId / tenantCode / schemaName / databaseKey |
|
|
61
|
+
| `TenantIsolationMode` | 枚举:`DATABASE` / `SCHEMA` / `FIELD`(默认 FIELD) |
|
|
62
|
+
| `@TenantSwitch` | 方法级切换租户 |
|
|
63
|
+
| `@TenantIgnore` | 方法级忽略租户过滤(系统级操作) |
|
|
64
|
+
| `@FeatureEnabled` | 功能开关注解 |
|
|
65
|
+
| `TenantRoutingDataSource` / `SchemaSwitchingDataSource` | 多数据源路由 |
|
|
66
|
+
|
|
67
|
+
**SPI 接口(业务方按需实现):**
|
|
68
|
+
|
|
69
|
+
| SPI | 用途 |
|
|
70
|
+
|-----|------|
|
|
71
|
+
| `TenantResolver` | 从请求中解析租户(Header / URL) |
|
|
72
|
+
| `TenantDomainRepository` | 查询租户元数据 |
|
|
73
|
+
| `TenantDataSourceProvider` | 提供租户对应数据源 |
|
|
74
|
+
| `TenantInfoRepository` | 查询租户详情 |
|
|
75
|
+
| `TenantFeatureRepository` | 查询租户功能开关 |
|
|
76
|
+
| `TenantDataInitializer` | 租户初始化钩子 |
|
|
77
|
+
| `TenantIsolationStrategy` | 自定义隔离策略 |
|
|
78
|
+
|
|
79
|
+
**典型用法:**
|
|
80
|
+
```java
|
|
81
|
+
TenantContextHolder.runAsTenant(targetTenant, () -> orderService.syncOrders());
|
|
82
|
+
TenantContextHolder.runWithoutTenant(() -> globalReportService.reloadAll());
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**所属模块:** `nebula-framework-tenant`,包 `com.huida.nebula.framework.tenant`
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
### A.4 nebula-framework-security — 认证授权契约
|
|
90
|
+
|
|
91
|
+
| 入口 | 用法 |
|
|
92
|
+
|------|------|
|
|
93
|
+
| `SecurityContextHolder` | 当前用户信息持有者 |
|
|
94
|
+
| `@RequiresPermission` | 权限校验,支持 SpEL 与 AND/OR(`logic = LogicType.OR`) |
|
|
95
|
+
| `@RequiresRole` | 角色校验 |
|
|
96
|
+
| `@AnonymousAccess` | 标记匿名可访问 |
|
|
97
|
+
| `IamUser` / `ClientIamUser` / `TokenInfo` / `SocialUserInfo` | 模型 |
|
|
98
|
+
|
|
99
|
+
**SPI 接口:** `UserDetailsLoader` / `PermissionChecker` / `TokenValidator` / `TokenStore` / `SocialAuthProvider`
|
|
100
|
+
|
|
101
|
+
**示例:**
|
|
102
|
+
```java
|
|
103
|
+
@RequiresPermission({"user:create", "user:edit"}) // AND
|
|
104
|
+
@RequiresPermission(value = {"user:manage", "admin:all"}, logic = LogicType.OR)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
> 注意:framework-security 只是契约,真正自动装配在 `nebula-boot-starter-security`。
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
### A.5 nebula-framework-idempotent — 幂等契约
|
|
112
|
+
|
|
113
|
+
| 入口 | 用法 |
|
|
114
|
+
|------|------|
|
|
115
|
+
| `@Idempotent` | 注解参数:`key`(SpEL)/ `prefix` / `ttl` / `timeUnit` / `message` |
|
|
116
|
+
| `IdempotentStore`(SPI) | 后端:Redis(默认)/ 内存 |
|
|
117
|
+
|
|
118
|
+
**示例:**
|
|
119
|
+
```java
|
|
120
|
+
@Idempotent(key = "#req.tradeNo", ttl = 30)
|
|
121
|
+
public void createOrder(CreateOrderRequest req) { ... }
|
|
122
|
+
|
|
123
|
+
@Idempotent(key = "#msgId", prefix = "mq:pay")
|
|
124
|
+
public void handlePayResult(String msgId, PayResultDTO dto) { ... }
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
### A.6 nebula-framework-web — Web 基础设施
|
|
130
|
+
|
|
131
|
+
| 入口 | 用法 |
|
|
132
|
+
|------|------|
|
|
133
|
+
| `ResponseResultHandler` | 自动包装返回值为 `R<T>` |
|
|
134
|
+
| `GlobalExceptionHandler` | 全局异常 → `R.fail(...)` |
|
|
135
|
+
| `RequestLoggingFilter` | 请求/响应日志 |
|
|
136
|
+
| `@RepeatSubmit` | 防重复提交:`interval`(默认 5s)/ `keyExtra`(SpEL) |
|
|
137
|
+
| `@IgnoreResponseWrap` | 跳过 R 包装(用于文件流返回) |
|
|
138
|
+
| `@Desensitize` | 字段脱敏(响应序列化时生效) |
|
|
139
|
+
| `SensitizeType` | 脱敏类型:手机、邮箱、身份证、银行卡等 |
|
|
140
|
+
| `WebUtils` | Web 工具方法 |
|
|
141
|
+
| `NebulaWebProperties` | 配置属性入口 |
|
|
142
|
+
|
|
143
|
+
**示例:**
|
|
144
|
+
```java
|
|
145
|
+
@PostMapping("/order/create")
|
|
146
|
+
@RepeatSubmit(interval = 5, message = "请勿重复提交订单")
|
|
147
|
+
public R<Long> createOrder(@RequestBody @Valid CreateOrderDTO dto) {
|
|
148
|
+
return R.ok(orderService.create(dto));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
public class UserVO {
|
|
152
|
+
@Desensitize(SensitizeType.MOBILE)
|
|
153
|
+
private String mobile;
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
### A.7 nebula-framework-mybatis — MyBatis-Plus 集成
|
|
160
|
+
|
|
161
|
+
| 入口 | 用法 |
|
|
162
|
+
|------|------|
|
|
163
|
+
| `AuditEntity` | 审计基类(id / 7 个公共字段,不含 deleteFlag) |
|
|
164
|
+
| `BaseEntity` | 业务实体基类,继承 AuditEntity 加上 `deleteFlag`(推荐默认使用) |
|
|
165
|
+
| `TenantBaseEntity` | 带租户字段的基类(额外含 `tenantId`) |
|
|
166
|
+
| `BaseMapper<T>` | 继承 MyBatis-Plus 的 BaseMapper,预留扩展点 |
|
|
167
|
+
| `BaseService<T>` / `BaseServiceImpl<M, T>` | 通用 Service,`getByIdOrThrow(id)` 等 |
|
|
168
|
+
| `MetaObjectHandlerImpl` | 字段自动填充(createTime / updateTime / creator / updater) |
|
|
169
|
+
|
|
170
|
+
**11 个公共字段(继承 BaseEntity 后默认拥有,不要重复声明):**
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
id tenantId createUserId creator createTime
|
|
174
|
+
modifyUserId updater modifyTime deleteFlag remark customFields
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
详见 [db-standards.md](db-standards.md) §二-2。
|
|
178
|
+
|
|
179
|
+
**所属模块:** `nebula-framework-mybatis`,包 `com.huida.nebula.framework.mybatis.entity`
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
### A.8 nebula-framework-flyway / nacos / swagger / ratelimit / file / excel / task
|
|
184
|
+
|
|
185
|
+
| 模块 | 用途 |
|
|
186
|
+
|-----|------|
|
|
187
|
+
| `nebula-framework-flyway` | Flyway 集成契约 |
|
|
188
|
+
| `nebula-framework-nacos` | Nacos 配置中心契约 |
|
|
189
|
+
| `nebula-framework-swagger` | OpenAPI 文档契约 |
|
|
190
|
+
| `nebula-framework-ratelimit` | 限流契约(注解 / SPI) |
|
|
191
|
+
| `nebula-framework-file` | 文件存储抽象 |
|
|
192
|
+
| `nebula-framework-excel` | EasyExcel 集成契约 |
|
|
193
|
+
| `nebula-framework-task` | 定时任务契约 |
|
|
194
|
+
|
|
195
|
+
> 实际生效需引入对应 starter。
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## B. Starter 层(22 个 starter)
|
|
200
|
+
|
|
201
|
+
starter 层使用 Spring Boot 3 的 `@AutoConfiguration`,注册在 `META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports`。所有 `@Bean` 默认带 `@ConditionalOnMissingBean`,允许下游覆盖。
|
|
202
|
+
|
|
203
|
+
### B.1 nebula-boot-starter-web
|
|
204
|
+
|
|
205
|
+
| 装配内容 | 入口 |
|
|
206
|
+
|---------|------|
|
|
207
|
+
| 统一响应包装 | `ResponseResultHandler` |
|
|
208
|
+
| 全局异常处理 | `GlobalExceptionHandler` |
|
|
209
|
+
| 请求日志 Filter | `RequestLoggingFilter` |
|
|
210
|
+
| @RepeatSubmit 拦截器 | (自动注册) |
|
|
211
|
+
| Jackson 全局配置 | `JacksonConfig` |
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
### B.2 nebula-boot-starter-trace
|
|
216
|
+
|
|
217
|
+
| 装配内容 | 说明 |
|
|
218
|
+
|---------|------|
|
|
219
|
+
| `TraceFilter` | HTTP 入口提取/生成 TraceId |
|
|
220
|
+
| MDC 自动注入 | `traceId` / `spanId` |
|
|
221
|
+
| 响应头追加 | `X-Trace-Id` |
|
|
222
|
+
| `TraceTaskDecorator` | 提供给线程池 |
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
### B.3 nebula-boot-starter-tenant
|
|
227
|
+
|
|
228
|
+
| 装配内容 | 说明 |
|
|
229
|
+
|---------|------|
|
|
230
|
+
| `TenantContextFilter` | HTTP 过滤器提取租户 |
|
|
231
|
+
| MyBatis-Plus 租户插件 | 自动追加 `WHERE tenant_id = ?`(仅对 BaseMapper / LambdaQueryWrapper 生效;`@Select` 自定义 SQL 不会自动追加) |
|
|
232
|
+
| 数据源路由 | DATABASE / SCHEMA 隔离时启用 |
|
|
233
|
+
|
|
234
|
+
**配置:**
|
|
235
|
+
```yaml
|
|
236
|
+
nebula:
|
|
237
|
+
tenant:
|
|
238
|
+
enabled: true
|
|
239
|
+
isolation-mode: FIELD # FIELD / SCHEMA / DATABASE
|
|
240
|
+
field:
|
|
241
|
+
ignore-tables: auth_login_log, auth_account # 不追加 tenant_id 的表
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
### B.4 nebula-boot-starter-jdbc
|
|
247
|
+
|
|
248
|
+
Druid 多数据源 + 监控 + SQL 防火墙(可选)。配合 tenant 启用时支持租户路由。
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
### B.5 nebula-boot-starter-mybatis
|
|
253
|
+
|
|
254
|
+
| 装配内容 | 说明 |
|
|
255
|
+
|---------|------|
|
|
256
|
+
| `PaginationInterceptor` | 分页插件 |
|
|
257
|
+
| `OptimisticLockerInnerInterceptor` | 乐观锁(`@Version` 字段) |
|
|
258
|
+
| `BlockAttackInnerInterceptor` | 防全表 UPDATE/DELETE |
|
|
259
|
+
| 逻辑删除全局配置 | `@TableLogic` → `delete_flag` |
|
|
260
|
+
| `MetaObjectHandlerImpl` | 自动填充 |
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
### B.6 nebula-boot-starter-redis ⭐
|
|
265
|
+
|
|
266
|
+
| 装配内容 | 入口 |
|
|
267
|
+
|---------|------|
|
|
268
|
+
| Redisson 客户端 | `RedissonClient` |
|
|
269
|
+
| **`NebulaLockHelper`** | 分布式锁,**禁止用 `StringRedisTemplate.setIfAbsent`** |
|
|
270
|
+
| **`NebulaCacheHelper`** | Redis 缓存工具 |
|
|
271
|
+
| `@DistributedLock` | 声明式分布式锁(SpEL Key) |
|
|
272
|
+
| `NebulaMultiLevelCacheAutoConfiguration` | 本地 + Redis 多级缓存 |
|
|
273
|
+
| `CacheEvictPublisher/Subscriber` | 多级缓存一致性 |
|
|
274
|
+
|
|
275
|
+
**典型用法:**
|
|
276
|
+
```java
|
|
277
|
+
// 函数式 — Runnable
|
|
278
|
+
lockHelper.tryLock("order:" + orderId, () -> orderService.create(...));
|
|
279
|
+
|
|
280
|
+
// 函数式 — Supplier(有返回值)
|
|
281
|
+
OrderVO vo = lockHelper.tryLock("order:" + orderId, () -> orderService.detail(orderId));
|
|
282
|
+
|
|
283
|
+
// 注解式
|
|
284
|
+
@DistributedLock(key = "'order:create:' + #orderId")
|
|
285
|
+
public OrderVO createOrder(Long orderId, OrderDTO dto) { ... }
|
|
286
|
+
|
|
287
|
+
// 缓存工具
|
|
288
|
+
cacheHelper.set("user:" + id, user, Duration.ofMinutes(10));
|
|
289
|
+
User u = cacheHelper.get("user:" + id, User.class);
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
> ⚠️ `NebulaCacheHelper` 没有 `hashGetAll`,整体对象读写改用 JSON 字符串存。
|
|
293
|
+
|
|
294
|
+
**所属模块:** `nebula-boot-starter-redis`,包 `com.huida.nebula.boot.autoconfigure.redis`
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
### B.7 nebula-boot-starter-mq
|
|
299
|
+
|
|
300
|
+
| 装配内容 | 说明 |
|
|
301
|
+
|---------|------|
|
|
302
|
+
| `NebulaRocketMQProducer` | 同步/异步/延迟/顺序消息发送,自动透传 TraceId/TenantCode |
|
|
303
|
+
| `AbstractNebulaMessageListener<T>` | 消费者抽象基类,自动恢复 TraceId/TenantCode 上下文 |
|
|
304
|
+
| `ConsumeContext` | 消费上下文(msgId / traceId / retry) |
|
|
305
|
+
| `DeadLetterHandler`(SPI) | 死信处理 |
|
|
306
|
+
|
|
307
|
+
**消费者用法:**
|
|
308
|
+
```java
|
|
309
|
+
@Component
|
|
310
|
+
@RocketMQMessageListener(topic = "order-topic", consumerGroup = "order-consumer-group")
|
|
311
|
+
public class OrderCreatedListener extends AbstractNebulaMessageListener<OrderCreatedEvent> {
|
|
312
|
+
@Override
|
|
313
|
+
protected void onMessage(OrderCreatedEvent event, ConsumeContext context) {
|
|
314
|
+
// TraceId / TenantCode 已自动恢复
|
|
315
|
+
orderService.handleCreated(event);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
### B.8 nebula-boot-starter-log ⭐
|
|
323
|
+
|
|
324
|
+
审计日志的全部代码在此 starter(framework 层无 log 模块)。
|
|
325
|
+
|
|
326
|
+
| 装配内容 | 入口 |
|
|
327
|
+
|---------|------|
|
|
328
|
+
| `AuditLogAspect` | 拦截 `@AuditLog` |
|
|
329
|
+
| `AuditDiffer` | 对象变更差异计算 |
|
|
330
|
+
| `AuditLogPipelineRouter` | 路由到 MySQL / Mongo / MQ / Console |
|
|
331
|
+
| `OperationLogAspect` | 操作日志记录 |
|
|
332
|
+
| 字段脱敏 | `MaskerRegistry` |
|
|
333
|
+
|
|
334
|
+
**核心注解:**
|
|
335
|
+
|
|
336
|
+
| 注解 | 用法 |
|
|
337
|
+
|------|------|
|
|
338
|
+
| `@AuditLog` | 参数 `bizType` / `bizId`(SpEL)/ `changeType` / `content`(SpEL)/ `executeBeforeFunc` |
|
|
339
|
+
| `@AuditObject` | 标记被审计对象 |
|
|
340
|
+
| `@AuditField` | 标记审计字段 |
|
|
341
|
+
| `@AuditFieldIgnore` | 忽略字段 |
|
|
342
|
+
|
|
343
|
+
**内置 SpEL 函数:** `#_DIFF(oldObj, newObj)` / `#_DIFF_ROWS(oldList, newList)` / `#_return` / `#_errorMsg`
|
|
344
|
+
|
|
345
|
+
**示例:**
|
|
346
|
+
```java
|
|
347
|
+
@AuditLog(
|
|
348
|
+
bizType = "ORDER",
|
|
349
|
+
bizId = "#order.id",
|
|
350
|
+
changeType = "UPDATE",
|
|
351
|
+
content = "'订单修改' + #_DIFF(#oldOrder, #order)"
|
|
352
|
+
)
|
|
353
|
+
public void updateOrder(OrderDO oldOrder, OrderDO order) { ... }
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**SPI:** `AuditLogPipeline` — 自定义日志输出目的地。
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
### B.9 nebula-boot-starter-idempotent
|
|
361
|
+
|
|
362
|
+
`@Idempotent` 拦截器 + Redis/Memory 后端实现。引入即可用注解。
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
### B.10 nebula-boot-starter-security
|
|
367
|
+
|
|
368
|
+
| 装配内容 | 说明 |
|
|
369
|
+
|---------|------|
|
|
370
|
+
| Spring Security 无状态配置 | JWT |
|
|
371
|
+
| Token 黑名单 | Redis 存储 |
|
|
372
|
+
| `@RequiresPermission` / `@RequiresRole` 拦截器 | (自动注册) |
|
|
373
|
+
|
|
374
|
+
> 注意:聚合 starter `nebula-boot-starter` 默认 **不** 引入 security,业务项目需自己引。
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
### B.11 nebula-boot-starter-openfeign
|
|
379
|
+
|
|
380
|
+
| 装配内容 | 说明 |
|
|
381
|
+
|---------|------|
|
|
382
|
+
| `FeignTraceInterceptor` | 自动透传 `X-Trace-Id` |
|
|
383
|
+
| `FeignTenantInterceptor` | (README 标记暂未透传 TenantCode,是已知缺口) |
|
|
384
|
+
| `NebulaFeignDecoder` | 统一 `R<T>` 解包 |
|
|
385
|
+
| `NebulaFeignErrorDecoder` | 错误响应处理 |
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
### B.12 nebula-boot-starter-threadpool
|
|
390
|
+
|
|
391
|
+
业务线程池统一装配,已内嵌 `TraceTaskDecorator` + `TenantTaskDecorator`,**用此 starter 提供的线程池就不会丢上下文**。
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
### B.13 其他 starter
|
|
396
|
+
|
|
397
|
+
| starter | 用途 |
|
|
398
|
+
|---------|------|
|
|
399
|
+
| `nebula-boot-starter-flyway` | Flyway 自动迁移 |
|
|
400
|
+
| `nebula-boot-starter-nacos` | Nacos 配置中心 |
|
|
401
|
+
| `nebula-boot-starter-swagger` | springdoc-openapi 集成 |
|
|
402
|
+
| `nebula-boot-starter-ratelimit` | 注解式限流 |
|
|
403
|
+
| `nebula-boot-starter-task` | 定时任务装配 |
|
|
404
|
+
| `nebula-boot-starter-excel` | EasyExcel 装配 |
|
|
405
|
+
| `nebula-boot-starter-file` | 文件存储抽象(本地 / OSS 接入点) |
|
|
406
|
+
| `nebula-boot-starter-elasticsearch` | ES 客户端 |
|
|
407
|
+
| `nebula-boot-starter-mongo` | MongoDB 客户端 |
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
### B.14 nebula-boot-starter(聚合器)
|
|
412
|
+
|
|
413
|
+
一行引入除 security 之外的全部 starter:
|
|
414
|
+
|
|
415
|
+
```gradle
|
|
416
|
+
api "com.huida.nebula.boot:nebula-boot-starter:${nebulaBootVersion}"
|
|
417
|
+
api "com.huida.nebula.boot:nebula-boot-starter-security:${nebulaBootVersion}" // 按需单引
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## C. 速查矩阵(关键词 → 组件)
|
|
423
|
+
|
|
424
|
+
写代码前先在这张表里找关键词。**没找到** 才进入 [[upgrade-decision]]。
|
|
425
|
+
|
|
426
|
+
| 场景关键词 | 该用的组件 | 文档锚点 |
|
|
427
|
+
|-----------|----------|---------|
|
|
428
|
+
| JSON 序列化 | `JsonUtils` | §A.1 |
|
|
429
|
+
| 雪花 ID | `IdUtils` | §A.1 |
|
|
430
|
+
| 业务号(订单号/工单号) | system `IdGenRpcService`(**不要 IdUtils**) | [[rpc-api-reference]] |
|
|
431
|
+
| 分布式锁 | `NebulaLockHelper` / `@DistributedLock` | §B.6 |
|
|
432
|
+
| Redis 缓存 | `NebulaCacheHelper` | §B.6 |
|
|
433
|
+
| 防重复提交(HTTP) | `@RepeatSubmit` | §A.6 |
|
|
434
|
+
| 接口幂等(业务 Key) | `@Idempotent` | §A.5 |
|
|
435
|
+
| 数据脱敏(响应) | `@Desensitize` | §A.6 |
|
|
436
|
+
| 限流 | `nebula-boot-starter-ratelimit` | §B.13 |
|
|
437
|
+
| 审计日志 | `@AuditLog` | §B.8 |
|
|
438
|
+
| 操作日志 | `OperationLogAspect`(starter-log) | §B.8 |
|
|
439
|
+
| 权限校验 | `@RequiresPermission` / `@RequiresRole` | §A.4 |
|
|
440
|
+
| 当前用户 | `SecurityContextHolder` | §A.4 |
|
|
441
|
+
| 多租户切换 | `TenantContextHolder.runAsTenant` / `@TenantSwitch` | §A.3 |
|
|
442
|
+
| 忽略租户过滤 | `TenantContextHolder.runWithoutTenant` / `@TenantIgnore` | §A.3 |
|
|
443
|
+
| 链路追踪当前 ID | `TraceContextHolder.getTraceId()` | §A.2 |
|
|
444
|
+
| 自建线程池保 traceId | `TraceTaskDecorator` 或直接用 starter-threadpool | §A.2 / §B.12 |
|
|
445
|
+
| 分页 | `PageParam` / `PageResult<T>` | §A.1 |
|
|
446
|
+
| 统一响应 | `R<T>` | §A.1 |
|
|
447
|
+
| 业务异常 | `BusinessException` + `GlobalErrorCode` | §A.1 |
|
|
448
|
+
| 系统异常 | `SystemException` | §A.1 |
|
|
449
|
+
| 实体基类 | `BaseEntity`(默认) / `AuditEntity`(物理删除) / `TenantBaseEntity` | §A.7 |
|
|
450
|
+
| 字段自动填充 | `MetaObjectHandlerImpl`(starter-mybatis 已装配) | §B.5 |
|
|
451
|
+
| 防全表 UPDATE/DELETE | `BlockAttackInnerInterceptor`(已装配) | §B.5 |
|
|
452
|
+
| RocketMQ 发送 | `NebulaRocketMQProducer` | §B.7 |
|
|
453
|
+
| RocketMQ 消费 | `extends AbstractNebulaMessageListener<T>` | §B.7 |
|
|
454
|
+
| Excel 导入导出 | `nebula-boot-starter-excel` | §B.13 |
|
|
455
|
+
| 文件存储 | `nebula-boot-starter-file` | §B.13 |
|
|
456
|
+
| Feign Trace 透传 | starter-openfeign 已自动 | §B.11 |
|
|
457
|
+
| Feign Tenant 透传 | ❌ 当前缺口 | [[upgrade-decision]] |
|
|
458
|
+
| Redis 多租户 Key 隔离 | ❌ 当前缺口 | [[upgrade-decision]] |
|
|
459
|
+
| XXL-Job 集成 | ❌ 当前缺口(`nebula-boot-starter-job` 未实现) | [[upgrade-decision]] |
|
|
460
|
+
| OSS 对象存储抽象 | ❌ 当前缺口(`nebula-boot-starter-oss` 未实现) | [[upgrade-decision]] |
|
|
461
|
+
| 可靠本地事件 | ❌ 当前缺口(`nebula-boot-starter-event` 未实现) | [[upgrade-decision]] |
|
|
462
|
+
| 短信 | ❌ 当前缺口(`nebula-boot-starter-sms` 未实现) | [[upgrade-decision]] |
|
|
463
|
+
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
## D. 请求生命周期(理解组件协作)
|
|
467
|
+
|
|
468
|
+
```
|
|
469
|
+
HTTP 请求
|
|
470
|
+
→ TraceFilter (生成/提取 TraceId → MDC + TraceContextHolder)
|
|
471
|
+
→ TenantContextFilter (解析 TenantCode → TenantContextHolder + 数据源路由)
|
|
472
|
+
→ RequestLoggingFilter (请求/响应日志)
|
|
473
|
+
→ Controller
|
|
474
|
+
→ @RepeatSubmit (body hash 防重)
|
|
475
|
+
→ @Idempotent (业务 Key 幂等)
|
|
476
|
+
→ @DistributedLock (Redisson 锁)
|
|
477
|
+
→ @RequiresPermission (权限校验)
|
|
478
|
+
→ @AuditLog (前置快照 → 执行 → 计算 diff → 写管道)
|
|
479
|
+
→ Service / Mapper (自动填充审计字段、自动追加 tenant_id 与 delete_flag = 0)
|
|
480
|
+
→ ResponseResultHandler (包装为 R<T>、响应头追加 X-Trace-Id)
|
|
481
|
+
→ finally (TraceContextHolder.clear / TenantContextHolder.clear / MDC.clear)
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
线程池场景:
|
|
485
|
+
- 用 `nebula-boot-starter-threadpool` 的线程池 → 上下文自动传播
|
|
486
|
+
- 自建 `ThreadPoolExecutor` → 必须包装 `TraceTaskDecorator` + `TenantTaskDecorator`
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
## E. 关键 SPI / 必备实现
|
|
491
|
+
|
|
492
|
+
`nebula-framework-task` 模块定义了 3 个**持久化 SPI 契约**,业务 starter 启动时若未提供实现会拿不到默认 Bean。业务项目初始化时**必须** 提供(哪怕是空实现):
|
|
493
|
+
|
|
494
|
+
| SPI | 包 | 方法签名 |
|
|
495
|
+
|-----|-----|---------|
|
|
496
|
+
| `ApiLogRepository` | `com.huida.nebula.framework.task.apilog` | `void saveAsync(ApiLogModel logModel)` |
|
|
497
|
+
| `TaskQueueService` | `com.huida.nebula.framework.task.queue` | `void publish(TaskMessage)` / `void publishDelayed(TaskMessage, long)` / `String queueType()` |
|
|
498
|
+
| `TaskInstanceRepository` | `com.huida.nebula.framework.task.core.executor` | `markRunning(Long)` / `markSuccess(Long, TaskContext)` / `markFailed(Long, String)` / `markCancelled(Long)` / `updateProgress(Long, int, long, long)` |
|
|
499
|
+
|
|
500
|
+
占位实现模板与 `@AutoConfiguration` 装配见 [[init-new-project]] §五-必备 SPI 空实现。
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
## F. 包导入约定(业务项目最常用)
|
|
505
|
+
|
|
506
|
+
```java
|
|
507
|
+
// core 工具
|
|
508
|
+
import com.huida.nebula.core.json.JsonUtils;
|
|
509
|
+
import com.huida.nebula.core.common.model.R;
|
|
510
|
+
import com.huida.nebula.core.common.model.PageParam;
|
|
511
|
+
import com.huida.nebula.core.common.model.PageResult;
|
|
512
|
+
import com.huida.nebula.core.exception.BusinessException;
|
|
513
|
+
import com.huida.nebula.core.common.constant.CommonConstants;
|
|
514
|
+
|
|
515
|
+
// MyBatis 基类
|
|
516
|
+
import com.huida.nebula.framework.mybatis.entity.BaseEntity;
|
|
517
|
+
import com.huida.nebula.framework.mybatis.entity.AuditEntity;
|
|
518
|
+
import com.huida.nebula.framework.mybatis.entity.TenantBaseEntity;
|
|
519
|
+
import com.huida.nebula.framework.mybatis.mapper.BaseMapper;
|
|
520
|
+
import com.huida.nebula.framework.mybatis.service.BaseService;
|
|
521
|
+
import com.huida.nebula.framework.mybatis.service.impl.BaseServiceImpl;
|
|
522
|
+
|
|
523
|
+
// 上下文
|
|
524
|
+
import com.huida.nebula.framework.trace.context.TraceContextHolder;
|
|
525
|
+
import com.huida.nebula.framework.tenant.context.TenantContextHolder;
|
|
526
|
+
import com.huida.nebula.framework.security.context.SecurityContextHolder;
|
|
527
|
+
|
|
528
|
+
// 注解
|
|
529
|
+
import com.huida.nebula.framework.web.annotation.RepeatSubmit;
|
|
530
|
+
import com.huida.nebula.framework.web.annotation.Desensitize;
|
|
531
|
+
import com.huida.nebula.framework.web.annotation.IgnoreResponseWrap;
|
|
532
|
+
import com.huida.nebula.framework.idempotent.Idempotent;
|
|
533
|
+
import com.huida.nebula.framework.security.annotation.RequiresPermission;
|
|
534
|
+
import com.huida.nebula.framework.security.annotation.RequiresRole;
|
|
535
|
+
import com.huida.nebula.framework.tenant.annotation.TenantSwitch;
|
|
536
|
+
import com.huida.nebula.framework.tenant.annotation.TenantIgnore;
|
|
537
|
+
|
|
538
|
+
// starter 提供(需引入对应 starter)
|
|
539
|
+
import com.huida.nebula.boot.autoconfigure.redis.NebulaLockHelper;
|
|
540
|
+
import com.huida.nebula.boot.autoconfigure.redis.NebulaCacheHelper;
|
|
541
|
+
import com.huida.nebula.boot.autoconfigure.redis.lock.DistributedLock;
|
|
542
|
+
import com.huida.nebula.boot.autoconfigure.log.audit.annotation.AuditLog;
|
|
543
|
+
import com.huida.nebula.boot.autoconfigure.mq.consumer.AbstractNebulaMessageListener;
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
不确定全限定类名时优先 IDE 自动 import,**不要去 Read 源码** 验证。
|