重构Service类实现,将QueryService泛型参数调整为VO类型,确保缓存VO对象而非实体。优化关联实体处理逻辑,减少重复代码。修改findById方法返回VO对象,新增getById方法获取实体。更新相关调用点以适配新接口。 调整WebSocket处理、控制器及Service实现,确保数据类型一致性。完善文档记录重构过程及发现的问题。为后续优化提供基础架构支持。
178 lines
6.6 KiB
Markdown
178 lines
6.6 KiB
Markdown
# Service类结构模式分析报告
|
||
|
||
## 1. 概述
|
||
|
||
本报告是"实体-VO转换机制与缓存策略任务拆分"子任务1的延伸分析,旨在详细分析Contract-Manager项目中Service类的实现模式,特别是QueryService接口泛型参数的使用情况,为将Server模块Service缓存从实体对象调整为VO对象提供具体的修改依据。
|
||
|
||
## 2. Service类实现模式分析
|
||
|
||
通过对Server模块中Service类的分析,发现了两种主要的实现模式:
|
||
|
||
### 2.1 模式一:正确实现模式(VO优先)
|
||
|
||
这种模式下,Service类实现QueryService接口时使用VO类型作为泛型参数,符合项目设计理念。
|
||
|
||
**示例代码:**
|
||
|
||
```java
|
||
@Service
|
||
@CacheConfig(cacheNames = "inventory")
|
||
public class InventoryService
|
||
implements IEntityService<Inventory>, QueryService<InventoryVo>, VoableService<Inventory, InventoryVo> {
|
||
// Service方法实现
|
||
}
|
||
|
||
@Service
|
||
@CacheConfig(cacheNames = "function")
|
||
public class FunctionService implements IEntityService<Function>, QueryService<FunctionVo>, VoableService<Function, FunctionVo> {
|
||
@Cacheable(key = "#p0")
|
||
public FunctionVo findById(Integer id) {
|
||
return repository.findById(id).map(Function::toVo).orElse(null);
|
||
}
|
||
}
|
||
```
|
||
|
||
**特点:**
|
||
1. QueryService接口使用VO类型作为泛型参数
|
||
2. findById等缓存方法返回VO对象
|
||
3. findAll方法通常使用map(Entity::toVo)转换为VO对象
|
||
4. 缓存的是VO对象,符合设计要求
|
||
|
||
**采用此模式的Service类:**
|
||
- InventoryService
|
||
- ProjectQuotationService
|
||
- FunctionService
|
||
- DepartmentService
|
||
- BankService
|
||
- ContractBidVendorService
|
||
- ProjectIndustryService
|
||
- ProjectBidService
|
||
- ProjectFundPlanService
|
||
- InventoryHistoryPriceService
|
||
- ProjectTypeService
|
||
- PermissionService
|
||
- ProjectCostItemService
|
||
- EmployeeRoleService
|
||
- CustomerSatisfactionSurveyService
|
||
|
||
### 2.2 模式二:错误实现模式(实体优先)
|
||
|
||
这种模式下,Service类实现QueryService接口时使用实体类型作为泛型参数,不符合项目设计理念。
|
||
|
||
**示例代码:**
|
||
|
||
```java
|
||
@Service
|
||
@CacheConfig(cacheNames = "company")
|
||
public class CompanyService extends EntityService<Company, Integer>
|
||
implements IEntityService<Company>, QueryService<Company>, VoableService<Company, CompanyVo> {
|
||
// Service方法实现
|
||
}
|
||
|
||
@Service
|
||
public class CompanyBlackReasonService implements IEntityService<CompanyBlackReason>, QueryService<CompanyBlackReason>,
|
||
VoableService<CompanyBlackReason, CompanyBlackReasonVo> {
|
||
// Service方法实现
|
||
}
|
||
```
|
||
|
||
**特点:**
|
||
1. QueryService接口使用实体类型作为泛型参数
|
||
2. findById等缓存方法返回实体对象
|
||
3. 缓存的是实体对象,不符合设计要求
|
||
4. 虽然同时实现了VoableService接口,但转换逻辑与缓存逻辑分离
|
||
|
||
**采用此模式的Service类:**
|
||
- CompanyService
|
||
- CompanyBlackReasonService
|
||
- ContractPayPlanService
|
||
- CompanyOldNameService
|
||
- CompanyCustomerEntityService
|
||
- ContractCatalogService
|
||
- CompanyInvoiceInfoService
|
||
- CompanyExtendInfoService
|
||
|
||
## 3. WebSocketServerCallbackManager分析
|
||
|
||
WebSocketServerCallbackManager类负责处理客户端与服务器之间的WebSocket通信,包括对查询服务的调用处理:
|
||
|
||
```java
|
||
private Object invokerFindByIdMethod(Object service, JsonNode argumentsNode) {
|
||
JsonNode paramsNode = argumentsNode.get(0);
|
||
if (service instanceof IEntityService<?> entityService) {
|
||
Integer id = paramsNode.asInt();
|
||
return entityService.getById(id);
|
||
}
|
||
// 其他实现...
|
||
}
|
||
|
||
private Object invokerFindAllMethod(Object service, JsonNode argumentsNode) throws JsonProcessingException {
|
||
JsonNode paramsNode = argumentsNode.get(0);
|
||
JsonNode pageableNode = argumentsNode.get(1);
|
||
PageArgument pageArgument = objectMapper.treeToValue(pageableNode, PageArgument.class);
|
||
QueryService<?> entityService = (QueryService<?>) service;
|
||
Page<?> page = entityService.findAll(paramsNode, pageArgument.toPageable());
|
||
return PageContent.of(page.map(entity -> {
|
||
if (entity instanceof Voable<?>) {
|
||
return ((Voable<?>) entity).toVo();
|
||
}
|
||
return entity;
|
||
}));
|
||
}
|
||
```
|
||
|
||
**关键点:**
|
||
1. invokerFindByIdMethod直接返回实体对象,没有进行VO转换
|
||
2. invokerFindAllMethod在返回前会尝试将实体转换为VO
|
||
3. 这种不一致的处理方式可能导致客户端接收的数据类型不一致
|
||
|
||
## 4. 缓存策略分析
|
||
|
||
### 4.1 正确的缓存策略(模式一)
|
||
|
||
```java
|
||
@Cacheable(key = "#p0")
|
||
public FunctionVo findById(Integer id) {
|
||
return repository.findById(id).map(Function::toVo).orElse(null);
|
||
}
|
||
```
|
||
|
||
**特点:**
|
||
1. 缓存方法直接返回VO对象
|
||
2. 在缓存方法内部完成实体到VO的转换
|
||
3. 缓存的是VO对象,符合设计要求
|
||
|
||
### 4.2 错误的缓存策略(模式二)
|
||
|
||
```java
|
||
@Cacheable(key = "#id")
|
||
public Contract findById(Integer id) {
|
||
// 直接返回实体对象
|
||
}
|
||
```
|
||
|
||
**特点:**
|
||
1. 缓存方法返回实体对象
|
||
2. 缓存的是实体对象,不符合设计要求
|
||
3. 客户端可能需要额外的转换步骤
|
||
|
||
## 5. 需要修改的Service类清单
|
||
|
||
基于以上分析,以下是需要修改的Service类清单:
|
||
|
||
| Service类名 | 问题 | 修改建议 |
|
||
|------------|------|---------|
|
||
| CompanyService | QueryService使用实体类型 | 将QueryService<Company>改为QueryService<CompanyVo> |
|
||
| CompanyBlackReasonService | QueryService使用实体类型 | 将QueryService<CompanyBlackReason>改为QueryService<CompanyBlackReasonVo> |
|
||
| ContractPayPlanService | QueryService使用实体类型 | 将QueryService<ContractPayPlan>改为QueryService<ContractPayPlanVo> |
|
||
| CompanyOldNameService | QueryService使用实体类型 | 将QueryService<CompanyOldName>改为QueryService<CompanyOldNameVo> |
|
||
| CompanyCustomerEntityService | QueryService使用实体类型 | 将QueryService<CompanyCustomerEntity>改为QueryService<CompanyCustomerEntityVo> |
|
||
| ContractCatalogService | QueryService使用实体类型 | 将QueryService<ContractCatalog>改为QueryService<ContractCatalogVo> |
|
||
| CompanyInvoiceInfoService | QueryService使用实体类型 | 将QueryService<CompanyInvoiceInfo>改为QueryService<CompanyInvoiceInfoVo> |
|
||
| CompanyExtendInfoService | QueryService使用实体类型 | 将QueryService<CompanyExtendInfo>改为QueryService<CompanyExtendInfoVo> |
|
||
|
||
## 6. 结论
|
||
|
||
通过对Service类实现模式的详细分析,我们明确了需要修改的Service类清单和具体的修改建议。这些修改将有助于统一Service类的实现模式,确保缓存的是VO对象而不是实体对象,从而提高系统的一致性和性能。
|
||
|
||
本报告为后续的子任务提供了具体的修改依据,帮助确定具体的实现方案和步骤。 |