反序列化问题。
This commit is contained in:
parent
d298a8770c
commit
45e6d70ca4
@ -1052,3 +1052,43 @@ eventSource.addEventListener('STDERR', (event) => {
|
|||||||
eventSource.onerror = () => {
|
eventSource.onerror = () => {
|
||||||
eventSource.close();
|
eventSource.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
hi.PROC_INST_ID_ as process_instance_id,
|
||||||
|
hi.PROC_DEF_ID_ as process_definition_id,
|
||||||
|
hi.START_TIME_ as start_time,
|
||||||
|
hi.END_TIME_ as end_time,
|
||||||
|
hi.DELETE_REASON_ as delete_reason,
|
||||||
|
-- 使用 GROUP_CONCAT 合并错误信息
|
||||||
|
GROUP_CONCAT(DISTINCT
|
||||||
|
CASE
|
||||||
|
WHEN var.NAME_ = 'errorDetail' THEN var.TEXT_
|
||||||
|
WHEN var.NAME_ IN ('errorMessage', 'error', 'exception') THEN var.TEXT_
|
||||||
|
END
|
||||||
|
SEPARATOR '; '
|
||||||
|
) as error_message,
|
||||||
|
-- 获取最后一个活动节点
|
||||||
|
MAX(CASE WHEN act.END_TIME_ IS NULL THEN act.ACT_NAME_ END) as last_activity_name,
|
||||||
|
MAX(CASE WHEN act.END_TIME_ IS NULL THEN act.ACT_ID_ END) as last_activity_id
|
||||||
|
FROM
|
||||||
|
ACT_HI_PROCINST hi
|
||||||
|
LEFT JOIN
|
||||||
|
ACT_HI_VARINST var ON hi.PROC_INST_ID_ = var.PROC_INST_ID_
|
||||||
|
LEFT JOIN
|
||||||
|
ACT_HI_ACTINST act ON hi.PROC_INST_ID_ = act.PROC_INST_ID_
|
||||||
|
WHERE
|
||||||
|
hi.PROC_INST_ID_ = '86faae44-bc47-11ef-a4cd-00155dcaffac'
|
||||||
|
AND (
|
||||||
|
var.NAME_ IN ('errorDetail', 'errorMessage', 'error', 'exception')
|
||||||
|
OR var.TEXT_ LIKE '%error%'
|
||||||
|
OR var.TEXT_ LIKE '%exception%'
|
||||||
|
OR var.TEXT_ LIKE '%失败%'
|
||||||
|
)
|
||||||
|
GROUP BY
|
||||||
|
hi.PROC_INST_ID_,
|
||||||
|
hi.PROC_DEF_ID_,
|
||||||
|
hi.START_TIME_,
|
||||||
|
hi.END_TIME_,
|
||||||
|
hi.DELETE_REASON_
|
||||||
|
ORDER BY
|
||||||
|
hi.START_TIME_ DESC;
|
||||||
@ -26,7 +26,7 @@
|
|||||||
<jjwt.version>0.12.3</jjwt.version>
|
<jjwt.version>0.12.3</jjwt.version>
|
||||||
<springdoc.version>2.2.0</springdoc.version>
|
<springdoc.version>2.2.0</springdoc.version>
|
||||||
<hutool.version>5.8.23</hutool.version>
|
<hutool.version>5.8.23</hutool.version>
|
||||||
<flowable.version>7.0.0</flowable.version>
|
<flowable.version>7.1.0</flowable.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
@ -222,6 +222,11 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<!-- <dependency>-->
|
<!-- <dependency>-->
|
||||||
<!-- <groupId>org.flowable</groupId>-->
|
<!-- <groupId>org.flowable</groupId>-->
|
||||||
|
<!-- <artifactId>flowable-bpmn-model</artifactId>-->
|
||||||
|
<!-- <version>${flowable.version}</version> <!– 使用您项目中的版本 –>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.flowable</groupId>-->
|
||||||
<!-- <artifactId>flowable-spring-boot-starter-rest</artifactId>-->
|
<!-- <artifactId>flowable-spring-boot-starter-rest</artifactId>-->
|
||||||
<!-- <version>${flowable.version}</version>-->
|
<!-- <version>${flowable.version}</version>-->
|
||||||
<!-- </dependency>-->
|
<!-- </dependency>-->
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import com.qqchen.deploy.backend.workflow.dto.WorkflowDefinitionDTO;
|
|||||||
import com.qqchen.deploy.backend.workflow.dto.WorkflowExecutionDTO;
|
import com.qqchen.deploy.backend.workflow.dto.WorkflowExecutionDTO;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceDTO;
|
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceDTO;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceStartRequest;
|
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceStartRequest;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.WorkflowTemplateWithInstancesDTO;
|
||||||
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
|
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
|
||||||
import com.qqchen.deploy.backend.workflow.entity.WorkflowInstance;
|
import com.qqchen.deploy.backend.workflow.entity.WorkflowInstance;
|
||||||
import com.qqchen.deploy.backend.workflow.query.WorkflowDefinitionQuery;
|
import com.qqchen.deploy.backend.workflow.query.WorkflowDefinitionQuery;
|
||||||
@ -24,6 +25,7 @@ import org.flowable.engine.RuntimeService;
|
|||||||
import org.flowable.engine.history.HistoricActivityInstance;
|
import org.flowable.engine.history.HistoricActivityInstance;
|
||||||
import org.flowable.engine.history.HistoricProcessInstance;
|
import org.flowable.engine.history.HistoricProcessInstance;
|
||||||
import org.flowable.variable.api.history.HistoricVariableInstance;
|
import org.flowable.variable.api.history.HistoricVariableInstance;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
@ -56,6 +58,13 @@ public class WorkflowInstanceApiController extends BaseController<WorkflowInstan
|
|||||||
return Response.success();
|
return Response.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "查询已发布流程模板及其最近实例")
|
||||||
|
@GetMapping("/templates-with-instances")
|
||||||
|
public Response<Page<WorkflowTemplateWithInstancesDTO>> getTemplatesWithInstances(WorkflowDefinitionQuery query) {
|
||||||
|
return Response.success(workflowInstanceService.findTemplatesWithRecentInstances(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void exportData(HttpServletResponse response, List<WorkflowInstanceDTO> data) {
|
protected void exportData(HttpServletResponse response, List<WorkflowInstanceDTO> data) {
|
||||||
|
|
||||||
|
|||||||
@ -103,7 +103,7 @@ public class WorkflowNodeInstanceApiController extends BaseController<WorkflowNo
|
|||||||
emitter.completeWithError(e);
|
emitter.completeWithError(e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.warn("No emitter found for process: {}", processInstanceId);
|
// log.warn("No emitter found for process: {}", processInstanceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,4 +10,5 @@ public interface WorkFlowConstants {
|
|||||||
|
|
||||||
String SEQUENCE_FLOW_ERROR_PREFIX = "SEQUENCE_FLOW_ERROR_";
|
String SEQUENCE_FLOW_ERROR_PREFIX = "SEQUENCE_FLOW_ERROR_";
|
||||||
|
|
||||||
|
String ASYNC_CONTINUATION = "async-continuation";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,21 +65,21 @@ public class ShellTaskDelegate implements JavaDelegate {
|
|||||||
// 如果流程变量中有值,优先使用流程变量
|
// 如果流程变量中有值,优先使用流程变量
|
||||||
if (execution.hasVariable("script")) {
|
if (execution.hasVariable("script")) {
|
||||||
scriptValue = (String) execution.getVariable("script");
|
scriptValue = (String) execution.getVariable("script");
|
||||||
log.info("从流程变量获取到script={}", scriptValue);
|
// log.info("从流程变量获取到script={}", scriptValue);
|
||||||
}
|
}
|
||||||
if (execution.hasVariable("workDir")) {
|
if (execution.hasVariable("workDir")) {
|
||||||
workDirValue = (String) execution.getVariable("workDir");
|
workDirValue = (String) execution.getVariable("workDir");
|
||||||
log.info("从流程变量获取到workDir={}", workDirValue);
|
// log.info("从流程变量获取到workDir={}", workDirValue);
|
||||||
}
|
}
|
||||||
if (execution.hasVariable("env")) {
|
if (execution.hasVariable("env")) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, String> envFromVar = (Map<String, String>) execution.getVariable("env");
|
Map<String, String> envFromVar = (Map<String, String>) execution.getVariable("env");
|
||||||
envValue = envFromVar;
|
envValue = envFromVar;
|
||||||
log.info("从流程变量获取到env={}", envValue);
|
// log.info("从流程变量获取到env={}", envValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scriptValue == null) {
|
if (scriptValue == null) {
|
||||||
log.error("脚本内容为空,执行失败");
|
// log.error("脚本内容为空,执行失败");
|
||||||
throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, "Script is required but not provided");
|
throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, "Script is required but not provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,16 +169,18 @@ public class ShellTaskDelegate implements JavaDelegate {
|
|||||||
|
|
||||||
if (exitCode != 0) {
|
if (exitCode != 0) {
|
||||||
log.error("Shell脚本执行失败,退出码: {}", exitCode);
|
log.error("Shell脚本执行失败,退出码: {}", exitCode);
|
||||||
log.error("错误输出: {}", finalError);
|
execution.setVariable("errorDetail", "Shell脚本执行失败,退出码: " + exitCode);
|
||||||
throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, "Shell脚本执行失败,退出码: " + exitCode);
|
throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, "Shell脚本执行失败,退出码: " + exitCode);
|
||||||
|
// throw new RuntimeException("Shell脚本执行失败,退出码: " + exitCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Shell脚本执行成功");
|
log.info("Shell脚本执行成功");
|
||||||
log.debug("脚本输出: {}", finalOutput);
|
log.debug("脚本输出: {}", finalOutput);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Shell脚本执行失败", e);
|
log.error("Shell脚本执行失败", e);
|
||||||
throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, "Shell脚本执行失败");
|
// runtimeService.deleteProcessInstance(execution.getProcessInstanceId(), e.getMessage());
|
||||||
|
// throw new FlowableException("任务执行失败: " + e.getMessage(), e);
|
||||||
|
throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,13 +197,13 @@ public class ShellTaskDelegate implements JavaDelegate {
|
|||||||
synchronized (output) {
|
synchronized (output) {
|
||||||
output.append(line).append("\n");
|
output.append(line).append("\n");
|
||||||
}
|
}
|
||||||
log.info("Shell output: {}", line);
|
// log.info("Shell output: {}", line);
|
||||||
} else {
|
} else {
|
||||||
StringBuilder error = errorMap.get(processInstanceId);
|
StringBuilder error = errorMap.get(processInstanceId);
|
||||||
synchronized (error) {
|
synchronized (error) {
|
||||||
error.append(line).append("\n");
|
error.append(line).append("\n");
|
||||||
}
|
}
|
||||||
log.error("Shell error: {}", line);
|
// log.error("Shell error: {}", line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.dto;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnums;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class WorkflowTemplateWithInstancesDTO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String businessKey;
|
||||||
|
|
||||||
|
private LocalDateTime lastExecutionTime;
|
||||||
|
|
||||||
|
private WorkflowInstanceStatusEnums lastExecutionStatus;
|
||||||
|
|
||||||
|
}
|
||||||
@ -10,6 +10,8 @@ import lombok.Getter;
|
|||||||
@Getter
|
@Getter
|
||||||
public enum WorkflowInstanceStatusEnums {
|
public enum WorkflowInstanceStatusEnums {
|
||||||
|
|
||||||
|
NOT_STARTED("NOT_STARTED", "未开始"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 已创建:流程实例已创建但还未开始运行
|
* 已创建:流程实例已创建但还未开始运行
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -2,14 +2,20 @@ package com.qqchen.deploy.backend.workflow.listener;
|
|||||||
|
|
||||||
import com.qqchen.deploy.backend.workflow.listener.handler.IFlowableEventHandler;
|
import com.qqchen.deploy.backend.workflow.listener.handler.IFlowableEventHandler;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
|
||||||
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
|
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
|
||||||
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
|
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
|
||||||
|
import org.flowable.engine.RuntimeService;
|
||||||
|
import org.flowable.job.service.impl.persistence.entity.JobEntityImpl;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants.ASYNC_CONTINUATION;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
public class FlowableEventDispatcher implements FlowableEventListener {
|
public class FlowableEventDispatcher implements FlowableEventListener {
|
||||||
@ -18,18 +24,20 @@ public class FlowableEventDispatcher implements FlowableEventListener {
|
|||||||
@Lazy
|
@Lazy
|
||||||
private List<IFlowableEventHandler> eventHandlers;
|
private List<IFlowableEventHandler> eventHandlers;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
@Lazy
|
||||||
|
private RuntimeService runtimeService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(FlowableEvent event) {
|
public void onEvent(FlowableEvent event) {
|
||||||
String eventType = event.getType().name();
|
String eventType = event.getType().name();
|
||||||
// log.info("Dispatching Flowable event: {}, event class: {}", eventType, event.getClass().getName());
|
log.info("Dispatching Flowable event: {}, event class: {}", eventType, event.getClass().getName());
|
||||||
|
|
||||||
for (IFlowableEventHandler handler : eventHandlers) {
|
for (IFlowableEventHandler handler : eventHandlers) {
|
||||||
if (handler.canHandle(eventType)) {
|
if (handler.canHandle(eventType)) {
|
||||||
try {
|
try {
|
||||||
handler.handle(event);
|
handler.handle(event);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error handling event {} by handler {}: {}",
|
log.error("Error handling event {} by handler {}: {}", eventType, handler.getClass().getSimpleName(), e.getMessage(), e);
|
||||||
eventType, handler.getClass().getSimpleName(), e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,179 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.workflow.listener;
|
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
|
||||||
import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnums;
|
|
||||||
import com.qqchen.deploy.backend.workflow.enums.WorkflowNodeInstanceStatusEnums;
|
|
||||||
import com.qqchen.deploy.backend.workflow.event.WorkflowInstanceStatusChangeEvent;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
|
|
||||||
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
|
|
||||||
import org.flowable.common.engine.api.delegate.event.FlowableEventType;
|
|
||||||
import org.flowable.engine.HistoryService;
|
|
||||||
import org.flowable.engine.delegate.event.FlowableProcessEngineEvent;
|
|
||||||
import org.flowable.engine.history.HistoricProcessInstance;
|
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
|
|
||||||
//@Component
|
|
||||||
@Slf4j
|
|
||||||
public class FlowableJobEventListener implements FlowableEventListener {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private ApplicationEventPublisher publisher;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
@Lazy
|
|
||||||
private HistoryService historyService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEvent(FlowableEvent event) {
|
|
||||||
FlowableEventType eventType = event.getType();
|
|
||||||
log.info("Received Flowable event: {}, event class: {}", eventType, event.getClass().getName());
|
|
||||||
// 只处理实体事件
|
|
||||||
// if (!(event instanceof FlowableEngineEntityEvent entity)) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// String processInstanceId = entity.getProcessInstanceId();
|
|
||||||
|
|
||||||
if (isProcessLevelEvent(eventType.name())) {
|
|
||||||
FlowableProcessEngineEvent flowableEntity = (FlowableProcessEngineEvent) event;
|
|
||||||
WorkflowInstanceStatusEnums status = convertProcessLevelEventToStatus(eventType.name());
|
|
||||||
log.info("Process level event received: {} -> {}, processInstanceId: {}", eventType, status, null);
|
|
||||||
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
|
|
||||||
.processInstanceId(flowableEntity.getProcessInstanceId())
|
|
||||||
.singleResult();
|
|
||||||
publisher.publishEvent(WorkflowInstanceStatusChangeEvent.builder()
|
|
||||||
.processInstanceId(flowableEntity.getProcessInstanceId())
|
|
||||||
.status(status)
|
|
||||||
.endTime(DateUtil.toLocalDateTime(historicProcessInstance.getEndTime()))
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isTaskInstanceEvent(eventType.name())) {
|
|
||||||
// WorkflowNodeInstanceStatusEnums status = convertJobEventToStatus(eventType.name());
|
|
||||||
// // 获取Job信息
|
|
||||||
// String executionId = entity.getExecutionId();
|
|
||||||
// org.flowable.job.api.Job job = (org.flowable.job.service.impl.persistence.entity.JobEntityImpl) entity.getEntity();
|
|
||||||
// String activityId = job.getElementId();
|
|
||||||
// String activityName = job.getElementName();
|
|
||||||
// String activityType = job.getJobHandlerType();
|
|
||||||
//
|
|
||||||
// LocalDateTime startTime = job.getCreateTime() != null ? DateUtil.toLocalDateTime(job.getCreateTime()) : null;
|
|
||||||
// LocalDateTime endTime = null;
|
|
||||||
// if (status == WorkflowNodeInstanceStatusEnums.COMPLETED ||
|
|
||||||
// status == WorkflowNodeInstanceStatusEnums.FAILED) {
|
|
||||||
// endTime = LocalDateTime.now(); // 对于完成或失败状态,使用当前时间作为结束时间
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// publisher.publishEvent(WorkflowNodeInstanceStatusChangeEvent.builder()
|
|
||||||
// .processInstanceId(processInstanceId)
|
|
||||||
// .executionId(executionId)
|
|
||||||
// .nodeId(activityId)
|
|
||||||
// .nodeName(activityName)
|
|
||||||
// .nodeType(activityType)
|
|
||||||
// .status(status)
|
|
||||||
// .startTime(startTime)
|
|
||||||
// .endTime(endTime)
|
|
||||||
// .build()
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// log.info("Job event received: {} -> {}, processInstanceId: {}, nodeId: {}, nodeName: {}",
|
|
||||||
// eventType, status, processInstanceId, activityId, activityName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isFailOnException() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isFireOnTransactionLifecycleEvent() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getOnTransaction() {
|
|
||||||
return "committed";
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isProcessLevelEvent(String eventType) {
|
|
||||||
return eventType.startsWith("PROCESS_");
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isTaskInstanceEvent(String eventType) {
|
|
||||||
return eventType.startsWith("JOB_EXECUTION_") ||
|
|
||||||
eventType.startsWith("ACTIVITY_"); // 添加对 ACTIVITY_ 事件的监听
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将Flowable流程级别事件类型转换为工作流实例状态
|
|
||||||
* 只处理流程实例级别的事件,不处理活动节点级别的事件
|
|
||||||
*
|
|
||||||
* @param eventType Flowable事件类型
|
|
||||||
* @return 工作流实例状态枚举,如果不是流程级别事件则返回null
|
|
||||||
*/
|
|
||||||
private WorkflowInstanceStatusEnums convertProcessLevelEventToStatus(String eventType) {
|
|
||||||
switch (eventType) {
|
|
||||||
// 创建相关
|
|
||||||
case "PROCESS_CREATED":
|
|
||||||
return WorkflowInstanceStatusEnums.CREATED;
|
|
||||||
|
|
||||||
// 运行相关
|
|
||||||
case "PROCESS_STARTED":
|
|
||||||
return WorkflowInstanceStatusEnums.RUNNING;
|
|
||||||
|
|
||||||
// 暂停相关
|
|
||||||
case "PROCESS_SUSPENDED":
|
|
||||||
return WorkflowInstanceStatusEnums.SUSPENDED;
|
|
||||||
|
|
||||||
// 恢复相关
|
|
||||||
case "PROCESS_RESUMED":
|
|
||||||
return WorkflowInstanceStatusEnums.RUNNING;
|
|
||||||
|
|
||||||
// 完成相关
|
|
||||||
case "PROCESS_COMPLETED":
|
|
||||||
return WorkflowInstanceStatusEnums.COMPLETED;
|
|
||||||
|
|
||||||
// 终止相关
|
|
||||||
case "PROCESS_CANCELLED":
|
|
||||||
return WorkflowInstanceStatusEnums.TERMINATED;
|
|
||||||
|
|
||||||
// 失败相关
|
|
||||||
case "PROCESS_COMPLETED_WITH_ERROR_END_EVENT":
|
|
||||||
return WorkflowInstanceStatusEnums.FAILED;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// 不是流程级别的事件,返回null
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将Flowable活动节点事件类型转换为工作流节点实例状态
|
|
||||||
*
|
|
||||||
* @param eventType Flowable事件类型
|
|
||||||
* @return 工作流节点实例状态枚举,如果不是节点级别事件则返回null
|
|
||||||
*/
|
|
||||||
private WorkflowNodeInstanceStatusEnums convertJobEventToStatus(String eventType) {
|
|
||||||
switch (eventType) {
|
|
||||||
case "JOB_EXECUTION_SUCCESS":
|
|
||||||
return WorkflowNodeInstanceStatusEnums.COMPLETED;
|
|
||||||
case "JOB_EXECUTION_START":
|
|
||||||
return WorkflowNodeInstanceStatusEnums.RUNNING;
|
|
||||||
case "JOB_EXECUTION_FAILURE":
|
|
||||||
return WorkflowNodeInstanceStatusEnums.FAILED;
|
|
||||||
case "JOB_EXECUTION_REJECTED": // 当作业被拒绝执行时
|
|
||||||
return WorkflowNodeInstanceStatusEnums.FAILED;
|
|
||||||
case "JOB_EXECUTION_NOJOB_FOUND": // 当找不到要执行的作业时
|
|
||||||
return WorkflowNodeInstanceStatusEnums.FAILED;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -3,13 +3,21 @@ package com.qqchen.deploy.backend.workflow.listener.handler;
|
|||||||
import com.qqchen.deploy.backend.workflow.enums.WorkflowNodeInstanceStatusEnums;
|
import com.qqchen.deploy.backend.workflow.enums.WorkflowNodeInstanceStatusEnums;
|
||||||
import com.qqchen.deploy.backend.workflow.event.WorkflowNodeInstanceStatusChangeEvent;
|
import com.qqchen.deploy.backend.workflow.event.WorkflowNodeInstanceStatusChangeEvent;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
|
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
|
||||||
import org.flowable.engine.delegate.event.FlowableActivityEvent;
|
import org.flowable.engine.delegate.event.FlowableActivityEvent;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants.BOUNDARY_EVENT_ERROR_PREFIX;
|
||||||
|
import static com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants.END_EVENT_ERROR_PREFIX;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@ -18,6 +26,7 @@ public class ActivityEventHandler implements IFlowableEventHandler {
|
|||||||
@Resource
|
@Resource
|
||||||
private ApplicationEventPublisher publisher;
|
private ApplicationEventPublisher publisher;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canHandle(String eventType) {
|
public boolean canHandle(String eventType) {
|
||||||
return eventType.startsWith("ACTIVITY_");
|
return eventType.startsWith("ACTIVITY_");
|
||||||
@ -26,26 +35,31 @@ public class ActivityEventHandler implements IFlowableEventHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void handle(FlowableEvent event) {
|
public void handle(FlowableEvent event) {
|
||||||
String eventType = event.getType().name();
|
String eventType = event.getType().name();
|
||||||
// log.info("Processing activity event: {}", eventType);
|
|
||||||
|
|
||||||
if (!(event instanceof FlowableActivityEvent activityEvent)) {
|
if (!(event instanceof FlowableActivityEvent activityEvent)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
log.info("Processing Flowable event: {}, id: {}, name:{}", eventType, activityEvent.getActivityId(), activityEvent.getActivityName());
|
||||||
|
|
||||||
|
List<String> ignoredList = Arrays.asList(BOUNDARY_EVENT_ERROR_PREFIX, END_EVENT_ERROR_PREFIX);
|
||||||
|
|
||||||
|
boolean ignored = ignoredList.stream().anyMatch(v -> activityEvent.getActivityId().contains(v));
|
||||||
|
if (ignored) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
WorkflowNodeInstanceStatusEnums status = convertToNodeStatus(eventType);
|
WorkflowNodeInstanceStatusEnums status = convertToNodeStatus(eventType);
|
||||||
|
|
||||||
if (status != null) {
|
if (status != null) {
|
||||||
// publisher.publishEvent(WorkflowNodeInstanceStatusChangeEvent.builder()
|
publisher.publishEvent(WorkflowNodeInstanceStatusChangeEvent.builder()
|
||||||
// .processInstanceId(activityEvent.getProcessInstanceId())
|
.processInstanceId(activityEvent.getProcessInstanceId())
|
||||||
// .executionId(activityEvent.getExecutionId())
|
.executionId(activityEvent.getExecutionId())
|
||||||
// .nodeId(activityEvent.getActivityId())
|
.nodeId(activityEvent.getActivityId())
|
||||||
// .nodeName(activityEvent.getActivityName())
|
.nodeName(StringUtils.isEmpty(activityEvent.getActivityName()) ? activityEvent.getActivityId() : activityEvent.getActivityName())
|
||||||
// .nodeType(activityEvent.getActivityType())
|
.nodeType(activityEvent.getActivityType())
|
||||||
// .status(status)
|
.status(status)
|
||||||
// .startTime(status == WorkflowNodeInstanceStatusEnums.RUNNING ? LocalDateTime.now() : null)
|
.startTime(status == WorkflowNodeInstanceStatusEnums.RUNNING ? LocalDateTime.now() : null)
|
||||||
// .endTime(status.isFinalState() ? LocalDateTime.now() : null)
|
.endTime(status.isFinalState() ? LocalDateTime.now() : null)
|
||||||
// .build()
|
.build()
|
||||||
// );
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,11 +2,14 @@ package com.qqchen.deploy.backend.workflow.listener.handler;
|
|||||||
|
|
||||||
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
|
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flowable事件处理器接口
|
* Flowable事件处理器接口
|
||||||
*/
|
*/
|
||||||
public interface IFlowableEventHandler {
|
public interface IFlowableEventHandler {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断是否可以处理该事件
|
* 判断是否可以处理该事件
|
||||||
*
|
*
|
||||||
|
|||||||
@ -11,7 +11,10 @@ import org.springframework.context.ApplicationEventPublisher;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@ -28,17 +31,12 @@ public class JobEventHandler implements IFlowableEventHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void handle(FlowableEvent event) {
|
public void handle(FlowableEvent event) {
|
||||||
String eventType = event.getType().name();
|
String eventType = event.getType().name();
|
||||||
// log.info("Processing job event: {}", eventType);
|
|
||||||
|
|
||||||
if (!(event instanceof FlowableEngineEntityEvent entityEvent)) {
|
if (!(event instanceof FlowableEngineEntityEvent entityEvent)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// log.info("Processing job event: {}, jobType: {}", eventType, entityEvent.getType());
|
// log.info("Processing job event: {}, jobType: {}", eventType, entityEvent.getType());
|
||||||
|
|
||||||
JobEntityImpl job = (JobEntityImpl) entityEvent.getEntity();
|
JobEntityImpl job = (JobEntityImpl) entityEvent.getEntity();
|
||||||
WorkflowNodeInstanceStatusEnums status = convertToNodeStatus(eventType);
|
WorkflowNodeInstanceStatusEnums status = convertToNodeStatus(eventType);
|
||||||
|
|
||||||
if (status != null) {
|
if (status != null) {
|
||||||
// publisher.publishEvent(WorkflowNodeInstanceStatusChangeEvent.builder()
|
// publisher.publishEvent(WorkflowNodeInstanceStatusChangeEvent.builder()
|
||||||
// .processInstanceId(job.getProcessInstanceId())
|
// .processInstanceId(job.getProcessInstanceId())
|
||||||
|
|||||||
@ -14,6 +14,9 @@ import org.springframework.stereotype.Component;
|
|||||||
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
public class ProcessEventHandler implements IFlowableEventHandler {
|
public class ProcessEventHandler implements IFlowableEventHandler {
|
||||||
@ -33,8 +36,6 @@ public class ProcessEventHandler implements IFlowableEventHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void handle(FlowableEvent event) {
|
public void handle(FlowableEvent event) {
|
||||||
String eventType = event.getType().name();
|
String eventType = event.getType().name();
|
||||||
log.info("Processing event: {}", eventType);
|
|
||||||
|
|
||||||
FlowableProcessEngineEvent processEvent = (FlowableProcessEngineEvent) event;
|
FlowableProcessEngineEvent processEvent = (FlowableProcessEngineEvent) event;
|
||||||
WorkflowInstanceStatusEnums status = convertToWorkflowStatus(eventType);
|
WorkflowInstanceStatusEnums status = convertToWorkflowStatus(eventType);
|
||||||
|
|
||||||
@ -59,12 +60,12 @@ public class ProcessEventHandler implements IFlowableEventHandler {
|
|||||||
case "PROCESS_CREATED" -> WorkflowInstanceStatusEnums.CREATED;
|
case "PROCESS_CREATED" -> WorkflowInstanceStatusEnums.CREATED;
|
||||||
case "PROCESS_STARTED" -> WorkflowInstanceStatusEnums.RUNNING;
|
case "PROCESS_STARTED" -> WorkflowInstanceStatusEnums.RUNNING;
|
||||||
case "PROCESS_COMPLETED" -> WorkflowInstanceStatusEnums.COMPLETED;
|
case "PROCESS_COMPLETED" -> WorkflowInstanceStatusEnums.COMPLETED;
|
||||||
case "PROCESS_COMPLETED_WITH_ERROR_END_EVENT" -> WorkflowInstanceStatusEnums.FAILED;
|
case "PROCESS_CANCELLED" -> WorkflowInstanceStatusEnums.FAILED;
|
||||||
case "PROCESS_CANCELLED" -> WorkflowInstanceStatusEnums.TERMINATED;
|
|
||||||
case "PROCESS_SUSPENDED" -> WorkflowInstanceStatusEnums.SUSPENDED;
|
case "PROCESS_SUSPENDED" -> WorkflowInstanceStatusEnums.SUSPENDED;
|
||||||
case "PROCESS_RESUMED" -> WorkflowInstanceStatusEnums.RUNNING;
|
// case "PROCESS_RESUMED" -> WorkflowInstanceStatusEnums.RUNNING;
|
||||||
case "PROCESS_COMPLETED_WITH_TERMINATE_END_EVENT" -> WorkflowInstanceStatusEnums.TERMINATED;
|
case "PROCESS_COMPLETED_WITH_TERMINATE_END_EVENT" -> WorkflowInstanceStatusEnums.TERMINATED;
|
||||||
default -> null;
|
default -> null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -2,8 +2,12 @@ package com.qqchen.deploy.backend.workflow.repository;
|
|||||||
|
|
||||||
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
|
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
|
||||||
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
|
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnums;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,4 +26,6 @@ public interface IWorkflowDefinitionRepository extends IBaseRepository<WorkflowD
|
|||||||
boolean existsByKeyAndDeletedFalse(String key);
|
boolean existsByKeyAndDeletedFalse(String key);
|
||||||
|
|
||||||
Optional<WorkflowDefinition> findByKey(String businessKey);
|
Optional<WorkflowDefinition> findByKey(String businessKey);
|
||||||
|
|
||||||
|
Page<WorkflowDefinition> findByStatus(WorkflowStatusEnums workflowStatusEnums, Pageable pageable);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,4 +21,5 @@ public interface IWorkflowInstanceRepository extends IBaseRepository<WorkflowIns
|
|||||||
*/
|
*/
|
||||||
List<WorkflowInstance> findByBusinessKey(String businessKey);
|
List<WorkflowInstance> findByBusinessKey(String businessKey);
|
||||||
|
|
||||||
|
List<WorkflowInstance> findTop1ByWorkflowDefinitionIdOrderByCreateTimeDesc(Long workflowDefinitionId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,4 +14,6 @@ public interface IWorkflowNodeInstanceRepository extends IBaseRepository<Workflo
|
|||||||
List<WorkflowNodeInstance> findByProcessInstanceId(String processInstanceId);
|
List<WorkflowNodeInstance> findByProcessInstanceId(String processInstanceId);
|
||||||
|
|
||||||
WorkflowNodeInstance findByNodeId(String nodeId);
|
WorkflowNodeInstance findByNodeId(String nodeId);
|
||||||
|
|
||||||
|
WorkflowNodeInstance findByProcessInstanceIdAndNodeId(String processInstanceId, String nodeId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,14 @@
|
|||||||
package com.qqchen.deploy.backend.workflow.service;
|
package com.qqchen.deploy.backend.workflow.service;
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.framework.service.IBaseService;
|
import com.qqchen.deploy.backend.framework.service.IBaseService;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.WorkflowDefinitionDTO;
|
|
||||||
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceDTO;
|
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceDTO;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceStartRequest;
|
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceStartRequest;
|
||||||
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
|
import com.qqchen.deploy.backend.workflow.dto.WorkflowTemplateWithInstancesDTO;
|
||||||
import com.qqchen.deploy.backend.workflow.entity.WorkflowInstance;
|
import com.qqchen.deploy.backend.workflow.entity.WorkflowInstance;
|
||||||
import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnums;
|
import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnums;
|
||||||
|
import com.qqchen.deploy.backend.workflow.query.WorkflowDefinitionQuery;
|
||||||
import org.flowable.engine.runtime.ProcessInstance;
|
import org.flowable.engine.runtime.ProcessInstance;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -58,4 +59,7 @@ public interface IWorkflowInstanceService extends IBaseService<WorkflowInstance,
|
|||||||
void completeInstance(String processInstanceId, Map<String, Object> variables);
|
void completeInstance(String processInstanceId, Map<String, Object> variables);
|
||||||
|
|
||||||
WorkflowInstanceDTO startWorkflow(WorkflowInstanceStartRequest request);
|
WorkflowInstanceDTO startWorkflow(WorkflowInstanceStartRequest request);
|
||||||
|
|
||||||
|
Page<WorkflowTemplateWithInstancesDTO> findTemplatesWithRecentInstances(WorkflowDefinitionQuery query);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,9 +7,12 @@ import com.qqchen.deploy.backend.workflow.converter.WorkflowInstanceConverter;
|
|||||||
import com.qqchen.deploy.backend.workflow.dto.WorkflowDefinitionDTO;
|
import com.qqchen.deploy.backend.workflow.dto.WorkflowDefinitionDTO;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceDTO;
|
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceDTO;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceStartRequest;
|
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceStartRequest;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.WorkflowTemplateWithInstancesDTO;
|
||||||
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
|
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
|
||||||
import com.qqchen.deploy.backend.workflow.entity.WorkflowInstance;
|
import com.qqchen.deploy.backend.workflow.entity.WorkflowInstance;
|
||||||
import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnums;
|
import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnums;
|
||||||
|
import com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnums;
|
||||||
|
import com.qqchen.deploy.backend.workflow.query.WorkflowDefinitionQuery;
|
||||||
import com.qqchen.deploy.backend.workflow.repository.IWorkflowDefinitionRepository;
|
import com.qqchen.deploy.backend.workflow.repository.IWorkflowDefinitionRepository;
|
||||||
import com.qqchen.deploy.backend.workflow.repository.IWorkflowInstanceRepository;
|
import com.qqchen.deploy.backend.workflow.repository.IWorkflowInstanceRepository;
|
||||||
import com.qqchen.deploy.backend.workflow.service.IWorkflowDefinitionService;
|
import com.qqchen.deploy.backend.workflow.service.IWorkflowDefinitionService;
|
||||||
@ -20,7 +23,12 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.flowable.engine.HistoryService;
|
import org.flowable.engine.HistoryService;
|
||||||
import org.flowable.engine.RuntimeService;
|
import org.flowable.engine.RuntimeService;
|
||||||
import org.flowable.engine.history.HistoricActivityInstance;
|
import org.flowable.engine.history.HistoricActivityInstance;
|
||||||
|
import org.flowable.engine.repository.ProcessDefinition;
|
||||||
import org.flowable.engine.runtime.ProcessInstance;
|
import org.flowable.engine.runtime.ProcessInstance;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.PageImpl;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.retry.annotation.Backoff;
|
import org.springframework.retry.annotation.Backoff;
|
||||||
import org.springframework.retry.annotation.Retryable;
|
import org.springframework.retry.annotation.Retryable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -30,6 +38,8 @@ import java.time.LocalDateTime;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class WorkflowInstanceServiceImpl extends BaseServiceImpl<WorkflowInstance, WorkflowInstanceDTO, Long> implements IWorkflowInstanceService {
|
public class WorkflowInstanceServiceImpl extends BaseServiceImpl<WorkflowInstance, WorkflowInstanceDTO, Long> implements IWorkflowInstanceService {
|
||||||
@ -59,7 +69,7 @@ public class WorkflowInstanceServiceImpl extends BaseServiceImpl<WorkflowInstanc
|
|||||||
workflowInstance.setProcessDefinitionId(processInstance.getProcessDefinitionId());
|
workflowInstance.setProcessDefinitionId(processInstance.getProcessDefinitionId());
|
||||||
workflowInstance.setWorkflowDefinitionId(workflowDefinitionId);
|
workflowInstance.setWorkflowDefinitionId(workflowDefinitionId);
|
||||||
workflowInstance.setBusinessKey(businessKey);
|
workflowInstance.setBusinessKey(businessKey);
|
||||||
workflowInstance.setStatus(WorkflowInstanceStatusEnums.CREATED);
|
workflowInstance.setStatus(WorkflowInstanceStatusEnums.NOT_STARTED);
|
||||||
workflowInstance.setStartTime(LocalDateTime.now());
|
workflowInstance.setStartTime(LocalDateTime.now());
|
||||||
workflowInstanceRepository.save(workflowInstance);
|
workflowInstanceRepository.save(workflowInstance);
|
||||||
// 3. 返回创建结果
|
// 3. 返回创建结果
|
||||||
@ -123,7 +133,7 @@ public class WorkflowInstanceServiceImpl extends BaseServiceImpl<WorkflowInstanc
|
|||||||
public List<WorkflowInstanceDTO> findByBusinessKey(String businessKey) {
|
public List<WorkflowInstanceDTO> findByBusinessKey(String businessKey) {
|
||||||
return workflowInstanceRepository.findByBusinessKey(businessKey).stream()
|
return workflowInstanceRepository.findByBusinessKey(businessKey).stream()
|
||||||
.map(instance -> getInstanceDetails(instance.getProcessInstanceId()))
|
.map(instance -> getInstanceDetails(instance.getProcessInstanceId()))
|
||||||
.collect(Collectors.toList());
|
.collect(toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -164,6 +174,26 @@ public class WorkflowInstanceServiceImpl extends BaseServiceImpl<WorkflowInstanc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<WorkflowTemplateWithInstancesDTO> findTemplatesWithRecentInstances(WorkflowDefinitionQuery query) {
|
||||||
|
Pageable pageable = PageRequest.of(query.getPageNum() - 1, query.getPageSize());
|
||||||
|
Page<WorkflowDefinition> definitionPage = workflowDefinitionRepository.findByStatus(WorkflowStatusEnums.PUBLISHED, pageable);
|
||||||
|
List<WorkflowTemplateWithInstancesDTO> result = definitionPage.getContent().stream().map(definition -> {
|
||||||
|
List<WorkflowInstance> workflowInstances = workflowInstanceRepository.findTop1ByWorkflowDefinitionIdOrderByCreateTimeDesc(definition.getId());
|
||||||
|
WorkflowTemplateWithInstancesDTO workflowTemplateWithInstancesDTO = new WorkflowTemplateWithInstancesDTO();
|
||||||
|
Optional<WorkflowInstance> optional = workflowInstances.stream().findFirst();
|
||||||
|
if (optional.isPresent()) {
|
||||||
|
workflowTemplateWithInstancesDTO.setLastExecutionStatus(optional.get().getStatus());
|
||||||
|
workflowTemplateWithInstancesDTO.setLastExecutionTime(optional.get().getCreateTime());
|
||||||
|
}
|
||||||
|
workflowTemplateWithInstancesDTO.setId(definition.getId());
|
||||||
|
workflowTemplateWithInstancesDTO.setName(definition.getName());
|
||||||
|
workflowTemplateWithInstancesDTO.setBusinessKey(definition.getKey());
|
||||||
|
return workflowTemplateWithInstancesDTO;
|
||||||
|
}).collect(toList());
|
||||||
|
return new PageImpl<>(result, definitionPage.getPageable(), definitionPage.getTotalElements());
|
||||||
|
}
|
||||||
|
|
||||||
// private WorkflowInstanceDTO.ActivityInstance convertToActivityInstance(HistoricActivityInstance hai) {
|
// private WorkflowInstanceDTO.ActivityInstance convertToActivityInstance(HistoricActivityInstance hai) {
|
||||||
// WorkflowInstanceDTO.ActivityInstance ai = new WorkflowInstanceDTO.ActivityInstance();
|
// WorkflowInstanceDTO.ActivityInstance ai = new WorkflowInstanceDTO.ActivityInstance();
|
||||||
// ai.setId(hai.getId());
|
// ai.setId(hai.getId());
|
||||||
|
|||||||
@ -67,7 +67,7 @@ public class WorkflowNodeInstanceServiceImpl extends BaseServiceImpl<WorkflowNod
|
|||||||
WorkflowNodeInstance nodeInstance = workflowNodeInstanceConverter.eventToEntity(event);
|
WorkflowNodeInstance nodeInstance = workflowNodeInstanceConverter.eventToEntity(event);
|
||||||
WorkflowInstance workflowInstance = workflowInstanceRepository.findByProcessInstanceId(nodeInstance.getProcessInstanceId())
|
WorkflowInstance workflowInstance = workflowInstanceRepository.findByProcessInstanceId(nodeInstance.getProcessInstanceId())
|
||||||
.orElseThrow(() -> new RuntimeException("Node instance not found for processInstanceId: " + nodeInstance.getProcessInstanceId()));
|
.orElseThrow(() -> new RuntimeException("Node instance not found for processInstanceId: " + nodeInstance.getProcessInstanceId()));
|
||||||
WorkflowNodeInstance workflowNodeInstance = workflowNodeInstanceRepository.findByNodeId(event.getNodeId());
|
WorkflowNodeInstance workflowNodeInstance = workflowNodeInstanceRepository.findByProcessInstanceIdAndNodeId(workflowInstance.getProcessInstanceId(), event.getNodeId());
|
||||||
if (workflowNodeInstance == null) {
|
if (workflowNodeInstance == null) {
|
||||||
nodeInstance.setWorkflowInstanceId(workflowInstance.getId());
|
nodeInstance.setWorkflowInstanceId(workflowInstance.getId());
|
||||||
nodeInstance.setWorkflowDefinitionId(workflowInstance.getWorkflowDefinitionId());
|
nodeInstance.setWorkflowDefinitionId(workflowInstance.getWorkflowDefinitionId());
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* BPMN 模型转换工具
|
* BPMN 模型转换工具
|
||||||
|
*
|
||||||
* @author cascade
|
* @author cascade
|
||||||
* @date 2024-12-11
|
* @date 2024-12-11
|
||||||
*/
|
*/
|
||||||
@ -40,6 +41,7 @@ public class BpmnConverter {
|
|||||||
// 创建BPMN模型
|
// 创建BPMN模型
|
||||||
BpmnModel bpmnModel = new BpmnModel();
|
BpmnModel bpmnModel = new BpmnModel();
|
||||||
bpmnModel.setTargetNamespace("http://www.flowable.org/test");
|
bpmnModel.setTargetNamespace("http://www.flowable.org/test");
|
||||||
|
bpmnModel.addError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, WorkFlowConstants.WORKFLOW_EXEC_ERROR);
|
||||||
|
|
||||||
Process process = new Process();
|
Process process = new Process();
|
||||||
// 确保processKey符合NCName规则
|
// 确保processKey符合NCName规则
|
||||||
@ -80,7 +82,7 @@ public class BpmnConverter {
|
|||||||
log.debug("转换连线: from {} to {}", edge.getFrom(), edge.getTo());
|
log.debug("转换连线: from {} to {}", edge.getFrom(), edge.getTo());
|
||||||
|
|
||||||
SequenceFlow flow = new SequenceFlow();
|
SequenceFlow flow = new SequenceFlow();
|
||||||
flow.setId("flow_" + edge.getId().replaceAll("[^a-zA-Z0-9-_.]", "_"));
|
flow.setId("FLOW_" + edge.getId().replaceAll("[^a-zA-Z0-9-_.]", "_"));
|
||||||
flow.setName(edge.getName());
|
flow.setName(edge.getName());
|
||||||
flow.setSourceRef(idMapping.get(edge.getFrom()));
|
flow.setSourceRef(idMapping.get(edge.getFrom()));
|
||||||
flow.setTargetRef(idMapping.get(edge.getTo()));
|
flow.setTargetRef(idMapping.get(edge.getTo()));
|
||||||
@ -105,11 +107,12 @@ public class BpmnConverter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String sanitizeId(String id) {
|
private String sanitizeId(String id) {
|
||||||
return "node_" + id.replaceAll("[^a-zA-Z0-9-_.]", "_");
|
return "NODE_" + id.replaceAll("[^a-zA-Z0-9-_.]", "_");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 配置流程节点的特定属性
|
* 配置流程节点的特定属性
|
||||||
|
*
|
||||||
* @param element 流程节点元素
|
* @param element 流程节点元素
|
||||||
* @param node 工作流节点定义
|
* @param node 工作流节点定义
|
||||||
* @param process 当前流程
|
* @param process 当前流程
|
||||||
@ -180,6 +183,7 @@ public class BpmnConverter {
|
|||||||
private BoundaryEvent createErrorBoundaryEvent(ServiceTask serviceTask) {
|
private BoundaryEvent createErrorBoundaryEvent(ServiceTask serviceTask) {
|
||||||
BoundaryEvent boundaryEvent = new BoundaryEvent();
|
BoundaryEvent boundaryEvent = new BoundaryEvent();
|
||||||
boundaryEvent.setId(WorkFlowConstants.BOUNDARY_EVENT_ERROR_PREFIX + serviceTask.getId());
|
boundaryEvent.setId(WorkFlowConstants.BOUNDARY_EVENT_ERROR_PREFIX + serviceTask.getId());
|
||||||
|
boundaryEvent.setName("边界事件异常");
|
||||||
boundaryEvent.setAttachedToRef(serviceTask);
|
boundaryEvent.setAttachedToRef(serviceTask);
|
||||||
boundaryEvent.setAttachedToRefId(serviceTask.getId());
|
boundaryEvent.setAttachedToRefId(serviceTask.getId());
|
||||||
boundaryEvent.setCancelActivity(true); // 确保取消原有活动
|
boundaryEvent.setCancelActivity(true); // 确保取消原有活动
|
||||||
@ -201,14 +205,14 @@ public class BpmnConverter {
|
|||||||
private EndEvent createErrorEndEvent(ServiceTask serviceTask) {
|
private EndEvent createErrorEndEvent(ServiceTask serviceTask) {
|
||||||
EndEvent errorEndEvent = new EndEvent();
|
EndEvent errorEndEvent = new EndEvent();
|
||||||
errorEndEvent.setId(WorkFlowConstants.END_EVENT_ERROR_PREFIX + serviceTask.getId());
|
errorEndEvent.setId(WorkFlowConstants.END_EVENT_ERROR_PREFIX + serviceTask.getId());
|
||||||
|
errorEndEvent.setName("结束事件异常");
|
||||||
// 添加终止定义
|
// 添加终止定义
|
||||||
// TerminateEventDefinition terminateEventDefinition = new TerminateEventDefinition();
|
TerminateEventDefinition terminateEventDefinition = new TerminateEventDefinition();
|
||||||
// errorEndEvent.addEventDefinition(terminateEventDefinition);
|
errorEndEvent.addEventDefinition(terminateEventDefinition);
|
||||||
|
|
||||||
ErrorEventDefinition errorEventDefinition = new ErrorEventDefinition();
|
// ErrorEventDefinition errorEventDefinition = new ErrorEventDefinition();
|
||||||
errorEventDefinition.setErrorCode(WorkFlowConstants.WORKFLOW_EXEC_ERROR);
|
// errorEventDefinition.setErrorCode(WorkFlowConstants.WORKFLOW_EXEC_ERROR);
|
||||||
errorEndEvent.addEventDefinition(errorEventDefinition);
|
// errorEndEvent.addEventDefinition(errorEventDefinition);
|
||||||
|
|
||||||
return errorEndEvent;
|
return errorEndEvent;
|
||||||
}
|
}
|
||||||
@ -223,6 +227,7 @@ public class BpmnConverter {
|
|||||||
private SequenceFlow createErrorSequenceFlow(BoundaryEvent boundaryEvent, EndEvent errorEndEvent) {
|
private SequenceFlow createErrorSequenceFlow(BoundaryEvent boundaryEvent, EndEvent errorEndEvent) {
|
||||||
SequenceFlow errorFlow = new SequenceFlow();
|
SequenceFlow errorFlow = new SequenceFlow();
|
||||||
errorFlow.setId(WorkFlowConstants.SEQUENCE_FLOW_ERROR_PREFIX + boundaryEvent.getAttachedToRefId());
|
errorFlow.setId(WorkFlowConstants.SEQUENCE_FLOW_ERROR_PREFIX + boundaryEvent.getAttachedToRefId());
|
||||||
|
errorFlow.setName("连接线异常");
|
||||||
errorFlow.setSourceRef(boundaryEvent.getId());
|
errorFlow.setSourceRef(boundaryEvent.getId());
|
||||||
errorFlow.setTargetRef(errorEndEvent.getId());
|
errorFlow.setTargetRef(errorEndEvent.getId());
|
||||||
|
|
||||||
|
|||||||
@ -473,7 +473,7 @@ CREATE TABLE workflow_instance
|
|||||||
process_definition_id VARCHAR(64) NOT NULL COMMENT '流程定义ID',
|
process_definition_id VARCHAR(64) NOT NULL COMMENT '流程定义ID',
|
||||||
workflow_definition_id BIGINT NOT NULL COMMENT '工作流定义ID',
|
workflow_definition_id BIGINT NOT NULL COMMENT '工作流定义ID',
|
||||||
business_key VARCHAR(64) NULL COMMENT '业务标识',
|
business_key VARCHAR(64) NULL COMMENT '业务标识',
|
||||||
status VARCHAR(32) NOT NULL COMMENT '实例状态',
|
status VARCHAR(100) NOT NULL COMMENT '实例状态',
|
||||||
variables TEXT NULL COMMENT '流程变量(JSON)',
|
variables TEXT NULL COMMENT '流程变量(JSON)',
|
||||||
start_time DATETIME(6) NULL COMMENT '开始时间',
|
start_time DATETIME(6) NULL COMMENT '开始时间',
|
||||||
end_time DATETIME(6) NULL COMMENT '结束时间'
|
end_time DATETIME(6) NULL COMMENT '结束时间'
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user