重构模型类包结构,将模型类按功能模块划分到不同的子包中。优化序列化处理,为VO类添加serialVersionUID并实现Serializable接口。移除部分冗余的serialVersionUID字段,简化模型类代码。同时修复UITools中空值处理的问题,并更新pom版本至0.0.100-SNAPSHOT。 - 将模型类按功能模块划分到ds子包中 - 为VO类添加序列化支持 - 移除冗余的serialVersionUID字段 - 修复UITools空值处理问题 - 更新项目版本号
20 KiB
6A工作流 - 架构阶段
任务名: Server模块Service缓存调整为Vo对象
1. 整体架构图
graph TD
subgraph 客户端层
Client[客户端应用]
end
subgraph 控制器层
Controller[REST控制器]
end
subgraph 服务层
IEntityService_Int[IEntityService<T, ID>接口]
QueryService_Int[QueryService<Vo>接口]
VoableService_Int[VoableService<Model, Vo>接口]
ServiceImpl1[Service实现类1]
ServiceImpl2[Service实现类2]
end
subgraph 数据访问层
Repository1[Repository接口1]
Repository2[Repository接口2]
JPA[Spring Data JPA]
end
subgraph 数据层
Model1[Model实体类1]
Model2[Model实体类2]
Vo1[Vo视图对象1]
Vo2[Vo视图对象2]
MySQL[MySQL数据库]
end
subgraph 缓存机制
Cacheable[Spring Cache注解]
Redis[Redis缓存]
end
subgraph 依赖组件
WebSocketServerCallbackManager[WebSocketServerCallbackManager]
WebSocketServerHandler[WebSocketServerHandler]
WebSocketServerTaskManager[WebSocketServerTaskManager]
Voable_Int[Voable<Vo>接口]
end
Client -->|HTTP请求| Controller
Controller -->|调用服务方法| ServiceImpl1
Controller -->|调用服务方法| ServiceImpl2
ServiceImpl1 -->|实现| IEntityService_Int
ServiceImpl1 -->|实现| QueryService_Int
ServiceImpl1 -->|实现| VoableService_Int
ServiceImpl2 -->|实现| IEntityService_Int
ServiceImpl2 -->|实现| QueryService_Int
ServiceImpl2 -->|实现| VoableService_Int
ServiceImpl1 -->|使用| Repository1
ServiceImpl2 -->|使用| Repository2
Repository1 -->|继承| JPA
Repository2 -->|继承| JPA
ServiceImpl1 -->|操作| Model1
ServiceImpl2 -->|操作| Model2
Model1 -->|实现| Voable_Int
Model2 -->|实现| Voable_Int
Model1 -->|转换为| Vo1
Model2 -->|转换为| Vo2
ServiceImpl1 -->|使用| Cacheable
ServiceImpl2 -->|使用| Cacheable
Cacheable -->|存储| Redis
WebSocketServerCallbackManager -->|调用| ServiceImpl1
WebSocketServerCallbackManager -->|调用| ServiceImpl2
WebSocketServerHandler -->|使用| WebSocketServerCallbackManager
WebSocketServerTaskManager -->|使用| WebSocketServerCallbackManager
2. 架构说明
本架构设计主要针对Server模块中Service缓存从实体类调整为Vo对象的需求,核心调整点包括:
2.1 缓存层调整
- 将Redis缓存中的数据从实体类(Model)改为视图对象(Vo)
- 所有查询操作返回Vo对象并缓存
- 缓存策略调整:findById方法使用@Cacheable注解,key为id值
2.2 服务层重构
- Service实现类同时实现三个核心接口:IEntityService<T, ID>、QueryService和VoableService<Model, Vo>
- 分离实体操作和查询操作,使系统更符合单一职责原则
- 添加基于Vo对象的更新和创建操作方法
2.3 数据转换层
- 引入Voable接口,定义实体类到Vo类的转换方法
- 所有实体类实现Voable接口,提供具体的转换逻辑
- Service层负责调用转换方法并管理转换过程中的异常处理
2.4 依赖组件兼容性
- 特别关注WebSocketServerCallbackManager、WebSocketServerHandler等依赖组件对Service接口的调用方式
- 增强这些组件的类型处理逻辑,确保它们能够正确处理Service类的新泛型参数
3. 分层设计和核心组件
3.1 客户端层
- 职责:发起HTTP请求,接收和展示返回的Vo对象数据
- 组件:前端应用程序
3.2 控制器层
- 职责:接收客户端请求,调用相应的服务方法,返回处理结果
- 组件:REST控制器
- 关键特性:处理请求路由和参数解析,异常统一处理
3.3 服务层
- 职责:实现业务逻辑,处理数据转换,管理缓存策略
- 核心接口:
- IEntityService<T, ID>:提供实体类的基本CRUD操作
- QueryService:提供Vo对象的查询操作并实现缓存
- VoableService<Model, Vo>:提供基于Vo对象的更新和创建操作
- 实现类:各种具体的Service实现类
- 关键特性:数据转换、缓存管理、事务处理、异常处理
3.4 数据访问层
- 职责:提供数据访问接口,实现数据持久化
- 组件:Repository接口、Spring Data JPA
- 关键特性:ORM映射、数据库操作、查询优化
3.5 数据层
- 职责:定义数据模型和视图对象
- 组件:
- Model实体类:映射数据库表结构,实现Voable接口
- Vo视图对象:面向前端展示的数据模型
- 关键特性:数据结构定义、属性映射、转换逻辑
3.6 缓存机制
- 职责:提供数据缓存服务,提高系统性能
- 组件:Spring Cache注解、Redis缓存
- 关键特性:缓存策略配置、缓存数据管理、缓存异常处理
3.7 依赖组件
- 职责:提供WebSocket通信、任务管理等辅助功能
- 组件:WebSocketServerCallbackManager、WebSocketServerHandler、WebSocketServerTaskManager
- 关键特性:与Service层交互、类型安全处理、异常降级
4. 模块依赖关系图
graph TD
IEntityService_Int[IEntityService<T, ID>接口]
QueryService_Int[QueryService<Vo>接口]
VoableService_Int[VoableService<Model, Vo>接口]
ServiceImpl1[Service实现类1]
ServiceImpl2[Service实现类2]
Repository1[Repository接口1]
Repository2[Repository接口2]
JPA[Spring Data JPA]
Model1[Model实体类1]
Model2[Model实体类2]
Vo1[Vo视图对象1]
Vo2[Vo视图对象2]
Cacheable[Spring Cache注解]
Redis[Redis缓存]
WebSocketServerCallbackManager[WebSocketServerCallbackManager]
WebSocketServerHandler[WebSocketServerHandler]
WebSocketServerTaskManager[WebSocketServerTaskManager]
Voable_Int[Voable<Vo>接口]
IEntityService_Int -->|实现| ServiceImpl1
QueryService_Int -->|实现| ServiceImpl1
VoableService_Int -->|实现| ServiceImpl1
IEntityService_Int -->|实现| ServiceImpl2
QueryService_Int -->|实现| ServiceImpl2
VoableService_Int -->|实现| ServiceImpl2
ServiceImpl1 -->|使用| Repository1
ServiceImpl2 -->|使用| Repository2
Repository1 -->|继承| JPA
Repository2 -->|继承| JPA
ServiceImpl1 -->|操作| Model1
ServiceImpl2 -->|操作| Model2
Model1 -->|实现| Voable_Int
Model2 -->|实现| Voable_Int
Model1 -->|转换为| Vo1
Model2 -->|转换为| Vo2
ServiceImpl1 -->|使用| Cacheable
ServiceImpl2 -->|使用| Cacheable
Cacheable -->|存储| Redis
WebSocketServerCallbackManager -->|调用| ServiceImpl1
WebSocketServerCallbackManager -->|调用| ServiceImpl2
WebSocketServerHandler -->|使用| WebSocketServerCallbackManager
WebSocketServerTaskManager -->|使用| WebSocketServerCallbackManager
依赖关系说明:
-
接口定义与服务实现:Service实现类依赖并实现了IEntityService、QueryService和VoableService<Model, Vo>三个接口,提供具体的业务逻辑实现。
-
服务实现与数据访问:Service实现类依赖Repository接口进行数据访问操作,Repository接口依赖Spring Data JPA实现数据持久化。
-
服务实现与数据模型:Service实现类操作实体类,并通过Voable接口将实体类转换为Vo类。
-
服务实现与缓存机制:Service实现类使用Spring Cache注解对查询结果进行缓存,缓存数据存储在Redis中。
-
依赖组件与服务实现:WebSocket相关组件依赖Service实现类提供的数据操作功能,需要特别关注这些组件对Service接口的调用方式。
5. 接口契约定义
5.1 IEntityService<T, ID>接口
接口定义:
public interface IEntityService<T, ID> {
T findById(ID id);
List<T> findAll();
Page<T> findAll(Pageable pageable);
T save(T entity);
void deleteById(ID id);
// 其他实体类操作方法
}
功能描述:提供实体类的基本CRUD操作,泛型T表示实体类类型,ID表示实体类主键类型。
实现说明:
- Service实现类需要实现此接口,确保实体类的基本操作功能正常。
- 此接口主要用于后端内部的数据处理,不直接返回给前端。
- 与QueryService接口配合使用,实现数据访问和数据展示的分离。
5.2 QueryService接口
接口定义:
public interface QueryService<Vo> {
@Cacheable(key = "#id", unless = "#result == null")
Vo findById(Object id);
Page<Vo> findAll(Pageable pageable);
// 其他查询方法
}
功能描述:提供Vo对象的查询操作,泛型Vo表示视图对象类型。
实现说明:
- Service实现类需要实现此接口,确保查询操作返回的是Vo对象。
- findById方法需要标注@Cacheable注解,缓存返回的Vo对象。
- 此接口主要用于向前端提供数据展示所需的Vo对象。
findById方法实现逻辑:
@Override
public CompanyFileTypeVo findById(Object id) {
// 1. 调用IEntityService的findById方法获取实体对象
CompanyFileType entity = super.findById((Long) id);
if (entity == null) {
return null;
}
// 2. 调用实体对象的toVo方法转换为Vo对象
return entity.toVo();
}
findAll方法实现逻辑:
@Override
public Page<CompanyFileTypeVo> findAll(Pageable pageable) {
// 1. 调用IEntityService的findAll方法获取实体对象的Page
Page<CompanyFileType> entityPage = super.findAll(pageable);
// 2. 将实体对象的Page转换为Vo对象的Page
return entityPage.map(CompanyFileType::toVo);
}
5.3 VoableService<Model, Vo>接口
接口定义:
public interface VoableService<Model, Vo> {
Vo updateByVo(Vo vo);
Vo createByVo(Vo vo);
// 其他Vo相关操作方法
}
功能描述:提供基于Vo对象的更新和创建操作,泛型Model表示实体类类型,Vo表示视图对象类型。
实现说明:
- Service实现类需要实现此接口,支持通过Vo对象进行数据的更新和创建。
- 实现时需要将Vo对象转换为实体类对象,然后调用IEntityService的方法进行数据操作。
updateByVo方法实现逻辑:
@Override
public CompanyFileTypeVo updateByVo(CompanyFileTypeVo vo) {
// 1. 验证Vo对象
if (vo == null || vo.getId() == null) {
throw new IllegalArgumentException("Vo对象或ID不能为空");
}
// 2. 查找对应的实体对象
CompanyFileType entity = findById(vo.getId());
if (entity == null) {
throw new EntityNotFoundException("未找到实体: " + vo.getId());
}
// 3. 将Vo对象的属性值复制到实体对象
BeanUtils.copyProperties(vo, entity, "id", "createDate", "createUser", "updateDate", "updateUser");
// 4. 保存更新后的实体对象
CompanyFileType updatedEntity = save(entity);
// 5. 转换为Vo对象返回
return updatedEntity.toVo();
}
createByVo方法实现逻辑:
@Override
public CompanyFileTypeVo createByVo(CompanyFileTypeVo vo) {
// 1. 验证Vo对象
if (vo == null) {
throw new IllegalArgumentException("Vo对象不能为空");
}
// 2. 创建新的实体对象
CompanyFileType entity = new CompanyFileType();
// 3. 将Vo对象的属性值复制到实体对象
BeanUtils.copyProperties(vo, entity, "id", "createDate", "createUser", "updateDate", "updateUser");
// 4. 设置创建信息
entity.setCreateDate(new Date());
entity.setCreateUser(getCurrentUser());
// 5. 保存新的实体对象
CompanyFileType savedEntity = save(entity);
// 6. 转换为Vo对象返回
return savedEntity.toVo();
}
5.4 Voable接口
接口定义:
public interface Voable<Vo> {
Vo toVo();
}
功能描述:定义实体类到Vo类的转换方法,泛型Vo表示目标视图对象类型。
实现说明:
- 所有实体类都需要实现此接口,提供具体的转换逻辑。
- toVo方法负责将实体类的属性值映射到Vo类的对应属性。
实现示例:
public class CompanyFileType implements Voable<CompanyFileTypeVo> {
// 实体类属性
private Long id;
private String name;
private String code;
private Date createDate;
private String createUser;
// 其他属性和getter/setter方法
@Override
public CompanyFileTypeVo toVo() {
CompanyFileTypeVo vo = new CompanyFileTypeVo();
vo.setId(this.id);
vo.setName(this.name);
vo.setCode(this.code);
// 只复制需要在前端展示的属性
return vo;
}
}
6. 数据流向图
6.1 请求处理流程
graph TD
Client[客户端请求]
Controller[控制器]
ServiceImpl[Service实现类]
Repository[Repository]
JPA[JPA]
MySQL[MySQL数据库]
Redis[Redis缓存]
Vo[Vo对象]
Model[Model实体类]
Client -->|findById请求| Controller
Controller -->|调用findById| ServiceImpl
ServiceImpl -->|检查缓存| Redis
Redis -->|缓存命中| Vo
ServiceImpl -->|缓存未命中| Repository
Repository -->|查询| JPA
JPA -->|访问| MySQL
MySQL -->|返回| Model
ServiceImpl -->|转换| Vo
ServiceImpl -->|存入缓存| Redis
Vo -->|返回| ServiceImpl
ServiceImpl -->|返回| Controller
Controller -->|返回| Client
数据流向说明:
-
查询请求处理:客户端发起查询请求,控制器接收请求并调用Service实现类的findById方法。
-
缓存检查:Service实现类首先检查Redis缓存中是否存在对应的Vo对象。
-
缓存命中:如果缓存命中,直接从缓存中获取Vo对象返回。
-
缓存未命中:如果缓存未命中,Service实现类通过Repository查询数据库获取实体类对象,然后将实体类对象转换为Vo对象,存入Redis缓存,并返回Vo对象。
6.2 数据转换流程
graph TD
DB[数据库
Model实体类数据] -->|查询| Repository[Repository]
Repository -->|返回| ServiceImpl[Service实现类]
ServiceImpl -->|调用toVo| Model[Model实体类
实现Voable接口]
Model -->|转换为| Vo[Vo对象]
ServiceImpl -->|缓存| Redis[Redis缓存
存储Vo对象]
ServiceImpl -->|返回| Controller[控制器]
Controller -->|返回| Client[客户端]
转换流程说明:
-
数据查询:从数据库查询实体类数据,通过Repository返回给Service实现类。
-
数据转换:Service实现类调用实体类的toVo方法,将实体类数据转换为Vo对象。
-
缓存存储:转换后的Vo对象被存入Redis缓存中,以提高后续查询性能。
-
数据返回:Vo对象通过控制器返回给客户端,用于前端展示。
7. 异常处理策略
7.1 转换异常处理
场景:实体类转换为Vo对象时发生异常
处理策略:
- 使用try-catch块捕获转换过程中可能发生的异常
- 记录异常日志,包括异常信息和上下文数据
- 返回友好的错误提示,避免将系统内部错误暴露给前端
- 针对关键业务,可以考虑使用补偿机制或降级处理
示例代码:
@Override
public CompanyFileTypeVo findById(Object id) {
try {
CompanyFileType entity = super.findById((Long) id);
if (entity == null) {
return null;
}
return entity.toVo();
} catch (Exception e) {
log.error("Failed to convert CompanyFileType to CompanyFileTypeVo for id: {}", id, e);
throw new ServiceException("数据转换异常: " + e.getMessage());
}
}
7.2 数据验证异常处理
场景:Vo对象数据不完整或不符合业务规则
处理策略:
- 在updateByVo和createByVo方法中,对输入的Vo对象进行严格验证
- 使用@Valid注解和Bean Validation框架进行参数校验
- 对于验证失败的情况,抛出ValidationException或自定义异常
- 返回详细的错误信息,指导前端用户进行正确的操作
示例代码:
@Override
public CompanyFileTypeVo updateByVo(@Valid CompanyFileTypeVo vo) {
if (vo == null || vo.getId() == null) {
throw new IllegalArgumentException("Vo对象或ID不能为空");
}
// 其他验证逻辑
// ...
}
7.3 事务处理异常
场景:数据操作过程中发生事务异常
处理策略:
- 使用Spring的事务管理机制,确保数据操作的原子性
- 使用@Transactional注解标记事务方法,并配置适当的事务传播特性和隔离级别
- 针对事务异常,Spring会自动回滚事务,确保数据一致性
- 记录异常日志,并返回适当的错误提示
示例代码:
@Transactional(rollbackFor = Exception.class)
@Override
public CompanyFileTypeVo createByVo(CompanyFileTypeVo vo) {
// 事务操作逻辑
// ...
}
7.4 缓存异常处理
场景:Redis缓存操作失败
处理策略:
- 使用try-catch块捕获缓存操作可能发生的异常
- 实现缓存降级策略,当缓存操作失败时,直接从数据库查询数据
- 记录异常日志,便于问题排查和监控
- 考虑使用Redis集群或哨兵模式提高缓存服务的可用性
示例代码:
@Override
@Cacheable(key = "#id", unless = "#result == null")
public CompanyFileTypeVo findById(Object id) {
try {
// 缓存操作逻辑
// ...
} catch (CacheException e) {
log.warn("Redis cache operation failed, querying from database directly", e);
// 降级到数据库查询
// ...
}
}
7.5 实体未找到异常
场景:根据ID查询实体类时,未找到对应的数据
处理策略:
- 定义EntityNotFoundException自定义异常
- 在findById等方法中,当查询结果为null时,抛出EntityNotFoundException
- 全局异常处理器捕获EntityNotFoundException,返回HTTP 404状态码和友好的错误信息
- 记录异常日志,便于问题排查
示例代码:
@Override
public CompanyFileTypeVo updateByVo(CompanyFileTypeVo vo) {
// 验证Vo对象
if (vo == null || vo.getId() == null) {
throw new IllegalArgumentException("Vo对象或ID不能为空");
}
// 查找对应的实体对象
CompanyFileType entity = findById(vo.getId());
if (entity == null) {
throw new EntityNotFoundException("未找到实体: " + vo.getId());
}
// 其他操作
// ...
}
7.6 WebSocket服务异常处理
场景:WebSocket服务组件处理Service类新泛型参数时发生异常
处理策略:
- 增强WebSocketServerCallbackManager等组件的类型处理逻辑,添加类型安全检查
- 使用反射API处理泛型参数时,捕获可能发生的异常,如ClassCastException、NoSuchMethodException等
- 记录异常日志,包括详细的上下文信息和堆栈跟踪
- 提供优雅的降级处理,确保WebSocket服务的基本功能不受影响
示例代码:
// 在WebSocketServerCallbackManager中
public <T> T createNewEntity(Class<?> serviceClass) {
try {
// 反射获取实体类型并创建实例
// ...
} catch (Exception e) {
log.error("Failed to create new entity for service: {}", serviceClass.getName(), e);
return null;
}
}
8. 设计原则
-
最小化修改原则:在满足需求的前提下,尽量减少对现有代码的修改,降低风险和工作量。
-
向后兼容性原则:确保修改后的代码能够与现有系统保持兼容,不影响系统的正常运行。
-
数据一致性原则:确保缓存数据与数据库数据的一致性,避免数据不一致导致的问题。
-
接口分离原则:将数据操作与查询操作分离到不同接口,使得系统更符合单一职责原则。
-
可扩展性原则:设计具有良好扩展性的架构,便于后续功能的增加和修改。
-
安全性原则:确保数据转换和缓存操作的安全性,防止数据泄露和恶意攻击。
-
性能优化原则:优化数据转换和缓存操作的性能,提高系统整体响应速度。
-
可测试性原则:确保设计的代码具有良好的可测试性,便于编写单元测试和集成测试。
-
代码复用原则:提取通用的转换逻辑和缓存策略,提高代码的复用性。