监听器

目录

任务监听器

说明

任务监听器是处理业务逻辑的重要的地方,当任务创建设定负责人完成任务时都可以监听的到从而来处理自己的业务。

常用于监听Assignment事件,设置完负责人给负责人发一个消息来通知提示。注意:任务监听器只能在节点UserTask上使用。

监听的事件类型(Event属性):

  • Create:任务创建后触发。常用于任务创建后设置任务负责人等。

  • Assignment:任务分配后触发。常用于设置完负责人后向负责人发邮件、短信等通知一下。

  • Delete:任务完成后触发。

  • All:所有事件发生都触发。

bpmn设置

直接点击Task Listeners 前面的三角是展示不了内容的,要先点击Task Listeners右边的空白处再点击三角才会展开,Listener也是如此。

class为java类名 in 包路径

监听器代码

任务监听器需要实现TaskListener,然后重写notify函数

public class OffWorkTaskListener implements TaskListener {

    @Override
    public void notify(DelegateTask delegateTask) {
        System.out.println(delegateTask.getName());
        // create,assignment,delete,all
        System.out.println(delegateTask.getEventName());

        // delegateTask.setAssignee("xxx");
    }
}

也可以自动指定责任人

public class MyTaskListener implements TaskListener {
    public void notify(DelegateTask delegateTask) {
         //判断当前的任务是 创建申请 并且是 create事件,则指定责任人为 张三
        if("创建申请".equals(delegateTask.getName()) &&
                "create".equals(delegateTask.getEventName())){
            delegateTask.setAssignee("张三");
        }
    }
}

或者根据任务名称发送通知

public class TaskListListener implements TaskListener {
 
    private ActivitiMapper activitiMapper = SpringContextHolder.getBean(ActivitiMapper.class);
 
    @Override
    public void notify(DelegateTask delegateTask) {
        String taskName = delegateTask.getName();
        List<String> listId = new ArrayList<>();
        switch (taskName) {
            case "环委办(督查科)发布任务":
                List<String> inspectorId = activitiMapper.findInspectorId();
                delegateTask.addCandidateUsers(inspectorId);
                break;
            case"牵头单位分发任务":
                String leadCooperate = activitiMapper.findLeadCooperate(delegateTask.getProcessDefinitionId());
                listId.add(leadCooperate);
                delegateTask.addCandidateUsers(listId);
                break;
            case"牵头单位完成任务":
                String leadCooperate1 = activitiMapper.findLeadCooperate(delegateTask.getProcessDefinitionId());
                listId.add(leadCooperate1);
                delegateTask.addCandidateUsers(listId);
                break;
            case"责任科室审核材料":
                String office = activitiMapper.findOffice(delegateTask.getProcessDefinitionId());
                listId.add(office);
                delegateTask.addCandidateUsers(listId);
                break;
            case"环委办(督查科)接收材料":
                List<String> inspectorId1 = activitiMapper.findInspectorId();
                delegateTask.addCandidateUsers(inspectorId1);
                break;
            default:
                break;
        }
 
    }
}

执行监听器

说明

执行侦听器意味着侦听一组有限的流程执行操作,如start、end和take,开发者可以在启动或结束之前添加一些特定的业务逻辑,执行监听器粒度较大

任务监听器只能监听UserTask,执行监听器用在流程的不同的阶段上:

  • 开始事件和结束事件的开始和结束

  • 经过输出顺序流

  • 流程活动的开始和结束

  • 流程网关的开始和结束

  • 中间事假的开始和结束

bpmn设置

监听器代码

执行监听器需要实现ExecutionListener

import org.activiti.engine.delegate.ExecutionListener;

public class MyExecutionListener implements ExecutionListener {
    @Override
    public void notify(DelegateExecution execution) {
        // Id=_2
        System.out.println("Id=" + execution.getCurrentFlowElement().getId());
        // Name=StartEvent
        System.out.println("Name=" + execution.getCurrentFlowElement().getName());
        // EventName=start
        System.out.println("EventName=" + execution.getEventName());
        // ProcessDefinitionId=helloworld:1:3
        System.out.println("ProcessDefinitionId=" + execution.getProcessDefinitionId());
        // ProcessInstanceId=2501
        System.out.println("ProcessInstanceId=" + execution.getProcessInstanceId());
    }
}

事件监听器

说明

事件监听器可以监听Activiti引擎抛出的一组大型事件,这些事件级别较低,类型非常丰富,触发次数也较多。

事件监听器粒度较小,出于便于维护的目的,建议使用事件监听器,将事件监听和流程文件分开管理。

可监听事件

官方文档给出了所有可监听事件https://www.activiti.org/userguide/#eventDispatcherEventTypes

  • 可监听事件的源码及翻译如下,太长折叠一下

    public enum ActivitiEventType {
    
      // ENTITY :流程实例,发起流程时,从流程模板中创建实例
      ENTITY_CREATED,  // 创建
    
      ENTITY_INITIALIZED,  // 初始化完成(如果这个实体的创建会包含子实体的创建,这个事件会在子实体都创建/初始化完成后被触发,这是与ENTITY_CREATED的区别)
    
      ENTITY_UPDATED,  // 更新
    
      ENTITY_DELETED,  // 删除
    
      ENTITY_SUSPENDED,  // 暂停(会被ProcessDefinitions, ProcessInstances 和 Tasks抛出)
    
      ENTITY_ACTIVATED,  // 激活(会被ProcessDefinitions, ProcessInstances 和 Tasks抛出)
    
      // 定时器
      TIMER_SCHEDULED,  // 创建
    
      TIMER_FIRED,  // 触发
    
      // 作业
      JOB_CANCELED,  // 取消
    
      JOB_EXECUTION_SUCCESS,  // 执行成功
    
      JOB_EXECUTION_FAILURE,  // 执行失败
    
      JOB_RETRIES_DECREMENTED,  // 重试减少(因为作业执行失败,导致重试次数减少)
    
      CUSTOM,  // 自定义
      
      // 引擎
      ENGINE_CREATED,  // 创建
    
      ENGINE_CLOSED,  // 关闭
    
      // 流程节点
      ACTIVITY_STARTED,  // 开始
    
      ACTIVITY_COMPLETED,  // 完成
    
      ACTIVITY_CANCELLED,  // 取消
    
      ACTIVITY_SIGNALED,  // 收到了一个信号
    
      ACTIVITY_COMPENSATE,  // 将要被补偿
      
      ACTIVITY_MESSAGE_SENT,  // 消息发送
     
      ACTIVITY_MESSAGE_WAITING,  // 消息等待
    
      ACTIVITY_MESSAGE_RECEIVED,  // 消息接收
    
      ACTIVITY_ERROR_RECEIVED,  // 接收失败
      
      // 流程历史
      HISTORIC_ACTIVITY_INSTANCE_CREATED,  // 创建
      
      HISTORIC_ACTIVITY_INSTANCE_ENDED,  // 结束
    
      // 队列流程
      SEQUENCEFLOW_TAKEN,  // 已采取
    
      UNCAUGHT_BPMN_ERROR,  // 未获取到bpmn 异常
    
      // 变量
      VARIABLE_CREATED,  // 创建
    
      VARIABLE_UPDATED,  // 更新
    
      VARIABLE_DELETED,  // 删除
    
      // 任务
      TASK_CREATED,  // 创建(它位于ENTITY_CREATE事件之后。当任务是由流程创建时,这个事件会在TaskListener执行之前被执行)
    
      TASK_ASSIGNED,  // 分配
    
      TASK_COMPLETED,  // 完成(它会在ENTITY_DELETE事件之前触发。当任务是流程一部分时,事件会在流程继续运行之前,   后续事件将是ACTIVITY_COMPLETE,对应着完成任务的节点)
    
      // 进程
      PROCESS_STARTED,  // 开始
    
      PROCESS_COMPLETED,  // 完成(在最后一个节点的ACTIVITY_COMPLETED事件之后触发。 当流程到达的状态,没有任何后续连线时, 流程就会结束。)
     
      PROCESS_COMPLETED_WITH_ERROR_END_EVENT,  // 异常结束
    
      PROCESS_CANCELLED,  // 取消
    
      HISTORIC_PROCESS_INSTANCE_CREATED,  // 流程实例创建
    
      HISTORIC_PROCESS_INSTANCE_ENDED,  // 流程实例创建
    
      // 成员
      MEMBERSHIP_CREATED,  // 用户被添加到一个组里
    
      MEMBERSHIP_DELETED,  // 用户被从一个组中删除
    
      MEMBERSHIPS_DELETED;  // 所有成员被从一个组中删除
      
      // other code ...
    }
    
    

全局事件监听器

实现 ActivitiEventListener 接口

实现 ActivitiEventListener 接口,重写 void onEvent(ActivitiEvent event) 方法

public class ActivitiTaskEventListener implements ActivitiEventListener {

    @Override
    public void onEvent(ActivitiEvent activitiEvent) {
        if (!StringUtils.hasText(activitiEvent.getProcessInstanceId())) {
            return;
        }
        processEngine = ProcessEngines.getDefaultProcessEngine();

        // 流程实例
        ProcessInstance processInstance = processEngine.getRuntimeService().createProcessInstanceQuery()
                .processInstanceId(activitiEvent.getProcessInstanceId()).singleResult();
        if (processInstance == null) {
            return;
        }

        List<ActivitiTaskLog> taskLogList = new ArrayList<>();
        switch (activitiEvent.getType()) {
            // 任务执行后
            case TASK_COMPLETED:
                // 任务被处理,给创建人, 下一个任务的候选人
                List<ActivitiTaskLog> taskCompletedLogs = this.taskCompleted(processInstance, activitiEvent.getExecutionId());
                if (!CollectionUtils.isEmpty(taskCompletedLogs)) {
                    taskLogList.addAll(taskCompletedLogs);
                }
                break;
            case PROCESS_COMPLETED:
                // 流程完成,给创建人,协助人,抄送人发通知
                List<ActivitiTaskLog> processCompletedLogs = this.processCompleted(processInstance);
                if (!CollectionUtils.isEmpty(processCompletedLogs)) {
                    taskLogList.addAll(processCompletedLogs);
                }
                break;
            default:
        }

        //执行日志操作
        if (!CollectionUtils.isEmpty(taskLogList)) {
            activitiTaskLogService.createBatch(taskLogList);
        }
    }
}

新增配置类

继承 DefaultActivityBehaviorFactoryMappingConfigurer 类(或实现 ProcessEngineConfigurationConfigurer 接口)并重写 configura() 方法, 给 SpringProcessEngineConfiguration 属性添加自定义的监听器实现类

@Configuration
public class ActivitiConfiguration extends DefaultActivityBehaviorFactoryMappingConfigurer {

    @Autowired
    ActivitiTaskLogService activitiTaskLogService;

    @Autowired
    UserService userService;

    public ActivitiConfiguration(VariablesMappingProvider variablesMappingProvider, ProcessVariablesInitiator processVariablesInitiator,
                                 EventSubscriptionPayloadMappingProvider eventSubscriptionPayloadMappingProvider) {
        super(variablesMappingProvider, processVariablesInitiator, eventSubscriptionPayloadMappingProvider);
    }

    @Override
    public void configure(SpringProcessEngineConfiguration springProcessEngineConfiguration) {
        super.configure(springProcessEngineConfiguration);

        springProcessEngineConfiguration.setEventListeners(
                Collections.singletonList(new ActivitiTaskEventListener(activitiTaskLogService, userService)));
    }
}

运行时状态监听器(推荐)

不需要实现 ActivitiEventlistener 接口,也不需要继承 DefaultActivityBehaviorFactoryMappingConfigurer 类或实现 ProcessEngineConfigurationConfigurer 接口,只需要注册相关事件的监听器即可

@Configuration
public class ActivitiConfiguration {

    private final RuntimeService runtimeService;

    private final ActRuTaskLogService actRuTaskLogService;

    public ActivitiConfiguration(RuntimeService runtimeService, ActRuTaskLogService actRuTaskLogService) {
        this.runtimeService = runtimeService;
        this.actRuTaskLogService = actRuTaskLogService;
    }

    @Bean
    public TaskRuntimeEventListener<TaskAssignedEvent> taskAssignedListener() {
        return taskAssigned -> {

            ExecutionEntity execution = (ExecutionEntity) runtimeService.createProcessInstanceQuery()
                    .processInstanceId(taskAssigned.getProcessInstanceId()).singleResult();
            String startUserId = execution.getStartUserId();
            String fileProcInstId = this.fileProcInstId(execution);

            // 排除发起申请的任务,给 assignee 发消息
            if (!taskAssigned.getEntity().getAssignee().equals(startUserId)) {
                Task task = taskAssigned.getEntity();
                ActRuTaskLog taskLog = new ActRuTaskLog(task.getProcessInstanceId(), task.getId(),
                        taskAssigned.getEntity().getAssignee(), String.format(NotifyConstants.PENDING_WARN,
                        this.userName(startUserId), this.processType(fileProcInstId), this.projName(execution)),
                        NotifyTypeConstants.CANDIDATE);
                actRuTaskLogService.create(taskLog);
            }
        };
    }

    @Bean
    public TaskRuntimeEventListener<TaskCompletedEvent> taskCompletedListener() {
        return taskCompleted -> {

            ExecutionEntity execution = (ExecutionEntity) runtimeService.createProcessInstanceQuery()
                    .processInstanceId(taskCompleted.getProcessInstanceId()).singleResult();
            String startUserId = execution.getStartUserId();
            String fileProcInstId = this.fileProcInstId(execution);
            Task task = taskCompleted.getEntity();
            // 发起审批,给抄送人、协助人发消息
            if (!taskCompleted.getEntity().getAssignee().equals(startUserId)) {
                // 任务所有人
                String owner = taskCompleted.getEntity().getOwner();
                ActRuTaskLog taskLog = new ActRuTaskLog(task.getProcessInstanceId(), task.getId(),
                        this.userName(owner), String.format(NotifyConstants.PENDING_WARN,
                        this.userName(startUserId), this.processType(fileProcInstId), this.projName(execution)),
                        NotifyTypeConstants.CANDIDATE);
                actRuTaskLogService.create(taskLog);
            } else {
                // 给发起人发送任务处理结果的通知
                ActRuTaskLog taskLog = new ActRuTaskLog(task.getProcessInstanceId(), task.getId(),
                        taskCompleted.getEntity().getAssignee(), String.format(NotifyConstants.PENDING,
                        this.userName(startUserId), this.processType(fileProcInstId), this.projName(execution),
                        this.userName(task.getAssignee()), ""), NotifyTypeConstants.PENDING);
                actRuTaskLogService.create(taskLog);
            }
        };
    }

    @Bean
    public TaskCandidateEventListener<TaskCandidateUserAddedEvent> taskCandidateUserEventListener() {
        return taskCandidateEvent -> log.info(">>> Task Candidate User Add: '"
                + taskCandidateEvent.getEntity().toString());
    }

    @Bean
    public TaskCandidateEventListener<TaskCandidateGroupAddedEvent> taskCandidateGroupEventListener() {
        return taskCandidateEvent -> log.info(">>> Task Candidate Group Add: '"
                + taskCandidateEvent.getEntity().toString());
    }

    @Bean
    public ProcessRuntimeEventListener<ProcessCompletedEvent> processCompletedEventListener() {
        return processCompletedEvent -> log.info("===>>> Process Completed: '"
                + processCompletedEvent.getEntity().toString());
    }

    /**
     * 获取流程表单名
     *
     * @param executionEntity 执行对象
     * @return 表单名
     */
    private String projName(ExecutionEntity executionEntity) {
        Object processInstanceName = executionEntity.getVariable("projName");
        return null == processInstanceName ? "" : processInstanceName.toString();
    }

    /**
     * 获取流程文件ID
     *
     * @param executionEntity 执行对象
     * @return 文件ID
     */
    private String fileProcInstId(ExecutionEntity executionEntity) {
        Object fileProcInstId = executionEntity.getVariable("fileProcInstId");
        return fileProcInstId == null ? "" : fileProcInstId.toString();
    }

    /**
     * 审批类型
     *
     * @param fileProcInstId 文件ID
     * @return 类型
     */
    private String processType(String fileProcInstId) {
        return StringUtils.hasText(fileProcInstId) ? "用印" : "合同";
    }

    /**
     * 获取姓名
     *
     * @param userId 用户ID
     * @return 用户姓名
     */
    private String userName(String userId) {
        return userId + "操作人";
    }
}

两种方案对比

更推荐使用第二种,因为第一种方案中,ActivitiEvent 是超类,而一些属性是直接获取不到的,如果要获取,就需要进行向下强转,而每种事件的类型,实现子类又是不同的,需要做很多的判断,但是第二种方法就不用,因为当前监听器中的对象就是改类型对应的事件的相关对象,能够直接获取到相关的变量和信息。

posted @ 2022-11-08 14:05  夏·舍  阅读(241)  评论(0编辑  收藏  举报