5.6 KiB
5.6 KiB
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> 定义了基础的实体操作方法:
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)提取结果