本文集体博客地址:Activiti7 事件监听 (leafage.top)
良久没有记录笔记了,最近做了一些对于工作流的事件,记录一下应用 activiti 7 的一些教训。
需要:
- 在流程发动和流程操作的过程中,给相干人员发送流程审批的告诉揭示;
- 不要在配置流程时手动增加,不能侵入到流程操作的过程,影响流程执行;
<mark> 这个怎么动手呢?没搞过 activiti,activiti7 的官网文档写的跟屎一样烂,感觉好难呀 </mark>😔…
文档参考性不高,那就试试看官网的示例,找到 activiti 的 repository,有一个示例 module 叫 activiti-examples,<mark> 这里的示例不能间接跑,只能看 </mark>,要想跑起来,就复制,粘贴,放到本人的我的项目中。 跑题了,说会主题。。。
activiti 中的几个关联的重要的类或接口:
-
activiti 中每个流程信息是通过 ProcessInstance 形容,它有这么几个状态:created、started、completed、cancelled、resumed、updated、suspended,与之对应的相干事件形容类是:ProcessCreatedEvent、ProcessStartedEvent、ProcessCompletedEvent、ProcessCancelledEvent、ProcessResumedEvent、ProcessUpdatedEvent、ProcessSuspendedEvent 等。
-
每个流程节点在 activiti 中 通过 Task 来形容,它有这么几个个状态:created、assigned、completed、updated、cancelled、suspended 等,与之对应的相干事件形容类是:TaskCreatedEvent、TaskAssignedEvent、TaskCompletedEvent、TaskUpdatedEvent、TaskCancelledEvent、TaskSuspendedEvent 等。
如何配置监听器?
1. 全局事件监听器:
波及到两个类 \ 接口,全局事件监听器 ActivitiEventListener 和 ProcessEngineConfigurationConfigurer(有一个默认的实现类:DefaultActivityBehaviorFactoryMappingConfigurer)
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));
}
}
如何来监听事件?
- 实现 ActivitiEventListener 接口,重写 void onEvent(ActivitiEvent event) 办法;
- 新增配置类,继承 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 是超类,而一些属性是间接获取不到的,如果要获取,就须要进行向下强转,而每种事件的类型,实现子类又是不同的,须要做很多的判断,然而第二种办法就不必,因为以后监听器中的对象就是改类型对应的事件的相干对象,可能间接获取到相干的变量和信息。