diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/annotation/FlowListenerAnnotation.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/annotation/FlowListenerAnnotation.java new file mode 100644 index 000000000..ad90df179 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/annotation/FlowListenerAnnotation.java @@ -0,0 +1,27 @@ +package org.dromara.workflow.annotation; + + +import java.lang.annotation.*; + +/** + * 流程任务监听注解 + * + * @author may + * @date 2023-12-27 + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface FlowListenerAnnotation { + + /** + * 流程定义 + */ + String processDefinitionKey(); + + /** + * 节点定义 + */ + String taskDefId() default ""; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java index 039783528..c483eab63 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java @@ -2,6 +2,8 @@ package org.dromara.workflow.flowable.config; import cn.hutool.core.collection.CollUtil; import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.flowable.strategy.FlowEventStrategy; +import org.dromara.workflow.flowable.strategy.FlowTaskEventHandler; import org.flowable.bpmn.model.BoundaryEvent; import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.FlowElement; @@ -10,9 +12,11 @@ import org.flowable.common.engine.impl.cfg.TransactionState; import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; +import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.Execution; import org.flowable.engine.task.Comment; import org.flowable.task.api.Task; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @@ -40,12 +44,16 @@ public class GlobalFlowableListener implements FlowableEventListener { @Lazy private RepositoryService repositoryService; + @Autowired + private FlowEventStrategy flowEventStrategy; + @Override public void onEvent(FlowableEvent flowableEvent) { if (flowableEvent instanceof FlowableEngineEvent flowableEngineEvent) { FlowableEngineEventType engineEventType = (FlowableEngineEventType) flowableEvent.getType(); switch (engineEventType) { case JOB_EXECUTION_SUCCESS -> jobExecutionSuccess((FlowableEngineEntityEvent) flowableEngineEvent); + case TASK_COMPLETED -> taskCompleted((FlowableEngineEntityEvent) flowableEngineEvent); } } } @@ -65,6 +73,11 @@ public class GlobalFlowableListener implements FlowableEventListener { return TransactionState.COMMITTED.name(); } + /** + * 处理边界定时事件自动审批记录 + * + * @param event 事件 + */ protected void jobExecutionSuccess(FlowableEngineEntityEvent event) { Execution execution = runtimeService.createExecutionQuery().executionId(event.getExecutionId()).singleResult(); BpmnModel bpmnModel = repositoryService.getBpmnModel(event.getProcessDefinitionId()); @@ -83,4 +96,21 @@ public class GlobalFlowableListener implements FlowableEventListener { } } } + + /** + * 处理任务办理监听 + * + * @param event 事件 + */ + protected void taskCompleted(FlowableEngineEntityEvent event) { + TaskEntity entity = (TaskEntity) event.getEntity(); + ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(entity.getProcessDefinitionId()).singleResult(); + String processDefinitionKey = processDefinition.getKey(); + String taskDefinitionKey = entity.getTaskDefinitionKey(); + String beanName = processDefinitionKey + "_" + taskDefinitionKey; + FlowTaskEventHandler handler = flowEventStrategy.getTaskHandler(beanName); + if (handler != null) { + handler.handleTask(entity); + } + } } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowEventStrategy.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowEventStrategy.java new file mode 100644 index 000000000..3b00a4843 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowEventStrategy.java @@ -0,0 +1,68 @@ +package org.dromara.workflow.flowable.strategy; + +import org.dromara.common.core.utils.StringUtils; +import org.dromara.workflow.annotation.FlowListenerAnnotation; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +/** + * 流程任务监听策略 + * + * @author may + * @date 2023-12-27 + */ +@Component +public class FlowEventStrategy implements BeanPostProcessor { + + private final Map flowTaskEventHandlers = new HashMap<>(); + private final Map flowProcessEventHandlers = new HashMap<>(); + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof FlowTaskEventHandler || bean instanceof FlowProcessEventHandler) { + FlowListenerAnnotation annotation = bean.getClass().getAnnotation(FlowListenerAnnotation.class); + if (null != annotation) { + if (StringUtils.isNotBlank(annotation.processDefinitionKey()) && StringUtils.isNotBlank(annotation.taskDefId())) { + String id = annotation.processDefinitionKey() + "_" + annotation.taskDefId(); + if (!flowTaskEventHandlers.containsKey(id)) { + flowTaskEventHandlers.put(id, (FlowTaskEventHandler) bean); + } + } + if (StringUtils.isNotBlank(annotation.processDefinitionKey()) && StringUtils.isBlank(annotation.taskDefId())) { + if (!flowProcessEventHandlers.containsKey(annotation.processDefinitionKey())) { + flowProcessEventHandlers.put(annotation.processDefinitionKey(), (FlowProcessEventHandler) bean); + } + } + } + } + return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName); + } + + /** + * 获取可执行bean + * + * @param beanName beanName + */ + public FlowTaskEventHandler getTaskHandler(String beanName) { + if (!flowTaskEventHandlers.containsKey(beanName)) { + return null; + } + return flowTaskEventHandlers.get(beanName); + } + + /** + * 获取可执行bean + * + * @param beanName beanName + */ + public FlowProcessEventHandler getProcessHandler(String beanName) { + if (!flowProcessEventHandlers.containsKey(beanName)) { + return null; + } + return flowProcessEventHandlers.get(beanName); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowProcessEventHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowProcessEventHandler.java new file mode 100644 index 000000000..a9ce28e57 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowProcessEventHandler.java @@ -0,0 +1,19 @@ +package org.dromara.workflow.flowable.strategy; + + +/** + * 流程监听 + * + * @author may + * @date 2023-12-27 + */ +public interface FlowProcessEventHandler { + + /** + * 执行办理任务监听 + * + * @param processInstanceId 流程实例id + * @param status 状态 + */ + void handleProcess(String processInstanceId, String status); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowTaskEventHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowTaskEventHandler.java new file mode 100644 index 000000000..98be53426 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/strategy/FlowTaskEventHandler.java @@ -0,0 +1,19 @@ +package org.dromara.workflow.flowable.strategy; + +import org.flowable.task.service.impl.persistence.entity.TaskEntity; + +/** + * 流程任务监听 + * + * @author may + * @date 2023-12-27 + */ +public interface FlowTaskEventHandler { + + /** + * 执行办理任务监听 + * + * @param taskEntity 任务 + */ + void handleTask(TaskEntity taskEntity); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomProcessHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomProcessHandler.java new file mode 100644 index 000000000..b24ecdf35 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomProcessHandler.java @@ -0,0 +1,24 @@ +package org.dromara.workflow.listener; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.workflow.annotation.FlowListenerAnnotation; +import org.dromara.workflow.flowable.strategy.FlowProcessEventHandler; +import org.springframework.stereotype.Component; + +/** + * 自定义监听测试 + * + * @author may + * @date 2023-12-27 + */ +@Slf4j +@Component +@FlowListenerAnnotation(processDefinitionKey = "leave1") +public class TestCustomProcessHandler implements FlowProcessEventHandler { + + + @Override + public void handleProcess(String processInstanceId, String status) { + log.info("流程实例ID:" + processInstanceId + ",状态:" + status); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomTaskHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomTaskHandler.java new file mode 100644 index 000000000..aa119a6bd --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestCustomTaskHandler.java @@ -0,0 +1,24 @@ +package org.dromara.workflow.listener; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.workflow.annotation.FlowListenerAnnotation; +import org.dromara.workflow.flowable.strategy.FlowTaskEventHandler; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; +import org.springframework.stereotype.Component; + +/** + * 自定义监听测试 + * + * @author may + * @date 2023-12-27 + */ +@Slf4j +@Component +@FlowListenerAnnotation(processDefinitionKey = "leave1", taskDefId = "sid-31C52262-04C3-43D8-A3FB-8434017A6572") +public class TestCustomTaskHandler implements FlowTaskEventHandler { + + @Override + public void handleTask(TaskEntity taskEntity) { + log.info("任务名称:" + taskEntity.getName()); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestLeaveExecutionListener.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestLeaveExecutionListener.java index a3c220f15..1a75414c0 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestLeaveExecutionListener.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/TestLeaveExecutionListener.java @@ -2,7 +2,6 @@ package org.dromara.workflow.listener; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.delegate.ExecutionListener; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java index b1dee83b8..14f38c79c 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java @@ -26,8 +26,10 @@ import org.dromara.workflow.domain.vo.GraphicInfoVo; import org.dromara.workflow.domain.vo.ProcessInstanceVo; import org.dromara.workflow.domain.vo.TaskVo; import org.dromara.workflow.flowable.CustomDefaultProcessDiagramGenerator; +import org.dromara.workflow.flowable.strategy.FlowEventStrategy; import org.dromara.workflow.flowable.cmd.DeleteExecutionCmd; import org.dromara.workflow.flowable.cmd.ExecutionChildByExecutionIdCmd; +import org.dromara.workflow.flowable.strategy.FlowProcessEventHandler; import org.dromara.workflow.service.IActHiProcinstService; import org.dromara.workflow.service.IActProcessInstanceService; import org.dromara.workflow.utils.WorkflowUtils; @@ -69,6 +71,7 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService private final TaskService taskService; private final IActHiProcinstService actHiProcinstService; private final ManagementService managementService; + private final FlowEventStrategy flowEventStrategy; @Value("${flowable.activity-font-name}") private String activityFontName; @@ -366,6 +369,8 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService } runtimeService.updateBusinessStatus(processInvalidBo.getProcessInstanceId(), BusinessStatusEnum.INVALID.getStatus()); runtimeService.deleteProcessInstance(processInvalidBo.getProcessInstanceId(), deleteReason); + FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(historicProcessInstance.getProcessDefinitionKey()); + processHandler.handleProcess(historicProcessInstance.getId(), BusinessStatusEnum.INVALID.getStatus()); return true; } catch (Exception e) { e.printStackTrace(); @@ -495,6 +500,8 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService managementService.executeCommand(deleteExecutionCmd); } runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.CANCEL.getStatus()); + FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey()); + processHandler.handleProcess(processInstanceId, BusinessStatusEnum.CANCEL.getStatus()); return true; } catch (Exception e) { e.printStackTrace(); diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java index edd102e34..9e38f45de 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java @@ -20,7 +20,9 @@ import org.dromara.workflow.common.enums.TaskStatusEnum; import org.dromara.workflow.domain.bo.*; import org.dromara.workflow.domain.vo.MultiInstanceVo; import org.dromara.workflow.domain.vo.TaskVo; +import org.dromara.workflow.flowable.strategy.FlowEventStrategy; import org.dromara.workflow.flowable.cmd.*; +import org.dromara.workflow.flowable.strategy.FlowProcessEventHandler; import org.dromara.workflow.service.IActTaskService; import org.dromara.workflow.utils.WorkflowUtils; import org.flowable.common.engine.impl.identity.Authentication; @@ -59,6 +61,7 @@ public class ActTaskServiceImpl implements IActTaskService { private final HistoryService historyService; private final IdentityService identityService; private final ManagementService managementService; + private final FlowEventStrategy flowEventStrategy; /** * 启动任务 @@ -161,6 +164,8 @@ public class ActTaskServiceImpl implements IActTaskService { if (CollUtil.isEmpty(list)) { UpdateBusinessStatusCmd updateBusinessStatusCmd = new UpdateBusinessStatusCmd(task.getProcessInstanceId(), BusinessStatusEnum.FINISH.getStatus()); managementService.executeCommand(updateBusinessStatusCmd); + FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey()); + processHandler.handleProcess(processInstance.getId(), BusinessStatusEnum.FINISH.getStatus()); } else { sendMessage(list, processInstance.getName(), completeTaskBo.getMessageType(), null); } @@ -431,6 +436,8 @@ public class ActTaskServiceImpl implements IActTaskService { runtimeService.deleteProcessInstance(task.getProcessInstanceId(), StrUtil.EMPTY); } runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.TERMINATION.getStatus()); + FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(historicProcessInstance.getProcessDefinitionKey()); + processHandler.handleProcess(historicProcessInstance.getId(), BusinessStatusEnum.TERMINATION.getStatus()); return true; } catch (Exception e) { throw new ServiceException(e.getMessage()); @@ -609,6 +616,8 @@ public class ActTaskServiceImpl implements IActTaskService { managementService.executeCommand(deleteExecutionCmd); } runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.BACK.getStatus()); + FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey()); + processHandler.handleProcess(processInstanceId, BusinessStatusEnum.BACK.getStatus()); } catch (Exception e) { throw new ServiceException(e.getMessage()); }