activiti 事件监听_js监听事件和处理事件

activiti 事件监听_js监听事件和处理事件本文个人博客地址:Activiti7事件监听(leafage.top)好久没有记录笔记了,最近做了一些关于工作流的事情,记录一下使用activiti7的一些经验。需求:在流程发起和流程操作的过程中,给相关人员发送流程审批的通知提醒;不要在配置流程时手动添加,不能侵入到流程操作的过程,影响流程执行;这个怎么入手呢?没搞过activiti,activiti7的官方文档写的跟屎一样烂,感觉好难呀????…文档参考性不高,那就试试看官方的示例,找到activiti的repositor

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

本文个人博客地址:Activiti7事件监听 (leafage.top)

好久没有记录笔记了,最近做了一些关于工作流的事情,记录一下使用activiti 7的一些经验。

需求:

  1. 在流程发起和流程操作的过程中,给相关人员发送流程审批的通知提醒;
  2. 不要在配置流程时手动添加,不能侵入到流程操作的过程,影响流程执行;

这个怎么入手呢?没搞过activiti,activiti7 的官方文档写的跟屎一样烂,感觉好难呀?…

文档参考性不高,那就试试看官方的示例,找到 activiti 的 repository ,有一个示例 module 叫 activiti-examples,这里的示例不能直接跑,只能看,要想跑起来,就复制,粘贴,放到自己的项目中。跑题了,说会主题。。。

activiti中的几个关联的重要的类或接口:

  1. activiti 中每个流程信息是通过 ProcessInstance 描述,它有这么几个状态:created、started、completed、cancelled、resumed、updated、suspended,与之对应的相关事件描述类是:ProcessCreatedEvent、ProcessStartedEvent、ProcessCompletedEvent、ProcessCancelledEvent、ProcessResumedEvent、ProcessUpdatedEvent、ProcessSuspendedEvent等。

    image.png

  2. 每个流程节点在 activiti 中 通过 Task 来描述,它有这么几个个状态:created、assigned、completed、updated、cancelled、suspended等,与之对应的相关事件描述类是:TaskCreatedEvent、TaskAssignedEvent、TaskCompletedEvent、TaskUpdatedEvent、TaskCancelledEvent、TaskSuspendedEvent等。

    image.png

如何配置监听器?

1. 全局事件监听器:

涉及到两个类\接口,全局事件监听器 ActivitiEventListener 和 ProcessEngineConfigurationConfigurer(有一个默认的实现类:DefaultActivityBehaviorFactoryMappingConfigurer)

image.png

ActitiviEventListener 接口有一个 void onEvent(ActivitiEvent activitiEvent) 方法,即在事件状态发生变化时,可以发生的动作都会在这个方法中进行。其源码如下:

/** * Describes a class that listens for {@link ActivitiEvent}s dispatched by the engine. * */
public interface ActivitiEventListener { 
   

  void onEvent(ActivitiEvent event);

  boolean isFailOnException();
}

ActivitiEvent 包含了流程的定义ID,示例ID,执行ID,和事件类型信息,源码如下:

public interface ActivitiEvent { 
   

  ActivitiEventType getType();

  String getExecutionId();

  String getProcessInstanceId();

  String getProcessDefinitionId();
}

其事件类型包括很多,源码如下:

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 ...
}

ProcessEngineConfigurationConfigurer 中的 void configure(SpringProcessEngineConfiguration springProcessEngineConfiguration) 方法可以添加自定义的事件监听器,这个监听器作用域为整个流程过程。其源码如下:

public class DefaultActivityBehaviorFactoryMappingConfigurer implements ProcessEngineConfigurationConfigurer { 
   

    private VariablesMappingProvider variablesMappingProvider;

    private ProcessVariablesInitiator processVariablesInitiator;
    
    private final EventSubscriptionPayloadMappingProvider eventSubscriptionPayloadMappingProvider;

    public DefaultActivityBehaviorFactoryMappingConfigurer(VariablesMappingProvider variablesMappingProvider,
                                                           ProcessVariablesInitiator processVariablesInitiator,
                                                           EventSubscriptionPayloadMappingProvider eventSubscriptionPayloadMappingProvider){ 
   
        this.variablesMappingProvider = variablesMappingProvider;
        this.processVariablesInitiator = processVariablesInitiator;
        this.eventSubscriptionPayloadMappingProvider = eventSubscriptionPayloadMappingProvider;
    }
    @Override
    public void configure(SpringProcessEngineConfiguration processEngineConfiguration){ 
   
        processEngineConfiguration.setEventSubscriptionPayloadMappingProvider(eventSubscriptionPayloadMappingProvider);

        processEngineConfiguration.setActivityBehaviorFactory(new MappingAwareActivityBehaviorFactory(variablesMappingProvider,
                                                                                                      processVariablesInitiator));
    }
}

如何来监听事件?

  1. 实现 ActivitiEventListener 接口,重写 void onEvent(ActivitiEvent event) 方法;
  2. 新增配置类,继承 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)));
    }
}
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);
        }
    }
}

2. 运行时状态监听器:

在实例中有一个 activiti-api-basic-process-example 和 activiti-api-basic-task-example 两个示例工程,展示了如何进行配置运行时的process和task的监听。

activiti-api-basic-process-example 中,流程监听示例:

@Bean
public ProcessRuntimeEventListener<ProcessCompletedEvent> processCompletedListener() { 
   
    return processCompleted -> logger.info(">>> Process Completed: '"
            + processCompleted.getEntity().getName() +
            "' We can send a notification to the initiator: " + processCompleted.getEntity().getInitiator());
}

activiti-api-basic-task-example 中,任务监听示例:

@Bean
public TaskRuntimeEventListener<TaskAssignedEvent> taskAssignedListener() { 
   
    return taskAssigned -> logger.info(">>> Task Assigned: '"
            + taskAssigned.getEntity().getName() +
            "' We can send a notification to the assginee: " + taskAssigned.getEntity().getAssignee());
}

@Bean
public TaskRuntimeEventListener<TaskCompletedEvent> taskCompletedListener() { 
   
    return taskCompleted -> logger.info(">>> Task Completed: '"
            + taskCompleted.getEntity().getName() +
            "' We can send a notification to the owner: " + taskCompleted.getEntity().getOwner());
}

参照示例,我们可以进行自定义的流程中事件监听的配置,这种方式,不需要实现 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 是超类,而一些属性是直接获取不到的,如果要获取,就需要进行向下强转,而每种事件的类型,实现子类又是不同的,需要做很多的判断,但是第二种方法就不用,因为当前监听器中的对象就是改类型对应的事件的相关对象,能够直接获取到相关的变量和信息。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/184815.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 四轴飞行器原理图详解(三旋翼飞行器)

    顾名思义,四轴飞行器由四个螺旋桨高速旋转产生升力,为其提供飞行动力。四个电机转向正反各两个,可以相互抵消反扭矩。不同于常规固定翼飞机,多旋翼无人机属于静不稳定系统,因此必须依赖于强大的飞控系统才能飞行。四轴飞行器可分为“十字型”和“X型”,其中“十字型”机动性强主要应用在穿越机或特技表演无人机;“X型”稳定性强,是最常见的四轴飞行器构型。本文中所介绍的飞控系统都是基于“X型”四轴飞

  • python安装教程[通俗易懂]

    python安装教程[通俗易懂]python安装教程本章节我们将向大家介绍如何在本地搭建Python开发环境。Python可应用于多平台包括Linux和MacOSX。你可以通过终端窗口输入"python&

  • 那些惊艳的算法们(三)—— 时间轮[通俗易懂]

    那些惊艳的算法们(三)—— 时间轮[通俗易懂]同步发表于:http://blog.lanjingdejia.com/articles/2018/08/13/1534132662997.html从定时任务说起自然界中定时任务无处不在,太阳每天东升西落,候鸟的迁徙,树木的年轮,人们每天按时上班,每个月按时发工资、交房租,四季轮换,潮涨潮落,等等,从某种意义上说,都可以认为是定时任务。大概很少有人想过,这些“定时”是怎样做到的。当然,计算机…

  • REST API和SOAP API区别[通俗易懂]

    REST API和SOAP API区别[通俗易懂]RESTAPI优点:1.轻量级的解决方案,不必向SOAP那样要构建一个标准的SOAPXML。2.可读性比较好:可以把URL的名字取得有实际意义。3.不需要SDK支持:直接一个Http请求就可以,但是SOAP则可能需要使用到一些Webservice的类库(例如Apache的Axis)缺点:1.复杂的应用中,URL可能非常长,而且不容易解析。SOAPAPI优点:1.定…

  • NOSQL(一)–Redis

    NOSQL(一)–Redis

    2021年11月26日
  • 走完同一条街,回到两个世界

    宿舍楼下就那么寥寥几棵树,知了一直在叫啊叫的不停.小时候跟着它们一起叫,用杆子粘着活好的面去黏它们,虽然从来都捉不到,现在,它们还在叫,我却已经过了跟它们玩的年纪.暑假回家呆了几天,上班,坐公交,下班,坐公交.在公司里清清爽爽几乎忘了这是夏天,下班了一出门喘口气都要流汗,还要被挤进密不透风的电梯里狠狠压缩一下,电梯也很累,每个楼层都要停一下,打开门叹口气接着往下走,满满一电梯的脑袋

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号