# Contract-Manager 项目 Service 层规则与逻辑总结 ## 1. 基础架构 ### 1.1 继承体系 - 所有业务Service都继承自泛型抽象类 `QueryService>` - `QueryService` 实现了 `IEntityService` 和 `ViewModelService` 接口 - 泛型参数说明: - `T`: 实体类型(通常为Vo类) - `TV`: 视图模型类型 ### 1.2 核心接口 `IEntityService` 定义了基础的实体操作方法: ```java public interface IEntityService { T findById(Integer id); T save(T entity); void delete(T entity); List findAll(); Page findAll(Map params, Pageable pageable); StringConverter 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 params, Pageable pageable)`: 带参数和分页的查询 ### 3.2 异步操作 - 通过 `async(String method, Object... params)` 方法实现异步调用 - 返回 `CompletableFuture` 对象 - 有专门的异步查询方法,如 `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,以枚举类型为键,方便按类型查找 - 方法上应添加`@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` 实例 - 通常会创建专门的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)` 提取结果