fix:支持任意节点开始执行

This commit is contained in:
2026-03-26 16:37:02 +08:00
parent c53d9f9363
commit c3db0d2fdc
6 changed files with 81 additions and 11 deletions

View File

@@ -21,10 +21,10 @@ public class FlowableClientFeignClientImpl implements IFlowableFeignClient {
@Autowired
private IFlowableFeignClient flowableFeignClient;
public SdmResponse<ProcessInstanceResp> startByProcessDefinitionId(String processDefinitionId, Map<String, Object> variables) {
public SdmResponse<ProcessInstanceResp> startByProcessDefinitionId(String processDefinitionId,String targetNodeId, Map<String, Object> variables) {
SdmResponse<ProcessInstanceResp> response;
try {
response = flowableFeignClient.startByProcessDefinitionId(processDefinitionId, variables);
response = flowableFeignClient.startByProcessDefinitionId(processDefinitionId,targetNodeId, variables);
log.info("启动流程实例:"+ response);
return response;
} catch (Exception e) {

View File

@@ -20,7 +20,7 @@ import java.util.Map;
public interface IFlowableFeignClient {
@GetMapping("/process/startByProcessDefinitionId")
SdmResponse<ProcessInstanceResp> startByProcessDefinitionId(@RequestParam String processDefinitionId, @RequestBody(required = false) Map<String, Object> variables);
SdmResponse<ProcessInstanceResp> startByProcessDefinitionId(@RequestParam String processDefinitionId, @RequestParam(required = false) String targetNodeId, @RequestBody(required = false) Map<String, Object> variables);
@PostMapping("/process/deploy")
SdmResponse<DeployFlowableResp> deploy(@RequestBody ProcessDefinitionDTO processDTO);

View File

@@ -119,14 +119,23 @@ public class ProcessController implements IFlowableFeignClient {
* 根据流程定义ID启动流程实例
*
* @param processDefinitionId 流程定义ID指定版本
* @param targetNodeId 可选,指定从该节点启动(内部会智能修正到真实入口节点)
* @param variables 可选的流程启动变量
*/
@PostMapping("/startByProcessDefinitionId")
public SdmResponse startByProcessDefinitionId(
@RequestParam String processDefinitionId,
@RequestParam(required = false) String targetNodeId,
@RequestBody(required = false) Map<String, Object> variables) {
log.info("开始启动流程定义: {}",processDefinitionId);
ProcessInstance processInstance = processService.startByProcessDefinitionId(processDefinitionId, variables);
log.info("开始启动流程定义: {}, targetNodeId: {}", processDefinitionId, targetNodeId);
ProcessInstance processInstance;
if (targetNodeId != null && !targetNodeId.isBlank()) {
processInstance = processService.startProcessAtNode(processDefinitionId, targetNodeId, variables);
} else {
processInstance = processService.startByProcessDefinitionId(processDefinitionId, variables);
}
ProcessInstanceResp processInstanceResp = new ProcessInstanceResp();
processInstanceResp.setProcessInstanceId(processInstance.getId());
processInstanceResp.setProcessDefinitionId(processInstance.getProcessDefinitionId());

View File

@@ -46,6 +46,7 @@ import org.flowable.validation.ProcessValidatorFactory;
import org.flowable.validation.ValidationError;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
@@ -149,14 +150,71 @@ public class ProcessService implements Iprocess{
if (variables == null) {
variables = Collections.emptyMap();
}
log.info("根据流程定义ID启动流程实例, 流程定义ID: {}, 变量数量: {}", processDefinitionId, variables.size());
ProcessInstance instance = runtimeService.startProcessInstanceById(processDefinitionId, variables);
log.info("流程实例启动成功, 实例ID: {}, 流程定义ID: {}, 业务Key: {}",
instance.getId(), instance.getProcessDefinitionId(), instance.getBusinessKey());
log.info("流程实例启动成功, 实例ID: {}, 流程定义ID: {}, 业务Key: {}",
instance.getId(), instance.getProcessDefinitionId(), instance.getBusinessKey());
return instance;
}
/**
* 从任意节点启动流程(利用 StartEvent 异步特性,在同事务内启动 + 跳转)
*
* @param processDefinitionId 流程定义ID
* @param targetNodeId 目标节点ID可传原始节点ID或复合节点ID
* @param variables 流程变量
* @return 启动后的流程实例
*/
@Transactional(rollbackFor = Exception.class)
public ProcessInstance startProcessAtNode(String processDefinitionId, String targetNodeId, Map<String, Object> variables) {
log.info("开始从指定节点启动流程. 流程定义: {}, 目标节点: {}", processDefinitionId, targetNodeId);
// 1. 获取 BPMN 模型
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
if (bpmnModel == null || bpmnModel.getMainProcess() == null) {
throw new RuntimeException("流程定义不存在: " + processDefinitionId);
}
// 2. 找 StartEvent
StartEvent startEvent = bpmnModel.getMainProcess().findFlowElementsOfType(StartEvent.class).stream()
.findFirst()
.orElseThrow(() -> new RuntimeException("流程模型中缺少 StartEvent"));
String startEventId = startEvent.getId();
// 3. 智能修正目标节点(复用现有复合节点规则)
String realTargetNodeId = targetNodeId;
String originalNodeId = FlowNodeIdUtils.parseOriginalNodeId(targetNodeId);
String registerNodeId = FlowNodeIdUtils.generateRegisterTaskId(originalNodeId);
String waitUserNodeId = FlowNodeIdUtils.generateWaitUserTaskId(originalNodeId);
if (bpmnModel.getMainProcess().getFlowElement(registerNodeId) != null) {
realTargetNodeId = registerNodeId;
} else if (bpmnModel.getMainProcess().getFlowElement(waitUserNodeId) != null) {
realTargetNodeId = waitUserNodeId;
} else if (bpmnModel.getMainProcess().getFlowElement(realTargetNodeId) == null) {
throw new RuntimeException("目标节点不存在: " + targetNodeId);
}
log.info("原始目标节点: {}, 智能修正后的真实入口: {}", targetNodeId, realTargetNodeId);
// 4. 启动流程StartEvent 异步,流程会先停在 StartEvent
if (variables == null) {
variables = new HashMap<>();
}
ProcessInstance instance = runtimeService.startProcessInstanceById(processDefinitionId, variables);
// 5. 同事务内立刻跳转到目标节点
runtimeService.createChangeActivityStateBuilder()
.processInstanceId(instance.getId())
.moveActivityIdTo(startEventId, realTargetNodeId)
.changeState();
log.info("流程已成功从节点 [{}] 启动实例ID: {}", realTargetNodeId, instance.getId());
return instance;
}

View File

@@ -18,5 +18,8 @@ public class SpdmTaskRunReq {
@Schema(description = "流程模板id")
private String templateId;
@Schema(description = "指定启动节点")
private String targetNodeId;
}

View File

@@ -2512,7 +2512,7 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
variables.put("userName", ThreadLocalContext.getUserName());
variables.put("tenantId", ThreadLocalContext.getTenantId());
// 启动流程实例 多次执行会生成多个流程实例id更新算例run表、同时更新flowable流程参数的流程实例id
SdmResponse<ProcessInstanceResp> sdmResponse = flowableFeignClient.startByProcessDefinitionId(simulationRun.getProcessDefinitionId(), variables);
SdmResponse<ProcessInstanceResp> sdmResponse = flowableFeignClient.startByProcessDefinitionId(simulationRun.getProcessDefinitionId(),req.getTargetNodeId(), variables);
if (sdmResponse.getData() != null) {
this.lambdaUpdate()
.set(SimulationRun::getFlowInstanceId, sdmResponse.getData().getProcessInstanceId())