一、Activiti簡介
Activiti 是一個針對商務人士、 開發人員和系統管理員的輕量級的工作流和業務流程管理 (BPM) 平台。它的核心是Java的高速和可靠的 BPMN 2 流程引擎。它是開源的、並且提供寬松的Apache許可。Activiti可以在任何Java應用中運行,可以運行在在服務器、集群或雲環境。它可以與Spring進行整合,它非常輕便和機遇簡單的概念。Activiti是由原來開發JBPM的作者所建立的,所以Activiti與JBPM早期的版本(JBPM4,BPM4之后版本已完全拋棄JBPM4的基礎代碼,轉而基於Drools Flow構建)比較相似,適合於早期的JBPM用戶使用。
Activiti 下載地址為:http://activiti.org/download.html 。這里使用的是activiti-5.18.0.zip 版本。
二、eclipse 流程設計器
使用Activiti需要設計流程,然后再進行部署,運行、流轉。這里使用Activiti提供的eclipse插件進行流程設計。以下為插件的安裝:
1、點擊eclipse Help -》 Install New Software. 並在界面點擊Add輸入如下內容,並點擊OK按鈕。如下圖所示
2、點擊Select All並點擊Next,按照界面的提示直到出現如下界面
點擊Finish,等待安裝,安裝完成重啟eclipse即可。
三、Activiti 數據庫配置
activiti-5.17.0.zip下載完成后,解壓。將libs下的activiti-engine-5.17.0.jar文件解壓。創建數據的腳步就在org\activiti\db\create目錄下。 該目錄下有多種版本的數據庫腳本。
- engine:為引擎運行所必須的表。
- identity: 為包含用戶,用戶組和用戶組里的成員。這些表是可選的,但是當引擎是使用默認的身份標識管理進行裝載的時候,這些表必須存在。
- history:這些表包含一些歷史和審計信息。當history level 設置成none的時候是可選的,但是這樣會使一些存儲在history數據庫里面的新特性失效(如任務里面的說明)。
注意:對於mysql來說,版本低於 5.6.4的mysql不支持 帶有毫秒精確度的timestamp和date 類型。所以低於 5.6.4版本的mysql需要執行如下腳本文件:
activiti.mysql55.create.engine.sql
activiti.mysql.create.identity.sql
activiti.mysql55.create.history.sql
而版本號在5.6.4以及以上的mysql需要執行如下腳本
activiti.mysql.create.engine.sql
activiti.mysql.create.identity.sql
activiti.mysql.create.history.sql
創建完成后,生成的表入下圖所示:
四、示例
1、設計流程定義
選擇新建一個Activiti Diagram 命名為test,在拖動Palette中的組件到右邊的設計區域。本例子使用到的有StartEvent、UserTask、EndEvent並使用SequenceFlow將它們連接起來,如下圖所示:
流程定義文件test.bpmn內容如下圖所示:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <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"> 3 <process id="test" name="My process" isExecutable="true"> 4 <startEvent id="start" name="Start"></startEvent> 5 <endEvent id="end" name="End"></endEvent> 6 <userTask id="usertask1" name="step1" activiti:assignee="kermit"></userTask> 7 <userTask id="usertask2" name="step2" activiti:candidateUsers="kermit,gonzo"></userTask> 8 <userTask id="usertask3" name="step3" activiti:candidateGroups="management,accountancy"></userTask> 9 <sequenceFlow id="flow1" sourceRef="start" targetRef="usertask1"></sequenceFlow> 10 <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow> 11 <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow> 12 <sequenceFlow id="flow4" sourceRef="usertask3" targetRef="end"></sequenceFlow> 13 </process> 14 <bpmndi:BPMNDiagram id="BPMNDiagram_test"> 15 <bpmndi:BPMNPlane bpmnElement="test" id="BPMNPlane_test"> 16 <bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start"> 17 <omgdc:Bounds height="35.0" width="35.0" x="20.0" y="129.0"></omgdc:Bounds> 18 </bpmndi:BPMNShape> 19 <bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end"> 20 <omgdc:Bounds height="35.0" width="35.0" x="610.0" y="129.0"></omgdc:Bounds> 21 </bpmndi:BPMNShape> 22 <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1"> 23 <omgdc:Bounds height="55.0" width="105.0" x="110.0" y="119.0"></omgdc:Bounds> 24 </bpmndi:BPMNShape> 25 <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2"> 26 <omgdc:Bounds height="55.0" width="105.0" x="290.0" y="119.0"></omgdc:Bounds> 27 </bpmndi:BPMNShape> 28 <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3"> 29 <omgdc:Bounds height="55.0" width="105.0" x="450.0" y="119.0"></omgdc:Bounds> 30 </bpmndi:BPMNShape> 31 <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1"> 32 <omgdi:waypoint x="55.0" y="146.0"></omgdi:waypoint> 33 <omgdi:waypoint x="110.0" y="146.0"></omgdi:waypoint> 34 </bpmndi:BPMNEdge> 35 <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2"> 36 <omgdi:waypoint x="215.0" y="146.0"></omgdi:waypoint> 37 <omgdi:waypoint x="290.0" y="146.0"></omgdi:waypoint> 38 </bpmndi:BPMNEdge> 39 <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3"> 40 <omgdi:waypoint x="395.0" y="146.0"></omgdi:waypoint> 41 <omgdi:waypoint x="450.0" y="146.0"></omgdi:waypoint> 42 </bpmndi:BPMNEdge> 43 <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4"> 44 <omgdi:waypoint x="555.0" y="146.0"></omgdi:waypoint> 45 <omgdi:waypoint x="610.0" y="146.0"></omgdi:waypoint> 46 </bpmndi:BPMNEdge> 47 </bpmndi:BPMNPlane> 48 </bpmndi:BPMNDiagram> 49 </definitions>
2、代碼示例
工程使用maven構建,pom.xml文件內容如下:
1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 3 <modelVersion>4.0.0</modelVersion> 4 5 <groupId>com.shh</groupId> 6 <artifactId>activitytest</artifactId> 7 <version>0.0.1-SNAPSHOT</version> 8 <packaging>jar</packaging> 9 10 <name>activitytest</name> 11 <url>http://maven.apache.org</url> 12 13 <properties> 14 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 15 <activiti-version>5.18.0</activiti-version> 16 </properties> 17 <dependencies> 18 <dependency> 19 <groupId>org.activiti</groupId> 20 <artifactId>activiti-engine</artifactId> 21 <version>${activiti-version}</version> 22 </dependency> 23 <dependency> 24 <groupId>org.activiti</groupId> 25 <artifactId>activiti-spring</artifactId> 26 <version>${activiti-version}</version> 27 </dependency> 28 <dependency> 29 <groupId>org.codehaus.groovy</groupId> 30 <artifactId>groovy-all</artifactId> 31 <version>2.0.4</version> 32 </dependency> 33 <dependency> 34 <groupId>mysql</groupId> 35 <artifactId>mysql-connector-java</artifactId> 36 <version>5.1.35</version> 37 </dependency> 38 <dependency> 39 <groupId>org.slf4j</groupId> 40 <artifactId>slf4j-api</artifactId> 41 <version>1.7.2</version> 42 </dependency> 43 <dependency> 44 <groupId>org.slf4j</groupId> 45 <artifactId>slf4j-jdk14</artifactId> 46 <version>1.7.2</version> 47 </dependency> 48 <dependency> 49 <groupId>junit</groupId> 50 <artifactId>junit</artifactId> 51 <version>4.11</version> 52 </dependency> 53 54 <dependency> 55 <groupId>org.springframework</groupId> 56 <artifactId>spring-core</artifactId> 57 <version>3.2.2.RELEASE</version> 58 </dependency> 59 <dependency> 60 <groupId>org.springframework</groupId> 61 <artifactId>spring-beans</artifactId> 62 <version>3.2.2.RELEASE</version> 63 </dependency> 64 <dependency> 65 <groupId>org.springframework</groupId> 66 <artifactId>spring-test</artifactId> 67 <version>3.2.2.RELEASE</version> 68 </dependency> 69 70 <dependency> 71 <groupId>org.springframework</groupId> 72 <artifactId>spring-context</artifactId> 73 <version>3.2.2.RELEASE</version> 74 </dependency> 75 <dependency> 76 <groupId>org.springframework</groupId> 77 <artifactId>spring-context-support</artifactId> 78 <version>3.2.2.RELEASE</version> 79 </dependency> 80 <dependency> 81 <groupId>org.springframework</groupId> 82 <artifactId>spring-tx</artifactId> 83 <version>3.2.2.RELEASE</version> 84 </dependency> 85 <dependency> 86 <groupId>org.springframework</groupId> 87 <artifactId>spring-orm</artifactId> 88 <version>3.2.2.RELEASE</version> 89 </dependency> 90 </dependencies> 91 </project>
spring配置文件activiti.cfg.xml內容如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 <bean id="processEngineConfiguration" 7 class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"> 8 <property name="databaseSchemaUpdate" value="true" /> 9 <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti?autoReconnect=true&useUnicode=true&characterEncoding=utf8" /> 10 <property name="jdbcDriver" value="com.mysql.jdbc.Driver" /> 11 <property name="jdbcUsername" value="root" /> 12 <property name="jdbcPassword" value="" /> 13 <property name="jobExecutorActivate" value="true" /> 14 </bean> 15 </beans>
測試類TestActiviti代碼如下:
1 package com.shh.test; 2 3 import java.util.List; 4 5 import org.activiti.engine.ProcessEngine; 6 import org.activiti.engine.ProcessEngineConfiguration; 7 import org.activiti.engine.RepositoryService; 8 import org.activiti.engine.RuntimeService; 9 import org.activiti.engine.TaskService; 10 import org.activiti.engine.repository.Deployment; 11 import org.activiti.engine.task.Task; 12 import org.junit.Before; 13 import org.junit.Test; 14 15 /** 16 * 測試流程 17 * @author 20150205 18 * 19 */ 20 public class TestActiviti { 21 ProcessEngine processEngine = null; 22 RepositoryService repositoryService = null; 23 RuntimeService runtimeService = null; 24 TaskService taskService = null; 25 26 @Before 27 public void init() { 28 //加載spring配置文件,創建 ProcessEngine 29 processEngine = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml") 30 .buildProcessEngine(); 31 repositoryService = processEngine.getRepositoryService(); 32 runtimeService = processEngine.getRuntimeService(); 33 taskService = processEngine.getTaskService(); 34 } 35 36 37 /** 38 * 部署流程定義加載test.bpmn文件 39 */ 40 @Test 41 public void deploy(){ 42 Deployment deployment = repositoryService.createDeployment().addClasspathResource("diagrams/test.bpmn").deploy(); 43 String id = deployment.getId(); 44 System.out.println("***************部署流程定義完成***************" + id); 45 } 46 47 /** 48 * 啟動一個請假流程 49 */ 50 @Test 51 public void start() { 52 for(int i = 0 ; i < 5; i++){ 53 String processId = runtimeService.startProcessInstanceByKey("test").getId(); 54 System.out.println("***************啟動第" + i + "個請假流程完成***************" + processId); 55 } 56 } 57 58 59 /** 60 * 第一步 61 */ 62 @Test 63 public void step1(){ 64 System.out.println("***************step1流程開始***************"); 65 List<Task> tasks = taskService.createTaskQuery().taskAssignee("kermit").list();//kermit的任務 66 List<Task> tasks2 = taskService.createTaskQuery().taskAssignee("gonzo").list();//gonzo的任務 67 System.out.println(tasks.size()); 68 System.out.println(tasks2.size());//指定了kermit,所以gonzo的任務數量為0 69 70 for (Task task : tasks) { 71 System.out.println("kermit的任務taskname:" + task.getName() + ",id:" + task.getId());//任務的name與id 72 System.out.println(task.getAssignee());//任務擁有者 73 System.out.println(task.getProcessInstanceId());//流程實例id 74 System.out.println(task.getProcessDefinitionId());//流程定義id 75 taskService.complete(task.getId());//完成任務 76 } 77 78 System.out.println("kermit的任務數量:" + taskService.createTaskQuery().taskAssignee("kermit").count()); 79 System.out.println("***************step1流程結束***************"); 80 } 81 82 /** 83 * 第二步 84 */ 85 @Test 86 public void step2(){ 87 System.out.println("***************step2流程開始***************"); 88 List<Task> tasks = taskService.createTaskQuery().taskCandidateUser("kermit").list();//kermit可領取的任務 89 List<Task> tasks2 = taskService.createTaskQuery().taskCandidateUser("gonzo").list();//gonzo可領取的任務 90 System.out.println(tasks.size()); 91 System.out.println(tasks2.size()); 92 93 for (int i = 0 ; i < tasks.size(); i++) { 94 Task task = tasks.get(i); 95 System.out.println("任務taskname:" + task.getName() + ",id:" + task.getId());//任務的name與id 96 if(i % 2 == 0){ 97 taskService.claim(task.getId(), "kermit");//kermit領取任務 98 }else{ 99 taskService.claim(task.getId(), "gonzo");//gonzo領取任務 100 } 101 } 102 103 tasks = taskService.createTaskQuery().taskAssignee("kermit").list(); 104 tasks2 = taskService.createTaskQuery().taskAssignee("gonzo").list(); 105 System.out.println("kermit的任務數量:" + tasks.size()); 106 System.out.println("gonzo的任務數量:" + tasks2.size()); 107 108 for(Task t : tasks){ 109 taskService.complete(t.getId());//完成任務 110 } 111 for(Task t : tasks2){ 112 taskService.complete(t.getId());//完成任務 113 } 114 tasks = taskService.createTaskQuery().taskAssignee("kermit").list(); 115 tasks2 = taskService.createTaskQuery().taskAssignee("gonzo").list(); 116 System.out.println("kermit的任務數量:" + tasks.size()); 117 System.out.println("gonzo的任務數量:" + tasks2.size()); 118 System.out.println("***************step2流程結束***************"); 119 } 120 121 @Test 122 public void step3(){ 123 System.out.println("***************step3流程開始***************"); 124 List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("management").list();//management組可領取的任務 125 List<Task> tasks2 = taskService.createTaskQuery().taskCandidateGroup("accountancy").list();//accountancy組可領取的任務 126 System.out.println(tasks.size()); 127 System.out.println(tasks2.size()); 128 129 for (int i = 0 ; i < tasks.size(); i++) { 130 Task task = tasks.get(i); 131 System.out.println("任務taskname:" + task.getName() + ",id:" + task.getId());//任務的name與id 132 if(i % 2 == 0){ 133 taskService.claim(task.getId(), "kermit"); 134 }else{ 135 taskService.claim(task.getId(), "gonzo"); 136 } 137 } 138 tasks = taskService.createTaskQuery().taskAssignee("kermit").list(); 139 tasks2 = taskService.createTaskQuery().taskAssignee("gonzo").list(); 140 System.out.println("kermit的任務數量:" + tasks.size()); 141 System.out.println("gonzo的任務數量:" + tasks2.size()); 142 143 for(Task t : tasks){ 144 taskService.complete(t.getId());//完成任務 145 } 146 for(Task t : tasks2){ 147 taskService.complete(t.getId());//完成任務 148 } 149 tasks = taskService.createTaskQuery().taskAssignee("kermit").list(); 150 tasks2 = taskService.createTaskQuery().taskAssignee("gonzo").list(); 151 System.out.println("kermit的任務數量:" + tasks.size()); 152 System.out.println("gonzo的任務數量:" + tasks2.size()); 153 154 System.out.println("***************step3流程結束***************"); 155 } 156 }
依次執行deploy();、start();、step1();、step2();、step3()方法,結果如下:
八月 04, 2015 10:48:41 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [activiti.cfg.xml] 八月 04, 2015 10:48:44 上午 org.activiti.engine.impl.ProcessEngineImpl <init> 信息: ProcessEngine default created 八月 04, 2015 10:48:44 上午 org.activiti.engine.impl.bpmn.deployer.BpmnDeployer deploy 信息: Processing resource diagrams/test.bpmn ***************部署流程定義完成***************60001 ***************啟動第0個請假流程完成***************60005 ***************啟動第1個請假流程完成***************60010 ***************啟動第2個請假流程完成***************60015 ***************啟動第3個請假流程完成***************60020 ***************啟動第4個請假流程完成***************60025 ***************step1流程開始*************** 5 0 kermit的任務taskname:step1,id:60008 kermit 60005 test:5:60004 kermit的任務taskname:step1,id:60013 kermit 60010 test:5:60004 kermit的任務taskname:step1,id:60018 kermit 60015 test:5:60004 kermit的任務taskname:step1,id:60023 kermit 60020 test:5:60004 kermit的任務taskname:step1,id:60028 kermit 60025 test:5:60004 kermit的任務數量:0 ***************step1流程結束*************** ***************step2流程開始*************** 5 5 任務taskname:step2,id:60031 任務taskname:step2,id:60036 任務taskname:step2,id:60041 任務taskname:step2,id:60046 任務taskname:step2,id:60051 kermit的任務數量:3 gonzo的任務數量:2 kermit的任務數量:0 gonzo的任務數量:0 ***************step2流程結束*************** ***************step3流程開始*************** 5 5 任務taskname:step3,id:60056 任務taskname:step3,id:60060 任務taskname:step3,id:60064 任務taskname:step3,id:60068 任務taskname:step3,id:60072 kermit的任務數量:3 gonzo的任務數量:2 kermit的任務數量:0 gonzo的任務數量:0 ***************step3流程結束***************