feat(service): 实现国际化支持并优化Service层
重构文件类型相关Service以支持国际化查询 添加findOneByLang辅助方法统一查询逻辑 实现StringConverter支持UI控件显示 优化缓存配置和查询性能 新增UnitStringConverter和CustomerCatalogStringConverter 完善文档和测试用例
This commit is contained in:
180
docs/task/service_compliance_analysis.md
Normal file
180
docs/task/service_compliance_analysis.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# Contract-Manager 项目 Service 层合规性分析报告
|
||||
|
||||
## 概述
|
||||
本报告对 Contract-Manager 项目中 `client\src\main\java\com\ecep\contract\service` 目录下的 Service 实现进行分析,评估它们是否符合 `docs\task\service_layer_rules.md` 文档中定义的规则和最佳实践。
|
||||
|
||||
## 合规性评估
|
||||
|
||||
### 1. 基础架构
|
||||
|
||||
#### 1.1 继承体系
|
||||
- **符合**: 大多数业务 Service 都继承自泛型抽象类 `QueryService<T extends IdentityEntity, TV extends IdentityViewModel<T>>`
|
||||
- 例如: `CompanyFileTypeService`, `ContractService`, `CompanyService`, `ProjectService`, `VendorService`
|
||||
- **不符合**: `SysConfService` 没有继承 `QueryService`,而是直接实现了自己的异步调用方法
|
||||
|
||||
#### 1.2 核心接口实现
|
||||
- **符合**: 继承 `QueryService` 的 Service 间接实现了 `IEntityService<T>` 和 `ViewModelService<T, TV>` 接口
|
||||
|
||||
### 2. 缓存管理
|
||||
|
||||
#### 2.1 缓存注解使用
|
||||
- **符合**: 许多 Service 使用了 `@CacheConfig` 和相关缓存注解
|
||||
- `@CacheConfig(cacheNames = "缓存名称")`: `ContractFileTypeService`, `ProjectFileTypeService`, `ContractService`, `CompanyService`, `SysConfService`
|
||||
- `@Cacheable`: 用于 `findById`, `findAll`, `findByCode` 等查询方法
|
||||
- `@CachePut`/`@CacheEvict`: 用于 `save`, `delete` 等修改方法
|
||||
- `@Caching`: 用于组合多个缓存操作
|
||||
- **不符合**: 部分 Service 未使用缓存注解
|
||||
- `VendorService`, `ProjectService` 没有配置缓存
|
||||
|
||||
#### 2.2 缓存键规则
|
||||
- **符合**: 缓存键的使用基本符合规则
|
||||
- `#p0`: 用于方法参数,如 `@Cacheable(key = "#p0")`
|
||||
- `'all'`: 用于所有数据,如 `@Cacheable(key = "'all'")`
|
||||
- 组合键: 如 `@Cacheable(key = "'code-'+#p0")`
|
||||
|
||||
### 3. 数据操作模式
|
||||
|
||||
#### 3.1 基础 CRUD 操作
|
||||
- **符合**: 所有继承 `QueryService` 的 Service 都获得了基础 CRUD 操作
|
||||
- `findById(Integer id)`: 根据 ID 查询单条数据
|
||||
- `save(T entity)`: 保存实体
|
||||
- `delete(T entity)`: 删除实体
|
||||
- `findAll()`: 查询所有数据
|
||||
- `findAll(Map<String, Object> params, Pageable pageable)`: 带参数和分页的查询
|
||||
|
||||
#### 3.2 异步操作
|
||||
- **符合**: 大多数 Service 使用 `QueryService` 提供的异步机制
|
||||
- 通过 `async(String method, Object... params)` 方法实现异步调用
|
||||
- 返回 `CompletableFuture<JsonNode>` 对象
|
||||
- **不符合**: `SysConfService` 实现了自己的异步方法,如 `asyncFindById`, `asyncFindAll`
|
||||
|
||||
#### 3.3 业务查询方法
|
||||
- **符合**: 业务 Service 通常添加特定的查询方法
|
||||
- `findByCode(String code)`: `ContractService`, `CompanyService`, `ProjectService`
|
||||
- `findByName(String name)`: `ContractService`, `CompanyService`, `ProjectService`
|
||||
- `findAllByName(String name)`: `CompanyService`
|
||||
|
||||
#### 3.4 参数构建
|
||||
- **符合**: 普遍使用 `ParamUtils` 工具类构建查询参数
|
||||
- `ParamUtils.builder().equals("字段名", 值).build()`
|
||||
- `ParamUtils.equal("字段名", 值)`
|
||||
|
||||
### 4. 国际化支持
|
||||
|
||||
#### 4.1 多语言查询
|
||||
- **符合**: 文件类型相关 Service 提供了基于 Locale 的查询方法
|
||||
- `findAll(Locale locale)`: `ContractFileTypeService`, `ProjectFileTypeService`, `CompanyFileTypeService`, `CompanyCustomerFileTypeService`
|
||||
- 通过 `locale.toLanguageTag()` 转换为语言标签进行查询
|
||||
- 返回结果通常转换为 Map,方便按类型查找
|
||||
- **不适用**: 对于不需要国际化的业务 Service,没有提供这些方法
|
||||
|
||||
#### 4.2 辅助方法
|
||||
- **符合**: 文件类型相关 Service 实现了辅助方法
|
||||
- `findOneByLang(Locale locale, String key, Object value)`: 私有辅助方法
|
||||
- `findByLocaleAndValue(Locale locale, String string)`: 按语言和值查询
|
||||
- `findByLocaleAndType(Locale locale, EnumType type)`: 按语言和枚举类型查询
|
||||
- **不适用**: 对于不需要国际化的业务 Service,没有提供这些方法
|
||||
|
||||
### 5. 类型转换
|
||||
|
||||
#### 5.1 StringConverter 实现
|
||||
- **符合**: 实体类型 Service 实现了 `getStringConverter()` 方法
|
||||
- 返回 `StringConverter<T>` 实例
|
||||
- 创建专门的 Converter 类,如 `ContractFileTypeStringConverter`, `ProjectFileTypeStringConverter`
|
||||
- **不符合**: 业务对象 Service 如 `ContractService`, `CompanyService`, `VendorService`, `ProjectService` 没有实现 `getStringConverter()` 方法
|
||||
|
||||
### 6. 业务特性
|
||||
|
||||
#### 6.1 文件路径管理
|
||||
- **符合**: 部分 Service 管理文件路径
|
||||
- `getBasePath()` 方法: `ContractService`, `CompanyService`, `VendorService`, `ProjectService`
|
||||
- 通过 `SysConfService` 获取配置的基础路径
|
||||
- 路径存储为 `File` 对象
|
||||
|
||||
#### 6.2 业务验证
|
||||
- **符合**: 包含业务特定的验证逻辑
|
||||
- `verifyEnterpriseStatus(CompanyVo company, LocalDate verifyDate, MessageHolder holder)`: `CompanyService`
|
||||
- `verify(ContractVo contract, MessageHolder holder)`: `VendorService`
|
||||
- 使用 `MessageHolder` 存储验证结果和错误信息
|
||||
|
||||
#### 6.3 Spring Bean 获取
|
||||
- **符合**: 使用 `SpringApp.getBean(ServiceClass.class)` 获取其他 Service 实例
|
||||
- 例如 `VendorService` 中获取 `SysConfService`,`ProjectService` 中获取 `ProjectSaleTypeService`
|
||||
|
||||
### 7. 代码规范
|
||||
|
||||
#### 7.1 类命名
|
||||
- **符合**: 服务类名以 `Service` 结尾
|
||||
- `ContractService`, `CompanyService`, `ProjectService` 等
|
||||
- 实现类直接使用业务名称+Service,无 I 前缀
|
||||
|
||||
#### 7.2 注释规范
|
||||
- **部分符合**: 大部分类和方法有 Javadoc 注释
|
||||
- 例如 `ContractService.getBasePath()` 方法有清晰的注释
|
||||
- **不符合**: 部分方法缺少注释
|
||||
- 例如 `VendorService.findByCompany()` 方法没有注释
|
||||
- 许多未实现的方法只有 TODO 注释
|
||||
|
||||
#### 7.3 异常处理
|
||||
- **符合**: 使用 `RuntimeException` 包装异常
|
||||
- 异常消息清晰描述错误情况
|
||||
- **不符合**: `SysConfService` 中有些异常处理直接打印堆栈,没有抛出自定义异常
|
||||
|
||||
### 8. 特定业务 Service 模式
|
||||
|
||||
#### 8.1 实体类型 Service
|
||||
- **符合**: 如 `ContractFileTypeService`, `ProjectFileTypeService` 等
|
||||
- 管理枚举类型的本地化数据
|
||||
- 提供缓存管理
|
||||
- 实现 StringConverter
|
||||
- 提供基于 Locale 的查询方法
|
||||
|
||||
#### 8.2 业务对象 Service
|
||||
- **符合**: 如 `ContractService`, `CompanyService`, `ProjectService` 等
|
||||
- 管理核心业务实体
|
||||
- 实现特定的业务逻辑
|
||||
- 处理文件和路径
|
||||
- 提供业务验证
|
||||
|
||||
#### 8.3 关联关系管理
|
||||
- **符合**: Service 之间通过依赖注入或 `SpringApp.getBean()` 进行协作
|
||||
- 处理实体之间的关联关系
|
||||
|
||||
### 9. 特殊实现模式
|
||||
|
||||
#### 9.1 自定义 BeanName
|
||||
- **符合**: 部分 Service 重写 `getBeanName()` 方法
|
||||
- 例如 `CompanyService` 指定 WebSocket 通信的 Bean 名称
|
||||
|
||||
#### 9.2 未实现方法
|
||||
- **符合**: 使用 `throw new UnsupportedOperationException("Unimplemented method 'methodName'")` 标记未实现的方法
|
||||
- 例如 `CompanyService.merge()`, `VendorService.getVendorApprovedListTemplate()` 等
|
||||
|
||||
#### 9.3 分页查询
|
||||
- **符合**: 大量使用 `Pageable.ofSize(1)` 进行单条记录的精确查询
|
||||
- 使用 `stream().findFirst().orElse(null)` 提取结果
|
||||
- 例如 `ProjectService.findByName()`, `ProjectService.findByCode()`
|
||||
|
||||
## 不符合规范的 Service 列表
|
||||
|
||||
| Service 类名 | 不符合项 | 建议改进 |
|
||||
|------------|---------|---------|
|
||||
| `SysConfService` | 未继承 `QueryService`,实现了自己的异步方法 | 重构为继承 `QueryService`,使用标准的异步方法 |
|
||||
| `VendorService` | 未使用缓存注解 | 添加 `@CacheConfig` 和相关缓存注解 |
|
||||
| `ProjectService` | 未使用缓存注解 | 添加 `@CacheConfig` 和相关缓存注解 |
|
||||
| 业务对象 Service | 没有实现 `getStringConverter()` 方法 | 如果需要类型转换,实现该方法 |
|
||||
| 多个 Service | 部分方法缺少注释 | 完善 Javadoc 注释 |
|
||||
| `SysConfService` | 异常处理不统一 | 统一使用 `RuntimeException` 包装异常 |
|
||||
|
||||
## 总结
|
||||
|
||||
Contract-Manager 项目的 Service 层实现整体上符合 `service_layer_rules.md` 文档中定义的规则和最佳实践。大多数 Service 遵循了基础架构、缓存管理、数据操作模式等规范,特别是实体类型 Service 的实现非常一致。
|
||||
|
||||
主要的改进点包括:
|
||||
1. 统一 Service 的继承体系,确保所有 Service 都继承自 `QueryService`
|
||||
2. 为所有 Service 添加适当的缓存管理
|
||||
3. 完善方法注释,提高代码可读性
|
||||
4. 统一异常处理机制
|
||||
5. 根据业务需求,为需要类型转换的 Service 实现 `getStringConverter()` 方法
|
||||
|
||||
通过这些改进,可以进一步提高项目的代码一致性、可维护性和性能。
|
||||
Reference in New Issue
Block a user