工做流activiti插件的使用

一、由於我用的是eclipse,因此介紹一下eclipse安裝activiti的方法,help——>Install new software,以下圖:java

點擊addspring

會出現以下圖:數據庫

安裝圖示輸入,點擊ok,而後finish,等待安裝完成。express

二、使用eclipse

建立一個項目:新建MyProcess.bpmn文件,代碼以下:ide

<?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視圖以下:ui

pom文件須要添加以下幾個包:url

<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事件。spa

項目中用到的四個監聽器代碼以下:rest

/**
 *@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.一、首先若是要使用工做流,必須先部署流程:

// 部署流程,只要是符合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());
		}

基本上一個項目中就用到了這些流程的功能,基本知足了,完畢

相關文章
相關標籤/搜索