工作流activiti插件的使用


声明:本文转载自https://my.oschina.net/u/3534905/blog/1790618,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

1、因为我用的是eclipse,所以介绍一下eclipse安装activiti的方法,help——>Install new software,如下图:

点击add

会出现如下图:

安装图示输入,点击ok,然后finish,等待安装完成。

2、使用

创建一个项目:新建MyProcess.bpmn文件,代码如下:

<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">   <process id="myProcess" name="My process" isExecutable="true">     <startEvent id="startevent1" name="Start">       <extensionElements>         <activiti:executionListener event="start" class="org.pan.activity.bpmnlistern.MyExecutionListern"></activiti:executionListener>       </extensionElements>     </startEvent>     <userTask id="usertask1" name="申请开始任务">       <extensionElements>         <activiti:taskListener event="create" class="org.pan.activity.bpmnlistern.MyTaskListernBegin"></activiti:taskListener>       </extensionElements>     </userTask>     <sequenceFlow id="flow1" name="申请" sourceRef="startevent1" targetRef="usertask1">       <extensionElements>         <activiti:executionListener event="take" class="org.pan.activity.bpmnlistern.MyExecutionListern"></activiti:executionListener>       </extensionElements>     </sequenceFlow>     <userTask id="usertask2" name="任务开始结束">       <extensionElements>         <activiti:taskListener event="create" class="org.pan.activity.bpmnlistern.MyTaskListernBegin"></activiti:taskListener>       </extensionElements>     </userTask>     <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2">       <extensionElements>         <activiti:executionListener event="take" class="org.pan.activity.bpmnlistern.MyExecutionListern"></activiti:executionListener>       </extensionElements>       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${isTrue == "true"}]]></conditionExpression>     </sequenceFlow>     <endEvent id="endevent1" name="End">       <extensionElements>         <activiti:executionListener event="end" class="org.pan.activity.bpmnlistern.MyExecutionListern"></activiti:executionListener>       </extensionElements>     </endEvent>     <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask4"></sequenceFlow>     <userTask id="usertask3" name="个人任务">       <extensionElements>         <activiti:taskListener event="create" class="org.pan.activity.bpmnlistern.MyTaskListernOwern"></activiti:taskListener>         <activiti:taskListener event="complete" class="org.pan.activity.bpmnlistern.MyTaskListernOwern"></activiti:taskListener>       </extensionElements>     </userTask>     <sequenceFlow id="flow4" sourceRef="usertask1" targetRef="usertask3">       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${isTrue == "false"}]]></conditionExpression>     </sequenceFlow>     <sequenceFlow id="flow5" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>     <userTask id="usertask4" name="分组任务">       <extensionElements>         <activiti:taskListener event="create" class="org.pan.activity.bpmnlistern.MyTaskListernGroup"></activiti:taskListener>       </extensionElements>     </userTask>     <sequenceFlow id="flow6" sourceRef="usertask4" targetRef="endevent1"></sequenceFlow>   </process>   <bpmndi:BPMNDiagram id="BPMNDiagram_myProcess">     <bpmndi:BPMNPlane bpmnElement="myProcess" id="BPMNPlane_myProcess">       <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">         <omgdc:Bounds height="35.0" width="35.0" x="50.0" y="216.0"></omgdc:Bounds>       </bpmndi:BPMNShape>       <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">         <omgdc:Bounds height="55.0" width="105.0" x="180.0" y="206.0"></omgdc:Bounds>       </bpmndi:BPMNShape>       <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">         <omgdc:Bounds height="55.0" width="105.0" x="362.0" y="100.0"></omgdc:Bounds>       </bpmndi:BPMNShape>       <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">         <omgdc:Bounds height="35.0" width="35.0" x="770.0" y="216.0"></omgdc:Bounds>       </bpmndi:BPMNShape>       <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">         <omgdc:Bounds height="55.0" width="105.0" x="466.0" y="310.0"></omgdc:Bounds>       </bpmndi:BPMNShape>       <bpmndi:BPMNShape bpmnElement="usertask4" id="BPMNShape_usertask4">         <omgdc:Bounds height="55.0" width="105.0" x="580.0" y="100.0"></omgdc:Bounds>       </bpmndi:BPMNShape>       <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">         <omgdi:waypoint x="85.0" y="233.0"></omgdi:waypoint>         <omgdi:waypoint x="180.0" y="233.0"></omgdi:waypoint>         <bpmndi:BPMNLabel>           <omgdc:Bounds height="14.0" width="24.0" x="85.0" y="233.0"></omgdc:Bounds>         </bpmndi:BPMNLabel>       </bpmndi:BPMNEdge>       <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">         <omgdi:waypoint x="232.0" y="206.0"></omgdi:waypoint>         <omgdi:waypoint x="414.0" y="155.0"></omgdi:waypoint>       </bpmndi:BPMNEdge>       <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">         <omgdi:waypoint x="467.0" y="127.0"></omgdi:waypoint>         <omgdi:waypoint x="580.0" y="127.0"></omgdi:waypoint>       </bpmndi:BPMNEdge>       <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">         <omgdi:waypoint x="232.0" y="261.0"></omgdi:waypoint>         <omgdi:waypoint x="518.0" y="310.0"></omgdi:waypoint>       </bpmndi:BPMNEdge>       <bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">         <omgdi:waypoint x="518.0" y="310.0"></omgdi:waypoint>         <omgdi:waypoint x="787.0" y="251.0"></omgdi:waypoint>       </bpmndi:BPMNEdge>       <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6">         <omgdi:waypoint x="632.0" y="155.0"></omgdi:waypoint>         <omgdi:waypoint x="787.0" y="216.0"></omgdi:waypoint>       </bpmndi:BPMNEdge>     </bpmndi:BPMNPlane>   </bpmndi:BPMNDiagram> </definitions>

activiti视图如下:

pom文件需要添加如下几个包:

        <dependency> 			<groupId>org.activiti</groupId> 			<artifactId>activiti-engine</artifactId> 			<version>5.21.0</version> 		</dependency> 		<dependency> 			<groupId>org.activiti</groupId> 			<artifactId>activiti-spring</artifactId> 			<version>5.21.0</version> 			<exclusions> 				<exclusion> 					<groupId>org.springframework</groupId> 					<artifactId>spring</artifactId> 				</exclusion> 			</exclusions> 		</dependency> 		<dependency> 			<groupId>org.activiti</groupId> 			<artifactId>activiti-diagram-rest</artifactId> 			<version>5.21.0</version> 			<exclusions> 				<exclusion> 					<groupId>org.springframework</groupId> 					<artifactId>spring</artifactId> 				</exclusion> 			</exclusions> 		</dependency> 		<dependency> 			<groupId>org.activiti</groupId> 			<artifactId>activiti-modeler</artifactId> 			<version>5.21.0</version> 			<exclusions> 				<exclusion> 					<groupId>org.springframework</groupId> 					<artifactId>spring</artifactId> 				</exclusion> 			</exclusions> 		</dependency>

activiti有两种监听器,分别是:ExecutionListern主要用于流程的开始、结束和连线的监听,共有三个值:"start"、"end"、"take",其中start和end用于整个流程的开始和结束,take用于连线。TaskListern主要用于节点的监听,共有四个事件:分别是:"create"、"assignment"、"complete"、"delete",当流转到这个节点是触发create事件,当被委托是触发assignment事件,当事件完成时, 因为activity会删除相应数据表中的节点信息所以会同时触发complete和delete事件。

项目中用到的四个监听器代码如下:

/**  *@description		executionListern主要用于流程的开始、结束和连线的监听  *					共有三个值:"start"、"end"、"take"。  *					其中start和end用于整个流程的开始和结束,take用于连线  *@auth panmingshuai  *@time 2018年4月5日下午8:59:16  *   */  public class MyExecutionListern implements ExecutionListener{  	/** 	 *  	 */ 	private static final long serialVersionUID = 1L;  	@Override 	public void notify(DelegateExecution execution) throws Exception { 		//得到现在事件阶段的值,用"start".endsWith(eventName)来判断 		String eventName = execution.getEventName(); 		if("start".endsWith(eventName)){ 			System.out.println("-------------------流程开始-------------------"); 		} else if("end".equals(eventName)){ 			System.out.println("-------------------流程结束-------------------"); 		} 		 		 		 	} }
/**  *@description   *@auth panmingshuai  *@time 2018年4月5日下午11:18:24  *   */  public class MyTaskListernBegin implements TaskListener {  	/** 	 *  	 */ 	private static final long serialVersionUID = 1L;  	@Override 	public void notify(DelegateTask delegateTask) { 		//得到现在事件阶段的值,用"create".endsWith(eventName)来判断 		String eventName = delegateTask.getEventName(); 		if("create".equals(eventName)){ 			System.out.println("-------------------分组任务开始---------------"); 			 			//指定组任务审核人员 			delegateTask.addCandidateUser("ming1"); 			delegateTask.addCandidateUser("ming2"); 		} else if("complete".equals(eventName)){ 			System.out.println("-------------------分组任务结束---------------"); 		} 		 	}  }
/**  *@description taskListern主要用于节点的监听  *				共有四个事件:分别是:"create"、"assignment"、"complete"、"delete"。  *				当流转到这个节点是触发create事件,当被委托是触发assignment事件,当事件完成时,  *				因为activity会删除相应数据表中的节点信息所以会触发complete和delete事件  *@auth panmingshuai  *@time 2018年4月5日下午8:59:16  *   */  public class MyTaskListernGroup implements TaskListener {  	/** 	 *  	 */ 	private static final long serialVersionUID = 1L;  	@Override 	public void notify(DelegateTask delegateTask) { 		//得到现在事件阶段的值,用"create".endsWith(eventName)来判断 		String eventName = delegateTask.getEventName(); 		if("create".equals(eventName)){ 			System.out.println("-------------------分组任务开始---------------"); 			 			//指定组任务审核人员 			delegateTask.addCandidateUser("ming1"); 			delegateTask.addCandidateUser("ming2"); 		} else if("complete".equals(eventName)){ 			System.out.println("-------------------分组任务结束---------------"); 		} 		 		 	}  }
/**  *@description   *@auth panmingshuai  *@time 2018年4月5日下午9:44:16  *   */  public class MyTaskListernOwern implements TaskListener {  	/** 	 *  	 */ 	private static final long serialVersionUID = 1L;  	@Override 	public void notify(DelegateTask delegateTask) { 		//得到现在事件阶段的值,用"create".endsWith(eventName)来判断 		String eventName = delegateTask.getEventName(); 		 		if("create".equals(eventName)){ 			System.out.println("-------------------个人任务开始---------------"); 			 			//添加个人任务 			delegateTask.setOwner("ming1"); 		} else if("complete".equals(eventName)){ 			System.out.println("-------------------个人任务结束---------------"); 		} 		 		 		 	}  }

接下来是activiti的配置,因为activiti需要操作数据表,因此如果要使用activiti必须要配置数据库连接池和事物管理:

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">         <property name="driverClass" value="${jdbc.driver}"/>         <property name="jdbcUrl" value="${jdbc.url}"/>         <property name="user" value="${jdbc.username}"/>         <property name="password" value="${jdbc.password}"/>         <property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>         <property name="minPoolSize" value="${jdbc.minPoolSize}"/>         <property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>         <property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>         <property name="maxIdleTime" value="${jdbc.maxIdleTime}"/>     </bean>      <!-- 启用注解式事务管理 --> 	<tx:annotation-driven transaction-manager="transactionManager" />      <!-- 加载activiti引擎 --> 	<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean"> 		<property name="processEngineConfiguration" ref="processEngineConfiguration" /> 	</bean> 	<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> 		<property name="dataSource" ref="dataSource" /> 		<property name="transactionManager" ref="transactionManager" /> 		<property name="databaseSchemaUpdate" value="true" /> 		<property name="jobExecutorActivate" value="false" /> 	</bean> 	<!-- activiti的各种服务接口 --> 	<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" /> 	<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" /> 	<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" /> 	<bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" />

对于其中activiti的服务接口的作用如下:

RepositoryService                    管理流程定义

RuntimeService                        执行管理,包括启动、推进、删除流程实例等操作

TaskService                                任务管理

HistoryService                            历史管理(执行完的数据的管理)

具体使用时需要注入相应的接口:

当然可以不使用这些接口使用processEngine的各种get方法也可以,只是不怎么方便:

3、具体的业务使用:

3.1、首先如果要使用工作流,必须先部署流程:

// 部署流程,只要是符合BPMN2规范的XML文件,理论上都可以被ACTIVITI部署 		Deployment deployment = repositoryService.createDeployment().addClasspathResource("org/pan/activity/bpmn/MyProcess.bpmn").deploy(); 		System.out.println("deployment: id: " + deployment.getId() + "----- name: " + deployment.getName()); 		return "发布成功";

注:项目启动时,activiti会自动在你连接的数据库生成它所需要的数据表,都是以act_打头的。

一般如果没改流程图的话,也没改数据库的话,只用部署一次就够了。

现在假设一个人提交了一个申请过来,怎么给他一个流程的实例呢?如下:

//开启流程时设置的变量是全局变量 		Map<String, Object> variables = new HashMap<>(); 		variables.put("shuai", "haha"); 		// 开启流程,myprocess是流程的ID,每个流程图都有自己专属的id,businessid代表每个具体的业务流程 		ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess", businessId, variables); 		Task activityTask = taskService.createTaskQuery().processInstanceId(processInstance.getId()).taskDefinitionKey(processInstance.getActivityId()).singleResult(); 		System.out.println("processInstance: id: " + processInstance.getId() + "----- activityTaskId: " + activityTask.getId()); 		return "开启成功";

这便开启了一个专属的流程实例给某一个业务,值得注意的是processInstance.getId()这个id是activiti自己生成的id,businessId是我们自己的业务id,但是这个可以不用设置,这看项目的需要,我们可以拥有自己的业务申请表,但是也可以把申请的内容放到variables中,需要的时候再查出来,这样就不用再建立自己的申请表了。

流程开始了就需要处理任务了,但是有谁来处理任务呢?

上面的监听器里其实就有代码,需要注意的是当任务的creat事件被触发时设置处理人,设置的处理人也只能处理这个任务,当然还有其他设置处理人的方式,但是我觉得这种方式最好。另外delegateTask.addCandidateUser("ming1");这个是设置组任务处理人的。 

delegateTask.setOwner("ming1");这个是设置个人任务的。所谓的组任务是指这个组里的人都会看到这个任务,个人任务是指只有这个人会看到这个任务。

任务处理人设置好了,那一个人怎么看到自己的任务呢?

// 个人任务查询 		List<Task> taskList = taskService.createTaskQuery().taskAssignee(userName).list(); 		for(Task task : taskList){ 			System.out.println("assignee: " + task.getAssignee() + "---- taskName:" + task.getName() + "---- taskId: " + task.getId()); 		} 		return taskList.size() + "";
// 组任务查询 		List<Task> taskList = taskService.createTaskQuery().taskCandidateUser(userName).list(); 		for(Task task : taskList){ 			System.out.println("assignee: " + task.getAssignee() + "---- taskName:" + task.getName() + "---- taskId: " + task.getId()); 		} 		return taskList.size() + "";

需要注意的一点是组任务查询时,只要是这个组的组员的人都会看到所有的组任务,但是组任务怎么确定是谁来处理的这个任务呢?这个时候就需要将这个任务指定了,比如说一个组员说这个任务归他了,那个我们就得把任务派发给他,不然不知道是谁搞定的。如下指定:

taskService.claim(taskId, userName);

好了任务也查好了,我该怎么处理呢:

String val = (String) taskService.getVariable(taskId, "isTrue"); 		String shuai = (String) taskService.getVariable(taskId, "shuai"); 		System.out.println(shuai); 		System.out.println(val); 		//这里设置的变量是局部变量,只对下一个节点有用 		Map<String, Object> variables = new HashMap<>(); 		variables.put("isTrue", isTrue); 		taskService.complete(taskId, variables); 		return "任务:" + taskId + " 完成";

这里的getVariable方法是获取从上一个节点传过来的参数,taskService调用complete方法完成节点,这个时候会触发该节点的complete和delete事件以及下一个节点的create事件。complete方法中的variables是传到下一个节点的参数。需要特别注意的是,启动流程实例时startProcessInstanceByKey方法中的variables参数是全局的,你可以在任意一个节点调到他们的值。其中有一个用处就是:比如你要限制一个申请被打回的次数,你可以用它。

好了任务完成了,我们怎么看这个流程走到了哪里呢?

ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(businessId).singleResult(); 		Task activityTask = taskService.createTaskQuery().processInstanceId(processInstance.getId()).taskDefinitionKey(processInstance.getActivityId()).singleResult(); 		System.out.print("----- activityTaskName: " + activityTask.getName()); 		System.out.println("----- isEnded:" + processInstance.isEnded()); 		return "查询成功";

其中activityTask即为当前流程所在的任务节点。

那怎么查一个任务经历了哪些节点呢?

HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessId).singleResult(); 		List<HistoricTaskInstance> taskInstances = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstance.getId()).orderByTaskCreateTime().asc().list(); 		for(HistoricTaskInstance taskInstance : taskInstances){ 			System.out.print("taskId:" + taskInstance.getId()); 			System.out.print("---taskName:" + taskInstance.getName()); 			System.out.print("---assignee:" + taskInstance.getAssignee()); 			System.out.print("---startTime:" + taskInstance.getStartTime()); 			System.out.print("---endTime:" + taskInstance.getEndTime()); 			System.out.println("---duration:" + taskInstance.getDurationInMillis()); 		} 		return "查询成功";

怎么查一个人处理了哪些任务呢?

List<HistoricTaskInstance> taskInstances = historyService.createHistoricTaskInstanceQuery().taskAssignee(userName).list(); 		for(HistoricTaskInstance taskInstance : taskInstances){ 			System.out.print("taskId:" + taskInstance.getId()); 			System.out.print("---taskName:" + taskInstance.getName()); 			System.out.print("---assignee:" + taskInstance.getAssignee()); 			System.out.print("---startTime:" + taskInstance.getStartTime()); 			System.out.print("---endTime:" + taskInstance.getEndTime()); 			System.out.println("---duration:" + taskInstance.getDurationInMillis()); 		}

基本上一个项目中就用到了这些流程的功能,基本满足了,完毕

本文发表于2018年04月07日 22:38
(c)注:本文转载自https://my.oschina.net/u/3534905/blog/1790618,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2148 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1