一。activiti簡介html
Activiti項目是一項新的基於Apache許可的開源BPM平臺,從基礎開始構建,旨在提供支持新的BPMN 2.0標準,包括支持對象管理組(OMG),面對新技術的機遇,諸如互操做性和雲架構,提供技術實現。
創始人Tom Baeyens是JBoss jBPM的項目架構師,以及另外一位架構師Joram Barrez,一塊兒加入到建立Alfresco這項首次實現Apache開源許可的BPMN 2.0引擎開發中來。
web
Activiti是一個獨立運做和經營的開源項目品牌,並將獨立於Alfresco開源ECM系統運行。 Activiti將是一種輕量級,可嵌入的BPM引擎,並且還設計適用於可擴展的雲架構。 Activiti將提供寬鬆的Apache許可2.0,以便這個項目能夠普遍被使用,同時促進Activiti BPM引擎和BPMN 2.0的匹配,該項目現正由OMG經過標準審定。 加入Alfresco Activiti項目的是VMware的SpringSource分支,Alfresco的計劃把該項目提交給Apache基礎架構,但願吸引更多方面的BPM專家和促進BPM的創新。spring
Activiti框架用於定義業務邏輯相關的流程 ,開啓相關流程實例,流程變量控制流程走向,用戶及組完成流程任務
數據庫
Activiti流程定義使用bpmn2.0標準 該標準經過xml定義了全部業務流程相關的節點 好比 開始 結束 用戶任務 排他路由 並行路由等 因爲編寫xml比較困難 activiti提供了eclipse相關插件 經過繪圖方式來生成xmlexpress
相關網站:eclipse插件安裝(參考用戶嚮導https://www.activiti.org/userguide/#activitiDesigner)
eclipse點擊菜單 Help → Install New Software
輸入如下信息:
Name:Activiti BPMN 2.0 designer
Location:http://activiti.org/designer/update/
api
點擊ok 後選擇贊成協議後安裝完成便可 新建任意項目 新建diagram文件 操做以下gif動態圖
springboot
相關概念解釋
架構
如下代碼就是流程引擎以及各服務的相關代碼
oracle
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = processEngine.getRuntimeService(); RepositoryService repositoryService = processEngine.getRepositoryService(); TaskService taskService = processEngine.getTaskService(); ManagementService managementService = processEngine.getManagementService(); IdentityService identityService = processEngine.getIdentityService(); HistoryService historyService = processEngine.getHistoryService(); FormService formService = processEngine.getFormService(); DynamicBpmnService dynamicBpmnService = processEngine.getDynamicBpmnService();
開始節點 全部的流程圖都須要有個開始節點
框架
結束節點 全部流程圖都必須有個結束節點
任務節點 須要用戶處理的任務 好比審批就是須要人工去完成的一個任務 就須要定義任務節點 該節點被廣泛
使用順序線 上一個節點完成後 須要走到的下一個節點能夠經過 順序線鏈接
排他節點 流程須要分支須要經過排他節點 進行判斷 若是有多個分支 最後流程只會走向其中一個分支
好比請假 天數<3天 走組長審批 3-5天 走項目經理審批 5天以上boss審批 最後請假了多少天 只會是某我的審批
具備排他性
並行節點 好比有兩個分支 有可能兩個分支流程都須要走 可使用並行節點
二。activiti配置
ProcessEngines.getDefaultProcessEngine()會在第一次調用時 初始化並建立一個流程引擎,之後再調用就會返回相同的流程引擎。 使用對應的方法能夠建立和關閉全部流程引擎:ProcessEngines.init() 和 ProcessEngines.destroy()。
ProcessEngines會掃描全部activiti.cfg.xml 和 activiti-context.xml 文件。 對於activiti.cfg.xml文件,流程引擎會使用Activiti的經典方式構建: ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream).buildProcessEngine(). 對於activiti-context.xml文件,流程引擎會使用Spring方法構建:先建立一個Spring的環境, 而後經過環境得到流程引擎。
全部流程相關的數據都保存在數據庫中 須要先經過流程引擎配置生成數據庫的表 具體的實現參考官方用戶嚮導
(https://www.activiti.org/userguide/#_configuration)
類路徑下添加 activiti.cfg.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"> <property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:orcl" /> <property name="jdbcDriver" value="oracle.jdbc.driver.OracleDriver" /> <property name="jdbcUsername" value="ac" /> <property name="jdbcPassword" value="ac" /> <property name="databaseSchemaUpdate" value="true" /> </bean> </beans>添加maven依賴
<dependencies> <!-- https://mvnrepository.com/artifact/org.activiti/activiti-engine --> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-engine</artifactId> <version>5.22.0</version> </dependency> <!-- https://mvnrepository.com/artifact/com.hynnet/oracle-driver-ojdbc --> <dependency> <groupId>com.hynnet</groupId> <artifactId>oracle-driver-ojdbc</artifactId> <version>12.1.0.2</version> </dependency> </dependencies>
獲取流程實例 自動建立表
package activiti; import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngines; public class TestCreateDb { public static void main(String[] args) { ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); } }
運行main方法 查看數據庫 發現產生了25張表
Activiti的表都以ACT_開頭。 第二部分是表示表的用途的兩個字母標識。 用途也和服務的API對應。
三。activiti 實例,bpmn及經常使用api操做
如下經過一個流程實例顯示 activiti的全部相關api操做
模擬實例 好比威客網站中某個僱主發佈了一個單人懸賞的任務 此時不一樣的威客均可以發起投稿投標的流程 流程圖以下
威客開啓一個流程定義流程變量(威客用戶id)威客交稿的任務當前威客經過威客id能夠查詢到任務 威客交稿任務
開始 用戶須要傳遞投稿的任務編號 僱主信息 稿件信息 完成任務後 僱主選稿 選稿任務完成 須要進入排他路由 選中
和未選中經過一個流程變量來控制 若是未選中 直接發送落選郵件到威客帳號 選中繼續後 使用並行路由 同時開啓兩個流程
(發送通知郵件 ,威客提交終稿)是同時執行 互不影響 只演示前半部分 後面部分類似
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="inviteProcess" name="inviteProcess" isExecutable="true"> <startEvent id="startevent1" name="Start"></startEvent> <userTask id="wkInvite" name="威客交稿" activiti:assignee="${userWk}"></userTask> <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="wkInvite"></sequenceFlow> <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway> <serviceTask id="mailtask1" name="發送落選郵件" activiti:type="mail"> <extensionElements> <activiti:field name="to"> <activiti:expression><![CDATA[${email_to}]]></activiti:expression> </activiti:field> <activiti:field name="from"> <activiti:expression><![CDATA[${email_from}]]></activiti:expression> </activiti:field> <activiti:field name="subject"> <activiti:expression><![CDATA[${email_title}]]></activiti:expression> </activiti:field> <activiti:field name="html"> <activiti:expression><![CDATA[${email_content}]]></activiti:expression> </activiti:field> <activiti:field name="charset"> <activiti:string><![CDATA[utf-8]]></activiti:string> </activiti:field> </extensionElements> </serviceTask> <endEvent id="endevent1" name="End"></endEvent> <sequenceFlow id="flow4" sourceRef="exclusivegateway1" targetRef="mailtask1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${shortlist==0}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow5" sourceRef="mailtask1" targetRef="endevent1"></sequenceFlow> <parallelGateway id="parallelgateway1" name="Parallel Gateway"></parallelGateway> <serviceTask id="mailtask2" name="發送中標郵件" activiti:type="mail"> <extensionElements> <activiti:field name="to"> <activiti:expression><![CDATA[${email_to}]]></activiti:expression> </activiti:field> <activiti:field name="from"> <activiti:expression><![CDATA[${email_from}]]></activiti:expression> </activiti:field> <activiti:field name="subject"> <activiti:expression><![CDATA[${email_title}]]></activiti:expression> </activiti:field> <activiti:field name="html"> <activiti:expression><![CDATA[${email_content}]]></activiti:expression> </activiti:field> <activiti:field name="charset"> <activiti:string><![CDATA[utf-8]]></activiti:string> </activiti:field> </extensionElements> </serviceTask> <sequenceFlow id="flow6" sourceRef="exclusivegateway1" targetRef="parallelgateway1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${shortlist==1}]]></conditionExpression> </sequenceFlow> <userTask id="usertask1" name="提交最終稿件" activiti:assignee="${userWk}"></userTask> <sequenceFlow id="flow7" sourceRef="parallelgateway1" targetRef="mailtask2"></sequenceFlow> <sequenceFlow id="flow8" sourceRef="parallelgateway1" targetRef="usertask1"></sequenceFlow> <userTask id="usertask2" name="僱主確認" activiti:assignee="${employer}"></userTask> <exclusiveGateway id="exclusivegateway2" name="Exclusive Gateway"></exclusiveGateway> <sequenceFlow id="flow9" sourceRef="exclusivegateway2" targetRef="usertask1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${ifaccept==0}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow10" sourceRef="usertask2" targetRef="exclusivegateway2"></sequenceFlow> <sequenceFlow id="flow11" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow> <userTask id="usertask3" name="威客收款" activiti:assignee="${userWk}"></userTask> <sequenceFlow id="flow12" sourceRef="exclusivegateway2" targetRef="usertask3"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${ifaccept==1}]]></conditionExpression> </sequenceFlow> <endEvent id="endevent2" name="End"></endEvent> <sequenceFlow id="flow13" sourceRef="usertask3" targetRef="endevent2"></sequenceFlow> <endEvent id="endevent3" name="End"></endEvent> <sequenceFlow id="flow14" sourceRef="mailtask2" targetRef="endevent3"></sequenceFlow> <userTask id="usertask4" name="僱主選稿" activiti:assignee="${employer}"></userTask> <sequenceFlow id="flow15" sourceRef="wkInvite" targetRef="usertask4"></sequenceFlow> <sequenceFlow id="flow16" sourceRef="usertask4" targetRef="exclusivegateway1"></sequenceFlow> </process> <bpmndi:BPMNDiagram id="BPMNDiagram_inviteProcess"> <bpmndi:BPMNPlane bpmnElement="inviteProcess" id="BPMNPlane_inviteProcess"> <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1"> <omgdc:Bounds height="35.0" width="35.0" x="0.0" y="172.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="wkInvite" id="BPMNShape_wkInvite"> <omgdc:Bounds height="55.0" width="105.0" x="60.0" y="162.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="exclusivegateway1" id="BPMNShape_exclusivegateway1"> <omgdc:Bounds height="40.0" width="40.0" x="300.0" y="169.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="mailtask1" id="BPMNShape_mailtask1"> <omgdc:Bounds height="55.0" width="105.0" x="380.0" y="216.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1"> <omgdc:Bounds height="35.0" width="35.0" x="415.0" y="380.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="parallelgateway1" id="BPMNShape_parallelgateway1"> <omgdc:Bounds height="40.0" width="40.0" x="380.0" y="110.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="mailtask2" id="BPMNShape_mailtask2"> <omgdc:Bounds height="55.0" width="105.0" x="470.0" y="56.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1"> <omgdc:Bounds height="55.0" width="105.0" x="470.0" y="135.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2"> <omgdc:Bounds height="55.0" width="105.0" x="640.0" y="135.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="exclusivegateway2" id="BPMNShape_exclusivegateway2"> <omgdc:Bounds height="40.0" width="40.0" x="672.0" y="223.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3"> <omgdc:Bounds height="55.0" width="105.0" x="640.0" y="300.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="endevent2" id="BPMNShape_endevent2"> <omgdc:Bounds height="35.0" width="35.0" x="675.0" y="414.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="endevent3" id="BPMNShape_endevent3"> <omgdc:Bounds height="35.0" width="35.0" x="670.0" y="66.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="usertask4" id="BPMNShape_usertask4"> <omgdc:Bounds height="55.0" width="105.0" x="180.0" y="164.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1"> <omgdi:waypoint x="35.0" y="189.0"></omgdi:waypoint> <omgdi:waypoint x="60.0" y="189.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4"> <omgdi:waypoint x="320.0" y="209.0"></omgdi:waypoint> <omgdi:waypoint x="320.0" y="243.0"></omgdi:waypoint> <omgdi:waypoint x="380.0" y="243.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5"> <omgdi:waypoint x="432.0" y="271.0"></omgdi:waypoint> <omgdi:waypoint x="432.0" y="380.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6"> <omgdi:waypoint x="320.0" y="169.0"></omgdi:waypoint> <omgdi:waypoint x="320.0" y="138.0"></omgdi:waypoint> <omgdi:waypoint x="353.0" y="138.0"></omgdi:waypoint> <omgdi:waypoint x="388.0" y="138.0"></omgdi:waypoint> <omgdi:waypoint x="388.0" y="138.0"></omgdi:waypoint> <omgdi:waypoint x="420.0" y="130.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7"> <omgdi:waypoint x="400.0" y="110.0"></omgdi:waypoint> <omgdi:waypoint x="400.0" y="83.0"></omgdi:waypoint> <omgdi:waypoint x="470.0" y="83.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8"> <omgdi:waypoint x="400.0" y="150.0"></omgdi:waypoint> <omgdi:waypoint x="400.0" y="162.0"></omgdi:waypoint> <omgdi:waypoint x="470.0" y="162.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9"> <omgdi:waypoint x="692.0" y="223.0"></omgdi:waypoint> <omgdi:waypoint x="522.0" y="190.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow10" id="BPMNEdge_flow10"> <omgdi:waypoint x="692.0" y="190.0"></omgdi:waypoint> <omgdi:waypoint x="692.0" y="223.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow11" id="BPMNEdge_flow11"> <omgdi:waypoint x="575.0" y="162.0"></omgdi:waypoint> <omgdi:waypoint x="640.0" y="162.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow12" id="BPMNEdge_flow12"> <omgdi:waypoint x="692.0" y="263.0"></omgdi:waypoint> <omgdi:waypoint x="692.0" y="300.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow13" id="BPMNEdge_flow13"> <omgdi:waypoint x="692.0" y="355.0"></omgdi:waypoint> <omgdi:waypoint x="692.0" y="414.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow14" id="BPMNEdge_flow14"> <omgdi:waypoint x="575.0" y="83.0"></omgdi:waypoint> <omgdi:waypoint x="670.0" y="83.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow15" id="BPMNEdge_flow15"> <omgdi:waypoint x="165.0" y="189.0"></omgdi:waypoint> <omgdi:waypoint x="180.0" y="191.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow16" id="BPMNEdge_flow16"> <omgdi:waypoint x="285.0" y="191.0"></omgdi:waypoint> <omgdi:waypoint x="300.0" y="189.0"></omgdi:waypoint> </bpmndi:BPMNEdge> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>演示代碼以下
//建立流程引擎對象 private ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
步驟1 發佈流程定義
/** * 發佈流程 添加發布bpmn和圖片 也能夠打包成 zip發佈 * */ @Test public void deployProcess() { //用於發佈流程資源 以及流程定義 RepositoryService repositoryService = processEngine.getRepositoryService(); Deployment deploy = repositoryService.createDeployment() .addClasspathResource("diagrams/MyProcess.bpmn") .addClasspathResource("diagrams/MyProcess.png") //.addZipInputStream(zipInputStream) 能夠添加壓縮包 web定義流程就可使用這個方法上傳 .name("威客單人投標流程") .deploy(); //資源文件在act_ge_bytearray表中 //流程定義在act_re_procdef表中 System.out.println("流程定義id:"+deploy.getId()); System.out.println("流程定義名稱:"+deploy.getName()); System.out.println("流程定義發佈時間:"+deploy.getDeploymentTime().toGMTString()); //查看發佈的流程信息 查看發佈的流程總和 long count = repositoryService.createDeploymentQuery().count(); System.out.println("總流程定義數:"+count); }步驟2 zs查看本身的任務編號 完成投稿任務
/** * 運行流程 * 相同的流程被髮布(id不一樣 _key相同)多, 每發佈 一次 ACT_RE_PROCDEF 多一條數據, Version都會加1, * 根據key來啓動 會啓動最新版本號的流程定義 * 若是想執行舊的流程定義就可使用id來啓動 * 模擬場景 某個威客 開始向某個任務投稿 任務就開始了 */ @Test public void startProcess() { //運行流程使用runtimesErvice RuntimeService runtimeService = processEngine.getRuntimeService(); //流程變量 傳入是誰啓動的流程 Map map=new HashMap(); map.put("userWk", "zs"); //key就是流程圖的 id (注意不是數據庫裏面的id 數據庫裏面的key是流程裏開始定義的id) //流程實例數據在 ACT_RU_EXECUTION表中 //流程變量 在 ACT_RU_VARIABLE中 //用戶任務在 ACT_RU_TASK中 ProcessInstance instance= runtimeService.startProcessInstanceByKey("inviteProcess",map); System.out.println("用戶"+map.get("userWk")+"開啓了一個投稿流程"); System.out.println("流程實例編號是:"+instance.getProcessInstanceId()); long count = runtimeService.createExecutionQuery().count(); System.out.println("總流程實例數:"+count); }
完成任務
/** * 張三完成任務 就須要交稿 定義流程變量 */ @Test public void submitTask() { //用戶任務的完成 使用TaskService TaskService taskService = processEngine.getTaskService(); String taskId="20005"; Map map=new HashMap(); /** * 張三交稿數據 * **/ map.put("employer", "ls");//設置任務的僱主 map.put("taskNo", "僱主任務編號"); map.put("taskContent", "用字符串模擬"); taskService.complete(taskId, map); }
步驟3 僱主ls查看本身的任務編號 完成選稿稿任務 這裏模擬shortlist==0表示沒選中 進入發送郵件結束流程的步驟
須要配置郵件的smtp和用戶密碼信息 修改activiti.cfg.xml 添加
<property name="mailServerHost" value="smtp.126.com" /> <property name="mailServerPort" value="25" /> <property name="mailServerUsername" value="lixin1112003@126.com"></property> <property name="mailServerPassword" value="XXXXXXXXXX您的郵箱密碼"></property>未選中代碼
/** * 李四完成任務 就須要選稿 */ @Test public void submitTask() { //用戶任務的完成 使用TaskService TaskService taskService = processEngine.getTaskService(); String taskId="20005"; Map map=new HashMap(); map.put("shortlist", 0); map.put("email_to", "973465719@qq.com"); map.put("email_from", "lixin1112003@126.com"); map.put("email_title", "973465719@qq.com"); map.put("email_content", "您對僱主任務編號"+taskService.getVariable(taskId, "taskNo")+"的投稿稿件 已經落選。。"); taskService.complete(taskId, map); }選中代碼
/** * 李四完成任務 就須要選稿 */ @Test public void submitTask() { //用戶任務的完成 使用TaskService TaskService taskService = processEngine.getTaskService(); String taskId="20005"; Map map=new HashMap(); map.put("shortlist", 1); map.put("email_to", "973465719@qq.com"); map.put("email_from", "lixin1112003@126.com"); map.put("email_title", "973465719@qq.com"); map.put("email_content", "您對僱主任務編號"+taskService.getVariable(taskId, "taskNo")+"的投稿稿件 已經被選中 請完成終稿。。"); taskService.complete(taskId, map); }
其餘代碼就不演示 具體參考https://www.activiti.org/userguide/#chapterApi
四。springboot集成activiti
集成web參考 https://www.activiti.org/userguide/#springintegration