feat(workflow): 从hwbm的新版本plus框架中直接复制,未经过测试!新增流程实例业务扩展对象和启动流程并推进功能

- 新增 FlowInstanceBizExt 类作为流程实例业务扩展对象
- 在 RemoteStartProcess 中添加 bizExt 字段用于业务扩展信息
- 在 StartProcessBo 中添加 bizExt 字段用于业务扩展信息
- 新增 startCompleteTask 方法实现启动流程并自动推进到下一节点
- 实现 getCurrentTaskIdByInstanceId 方法根据流程实例ID获取当前活跃任务
- 通过独立事务机制避免数据库死锁问题
- 添加完整的注释文档说明新功能的使用场景和核心机制
master
zangch@mesnac.com 3 weeks ago
parent e75762694e
commit 871696d50a

@ -112,4 +112,24 @@ public interface RemoteWorkflowService {
*/ */
Long getCurrentTaskIdByInstanceId(Long instanceId); Long getCurrentTaskIdByInstanceId(Long instanceId);
/**
* hwbmplus
*
* <p>
* startWorkFlow() completeTask()
* 使
* </p>
* <p>
*
* <ul>
* <li></li>
* <li> flow_instance flow_task </li>
* </ul>
* </p>
*
* @param startProcess flowCode, businessId, variables
* @return true=, false=
*/
boolean startCompleteTask(RemoteStartProcess startProcess);
} }

@ -1,6 +1,7 @@
package org.dromara.workflow.api.domain; package org.dromara.workflow.api.domain;
import cn.hutool.core.util.ObjectUtil;
import lombok.Data; import lombok.Data;
import java.io.Serial; import java.io.Serial;
@ -35,6 +36,13 @@ public class RemoteStartProcess implements Serializable {
*/ */
private Map<String, Object> variables; private Map<String, Object> variables;
/**
* hwbmplus
*
*
*/
private Object bizExt;
public Map<String, Object> getVariables() { public Map<String, Object> getVariables() {
if (variables == null) { if (variables == null) {
return new HashMap<>(16); return new HashMap<>(16);
@ -42,4 +50,13 @@ public class RemoteStartProcess implements Serializable {
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
return variables; return variables;
} }
//从hwbm的新版本plus框架中直接复制未经过测试
public Object getBizExt() {
if (ObjectUtil.isNull(bizExt)) {
bizExt = new Object();
}
return bizExt;
}
} }

@ -0,0 +1,60 @@
package org.dromara.workflow.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.tenant.core.TenantEntity;
import java.io.Serial;
/**
* hwbmplus
* flow_instance_biz_ext
*
* @author may
* @date 2025-08-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("flow_instance_biz_ext")
public class FlowInstanceBizExt extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId(value = "id")
private Long id;
/**
* ID
*/
private Long instanceId;
/**
* ID
*/
private String businessId;
/**
*
*/
private String businessCode;
/**
*
*/
private String businessTitle;
/**
* 0 1
*/
@TableLogic
private String delFlag;
}

@ -1,6 +1,7 @@
package org.dromara.workflow.domain.bo; package org.dromara.workflow.domain.bo;
import cn.hutool.core.util.ObjectUtil;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import org.dromara.common.core.validate.AddGroup; import org.dromara.common.core.validate.AddGroup;
@ -39,6 +40,13 @@ public class StartProcessBo implements Serializable {
*/ */
private Map<String, Object> variables; private Map<String, Object> variables;
/**
* hwbmplus
*
*
*/
private Object bizExt;
public Map<String, Object> getVariables() { public Map<String, Object> getVariables() {
if (variables == null) { if (variables == null) {
return new HashMap<>(16); return new HashMap<>(16);
@ -46,4 +54,13 @@ public class StartProcessBo implements Serializable {
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
return variables; return variables;
} }
//从hwbm的新版本plus框架中直接复制未经过测试
public Object getBizExt() {
if (ObjectUtil.isNull(bizExt)) {
bizExt = new Object();
}
return bizExt;
}
} }

@ -83,4 +83,10 @@ public class RemoteWorkflowServiceImpl implements RemoteWorkflowService {
return workflowService.getCurrentTaskIdByInstanceId(instanceId); return workflowService.getCurrentTaskIdByInstanceId(instanceId);
} }
//从hwbm的新版本plus框架中直接复制未经过测试
@Override
public boolean startCompleteTask(RemoteStartProcess startProcess) {
return workflowService.startCompleteTask(startProcess);
}
} }

@ -109,4 +109,17 @@ public interface WorkflowService {
*/ */
Long getCurrentTaskIdByInstanceId(Long instanceId); Long getCurrentTaskIdByInstanceId(Long instanceId);
/**
* hwbmplus
*
* <p>
* startWorkFlow() completeTask()
* 使
* </p>
*
* @param startProcess flowCode, businessId, variables
* @return true=, false=
*/
boolean startCompleteTask(RemoteStartProcess startProcess);
} }

@ -4,12 +4,15 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.warm.flow.orm.entity.FlowInstance; import org.dromara.warm.flow.orm.entity.FlowInstance;
import org.dromara.workflow.api.domain.RemoteCompleteTask; import org.dromara.workflow.api.domain.RemoteCompleteTask;
import org.dromara.workflow.api.domain.RemoteStartProcess; import org.dromara.workflow.api.domain.RemoteStartProcess;
import org.dromara.workflow.api.domain.RemoteStartProcessReturn; import org.dromara.workflow.api.domain.RemoteStartProcessReturn;
import org.dromara.workflow.common.ConditionalOnEnable; import org.dromara.workflow.common.ConditionalOnEnable;
import org.dromara.workflow.common.enums.MessageTypeEnum;
import org.dromara.workflow.domain.FlowInstanceBizExt;
import org.dromara.workflow.domain.bo.CompleteTaskBo; import org.dromara.workflow.domain.bo.CompleteTaskBo;
import org.dromara.workflow.domain.bo.StartProcessBo; import org.dromara.workflow.domain.bo.StartProcessBo;
import org.dromara.workflow.service.IFlwDefinitionService; import org.dromara.workflow.service.IFlwDefinitionService;
@ -17,7 +20,10 @@ import org.dromara.workflow.service.IFlwInstanceService;
import org.dromara.workflow.service.IFlwTaskService; import org.dromara.workflow.service.IFlwTaskService;
import org.dromara.workflow.service.WorkflowService; import org.dromara.workflow.service.WorkflowService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -198,4 +204,129 @@ public class WorkflowServiceImpl implements WorkflowService {
} }
} }
/**
*
* <p>
* startWorkFlow() completeTask()
* 使
* </p>
* <p>
*
* <ul>
* <li>1. 1 flow_instance flow_task</li>
* <li>2. 1</li>
* <li>3. 2</li>
* </ul>
* </p>
*
* @param startProcess
* @return true=, false=
*/
// @Override
// public boolean startCompleteTask(RemoteStartProcess startProcess) {
// try {
// // 阶段1启动流程独立事务
// // startWorkFlow() 方法已有 @Transactional 注解,会在独立事务中执行
// RemoteStartProcessReturn startResult = flwTaskService.startWorkFlow(
// BeanUtil.toBean(startProcess, StartProcessBo.class)
// );
//
// if (startResult == null || startResult.getTaskId() == null) {
// log.error("启动工作流失败flowCode: {}, businessId: {}",
// startProcess.getFlowCode(), startProcess.getBusinessId());
// return false;
// }
//
// Long taskId = startResult.getTaskId();
//
// // 阶段1事务已提交数据库锁已释放
//
// // 阶段2推进流程新独立事务
// // 使用 REQUIRES_NEW 确保在新事务中执行避免与阶段1的事务冲突
// return completeTaskInNewTransaction(taskId, startProcess);
//
// } catch (Exception e) {
// log.error("startCompleteTask 执行异常flowCode: {}, businessId: {}, error: {}",
// startProcess.getFlowCode(), startProcess.getBusinessId(), e.getMessage(), e);
// return false;
// }
// }
/**
*
* <p>
* 使 REQUIRES_NEW
* startWorkFlow()
* </p>
*
* @param taskId ID
* @param startProcess variables
* @return true=, false=
*/
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
protected boolean completeTaskInNewTransaction(Long taskId, RemoteStartProcess startProcess) {
try {
RemoteCompleteTask completeTask = new RemoteCompleteTask();
completeTask.setTaskId(taskId);
// 传递 variables如果有
// variables 可以包含流程分支条件、message、messageType、notice 等参数
if (startProcess.getVariables() != null && !startProcess.getVariables().isEmpty()) {
completeTask.setVariables(startProcess.getVariables());
}
// 调用 completeTask在新事务中
boolean result = flwTaskService.completeTask(BeanUtil.toBean(completeTask, CompleteTaskBo.class));
if (result) {
log.info("工作流启动并推进成功flowCode: {}, businessId: {}, taskId: {}",
startProcess.getFlowCode(), startProcess.getBusinessId(), taskId);
} else {
log.warn("工作流推进失败flowCode: {}, businessId: {}, taskId: {}",
startProcess.getFlowCode(), startProcess.getBusinessId(), taskId);
}
return result;
} catch (Exception e) {
log.error("completeTaskInNewTransaction 执行异常taskId: {}, businessId: {}, error: {}",
taskId, startProcess.getBusinessId(), e.getMessage(), e);
throw e; // 重新抛出异常,触发事务回滚
}
}
/**
*
* hwbmplus
*
* @param startProcess
*/
@Override
public boolean startCompleteTask(RemoteStartProcess startProcess) {
try {
StartProcessBo processBo = new StartProcessBo();
processBo.setBusinessId(startProcess.getBusinessId());
processBo.setFlowCode(startProcess.getFlowCode());
processBo.setVariables(startProcess.getVariables());
// processBo.setHandler(startProcess.getHandler());
processBo.setBizExt(BeanUtil.toBean(startProcess.getBizExt(), FlowInstanceBizExt.class));
RemoteStartProcessReturn result = flwTaskService.startWorkFlow(processBo);
CompleteTaskBo taskBo = new CompleteTaskBo();
taskBo.setTaskId(result.getTaskId());
taskBo.setMessageType(Collections.singletonList(MessageTypeEnum.SYSTEM_MESSAGE.getCode()));
taskBo.setVariables(startProcess.getVariables());
// taskBo.setHandler(startProcess.getHandler());
boolean flag = flwTaskService.completeTask(taskBo);
if (!flag) {
throw new ServiceException("流程发起异常");
}
return true;
} catch (Exception e) {
throw new ServiceException(e.getMessage());
}
}
} }

Loading…
Cancel
Save