refactor(model): 重构模型类包结构并优化序列化处理

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

- 将模型类按功能模块划分到ds子包中
- 为VO类添加序列化支持
- 移除冗余的serialVersionUID字段
- 修复UITools空值处理问题
- 更新项目版本号
This commit is contained in:
2025-10-09 18:27:48 +08:00
parent 51b8c16798
commit c4eec0a9dd
457 changed files with 8426 additions and 3669 deletions

View File

@@ -0,0 +1,146 @@
# 客户端 Service 类规则
## 1. 目录结构
- 所有客户端 Service 类位于 `client/src/main/java/com/ecep/contract/service/` 目录下
- 按业务领域组织,直接放置在 service 包下,不进行子包划分
- 服务类命名与实体类一一对应
## 2. 命名规范
- 服务类命名格式为:`[实体名称]Service.java`
- 例如:`CompanyService.java``ContractService.java``ProjectService.java`
- 基础服务接口命名为:`IEntityService.java``ViewModelService.java`
- 泛型基础服务类命名为:`QueryService.java`
## 3. 继承关系
- 业务服务类通常继承自泛型基础服务类 `QueryService<T, TV>`
- `T` 表示 VO 类型(实现了 IdentityEntity 接口)
- `TV` 表示 ViewModel 类型(实现了 IdentityViewModel<T> 接口)
- `QueryService` 实现了 `ViewModelService<T, TV>` 接口
- `ViewModelService` 继承了 `IEntityService<T>` 接口
- 特定场景下可以不继承 `QueryService`,直接实现所需接口或创建独立服务类
```java
@Service
@CacheConfig(cacheNames = "company")
public class CompanyService extends QueryService<CompanyVo, CompanyViewModel> {
// 业务方法实现
}
```
## 4. 注解使用
- **@Service**:标记为 Spring 服务组件,使其可被自动发现和注入
- **@CacheConfig**:配置缓存名称,通常与服务类名对应
- **@Cacheable**标记方法结果可缓存需指定缓存键key
- **@CacheEvict**:标记方法执行后清除缓存,可指定缓存键或清除所有
- **@Caching**:组合多个缓存操作(如同时清除多个缓存条目)
- **@Autowired**:用于自动注入依赖的其他服务
```java
@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 并提供详细错误信息
```java
@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`
- 转换器实例应作为服务类的成员变量,避免重复创建
```java
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 注释,说明其功能和参数含义