Files
rui-docs/backend/spring-rui 代码分析报告.md
T
vifo 19de7e24ec 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分模块打包设计
2026-06-04 09:34:03 +08:00

279 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 中写完整表名。