spring boot 2.2整合activiti 工作流
pom 檔案新增jar
<!--jwt token--> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.3.0</version> </dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.activiti/activiti-spring --> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring</artifactId> <version>6.0.0</version> </dependency>
寫好配置類
import org.activiti.engine.*; import org.activiti.spring.SpringProcessEngineConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import javax.sql.DataSource; import java.io.IOException; /** * @author wangsx * @date Created in 09-10-2018 * @description */ @Configuration public class ActivitiConfig { @Bean public ProcessEngine processEngine(DataSourceTransactionManager transactionManager, DataSource dataSource) throws IOException { SpringProcessEngineConfiguration configuration = new SpringProcessEngineConfiguration(); //自動部署已有的流程檔案 Resource[] resources = new PathMatchingResourcePatternResolver().getResources(ResourceLoader.CLASSPATH_URL_PREFIX + "processes/*.bpmn"); configuration.setTransactionManager(transactionManager); configuration.setDataSource(dataSource); configuration.setDatabaseSchemaUpdate("true"); configuration.setDeploymentResources(resources); configuration.setDbIdentityUsed(false); return configuration.buildProcessEngine(); } @Bean public RepositoryService repositoryService(ProcessEngine processEngine) { return processEngine.getRepositoryService(); } @Bean public RuntimeService runtimeService(ProcessEngine processEngine) { return processEngine.getRuntimeService(); } @Bean public TaskService taskService(ProcessEngine processEngine) { return processEngine.getTaskService(); } @Bean public HistoryService historyService(ProcessEngine processEngine) { return processEngine.getHistoryService(); } @Bean public ManagementService managementService(ProcessEngine processEngine) { return processEngine.getManagementService(); } @Bean public IdentityService identityService(ProcessEngine processEngine) { return processEngine.getIdentityService(); } @Bean public FormService formService(ProcessEngine processEngine){ return processEngine.getFormService(); } }
springboot 在啟動專案時會自動配置
測試的流程圖
<?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="act_demo_audit"> <process id="act_demo_audit" name="act_demo_audit" isExecutable="true"> <startEvent id="Start" name="開始" activiti:formKey="demo/form"></startEvent> <userTask id="firstLevelAudit" name="一級審批" activiti:candidateUsers="${firstLevel}"></userTask> <userTask id="secondLevelAudit" name="二級審批" activiti:candidateUsers="${secondLevel}"></userTask> <endEvent id="refuse" name="成功"></endEvent> <sequenceFlow id="flow1" sourceRef="Start" targetRef="firstLevelAudit"></sequenceFlow> <serviceTask id="acceptService" name="通過時業務處理" activiti:class="com.siemens.pms.act.service.impl.DemoAuditProcessor"></serviceTask> <sequenceFlow id="flow4" sourceRef="secondLevelAudit" targetRef="refuseService"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${secondLevelPass}]]></conditionExpression> </sequenceFlow> <serviceTask id="refuseService" name="不通過時業務處理" activiti:class="com.siemens.pms.act.service.impl.DemoAuditProcessor"></serviceTask> <sequenceFlow id="flow6" name="不通過" sourceRef="secondLevelAudit" targetRef="refuseService"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!secondLevelPass}]]></conditionExpression> </sequenceFlow> <endEvent id="accept" name="失敗"></endEvent> <sequenceFlow id="flow8" sourceRef="refuseService" targetRef="accept"></sequenceFlow> <sequenceFlow id="flow9" name="不通過" sourceRef="firstLevelAudit" targetRef="refuseService"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!firstLevelPass}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow10" name="通過" sourceRef="secondLevelAudit" targetRef="acceptService"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${secondLevelPass}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow11" sourceRef="acceptService" targetRef="refuse"></sequenceFlow> <exclusiveGateway id="exclusivegateway1" name="是否二級"></exclusiveGateway> <sequenceFlow id="flow14" name="是" sourceRef="exclusivegateway1" targetRef="secondLevelAudit"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${secondLevel!=null}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow15" name="否" sourceRef="exclusivegateway1" targetRef="acceptService"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${secondLevel==null}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow16" name="通過" sourceRef="firstLevelAudit" targetRef="exclusivegateway1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${firstLevelPass}]]></conditionExpression> </sequenceFlow> </process> <bpmndi:BPMNDiagram id="BPMNDiagram_act_demo_audit"> <bpmndi:BPMNPlane bpmnElement="act_demo_audit" id="BPMNPlane_act_demo_audit"> <bpmndi:BPMNShape bpmnElement="Start" id="BPMNShape_Start"> <omgdc:Bounds height="51.0" width="71.0" x="30.0" y="165.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="firstLevelAudit" id="BPMNShape_firstLevelAudit"> <omgdc:Bounds height="61.0" width="161.0" x="140.0" y="160.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="secondLevelAudit" id="BPMNShape_secondLevelAudit"> <omgdc:Bounds height="61.0" width="181.0" x="480.0" y="160.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="refuse" id="BPMNShape_refuse"> <omgdc:Bounds height="51.0" width="71.0" x="1020.0" y="165.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="acceptService" id="BPMNShape_acceptService"> <omgdc:Bounds height="81.0" width="151.0" x="780.0" y="150.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="refuseService" id="BPMNShape_refuseService"> <omgdc:Bounds height="61.0" width="181.0" x="480.0" y="290.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="accept" id="BPMNShape_accept"> <omgdc:Bounds height="41.0" width="61.0" x="540.0" y="430.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="exclusivegateway1" id="BPMNShape_exclusivegateway1"> <omgdc:Bounds height="40.0" width="40.0" x="360.0" y="170.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1"> <omgdi:waypoint x="101.0" y="190.0"></omgdi:waypoint> <omgdi:waypoint x="140.0" y="190.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4"> <omgdi:waypoint x="570.0" y="221.0"></omgdi:waypoint> <omgdi:waypoint x="570.0" y="290.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6"> <omgdi:waypoint x="570.0" y="221.0"></omgdi:waypoint> <omgdi:waypoint x="570.0" y="290.0"></omgdi:waypoint> <bpmndi:BPMNLabel> <omgdc:Bounds height="16.0" width="48.0" x="570.0" y="221.0"></omgdc:Bounds> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8"> <omgdi:waypoint x="570.0" y="351.0"></omgdi:waypoint> <omgdi:waypoint x="570.0" y="430.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9"> <omgdi:waypoint x="220.0" y="221.0"></omgdi:waypoint> <omgdi:waypoint x="220.0" y="320.0"></omgdi:waypoint> <omgdi:waypoint x="480.0" y="320.0"></omgdi:waypoint> <bpmndi:BPMNLabel> <omgdc:Bounds height="16.0" width="48.0" x="220.0" y="221.0"></omgdc:Bounds> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow10" id="BPMNEdge_flow10"> <omgdi:waypoint x="661.0" y="190.0"></omgdi:waypoint> <omgdi:waypoint x="780.0" y="190.0"></omgdi:waypoint> <bpmndi:BPMNLabel> <omgdc:Bounds height="16.0" width="32.0" x="661.0" y="190.0"></omgdc:Bounds> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow11" id="BPMNEdge_flow11"> <omgdi:waypoint x="931.0" y="190.0"></omgdi:waypoint> <omgdi:waypoint x="1020.0" y="190.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow14" id="BPMNEdge_flow14"> <omgdi:waypoint x="400.0" y="190.0"></omgdi:waypoint> <omgdi:waypoint x="480.0" y="190.0"></omgdi:waypoint> <bpmndi:BPMNLabel> <omgdc:Bounds height="16.0" width="16.0" x="400.0" y="190.0"></omgdc:Bounds> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow15" id="BPMNEdge_flow15"> <omgdi:waypoint x="380.0" y="170.0"></omgdi:waypoint> <omgdi:waypoint x="380.0" y="88.0"></omgdi:waypoint> <omgdi:waypoint x="578.0" y="88.0"></omgdi:waypoint> <omgdi:waypoint x="855.0" y="88.0"></omgdi:waypoint> <omgdi:waypoint x="855.0" y="150.0"></omgdi:waypoint> <bpmndi:BPMNLabel> <omgdc:Bounds height="16.0" width="16.0" x="380.0" y="170.0"></omgdc:Bounds> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow16" id="BPMNEdge_flow16"> <omgdi:waypoint x="301.0" y="190.0"></omgdi:waypoint> <omgdi:waypoint x="360.0" y="190.0"></omgdi:waypoint> <bpmndi:BPMNLabel> <omgdc:Bounds height="16.0" width="32.0" x="301.0" y="190.0"></omgdc:Bounds> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>
核心API
ProcessEngine
說明:
- 在Activiti中最核心的類,其他的類都是由他而來。
- 產生方式:
在前面看到了兩種建立ProcessEngine(流程引擎)的方式,而這裡要簡化很多,呼叫ProcessEngines的getDefaultProceeEngine方法時會自動載入classpath下名為activiti.cfg.xml檔案。
- 可以產生RepositoryService
- 可以產生RuntimeService
- 可以產生TaskService
各個Service的作用:
RepositoryService |
管理流程定義 |
RuntimeService |
執行管理,包括啟動、推進、刪除流程例項等操作 |
TaskService |
任務管理 |
HistoryService |
歷史管理(執行完的資料的管理) |
IdentityService |
組織機構管理 |
FormService |
一個可選服務,任務表單管理 |
ManagerService |
RepositoryService
是Activiti的倉庫服務類。所謂的倉庫指流程定義文件的兩個檔案:bpmn檔案和流程圖片。
- 產生方式
- 可以產生DeploymentBuilder,用來定義流程部署的相關引數
- 刪除流程定義
RuntimeService
是activiti的流程執行服務類。可以從這個服務類中獲取很多關於流程執行相關的資訊。
TaskService
是activiti的任務服務類。可以從這個類中獲取任務的資訊。
HistoryService
是activiti的查詢歷史資訊的類。在一個流程執行完成後,這個物件為我們提供查詢歷史資訊。
ProcessDefinition
流程定義類。可以從這裡獲得資原始檔等。
ProcessInstance
代表流程定義的執行例項。如范冰冰請了一天的假,她就必須發出一個流程例項的申請。一個流程例項包括了所有的執行節點。我們可以利用這個物件來了解當前流程例項的進度等資訊。流程例項就表示一個流程從開始到結束的最大的流程分支,即一個流程中流程例項只有一個。
Execution
Activiti用這個物件去描述流程執行的每一個節點。在沒有併發的情況下,Execution就是同ProcessInstance。流程按照流程定義的規則執行一次的過程,就可以表示執行物件Execution。
如圖為ProcessInstance的原始碼:
從原始碼中可以看出ProcessInstance就是Execution。但在現實意義上有所區別:
在單線流程中,如上圖的貸款流程,ProcessInstance與Execution是一致的。
這個例子有一個特點:wire money(匯錢)和archive(存檔)是併發執行的。 這個時候,匯流排路代表ProcessInstance,而分線路中每個活動代表Execution。
總結:
* 一個流程中,執行物件可以存在多個,但是流程例項只能有一個。
* 當流程按照規則只執行一次的時候,那麼流程例項就是執行物件。