docs: 迁移 spring-ai 通用文档到 rui-docs

从 docs-local 迁移以下文档:

- backend/guides/: AI开发环境配置、Nacos配置、GitNexus指南、OpenCode工作流等

- backend/templates/: Superpowers设计模板、计划模板、审查清单

- backend/config-templates/: 应用配置模板、Nacos配置

- backend/design/: 数据库表结构规划

- backend/specs/: 项目文档治理、MQ统一推送设计

- backend/: 代码分析报告、Feign分析报告、文档治理报告

- frontend/design/: Admin-UI分模块打包设计
This commit is contained in:
2026-06-04 09:31:24 +08:00
parent 2e38c53434
commit 19de7e24ec
36 changed files with 5872 additions and 0 deletions
+278
View File
@@ -0,0 +1,278 @@
# spring-rui 代码分析报告
> 分析日期:2026-05-26
> 目标:分析 `~/rhkj/spring-rui`(排除 `app/` 目录),对比 {root},识别可复用模式和缺失能力。
---
## 一、项目架构对比
| 维度 | spring-rui | {root}(本项目) |
|------|-----------|-------------------|
| 包名 | `org.rui` | `com.rui` |
| 模块组织 | 单体 `rui-common` 内含 15 子模块 | 平铺 4 子模块 `core/mybatis/security/web` |
| ORM | MyBatis Plus + 自定义类型处理器 | MyBatis Plus |
| 响应模型 | `Result<T>` extends `JSONObject` | `R<T>` POJO |
| JSON 框架 | **fastjson2**(核心依赖) | Jackson |
| 多租户 | 配置驱动(TABLE/IGNORE/NONE 三种模式) | 硬编码忽略表列表 |
| 缓存 | Redis Manager(发布/订阅) | 无 |
---
## 二、spring-rui 各模块分析
### 2.1 rui-common-core
| 文件 | 说明 | {root} 状态 |
|------|------|---------------|
| `Result.java` | 响应模型,extends `JSONObject`,含 `error`/`message`/`code`/`data`/`rows`/`results`,支持链式调用 | 已有 `R<T>`,功能较弱 |
| `ResultResponse.java` | 简单响应 holder | 已有 `ResultCode` |
| `ResponseStatus.java` | 枚举:SUCCESSFUL/UNAUTHORIZED/FORBIDDEN/NOT_FOUND/VALIDATE_FAILED 等 | 可参考补全 |
| `TenantContextHolder.java` | 租户上下文 ThreadLocal | 已有 `TenantContextHolder` |
| `TenantBroker.java` | 支持在指定租户下执行代码 | 无,可选 |
| `IdWorker.java` | ID 生成器 | 无 |
| `JacksonConfig.java` | Jackson 全局配置 | 可参考 |
| `KeyStrResolver.java` / `TenantKeyStrResolver.java` | 缓存 Key 解析(含租户隔离) | 无,可复用 |
| `SpringUtil.java` | Spring 上下文工具 | 无 |
| `ServletUtil.java` | Servlet 请求工具(提取所有参数为 Map) | 无 |
| `JsonUtil.java` | JSON 合并/赋值工具(`JsonUtil.assign()` | 无 |
| `AmountUtil.java` / `NumberUtil.java` / `RandomUtil.java` | 金额/数字/随机工具 | 无 |
| `IPSeekerUtil.java` / `IpUtil.java` | IP 归属地查询 | 无 |
| `StringUtil.java` | 字符串增强工具 | 已有 hutool |
| `LocalDateTimeUtil.java` | 时间工具 | 无 |
| `Validate.java` / `BaseRegex.java` / `NumericUtil.java` | 正则/校验工具 | 无 |
| `HttpClient.java` | HTTP 客户端封装 | 无 |
| `CertHelper.java` / `CertUtil.java` / `RsaUtil.java` / `AesUtil.java` / `MD5Util.java` / `ShaUtil.java` / `SignatureUtil.java` | 加密/证书工具链 | 无 |
| `DelayQueueManager.java` / `QueueTask.java` | 延迟队列 | 无 |
| `Scheduled.java` / `Task.java` / `TaskConfiguration.java` / `TaskFactory.java` | 定时任务调度 | 无 |
| `ProxyProperties.java` / `ProxyInterceptor.java` / `ProxyProperty.java` | 代理链支持 | 无(我们有 proxy chain ThreadLocal |
| `LocaleContextHolder.java` / `LocaleUtil.java` | 国际化支持 | 无 |
| `FileUtil.java` / `MimeUtil.java` / `ZipUtil.java` / `GzipUtil.java` | 文件/压缩工具 | 无 |
| `AntPathMatcher.java` / `PathMatcher.java` | 路径匹配 | 无 |
| `AccountProperty.java` / `AppProperty.java` / `MqttProperty.java` / `WsProperty.java` | 配置属性类 | 无 |
### 2.2 rui-common-data
| 文件 | 说明 | {root} 状态 |
|------|------|---------------|
| `MybatisPlusConfiguration.java` | MP 插件配置(分页 + 多租户 + 防全表更新) | 已有,缺 `BlockAttackInnerInterceptor` |
| `MybatisProperties.java` | MP 配置属性(表前缀、租户模式、忽略表列表) | 无 |
| **`PageService.java`** | **通用查询构建器**(类型字段 + 排序 + 分页 + 返回 Result | **2026-05-26 已移植** |
| `PageOptions.java` | 查询选项(下拉框过滤) | 无,可选 |
| `TenantHandler.java` | 配置驱动多租户(TABLE/IGNORE/NONE 三种模式) | 可参考优化 |
| `BaseMultiTableInnerInterceptor.java` | 多表拦截器 | 无 |
| `TableInterceptor.java` | 表前缀替换(`#prefix#` 占位符) | 无 |
| `AbstractObjectTypeHandler.java` / `JsonObjectTypeHandler.java` / `JsonArrayTypeHandler.java` / `StringArrayTypeHandler.java` / `LongTypeHandler.java` / `IntegerTypeHandler.java` / `BigDecimalArrayTypeHandler.java` / `ArrayTypeHandler.java` | 类型处理器 | 无 |
### 2.3 rui-common-security
| 文件 | 说明 | {root} 状态 |
|------|------|---------------|
| `ResourceServerAutoConfiguration.java` / `ResourceServerConfiguration.java` | OAuth2 资源服务器配置 | 无(不同安全架构) |
| `AuthUtil.java` / `UserUtil.java` | 认证用户工具 | 部分(`SecurityUtils` |
| `OAuthBearerTokenResolver.java` | Token 解析器 | 无 |
| `RedisOAuth2AuthorizationService.java` | Redis 授权存储 | 无 |
| `CustomOAuth2FeignRequestInterceptor.java` | Feign Token 传递 | 无 |
| `OAuthUserDetailsService.java` | 用户详情服务接口 | 无 |
| `DefaultOAuthUserDetailsServiceImpl.java` | 默认实现 | 无 |
| `WeixinOAuthUserDetailsServiceImpl.java` | 微信登录实现 | 无 |
| `RestTemplateUserDetailsServiceImpl.java` | RestTemplate 远程调用实现 | 无 |
| `PermissionService.java` | 权限校验 Bean`@perm.isSystemTenant()` | 无 |
| `AuthIgnore.java` / `Inner.java` | 注解 | 无 |
| `SecurityInnerAspect.java` | 内部调用切面 | 无 |
| `FeignClientConfiguration.java` / `FeignConfiguration.java` | Feign 配置 | 无 |
| `RemoteUserService.java` / `RemoteClientService.java` | Feign 远程调用接口 | 无 |
| `GlobalExceptionHandler.java` | 全局异常处理 | 已有 |
### 2.4 rui-service-system(参考 CRUD 模式)
**重点分析 — CRUD 标准模式:**
```
Controller
├── GET /{module}/list → PageService 分页列表
├── GET /{module}/{id} → doGet: service.getById(id)
├── POST /{module} → doAdd: service.doAdd(bean)
├── PUT /{module}/{id} → doUpdate: service.doUpdate(bean)
├── DELETE /{module}/remove/{id} → doRemove: 物理删除
└── DELETE /{module}/{id} → doDelete: 软删除
Service (extends ServiceImpl<Mapper, Entity>)
├── doAdd(bean) → bean.setDefaultValue(); this.save(bean)
├── doUpdate(bean) → bean.setUpdatedAt(); this.updateById(bean)
├── doRemove(id) → this.removeById(id)
└── doDelete(id) → baseMapper.doDelete(id) // SQL: UPDATE SET deleted=!deleted
Mapper (extends BaseMapper<Entity>)
└── @Update("UPDATE #prefix#table SET deleted=!deleted WHERE id=#{id}")
Integer doDelete(Serializable id);
```
**模式要点:**
- `doRemove` = 物理删除,`doDelete` = 软删除(toggle deleted 标记)
- 所有 Service 方法返回 `Result<?>` 而非实体
- Mapper 中使用 `#prefix#` 占位符,由 `TableInterceptor` 自动替换为实际表前缀
- Entity 实现 `setDefaultValue()` 方法初始化字段
### 2.5 rui-service-users(同上,CRUD 模式验证)
与 rui-service-system 完全一致的 CRUD 模式。每个模块有:
- `model/` — 实体类(`implements Serializable`
- `mapper/` — MyBatis Plus Mapper
- `service/` — 接口
- `service/impl/` — 实现(`extends ServiceImpl` + `doAdd/doUpdate/doRemove/doDelete`
- `controller/` — 接口(`extends BaseController` + CRUD 端点)
### 2.6 rui-gateway
| 文件 | 说明 | {root} 状态 |
|------|------|---------------|
| `GrayLoadBalancer.java` | 灰度负载均衡 | 无 |
| `GrayReactiveLoadBalancerClientFilter.java` | 灰度过滤器 | 无 |
| `GlobalExceptionHandler.java` | 网关异常处理 | 无 |
### 2.7 rui-oauth2
| 文件 | 说明 | {root} 状态 |
|------|------|---------------|
| `OauthApplication.java` | 启动类(无额外配置) | 已有 AuthApplication |
---
## 三、已移植到 {root} 的内容
### 2026-05-26 批量移植
| 文件 | 位置 | 对应 spring-rui |
|------|------|----------------|
| `PageResult.java` | `rui-common-core` | 新增(基于 Result 分页字段) |
| `PageService.java` | `rui-common-mybatis` | `rui-common-data/PageService.java` |
| `BaseController.java` | `rui-common-web` | `rui-service-system/controller/BaseController.java` |
| 防全表更新 | `MyBatisPlusConfig.java` | `MybatisPlusConfiguration.java` 中的 `BlockAttackInnerInterceptor` |
---
## 四、后续可选移植项
### 优先级高(核心能力)
| 功能 | 来源模块 | 说明 |
|------|---------|------|
| `SpringUtil.java` | core | Spring 上下文静态获取 |
| `ServletUtil.java` | core | 请求参数提取工具(PageService 用) |
| `JsonUtil.java` | core | JSON 合并/赋值(`assign` 方法在更新场景很有用) |
| `MybatisProperties.java` | data | 配置化表前缀/租户模式,替代硬编码 |
### 优先级中(开发提效)
| 功能 | 来源模块 | 说明 |
|------|---------|------|
| `StringUtil.java` / `AmountUtil.java` / `NumberUtil.java` | core | 常用工具 |
| `LocalDateTimeUtil.java` | core | 时间工具 |
| `IdWorker.java` | core | ID 生成器 |
| `IPSeekerUtil.java` / `IpUtil.java` | core | IP 工具 |
| `ArrayTypeHandler.java` 系列 | data | MP 类型处理器(JSON/数组) |
| `KeyStrResolver.java` 系列 | core | 缓存 Key 租户隔离 |
### 优先级低(按需移植)
| 功能 | 来源模块 | 说明 |
|------|---------|------|
| 加密工具链(RSA/AES/MD5/SHA/证书) | core | spring-rui 安全相关 |
| `HttpClient.java` | core | HTTP 客户端 |
| `DelayQueueManager.java` | core | 延迟队列 |
| 定时任务调度 | core | 自定义任务框架 |
| 国际化 | core | Locale 工具 |
| 灰度负载均衡 | gateway | 与部署环境强相关 |
| Feign 远程调用 | security | 与认证架构耦合 |
---
## 五、CRUD 编程规范(推荐)
基于 spring-rui 模式,推荐 {root} 业务模块遵循以下规范:
### Controller 规范
```java
@RestController
@RequiredArgsConstructor
@RequestMapping("system/tenant")
public class SysTenantController extends BaseController {
private final SysTenantService service;
@GetMapping("/list")
public R<PageResult<SysTenant>> list(HttpServletRequest request) {
PageService<SysTenant> ps = new PageService<>(request);
ps.setDefaultOrderColumn("updatedAt");
ps.putBoolean("deleted").putQuery("deleted", false);
ps.putLike("name");
return ps.getResults(service);
}
@GetMapping("{id}")
public R<SysTenant> get(@PathVariable Long id) {
return R.ok(service.getById(id));
}
@PostMapping
public R<Void> add(@RequestBody SysTenant bean) {
return service.doAdd(bean);
}
@PutMapping("{id}")
public R<Void> update(@RequestBody SysTenant bean) {
return service.doUpdate(bean);
}
@DeleteMapping("{id}")
public R<Void> delete(@PathVariable Long id) {
return service.doDelete(id);
}
}
```
### Service 规范
```java
public interface SysTenantService extends IService<SysTenant> {
R<Void> doAdd(SysTenant bean);
R<Void> doUpdate(SysTenant bean);
R<Void> doDelete(Long id);
}
public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant>
implements SysTenantService {
public R<Void> doAdd(SysTenant bean) {
bean.setDefaultValue();
if (this.save(bean)) return R.ok("添加成功");
return R.fail("添加失败");
}
public R<Void> doUpdate(SysTenant bean) {
bean.setUpdatedAt(LocalDateTime.now());
if (this.updateById(bean)) return R.ok("更新成功");
return R.fail("更新失败");
}
public R<Void> doDelete(Long id) {
if (baseMapper.doDelete(id) == 1) return R.ok("删除成功");
return R.fail("删除失败");
}
}
```
### Mapper 规范
```java
@Mapper
public interface SysTenantMapper extends BaseMapper<SysTenant> {
@Update("UPDATE rui_system_tenant SET deleted = !deleted WHERE id = #{id}")
int doDelete(@Param("id") Long id);
}
```
> 注:spring-rui 使用 `#prefix#` 占位符 + TableInterceptor 自动替换表前缀。本项目暂不引入该机制,直接在 SQL 中写完整表名。