From 6a640020f69259aa35afe30ef0c9a592dee8a452 Mon Sep 17 00:00:00 2001 From: yang chen Date: Wed, 12 Nov 2025 17:07:03 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat(mapper):=20=E6=B7=BB=E5=8A=A0Statement?= =?UTF-8?q?Type=E9=85=8D=E7=BD=AE=E4=BB=A5=E6=94=AF=E6=8C=81=E5=8A=A8?= =?UTF-8?q?=E6=80=81SQL=E6=89=A7=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在JeeLowCodeSqlMapper接口中引入StatementType配置-为selectData方法添加@Options注解并设置statementType为STATEMENT -为selectPageData方法添加@Options注解并设置statementType为STATEMENT - 引入org.apache.ibatis.mapping.StatementType包以支持新功能 - 此变更使得Mapper能够正确处理动态生成的SQL语句 --- .../jeelowcode/core/framework/mapper/JeeLowCodeSqlMapper.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jeelowcode-core/src/main/java/com/jeelowcode/core/framework/mapper/JeeLowCodeSqlMapper.java b/jeelowcode-core/src/main/java/com/jeelowcode/core/framework/mapper/JeeLowCodeSqlMapper.java index 03c1424..fc675e8 100644 --- a/jeelowcode-core/src/main/java/com/jeelowcode/core/framework/mapper/JeeLowCodeSqlMapper.java +++ b/jeelowcode-core/src/main/java/com/jeelowcode/core/framework/mapper/JeeLowCodeSqlMapper.java @@ -6,6 +6,7 @@ import com.baomidou.dynamic.datasource.annotation.Master; import com.baomidou.mybatisplus.core.metadata.IPage; import com.jeelowcode.framework.tenant.annotation.JeeLowCodeTenantIgnore; import org.apache.ibatis.annotations.*; +import org.apache.ibatis.mapping.StatementType; import java.util.List; import java.util.Map; @@ -24,11 +25,13 @@ public interface JeeLowCodeSqlMapper { //获取数据 - 多个 @DS(value = "#dataSourceType") @Select("${jeeLowCodeSelectSql}") + @Options(statementType = StatementType.STATEMENT) List> selectData(@Param("dataSourceType") String dataSourceType,@Param("jeeLowCodeSelectSql") String jeeLowCodeSelectSql,@Param("ew") Map ew); //分页 @DS(value = "#dataSourceType") @Select("${jeeLowCodeSelectSql}") + @Options(statementType = StatementType.STATEMENT) IPage> selectPageData(@Param("dataSourceType") String dataSourceType,IPage page,@Param("jeeLowCodeSelectSql") String jeeLowCodeSelectSql,@Param("ew") Map ew); //新增数据 From 64704b9ab4f296b701835b703303363ec1d84c3d Mon Sep 17 00:00:00 2001 From: yang chen Date: Wed, 12 Nov 2025 17:27:17 +0800 Subject: [PATCH 2/5] =?UTF-8?q?fix(lowcode):=20=E6=9B=B4=E6=96=B0=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E8=A1=A8=E5=90=8C=E6=AD=A5=E7=8A=B6=E6=80=81?= =?UTF-8?q?-=20=E5=B0=86=E5=A4=9A=E4=B8=AA=E4=BD=9C=E4=B8=9A=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E8=A1=A8=E7=9A=84IS=5FDB=5FSYNC=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E4=B8=BA'N'-=20=E6=B6=89=E5=8F=8A=E5=8F=97?= =?UTF-8?q?=E9=99=90=E7=A9=BA=E9=97=B4=E3=80=81=E5=8A=A8=E7=81=AB=E3=80=81?= =?UTF-8?q?=E9=AB=98=E7=A9=BA=E7=AD=8911=E4=B8=AA=E4=BD=9C=E4=B8=9A?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E8=A1=A8=20-=20=E7=A1=AE=E4=BF=9D=E8=BF=99?= =?UTF-8?q?=E4=BA=9B=E8=A1=A8=E5=9C=A8=E4=B8=8B=E6=AC=A1=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E6=97=B6=E9=87=8D=E6=96=B0=E5=88=9D=E5=A7=8B=E5=8C=96=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SQL/202511/20251112/z_exec_last.sql | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 SQL/202511/20251112/z_exec_last.sql diff --git a/SQL/202511/20251112/z_exec_last.sql b/SQL/202511/20251112/z_exec_last.sql new file mode 100644 index 0000000..12d2ad3 --- /dev/null +++ b/SQL/202511/20251112/z_exec_last.sql @@ -0,0 +1,9 @@ +update "LOWCODE_FRAME"."LOWCODE_DBFORM" +set IS_DB_SYNC='N' +where TABLE_NAME in ('lc_confined_space_operation', + 'lc_fire_operation', 'lc_high_operation', + 'lc_item_result', 'lc_land_operation', + 'lc_lifting_operation', 'lc_outside_person', + 'lc_risk_hazard_manage', 'lc_risk_identify_assessment', + 'lc_temporary_power_operation', 'lc_todo_request_info', + 'lc_work_item'); From c94aa3c898c2980a8e794eac508069d69659ad30 Mon Sep 17 00:00:00 2001 From: yang chen Date: Wed, 12 Nov 2025 20:47:37 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat(config):=20=E6=9B=B4=E6=96=B0=20Redis?= =?UTF-8?q?=20=E9=85=8D=E7=BD=AE=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 启用 Redis 端口配置,默认值为6379 - 设置 Redis 数据库索引为 0 - 注释掉密码配置项,建议生产环境开启 - 调整配置文件结构以提高可读性 --- jeelowcode-admin/src/main/resources/application-office.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jeelowcode-admin/src/main/resources/application-office.yaml b/jeelowcode-admin/src/main/resources/application-office.yaml index 0e07093..48656e5 100644 --- a/jeelowcode-admin/src/main/resources/application-office.yaml +++ b/jeelowcode-admin/src/main/resources/application-office.yaml @@ -33,8 +33,8 @@ spring: # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 redis: host: redis # 地址 - # port: 6379 # 端口 - # database: 10 # 数据库索引 + port: 6379 # 端口 + database: 0 # 数据库索引 # password: 123456 # 密码,建议生产环境开启 From 114f37fc99ef0b70b450ea8c728d26b8d1bee77b Mon Sep 17 00:00:00 2001 From: yang chen Date: Thu, 13 Nov 2025 09:54:58 +0800 Subject: [PATCH 4/5] =?UTF-8?q?refactor(mapper):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E4=B8=8D=E5=BF=85=E8=A6=81=E7=9A=84@Options=E6=B3=A8=E8=A7=A3-?= =?UTF-8?q?=20=E5=88=A0=E9=99=A4selectData=E6=96=B9=E6=B3=95=E4=B8=AD?= =?UTF-8?q?=E7=9A=84@Options(statementType=20=3D=20StatementType.STATEMENT?= =?UTF-8?q?)=20-=20=E5=88=A0=E9=99=A4selectPageData=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E4=B8=AD=E7=9A=84@Options(statementType=20=3D=20StatementType.?= =?UTF-8?q?STATEMENT)=20-=20=E7=AE=80=E5=8C=96MyBatis=20SQL=E6=89=A7?= =?UTF-8?q?=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jeelowcode/core/framework/mapper/JeeLowCodeSqlMapper.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/jeelowcode-core/src/main/java/com/jeelowcode/core/framework/mapper/JeeLowCodeSqlMapper.java b/jeelowcode-core/src/main/java/com/jeelowcode/core/framework/mapper/JeeLowCodeSqlMapper.java index fc675e8..5267b41 100644 --- a/jeelowcode-core/src/main/java/com/jeelowcode/core/framework/mapper/JeeLowCodeSqlMapper.java +++ b/jeelowcode-core/src/main/java/com/jeelowcode/core/framework/mapper/JeeLowCodeSqlMapper.java @@ -25,13 +25,11 @@ public interface JeeLowCodeSqlMapper { //获取数据 - 多个 @DS(value = "#dataSourceType") @Select("${jeeLowCodeSelectSql}") - @Options(statementType = StatementType.STATEMENT) List> selectData(@Param("dataSourceType") String dataSourceType,@Param("jeeLowCodeSelectSql") String jeeLowCodeSelectSql,@Param("ew") Map ew); //分页 @DS(value = "#dataSourceType") @Select("${jeeLowCodeSelectSql}") - @Options(statementType = StatementType.STATEMENT) IPage> selectPageData(@Param("dataSourceType") String dataSourceType,IPage page,@Param("jeeLowCodeSelectSql") String jeeLowCodeSelectSql,@Param("ew") Map ew); //新增数据 From b0edcc4feea51fd9f27b03be4b1c78c5cfcd7eb8 Mon Sep 17 00:00:00 2001 From: yang chen Date: Thu, 13 Nov 2025 10:35:14 +0800 Subject: [PATCH 5/5] =?UTF-8?q?fix(bpm):=E4=BC=98=E5=8C=96=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E5=AE=9E=E4=BE=8B=E5=8F=96=E6=B6=88=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 当流程实例不存在时,通过历史表查询并更新状态 - 增加对已删除流程实例的处理,确保审批状态正确修改-保留原有权限校验逻辑,确保只能取消自己的流程实例- 引入 FlowableEventType 用于事件处理 - 移除冗余的事务注解,简化代码结构 --- .../BpmProcessInstanceController.java | 24 +++++++------------ .../impl/BpmProcessInstanceServiceImpl.java | 2 +- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/jeelowcode-service/jeelowcode-service-bpm-biz/src/main/java/com/jeelowcode/service/bpm/controller/BpmProcessInstanceController.java b/jeelowcode-service/jeelowcode-service-bpm-biz/src/main/java/com/jeelowcode/service/bpm/controller/BpmProcessInstanceController.java index 65ab41f..3548826 100644 --- a/jeelowcode-service/jeelowcode-service-bpm-biz/src/main/java/com/jeelowcode/service/bpm/controller/BpmProcessInstanceController.java +++ b/jeelowcode-service/jeelowcode-service-bpm-biz/src/main/java/com/jeelowcode/service/bpm/controller/BpmProcessInstanceController.java @@ -1,12 +1,9 @@ package com.jeelowcode.service.bpm.controller; import com.jeelowcode.core.framework.controller.BaseController; -import com.jeelowcode.core.framework.enums.ApproveStatusEnum; import com.jeelowcode.framework.utils.model.ResultDataModel; -import com.jeelowcode.framework.utils.tool.CollectionUtil; import com.jeelowcode.framework.utils.tool.NumberUtil; import com.jeelowcode.service.bpm.controller.vo.instance.*; -import com.jeelowcode.service.bpm.controller.vo.process.BpmProcessDefinitionRespVO; import com.jeelowcode.service.bpm.service.IBpmProcessInstanceService; import com.jeelowcode.tool.framework.common.pojo.CommonResult; import com.jeelowcode.tool.framework.common.pojo.PageResult; @@ -19,9 +16,7 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; - import java.util.HashMap; -import java.util.List; import java.util.Objects; import static com.jeelowcode.tool.framework.common.pojo.CommonResult.success; @@ -37,7 +32,7 @@ public class BpmProcessInstanceController extends BaseController { private IBpmProcessInstanceService processInstanceService; @GetMapping("/my-page") - @Operation(tags = "流程管理",summary = "获得我的实例分页列表", description = "在【我的流程】菜单中,进行调用") + @Operation(tags = "流程管理", summary = "获得我的实例分页列表", description = "在【我的流程】菜单中,进行调用") @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") public CommonResult> getMyProcessInstancePage( @Valid BpmProcessInstanceMyPageReqVO pageReqVO) { @@ -45,19 +40,19 @@ public class BpmProcessInstanceController extends BaseController { } @PostMapping("/create") - @Operation(tags = "流程管理",summary = "新建流程实例") + @Operation(tags = "流程管理", summary = "新建流程实例") @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") public CommonResult createProcessInstance(@Valid @RequestBody BpmProcessInstanceCreateReqVO createReqVO) { return success(processInstanceService.createProcessInstance(getLoginUserId(), createReqVO)); } @PostMapping("/listCreate") - @Operation(tags = "流程管理",summary = "新建流程实例") + @Operation(tags = "流程管理", summary = "新建流程实例") @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") public CommonResult createListProcessInstance(@Valid @RequestBody BpmProcessInstanceCreateReqVO createReqVO) { - ResultDataModel dataDetail = super.getDataDetail(NumberUtil.toLong(createReqVO.getDbFormId()),NumberUtil.toLong(createReqVO.getDataId()),new HashMap()); - if(Objects.nonNull(dataDetail)){ - dataDetail.getRecords().get(0).put("approveStatusName",""); + ResultDataModel dataDetail = super.getDataDetail(NumberUtil.toLong(createReqVO.getDbFormId()), NumberUtil.toLong(createReqVO.getDataId()), new HashMap()); + if (Objects.nonNull(dataDetail)) { + dataDetail.getRecords().get(0).put("approveStatusName", ""); createReqVO.setVariables(dataDetail.getRecords().get(0)); } @@ -65,9 +60,8 @@ public class BpmProcessInstanceController extends BaseController { } - @PostMapping("/createV2") - @Operation(tags = "流程管理",summary = "新建流程实例(自定义流程发起使用)") + @Operation(tags = "流程管理", summary = "新建流程实例(自定义流程发起使用)") @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") public CommonResult createProcessInstanceV2(@Valid @RequestBody BpmProcessInstanceCreateReqVO createReqVO) { return success(processInstanceService.createProcessInstanceV2(getLoginUserId(), createReqVO)); @@ -75,7 +69,7 @@ public class BpmProcessInstanceController extends BaseController { @GetMapping("/get") - @Operation(tags = "流程管理",summary = "获得指定流程实例", description = "在【流程详细】界面中,进行调用") + @Operation(tags = "流程管理", summary = "获得指定流程实例", description = "在【流程详细】界面中,进行调用") @Parameter(name = "id", description = "流程实例的编号", required = true) @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") public CommonResult getProcessInstance(@RequestParam("id") String id) { @@ -83,7 +77,7 @@ public class BpmProcessInstanceController extends BaseController { } @DeleteMapping("/cancel") - @Operation(tags = "流程管理",summary = "取消流程实例", description = "撤回发起的流程") + @Operation(tags = "流程管理", summary = "取消流程实例", description = "撤回发起的流程") @PreAuthorize("@ss.hasPermission('bpm:process-instance:cancel')") public CommonResult cancelProcessInstance(@Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) { processInstanceService.cancelProcessInstance(getLoginUserId(), cancelReqVO); diff --git a/jeelowcode-service/jeelowcode-service-bpm-biz/src/main/java/com/jeelowcode/service/bpm/service/impl/BpmProcessInstanceServiceImpl.java b/jeelowcode-service/jeelowcode-service-bpm-biz/src/main/java/com/jeelowcode/service/bpm/service/impl/BpmProcessInstanceServiceImpl.java index 807db66..592a602 100644 --- a/jeelowcode-service/jeelowcode-service-bpm-biz/src/main/java/com/jeelowcode/service/bpm/service/impl/BpmProcessInstanceServiceImpl.java +++ b/jeelowcode-service/jeelowcode-service-bpm-biz/src/main/java/com/jeelowcode/service/bpm/service/impl/BpmProcessInstanceServiceImpl.java @@ -1 +1 @@ -package com.jeelowcode.service.bpm.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.jeelowcode.service.bpm.config.convert.task.BpmProcessInstanceConvert; import com.jeelowcode.service.bpm.config.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import com.jeelowcode.service.bpm.controller.vo.enu.BpmFormType; import com.jeelowcode.service.bpm.controller.vo.instance.*; import com.jeelowcode.service.bpm.dto.BpmProcessInstanceCreateReqDTO; import com.jeelowcode.service.bpm.entity.BpmProcessDefinitionExtDO; import com.jeelowcode.service.bpm.entity.BpmProcessInstanceExtDO; import com.jeelowcode.service.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import com.jeelowcode.service.bpm.enums.task.BpmProcessInstanceResultEnum; import com.jeelowcode.service.bpm.enums.task.BpmProcessInstanceStatusEnum; import com.jeelowcode.service.bpm.mapper.BpmProcessInstanceExtMapper; import com.jeelowcode.service.bpm.service.IBpmMessageService; import com.jeelowcode.service.bpm.service.IBpmProcessDefinitionService; import com.jeelowcode.service.bpm.service.IBpmProcessInstanceService; import com.jeelowcode.service.bpm.service.IBpmTaskService; import com.jeelowcode.service.system.api.IApiAdminUserApi; import com.jeelowcode.service.system.api.IApiDeptApi; import com.jeelowcode.service.system.dto.AdminUserRespDTO; import com.jeelowcode.service.system.dto.DeptRespDTO; import com.jeelowcode.tool.framework.common.pojo.PageResult; import com.jeelowcode.tool.framework.common.util.number.NumberUtils; import com.jeelowcode.tool.framework.flowable.core.context.FlowableContextHolder; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.time.LocalDateTime; import java.util.*; import static com.jeelowcode.service.bpm.enums.ErrorCodeConstants.*; import static com.jeelowcode.tool.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.jeelowcode.tool.framework.common.util.collection.CollectionUtils.convertList; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements IBpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private IBpmTaskService taskService; @Resource private IBpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private IApiAdminUserApi apiAdminUserApi; @Resource private IApiDeptApi apiDeptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private IBpmMessageService messageService; @Resource private BillApproveStatusService billApproveStatusService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap); } @Override @DSTransactional(rollbackFor = Exception.class) public String createProcessInstanceV2(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(BpmFormType.ZUOYE.getBpmId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override @DSTransactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = apiAdminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = apiDeptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); // 修改单据审批状态 billApproveStatusService.afterCancel(instance.getProcessInstanceId()); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @DSTransactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables).setAssignee(assignee)); billApproveStatusService.afterSubmit(instance.getProcessInstanceId()); return instance.getId(); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } if (CollUtil.isNotEmpty(instance.getAssignee())) { return instance.getAssignee().get(taskDefinitionKey); } return Collections.emptyList(); } } \ No newline at end of file +package com.jeelowcode.service.bpm.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.jeelowcode.service.bpm.config.convert.task.BpmProcessInstanceConvert; import com.jeelowcode.service.bpm.config.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import com.jeelowcode.service.bpm.controller.vo.enu.BpmFormType; import com.jeelowcode.service.bpm.controller.vo.instance.*; import com.jeelowcode.service.bpm.dto.BpmProcessInstanceCreateReqDTO; import com.jeelowcode.service.bpm.entity.BpmProcessDefinitionExtDO; import com.jeelowcode.service.bpm.entity.BpmProcessInstanceExtDO; import com.jeelowcode.service.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import com.jeelowcode.service.bpm.enums.task.BpmProcessInstanceResultEnum; import com.jeelowcode.service.bpm.enums.task.BpmProcessInstanceStatusEnum; import com.jeelowcode.service.bpm.mapper.BpmProcessInstanceExtMapper; import com.jeelowcode.service.bpm.service.IBpmMessageService; import com.jeelowcode.service.bpm.service.IBpmProcessDefinitionService; import com.jeelowcode.service.bpm.service.IBpmProcessInstanceService; import com.jeelowcode.service.bpm.service.IBpmTaskService; import com.jeelowcode.service.system.api.IApiAdminUserApi; import com.jeelowcode.service.system.api.IApiDeptApi; import com.jeelowcode.service.system.dto.AdminUserRespDTO; import com.jeelowcode.service.system.dto.DeptRespDTO; import com.jeelowcode.tool.framework.common.pojo.PageResult; import com.jeelowcode.tool.framework.common.util.number.NumberUtils; import com.jeelowcode.tool.framework.flowable.core.context.FlowableContextHolder; import lombok.extern.slf4j.Slf4j; import org.flowable.common.engine.api.delegate.event.FlowableEventType; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.time.LocalDateTime; import java.util.*; import static com.jeelowcode.service.bpm.enums.ErrorCodeConstants.*; import static com.jeelowcode.tool.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.jeelowcode.tool.framework.common.util.collection.CollectionUtils.convertList; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements IBpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private IBpmTaskService taskService; @Resource private IBpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private IApiAdminUserApi apiAdminUserApi; @Resource private IApiDeptApi apiDeptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private IBpmMessageService messageService; @Resource private BillApproveStatusService billApproveStatusService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap); } @Override @DSTransactional(rollbackFor = Exception.class) public String createProcessInstanceV2(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(BpmFormType.ZUOYE.getBpmId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override @DSTransactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = apiAdminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = apiDeptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { // 如果找不到,则通过历史表查询 HistoricProcessInstance historicInstance = getHistoricProcessInstance(cancelReqVO.getId()); if (historicInstance != null) { // 只能取消自己的 if (!Objects.equals(historicInstance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 流程实例已经删除了,需要更新流程的状态 updateProcessInstanceExtCancel(new FlowableCancelledEvent() { @Override public Object getCause() { return BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason()); } @Override public String getExecutionId() { return ""; } @Override public String getProcessInstanceId() { return cancelReqVO.getId(); } @Override public String getProcessDefinitionId() { return ""; } @Override public String getScopeType() { return ""; } @Override public String getScopeId() { return ""; } @Override public String getSubScopeId() { return ""; } @Override public String getScopeDefinitionId() { return ""; } @Override public FlowableEventType getType() { return null; } }); // 修改单据审批状态 billApproveStatusService.afterCancel(historicInstance.getId()); } else { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } } else { // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); // 修改单据审批状态 billApproveStatusService.afterCancel(instance.getProcessInstanceId()); } } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @DSTransactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey, Map> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables).setAssignee(assignee)); billApproveStatusService.afterSubmit(instance.getProcessInstanceId()); return instance.getId(); } @Override public List getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } if (CollUtil.isNotEmpty(instance.getAssignee())) { return instance.getAssignee().get(taskDefinitionKey); } return Collections.emptyList(); } } \ No newline at end of file