# 6A工作流 - 架构阶段
# 任务名: Server模块Service缓存调整为Vo对象

## 1. 整体架构图

```mermaid
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<Vo>和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>：提供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. 模块依赖关系图

```mermaid
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
```

**依赖关系说明**：

1. **接口定义与服务实现**：Service实现类依赖并实现了IEntityService<Model>、QueryService<Vo>和VoableService<Model, Vo>三个接口，提供具体的业务逻辑实现。

2. **服务实现与数据访问**：Service实现类依赖Repository接口进行数据访问操作，Repository接口依赖Spring Data JPA实现数据持久化。

3. **服务实现与数据模型**：Service实现类操作实体类，并通过Voable接口将实体类转换为Vo类。

4. **服务实现与缓存机制**：Service实现类使用Spring Cache注解对查询结果进行缓存，缓存数据存储在Redis中。

5. **依赖组件与服务实现**：WebSocket相关组件依赖Service实现类提供的数据操作功能，需要特别关注这些组件对Service接口的调用方式。

## 5. 接口契约定义

### 5.1 IEntityService<T, ID>接口

**接口定义**：
```java
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<Vo>接口配合使用，实现数据访问和数据展示的分离。

### 5.2 QueryService<Vo>接口

**接口定义**：
```java
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方法实现逻辑**：
```java
@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方法实现逻辑**：
```java
@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>接口

**接口定义**：
```java
public interface VoableService<Model, Vo> {
    Vo updateByVo(Vo vo);
    Vo createByVo(Vo vo);
    // 其他Vo相关操作方法
}
```

**功能描述**：提供基于Vo对象的更新和创建操作，泛型Model表示实体类类型，Vo表示视图对象类型。

**实现说明**：
- Service实现类需要实现此接口，支持通过Vo对象进行数据的更新和创建。
- 实现时需要将Vo对象转换为实体类对象，然后调用IEntityService的方法进行数据操作。

**updateByVo方法实现逻辑**：
```java
@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方法实现逻辑**：
```java
@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接口

**接口定义**：
```java
public interface Voable<Vo> {
    Vo toVo();
}
```

**功能描述**：定义实体类到Vo类的转换方法，泛型Vo表示目标视图对象类型。

**实现说明**：
- 所有实体类都需要实现此接口，提供具体的转换逻辑。
- toVo方法负责将实体类的属性值映射到Vo类的对应属性。

**实现示例**：
```java
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 请求处理流程

```mermaid
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
```

**数据流向说明**：

1. **查询请求处理**：客户端发起查询请求，控制器接收请求并调用Service实现类的findById方法。

2. **缓存检查**：Service实现类首先检查Redis缓存中是否存在对应的Vo对象。

3. **缓存命中**：如果缓存命中，直接从缓存中获取Vo对象返回。

4. **缓存未命中**：如果缓存未命中，Service实现类通过Repository查询数据库获取实体类对象，然后将实体类对象转换为Vo对象，存入Redis缓存，并返回Vo对象。

### 6.2 数据转换流程

```mermaid
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[客户端]
```

**转换流程说明**：

1. **数据查询**：从数据库查询实体类数据，通过Repository返回给Service实现类。

2. **数据转换**：Service实现类调用实体类的toVo方法，将实体类数据转换为Vo对象。

3. **缓存存储**：转换后的Vo对象被存入Redis缓存中，以提高后续查询性能。

4. **数据返回**：Vo对象通过控制器返回给客户端，用于前端展示。

## 7. 异常处理策略

### 7.1 转换异常处理

**场景**：实体类转换为Vo对象时发生异常

**处理策略**：
- 使用try-catch块捕获转换过程中可能发生的异常
- 记录异常日志，包括异常信息和上下文数据
- 返回友好的错误提示，避免将系统内部错误暴露给前端
- 针对关键业务，可以考虑使用补偿机制或降级处理

**示例代码**：
```java
@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或自定义异常
- 返回详细的错误信息，指导前端用户进行正确的操作

**示例代码**：
```java
@Override
public CompanyFileTypeVo updateByVo(@Valid CompanyFileTypeVo vo) {
    if (vo == null || vo.getId() == null) {
        throw new IllegalArgumentException("Vo对象或ID不能为空");
    }
    // 其他验证逻辑
    // ...
}
```

### 7.3 事务处理异常

**场景**：数据操作过程中发生事务异常

**处理策略**：
- 使用Spring的事务管理机制，确保数据操作的原子性
- 使用@Transactional注解标记事务方法，并配置适当的事务传播特性和隔离级别
- 针对事务异常，Spring会自动回滚事务，确保数据一致性
- 记录异常日志，并返回适当的错误提示

**示例代码**：
```java
@Transactional(rollbackFor = Exception.class)
@Override
public CompanyFileTypeVo createByVo(CompanyFileTypeVo vo) {
    // 事务操作逻辑
    // ...
}
```

### 7.4 缓存异常处理

**场景**：Redis缓存操作失败

**处理策略**：
- 使用try-catch块捕获缓存操作可能发生的异常
- 实现缓存降级策略，当缓存操作失败时，直接从数据库查询数据
- 记录异常日志，便于问题排查和监控
- 考虑使用Redis集群或哨兵模式提高缓存服务的可用性

**示例代码**：
```java
@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状态码和友好的错误信息
- 记录异常日志，便于问题排查

**示例代码**：
```java
@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服务的基本功能不受影响

**示例代码**：
```java
// 在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. 设计原则

1. **最小化修改原则**：在满足需求的前提下，尽量减少对现有代码的修改，降低风险和工作量。

2. **向后兼容性原则**：确保修改后的代码能够与现有系统保持兼容，不影响系统的正常运行。

3. **数据一致性原则**：确保缓存数据与数据库数据的一致性，避免数据不一致导致的问题。

4. **接口分离原则**：将数据操作与查询操作分离到不同接口，使得系统更符合单一职责原则。

5. **可扩展性原则**：设计具有良好扩展性的架构，便于后续功能的增加和修改。

6. **安全性原则**：确保数据转换和缓存操作的安全性，防止数据泄露和恶意攻击。

7. **性能优化原则**：优化数据转换和缓存操作的性能，提高系统整体响应速度。

8. **可测试性原则**：确保设计的代码具有良好的可测试性，便于编写单元测试和集成测试。

9. **代码复用原则**：提取通用的转换逻辑和缓存策略，提高代码的复用性。