zn-cloud/issues/流程附件上传机制优化.md
aikai 79e96d3546 feat(infra): 实现 MinIO 分片上传功能
- 新增分片上传相关接口和 VO 类
- 实现分片上传服务,包括初始化、获取预签名 URL、完成上传和取消上传
- 添加分片上传会话的数据库表结构和 Mapper
- 优化错误处理和参数验证
2025-07-03 11:18:53 +08:00

5.2 KiB
Raw Blame History

流程附件上传机制优化

任务概述

BpmProcessInstanceController.uploadAttachment 方法从硬编码映射改为通过配置表动态获取实体类和Mapper类ProcessQueryServiceImpl 保持一致的反射机制。

实施方案

方案1完全使用配置表机制已采用

  • 移除硬编码的 entityTypeMap
  • 注入 ProcessMappingConfigService
  • 修改 resolveEntityType 方法通过配置表动态获取类信息
  • 参数兼容:processType 映射到 processCode

具体修改

1. 移除硬编码机制

// 删除了以下内容:
private final Map<String, List> entityTypeMap = new ConcurrentHashMap<>();

@PostConstruct
public void init() {
    // 注册支持的实体类型
    entityTypeMap.put("oa_reimbursement", new ArrayList<Class<?>>(Arrays.asList(BpmOAReimbursementDO.class, BpmOAReimbursementMapper.class)));
    // ... 其他30多个映射关系
}

2. 新增依赖注入

@Resource
private ProcessMappingConfigService processMappingConfigService;

3. 重构解析方法

private List<Class<?>> resolveEntityType(String processCode) {
    try {
        // 1. 获取流程映射配置
        BpmProcessMappingConfigDO config = processMappingConfigService.getProcessMappingConfigByCode(processCode);
        if (config == null) {
            log.error("[resolveEntityType][流程映射配置不存在] processCode={}", processCode);
            throw exception(PROCESS_MAPPING_CONFIG_NOT_EXISTS);
        }

        // 2. 动态加载实体类和Mapper类
        Class<?> entityClass = ClassUtil.loadClass(config.getEntityClass());
        Class<?> mapperClass = ClassUtil.loadClass(config.getMapperClass());

        // 3. 验证Mapper类是否可获取Bean实例
        SpringUtil.getBean(mapperClass);

        return Arrays.asList(entityClass, mapperClass);
        
    } catch (Exception e) {
        log.error("[resolveEntityType][解析流程类型失败] processCode={}", processCode, e);
        throw new ServiceException(500, String.format("不支持的流程类型: %s, 错误信息: %s", processCode, e.getMessage()));
    }
}

4. 新增import语句

import cn.hutool.core.util.ClassUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.module.bpm.dal.dataobject.processmapping.BpmProcessMappingConfigDO;
import cn.iocoder.yudao.module.bpm.service.processmapping.ProcessMappingConfigService;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_MAPPING_CONFIG_NOT_EXISTS;

技术优势

1. 统一反射机制

  • ProcessQueryServiceImpl 采用相同的配置表查询方式
  • 使用相同的工具类(ClassUtil, SpringUtil
  • 统一的异常处理和错误码

2. 动态配置支持

  • 支持通过配置表动态添加新的流程类型
  • 无需修改代码和重启服务
  • 配置变更可通过管理界面完成

3. 代码质量提升

  • 消除了30多行硬编码映射
  • 减少了代码维护成本
  • 提高了系统的可扩展性

4. 兼容性保证

  • API接口保持不变
  • 前端代码无需修改
  • processType 参数直接作为 processCode 使用

配置表结构

系统依赖 bmp_process_mapping_config 表的以下字段:

  • process_code: 流程唯一标识(对应前端传入的 processType
  • entity_class: 实体类全限定名
  • mapper_class: Mapper接口全限定名

使用示例

前端调用方式保持不变:

{
  "processType": "oa_reimbursement",  // 会作为processCode查询配置表
  "processBusinessId": 123,
  "fileItems": [...]
}

后台会自动:

  1. 根据 processType="oa_reimbursement" 查询配置表
  2. 获取对应的实体类和Mapper类
  3. 动态实例化并调用附件更新服务

执行时间

2024年12月19日

状态

已完成(已优化架构)

后续优化

2024年12月19日 - 架构优化:

1. 分层重构

  • 问题resolveEntityType 方法不应放在Controller层
  • 解决:将类型解析逻辑移至 BpmOAAttachmentService 服务层
  • 优势符合分层架构原则Controller只负责接口调用

2. 使用ReflectionInvoker工具类

  • 问题BpmOAAttachmentServiceImpl.updateAttachment 使用手动反射
  • 解决:替换为 ReflectionInvoker.invokeMapperMethod 调用
  • 优势:更安全、统一的反射机制,支持代理类处理

3. 优化后的调用链

Controller -> Service (类型解析) -> Service (附件更新) -> ReflectionInvoker (Mapper调用)

4. 主要变更文件

  • BpmOAAttachmentService.java: 添加 resolveEntityType 接口方法
  • BpmOAAttachmentServiceImpl.java: 实现类型解析和优化反射调用
  • BpmProcessInstanceController.java: 简化Controller逻辑移除业务逻辑

5. 技术收益

  • 更清晰的分层架构
  • 统一的反射调用机制
  • 更好的错误处理和日志记录
  • 代码复用性提升

验证要点

  1. 确保配置表中存在对应的流程映射配置
  2. 验证实体类和Mapper类路径正确
  3. 测试异常情况的错误处理和日志记录
  4. 确认ReflectionInvoker正确处理代理类和方法调用