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()); }
基本上一个项目中就用到了这些流程的功能,基本满足了,完毕