一、由於我用的是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()); }
基本上一個項目中就用到了這些流程的功能,基本知足了,完畢