Files
contract-manager/.trae/rules/client_service_rules.md
songqq c4eec0a9dd refactor(model): 重构模型类包结构并优化序列化处理
重构模型类包结构,将模型类按功能模块划分到不同的子包中。优化序列化处理,为VO类添加serialVersionUID并实现Serializable接口。移除部分冗余的serialVersionUID字段,简化模型类代码。同时修复UITools中空值处理的问题,并更新pom版本至0.0.100-SNAPSHOT。

- 将模型类按功能模块划分到ds子包中
- 为VO类添加序列化支持
- 移除冗余的serialVersionUID字段
- 修复UITools空值处理问题
- 更新项目版本号
2025-10-09 18:27:48 +08:00

5.7 KiB
Raw Blame History

客户端 Service 类规则

1. 目录结构

  • 所有客户端 Service 类位于 client/src/main/java/com/ecep/contract/service/ 目录下
  • 按业务领域组织,直接放置在 service 包下,不进行子包划分
  • 服务类命名与实体类一一对应

2. 命名规范

  • 服务类命名格式为:[实体名称]Service.java
  • 例如:CompanyService.javaContractService.javaProjectService.java
  • 基础服务接口命名为:IEntityService.javaViewModelService.java
  • 泛型基础服务类命名为:QueryService.java

3. 继承关系

  • 业务服务类通常继承自泛型基础服务类 QueryService<T, TV>
    • T 表示 VO 类型(实现了 IdentityEntity 接口)
    • TV 表示 ViewModel 类型(实现了 IdentityViewModel 接口)
  • QueryService 实现了 ViewModelService<T, TV> 接口
  • ViewModelService 继承了 IEntityService<T> 接口
  • 特定场景下可以不继承 QueryService,直接实现所需接口或创建独立服务类
@Service
@CacheConfig(cacheNames = "company")
public class CompanyService extends QueryService<CompanyVo, CompanyViewModel> {
    // 业务方法实现
}

4. 注解使用

  • @Service:标记为 Spring 服务组件,使其可被自动发现和注入
  • @CacheConfig:配置缓存名称,通常与服务类名对应
  • @Cacheable标记方法结果可缓存需指定缓存键key
  • @CacheEvict:标记方法执行后清除缓存,可指定缓存键或清除所有
  • @Caching:组合多个缓存操作(如同时清除多个缓存条目)
  • @Autowired:用于自动注入依赖的其他服务
@Service
@CacheConfig(cacheNames = "contract")
public class ContractService extends QueryService<ContractVo, ContractViewModel> {
    @Autowired
    private SysConfService confService;
    
    @Cacheable(key = "#p0")
    public ContractVo findById(Integer id) {
        return super.findById(id);
    }
    
    @Caching(evict = {
            @CacheEvict(key = "#p0.id"),
            @CacheEvict(key = "'code-'+#p0.code")
    })
    public ContractVo save(ContractVo contract) {
        return super.save(contract);
    }
}

5. 缓存机制

  • 每个服务类应有独立的缓存名称空间
  • 缓存键key应具有唯一性通常使用 ID、代码或名称等唯一标识
  • 保存和删除操作时应清除相关缓存,保持数据一致性
  • 可使用 SpEL 表达式动态生成缓存键
  • 频繁查询的数据应考虑缓存,提高性能

6. 异步调用机制

  • 使用 async() 方法进行异步远程调用
  • 方法参数通常包括:方法名、参数值、参数类型列表
  • 使用 CompletableFuture 处理异步结果
  • 使用 handle() 方法处理响应和异常
  • 远程调用异常应包装为 RuntimeException 并提供详细错误信息
@Cacheable(key = "'code-'+#p0")
public ContractVo findByCode(String code) {
    try {
        return async("findByCode", code, String.class).handle((response, ex) -> {
            if (ex != null) {
                throw new RuntimeException("远程方法+findByCode+调用失败", ex);
            }
            if (response != null) {
                return updateValue(createNewEntity(), response);
            }
            return null;
        }).get();
    } catch (Exception e) {
        throw new RuntimeException("查询失败: " + code, e);
    }
}

7. 基础方法实现

  • 应实现 IEntityService<T> 接口定义的核心方法:
    • findById(Integer id):根据 ID 查询实体
    • save(T entity):保存实体
    • delete(T entity):删除实体
    • findAll():查询所有实体
    • findAll(Map<String, Object> params, Pageable pageable):条件分页查询
    • getStringConverter():获取类型转换器
  • 通常通过继承 QueryService 来复用这些基础方法的实现
  • 可根据业务需求重写或扩展基础方法

8. 业务方法规范

  • 业务方法应与服务端对应,保持方法名和参数一致
  • 方法命名应清晰表达其功能,如 findByName, findByCode
  • 复杂业务逻辑应封装为独立方法
  • 参数校验应在方法开始处进行
  • 返回值类型应明确,避免使用过于泛化的类型

9. 类型转换器

  • 实现 getStringConverter() 方法,返回对应的 StringConverter 实例
  • 通常创建专用的 Converter 类,如 CustomerCatalogStringConverter
  • 转换器实例应作为服务类的成员变量,避免重复创建
public class CustomerCatalogService extends QueryService<CustomerCatalogVo, CustomerCatalogViewModel> {
    private final CustomerCatalogStringConverter stringConverter = new CustomerCatalogStringConverter(this);
    
    @Override
    public StringConverter<CustomerCatalogVo> getStringConverter() {
        return stringConverter;
    }
}

10. 错误处理

  • 远程调用异常应捕获并包装为更具描述性的 RuntimeException
  • 提供详细的错误信息,包括调用的方法名和参数
  • 对于可预期的业务异常,可添加专门的处理逻辑
  • 不推荐使用 printStackTrace(),应使用日志记录异常

11. 工具方法和辅助功能

  • 通用功能可封装为工具方法
  • 配置相关操作可通过 SysConfService 实现
  • 文件路径处理应使用 File 类和相关工具方法
  • 日期时间处理应使用 Java 8+ 的日期时间 API

12. 最佳实践

  • 遵循单一职责原则,每个服务类专注于一个业务领域
  • 优先使用继承和接口实现来复用代码
  • 合理使用缓存提高性能,但注意缓存一致性
  • 异步调用应正确处理异常和超时情况
  • 服务类之间的依赖应通过 @Autowired 注入,避免硬编码
  • 方法实现应简洁明了,复杂逻辑应拆分
  • 为重要方法添加 JavaDoc 注释,说明其功能和参数含义