工作流activiti插件的使用

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());
		}

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

猜你喜欢

转载自my.oschina.net/u/3534905/blog/1790618