activiti学习(十)——自定义对象解析器

上一篇博文分析了对象解析器的原理。本文来编写一个自定义对象解析器。考虑这样的场景:生产中我们常常在流程的上一环节选择下环节的处理人,然后再提交流程。之后流程运转到下一个环节后,会在对应的处理人名下,即userTask的candidate或assignee是上环节选中的处理人。

上述的实现方式可以是这样,对userTask添加自定义任务监听器,该监听器主要作用是把流程实例中的变量设置为userTask的candidate或assignee。这样在流程执行的时候,上一环节选择了处理人,写入流程变量中,待下一环节的任务监听器把变量读出来设置到userTask的candidate或assignee。但是在bpmn图上为每个userTask上添加这样的监听器,随着流程和userTask增多,维护起来非常繁琐。生产系统常常有十几个不同的流程,每个流程数个或十数个节点,而且随着业务变化,流程图也要时不时进行修改,手动对每个userTask添加监听器不现实。有没有办法为任务节点统一添加监听器呢?答案是有的!我们可以自定义一个userTask的对象解析器,在解析每个userTask时,为其添加监听器,这样我们就没必要在bpmn图上手动添加了。不仅省时省力,而且方便统一管理。

首先我们自定义一个监听器AssignmentTaskListener.java

public class AssignmentTaskListener implements TaskListener{

	public void notify(DelegateTask delegateTask) {
		String assignee = (String)delegateTask.getVariable("assignee");
		delegateTask.setAssignee(assignee);
	}
}

改监听器主要作用就是在触发的时候,把流程变量"assignee"中的值设置到userTask的assignee中。

接着我们扩展userTask的解析器,自定义MyUserTaskParseHandler.java

public class MyUserTaskParseHandler extends UserTaskParseHandler{

	private List<TaskListener> taskListenerList;
	
	@Override
	protected void executeParse(BpmnParse bpmnParse, UserTask userTask) {
		//由父类完成元素解析
		super.executeParse(bpmnParse, userTask);
		
		for(TaskListener taskListener : taskListenerList) {
			TaskDefinition taskDefinition = (TaskDefinition)bpmnParse.getCurrentActivity().getProperty(UserTaskParseHandler.PROPERTY_TASK_DEFINITION);
			taskDefinition.addTaskListener(TaskListener.EVENTNAME_CREATE, taskListener);
		}
	}

	public List<TaskListener> getTaskListenerList() {
		return taskListenerList;
	}

	public void setTaskListenerList(List<TaskListener> taskListenerList) {
		this.taskListenerList = taskListenerList;
	}
}

第8行先调用父类进行元素解析。10-12行对当前userTask添加create事件的任务监听器。为何不在assignment事件触发时添加任务监听器呢?因为如果bpmn图中userTask没有设置assignee的话,流程引擎就不会触发assignment事件,自然就不会调用任务监听器了。

接着我们新建一个流程引擎配置文件,命名为activitiParseHandler.cfg.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="processEngineConfiguration"
		class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">

		<property name="jdbcUrl"
			value="jdbc:mysql://localhost:3306/db_activiti?useUnicode=true&amp;&amp;characterEncoding=utf8&amp;serverTimezone=UTC" />
		<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUsername" value="root" />
		<property name="jdbcPassword" value="" />
		
		<property name="databaseSchemaUpdate" value="true" />
		
		<property name="customDefaultBpmnParseHandlers">
			<list>
				<bean class="parseHandler.MyUserTaskParseHandler">
					<property name="taskListenerList">
						<list>
							<bean class="parseHandler.AssignmentTaskListener"></bean>
						</list>
					</property>
				</bean>
			</list>
		</property>
	</bean>
</beans>

17-27为自定义对象解析器。在初始化流程引擎时,对象解析器通过map方式管理,自定义添加的对象解析器会替换getHandledType()返回值相同的默认对象解析器。MyUserTaskParseHandler继承了UserTaskParseHandler,getHandledType()返回的都是UserTask.class,因此前者会替换后者。20-24行通过xml注入监听器,增加配置灵活度。

然后我们部署流程:


	private ProcessEngine pe;

	public void getFromProcessEngineConfiguration() {
		ProcessEngineConfiguration pec = ProcessEngineConfiguration
				.createProcessEngineConfigurationFromResource("activitiParseHandler.cfg.xml");
		pe = pec.buildProcessEngine();
	}
	
	public void deploy() {
		RepositoryService repositoryService = pe.getRepositoryService();
		DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
		
		InputStream inputStream = null;
		try {
			inputStream = App.class.getClassLoader().getResource("bpmn/parseHandlerBPM.bpmn").openStream();
			deploymentBuilder.addInputStream("parseHandler.bpmn", inputStream);
			deploymentBuilder.name("parseHandlerDeployment");
			Deployment deployment = deploymentBuilder.deploy();
			System.out.println("流程部署ID:" + deployment.getId());
			System.out.println("流程部署名:" + deployment.getName());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	

查看act_ru_procdef表:

接下来我们启动parseHandlerBPM:1:4流程,启动时加入流程变量:

	public void startProcessById() {
		RuntimeService runtimeService = pe.getRuntimeService();
		Map<String, Object> var = new HashMap<String, Object>();
		var.put("assignee", "张三");
		ProcessInstance pi = runtimeService.startProcessInstanceById("parseHandlerBPM:1:4", var);
	}

启动成功后,此时流程应该运行到userTask1节点上,观察act_ru_task:

ASSIGNEE属性值为“张三”,证明自定义对象解析器成功为userTask1添加监听器,并且监听器根据流程变量为userTask1设置了ASSIGNEE。接下来尝试把流程提交到userTask2节点:

	public void completeTask() {
		TaskService taskService = pe.getTaskService();
		Map<String, Object> var = new HashMap<String, Object>();
		var.put("assignee", "李四");
		taskService.complete("2505", var);
	}

提交完成后,观察act_ru_task:

 通过截图看到“李四”也成功设置为userTask2的ASSIGNEE。

在企业流程应用中,设置环节处理人的方法很多,上述仅仅是一个示例。除了把下环节处理人写到流程变量,也可以写到数据库表中,或者通过其他方式去实现,这里不再细述。使用自定义对象解析器,我们除了可以实现本文提到的为节点添加监听器的功能外,还可以实现自定义扩展属性的读取。例如在bpmn图中,我们为某个元素添加了自定义扩展属性。在解析元素时,读取这些自定义扩展属性,可以扩展元素的功能。

发布了39 篇原创文章 · 获赞 5 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/sadoshi/article/details/105182858