150 lines
5.6 KiB
Markdown
150 lines
5.6 KiB
Markdown
# Contract-Manager 项目 客户端模块的 Service 层规则与逻辑总结
|
||
|
||
## 1. 基础架构
|
||
|
||
### 1.1 继承体系
|
||
- 所有业务Service都继承自泛型抽象类 `QueryService<T extends IdentityEntity, TV extends IdentityViewModel<T>>`
|
||
- `QueryService` 实现了 `IEntityService<T>` 和 `ViewModelService<T, TV>` 接口
|
||
- 泛型参数说明:
|
||
- `T`: 实体类型(通常为Vo类)
|
||
- `TV`: 视图模型类型
|
||
|
||
### 1.2 核心接口
|
||
`IEntityService<T>` 定义了基础的实体操作方法:
|
||
```java
|
||
public interface IEntityService<T> {
|
||
T findById(Integer id);
|
||
T save(T entity);
|
||
void delete(T entity);
|
||
List<T> findAll();
|
||
Page<T> findAll(Map<String, Object> params, Pageable pageable);
|
||
StringConverter<T> getStringConverter();
|
||
}
|
||
```
|
||
|
||
## 2. 缓存管理
|
||
|
||
### 2.1 缓存注解使用
|
||
- 使用 `@CacheConfig(cacheNames = "缓存名称")` 设置缓存名称
|
||
- 使用 `@Cacheable` 注解标记查询方法,如 `findById`、`findAll`
|
||
- 使用 `@CachePut` 注解标记更新方法,如 `save`、`delete`
|
||
- 使用 `@CacheEvict` 注解标记清除缓存的方法
|
||
- 使用 `@Caching` 组合多个缓存操作
|
||
|
||
### 2.2 缓存键规则
|
||
- `#p0`: 表示方法的第一个参数
|
||
- `'all'`: 表示所有数据的缓存键
|
||
- `'code-'+#p0`: 组合键,如 `'code-'+#p0.code` 用于按编码缓存
|
||
|
||
## 3. 数据操作模式
|
||
|
||
### 3.1 基础CRUD操作
|
||
所有Service通过继承`QueryService`获得以下基础操作:
|
||
- `findById(Integer id)`: 根据ID查询单条数据
|
||
- `save(T entity)`: 保存实体
|
||
- `delete(T entity)`: 删除实体
|
||
- `findAll()`: 查询所有数据
|
||
- `findAll(Map<String, Object> params, Pageable pageable)`: 带参数和分页的查询
|
||
|
||
### 3.2 异步操作
|
||
- 通过 `async(String method, Object... params)` 方法实现异步调用
|
||
- 返回 `CompletableFuture<JsonNode>` 对象
|
||
- 有专门的异步查询方法,如 `asyncFindById`、`asyncFindAll`、`asyncCount`
|
||
|
||
### 3.3 业务查询方法
|
||
业务Service通常会添加特定的查询方法:
|
||
- `findByCode(String code)`: 按编码查询
|
||
- `findByName(String name)`: 按名称查询
|
||
- `findAllByName(String name)`: 按名称查询所有匹配项
|
||
|
||
### 3.4 参数构建
|
||
- 使用 `ParamUtils` 工具类构建查询参数
|
||
- 常用方法:`ParamUtils.builder().equals("字段名", 值).build()`
|
||
|
||
## 4. 国际化支持
|
||
|
||
### 4.1 多语言查询
|
||
- 所有继承自`BaseEnumEntity`的Vo类对应的Service都必须实现国际化支持
|
||
- 提供基于Locale的查询方法:`findAll(Locale locale)`
|
||
- 实现方式:通过 `locale.toLanguageTag()` 转换为语言标签进行查询
|
||
- 返回结果通常转换为Map<EnumType, EntityType>,以枚举类型为键,方便按类型查找
|
||
- 方法上应添加`@Cacheable`注解进行缓存
|
||
|
||
### 4.2 辅助方法
|
||
- 必须实现`findOneByLang(Locale locale, String key, Object value)`私有辅助方法,根据语言和参数查找单个对象
|
||
- 实现方式:使用`ParamUtils.builder().equals("lang", locale.toLanguageTag()).equals(key, value).build()`构建参数
|
||
- 使用`Pageable.ofSize(1)`进行单条记录的精确查询
|
||
- 使用`stream().findFirst().orElse(null)`提取结果
|
||
- 必须实现`findByLocaleAndValue(Locale locale, String string)`方法,按语言和值查询
|
||
- 调用`findOneByLang(locale, "value", string)`实现
|
||
- 必须实现`findByLocaleAndType(Locale locale, EnumType type)`方法,按语言和枚举类型查询
|
||
- 调用`findOneByLang(locale, "type", type)`实现
|
||
|
||
## 5. 类型转换
|
||
|
||
### 5.1 StringConverter实现
|
||
- 所有Service都实现 `getStringConverter()` 方法,返回 `StringConverter<T>` 实例
|
||
- 通常会创建专门的Converter类,如 `CompanyFileTypeStringConverter`、`CustomerFileTypeStringConverter`
|
||
- Converter类通常接收对应的Service作为构造参数
|
||
|
||
## 6. 业务特性
|
||
|
||
### 6.1 文件路径管理
|
||
- 部分Service管理文件路径,如 `getBasePath()` 方法
|
||
- 通常通过 `SysConfService` 获取配置的基础路径
|
||
- 路径存储为 `File` 对象
|
||
|
||
### 6.2 业务验证
|
||
- 包含业务特定的验证逻辑,如 `verifyEnterpriseStatus`、`verify` 方法
|
||
- 使用 `MessageHolder` 存储验证结果和错误信息
|
||
|
||
### 6.3 Spring Bean获取
|
||
- 使用 `SpringApp.getBean(ServiceClass.class)` 获取其他Service实例
|
||
- 用于Service之间的协作调用
|
||
|
||
## 7. 代码规范
|
||
|
||
### 7.1 类命名
|
||
- 服务类名以 `Service` 结尾,如 `ContractService`、`CompanyService`
|
||
- 实现类直接使用业务名称+Service,无I前缀
|
||
|
||
### 7.2 注释规范
|
||
- 方法和类应有清晰的Javadoc注释
|
||
- 私有辅助方法也应有注释说明其用途
|
||
|
||
### 7.3 异常处理
|
||
- 使用 `RuntimeException` 包装所有异常
|
||
- 异常消息应清晰描述错误情况
|
||
- 部分Service使用日志记录错误信息
|
||
|
||
## 8. 特定业务Service模式
|
||
|
||
### 8.1 实体类型Service
|
||
如 `CompanyFileTypeService`、`CompanyCustomerFileTypeService` 等:
|
||
- 管理枚举类型的本地化数据
|
||
- 提供缓存管理
|
||
- 实现StringConverter
|
||
- 提供基于Locale的查询方法
|
||
|
||
### 8.2 业务对象Service
|
||
如 `ContractService`、`CompanyService`、`ProjectService` 等:
|
||
- 管理核心业务实体
|
||
- 实现特定的业务逻辑
|
||
- 处理文件和路径
|
||
- 提供业务验证
|
||
|
||
### 8.3 关联关系管理
|
||
- Service之间通过依赖注入或 `SpringApp.getBean()` 进行协作
|
||
- 处理实体之间的关联关系,如 `Contract` 与 `Company`、`Vendor` 等
|
||
|
||
## 9. 特殊实现模式
|
||
|
||
### 9.1 自定义BeanName
|
||
部分Service重写 `getBeanName()` 方法,指定WebSocket通信的Bean名称
|
||
|
||
### 9.2 未实现方法
|
||
使用 `throw new UnsupportedOperationException("Unimplemented method 'methodName'")` 标记未实现的方法
|
||
|
||
### 9.3 分页查询
|
||
- 大量使用 `Pageable.ofSize(1)` 进行单条记录的精确查询
|
||
- 使用 `stream().findFirst().orElse(null)` 提取结果 |