一、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流程结束***************