# 流程附件上传机制优化 ## 任务概述 将 `BpmProcessInstanceController.uploadAttachment` 方法从硬编码映射改为通过配置表动态获取实体类和Mapper类,与 `ProcessQueryServiceImpl` 保持一致的反射机制。 ## 实施方案 **方案1:完全使用配置表机制(已采用)** - 移除硬编码的 `entityTypeMap` - 注入 `ProcessMappingConfigService` - 修改 `resolveEntityType` 方法通过配置表动态获取类信息 - 参数兼容:`processType` 映射到 `processCode` ## 具体修改 ### 1. 移除硬编码机制 ```java // 删除了以下内容: private final Map entityTypeMap = new ConcurrentHashMap<>(); @PostConstruct public void init() { // 注册支持的实体类型 entityTypeMap.put("oa_reimbursement", new ArrayList>(Arrays.asList(BpmOAReimbursementDO.class, BpmOAReimbursementMapper.class))); // ... 其他30多个映射关系 } ``` ### 2. 新增依赖注入 ```java @Resource private ProcessMappingConfigService processMappingConfigService; ``` ### 3. 重构解析方法 ```java private List> 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语句 ```java 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接口全限定名 ## 使用示例 前端调用方式保持不变: ```javascript { "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正确处理代理类和方法调用