feat(service): 实现国际化支持并优化Service层

重构文件类型相关Service以支持国际化查询
添加findOneByLang辅助方法统一查询逻辑
实现StringConverter支持UI控件显示
优化缓存配置和查询性能
新增UnitStringConverter和CustomerCatalogStringConverter
完善文档和测试用例
This commit is contained in:
2025-09-24 16:20:49 +08:00
parent 45eed8281f
commit 09b0da498b
32 changed files with 1968 additions and 78 deletions

View File

@@ -0,0 +1,124 @@
# StringConverter 创建规则与实现逻辑
## 目的
StringConverter 在 Contract-Manager 项目中用于:
- 在UI组件如ComboBox中显示对象的可读字符串表示
- 从用户输入的字符串中还原对应的对象实例
- 支持表单数据的绑定和转换
## 创建规则
### 1. 文件位置
StringConverter 类应位于 `com.ecep.contract.converter` 包下
### 2. 命名规范
- 类名格式:`[EntityName]StringConverter`
- 例如:`CustomerCatalogStringConverter``VendorCatalogStringConverter`
### 3. 继承关系
- 实现 `javafx.util.StringConverter<T>` 接口其中T为实体的VO类型
- 例如:`StringConverter<CustomerCatalogVo>`
### 4. 构造函数
- 通常需要注入对应的Service实例
- 构造函数接收Service作为参数
- 例如:`public CustomerCatalogStringConverter(CustomerCatalogService service)`
### 5. 核心方法实现
#### toString(T object)
- 将对象转换为可读的字符串表示
- 通常返回对象的名称或关键标识
- 处理null情况
#### fromString(String string)
- 从字符串还原对象实例
- 通常调用Service的findByName或findByCode方法
## 与Service类的关联
### 1. 在Service类中创建Converter实例
```java
@Service
@CacheConfig(cacheNames = "[entity-name]-cache")
public class [EntityName]Service extends QueryService<[EntityName]Vo, [EntityName]ViewModel> {
private final [EntityName]StringConverter stringConverter = new [EntityName]StringConverter(this);
// 实现findByName方法供StringConverter使用
public [EntityName]Vo findByName(String name) {
return findAll(ParamUtils.builder().equals("name", name).build(), Pageable.ofSize(1))
.stream().findFirst().orElse(null);
}
@Override
public StringConverter<[EntityName]Vo> getStringConverter() {
return stringConverter;
}
}
```
### 2. 缓存配置
Service类通常需要添加缓存注解以提高性能
- `@Cacheable(key = "#id")` 用于findById方法
- `@Cacheable(key = "'all'")` 用于findAll方法
- `@Caching(evict = {@CacheEvict(key = "'all'"), @CacheEvict(key = "#entity.id")})` 用于save和delete方法
## 示例实现
### CustomerCatalogStringConverter 示例
```java
package com.ecep.contract.converter;
import com.ecep.contract.service.CustomerCatalogService;
import com.ecep.contract.vo.CustomerCatalogVo;
import javafx.util.StringConverter;
public class CustomerCatalogStringConverter extends StringConverter<CustomerCatalogVo> {
private final CustomerCatalogService service;
public CustomerCatalogStringConverter(CustomerCatalogService service) {
this.service = service;
}
@Override
public String toString(CustomerCatalogVo object) {
return object == null ? "" : object.getName();
}
@Override
public CustomerCatalogVo fromString(String string) {
return service.findByName(string);
}
}
```
## 使用场景
### 在UI组件中的使用
StringConverter 主要用于:
- ComboBox的数据绑定和显示
- 表单字段的字符串转换
- 表格单元格的格式化显示
### 获取StringConverter实例
```java
// 方式1直接从Service获取
StringConverter<CustomerCatalogVo> converter = customerCatalogService.getStringConverter();
// 方式2通过Spring容器获取
StringConverter<CustomerCatalogVo> converter = context.getBean(CustomerCatalogStringConverter.class);
```
## 常见模式
1. **基础模式**直接继承StringConverter实现toString和fromString方法
2. **组件模式**继承EntityStringConverter基类设置初始化、建议和字符串转换方法
3. **枚举模式**:针对枚举类型的特殊处理
## 注意事项
1. 确保Service类实现了必要的find方法如findByName
2. 处理null值情况避免空指针异常
3. 考虑缓存策略,提高频繁转换场景下的性能
4. 保持Converter与Service的同步更新确保字段变更时转换逻辑也相应更新