一、相關概念
-
工作流概念
工作流是指業(yè)務過程的部分或整體在計算機應用環(huán)境下的自動化。是對工作流程及其各操作步驟之間業(yè)務規(guī)則的抽象、概括描述。
-
activiti介紹
activiti是一個工作流引擎,可以將業(yè)務系統(tǒng)中復雜的業(yè)務流程抽取出來,使用專門的建模語言BPMN進行定義,業(yè)務流程按照預先定義的流程進行執(zhí)行。實現(xiàn)了系統(tǒng)的流程由activiti進行管理,減少業(yè)務系統(tǒng)由于流程變更進行系統(tǒng)升級改造的工作流量,從而提高系統(tǒng)的健壯性,同時也減少了系統(tǒng)開發(fā)維護成本。
-
BPM(Business Process Management)
業(yè)務流程管理
-
BPM軟件
通過BPM軟件可以實現(xiàn)對業(yè)務流程的整個生命周期進行建模、自動化、管理監(jiān)控和優(yōu)化。
-
BPMN(Business Process MOdel And Notation 業(yè)務流程模型和符號)
業(yè)務流程模型和符號,是由BPMI開發(fā)的一套標準的業(yè)務流程建模符號,使用BPMN提供的符號可以創(chuàng)建業(yè)務流程。
-
ProcessDefinition:流程定義
-
ProcessInstance:流程實例
二、使用步驟
-
部署activiti
activiti是一個工作流程,業(yè)務系統(tǒng)訪問activiti的接口,就可以方便操作流程間的相關數(shù)據(jù),這樣就可以把工作流環(huán)境和業(yè)務系統(tǒng)的環(huán)境集成在一起。
-
流程定義
使用activiti建模工具定義業(yè)務流程,生成.bpmn文件(通過xml定義業(yè)務流程)。
-
流程定義部署
使用activiti提供的api把流程定義的內(nèi)容存儲起來,再Activiti執(zhí)行過中可以查詢的內(nèi)容。activiti執(zhí)行把流程定內(nèi)容存儲在數(shù)據(jù)庫中。
-
啟動一個流程實例
流程實例也叫ProcessInstance
啟動一個流程實例表示開始一次業(yè)務流程的執(zhí)行
比如同一個流程,張三可以啟動,李四也可以啟動,但是兩次流程實例是互不影響的。
-
用戶查詢待辦任務
由于集成了activiti,所有的任務都可以直接通過activiti提供的api進行查詢,不需要我們自己查庫。
-
用戶辦理任務
流程辦理等操作,也是可以直接使用activiti提供的api即可。
-
流程結束
當沒有下一個需要辦理的節(jié)點,說明任務就結束了。
三、activiti配置生成表
-
idea軟件安裝actiBPM插件,若idea找不到插件,可去官網(wǎng)下載,導入即可,可參考
https://blog.csdn.net/weixin_40496191/article/details/125097860
-
pom配置
<!-- springboot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 工作流 --> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring-boot-starter</artifactId> <version>7.1.0.M1</version> </dependency> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-json-converter</artifactId> <version>7.1.0.M1</version> </dependency> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-image-generator</artifactId> <version>7.1.0.M1</version> </dependency> <dependency> <groupId>org.apache.xmlgraphics</groupId> <artifactId>batik-all</artifactId> <version>1.10</version> </dependency> <!-- 數(shù)據(jù)庫 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.2</version> </dependency>
-
配置文件配置activiti相關參數(shù)和數(shù)據(jù)庫信息
server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: tiger url: jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=utf-8 &allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8&nullCatalogMeansCurrent=true type: com.alibaba.druid.pool.DruidDataSource servlet: multipart: max-file-size: 100MB max-request-size: 100MB activiti: # false:默認,數(shù)據(jù)庫表不變,但是如果版本不對或者缺失表會拋出異常(生產(chǎn)使用) # true:表不存在,自動創(chuàng)建(開發(fā)使用) # create_drop: 啟動時創(chuàng)建,關閉時刪除表(測試使用) # drop_create: 啟動時刪除表,在創(chuàng)建表 (不需要手動關閉引擎) database-schema-update: true #監(jiān)測歷史表是否存在,activities7默認不開啟歷史表 db-history-used: true #none:不保存任何歷史數(shù)據(jù),流程中這是最高效的 #activity:只保存流程實例和流程行為 #audit:除了activity,還保存全部的流程任務以及其屬性,audit為history默認值 #full:除了audit、還保存其他全部流程相關的細節(jié)數(shù)據(jù),包括一些流程參數(shù) history-level: full #校驗流程文件,默認校驗resources下的process 文件夾的流程文件 check-process-definitions: true
-
啟動項目,即可生成相關表
-
相關表關系
re表:流程定義和流程相關屬性
ru表:運行時產(chǎn)生的數(shù)據(jù)
hi表:歷史信息
ge表:通用信息
四、簡單畫一個流程
-
畫圖
創(chuàng)建demo.bpmn文件,簡單實現(xiàn)流程圖,id為“myLeave“,流程名稱為“員工請假審批流程”,責任人從上往下依次為worker、manager、financer。
-
畫完圖后,可以將流程圖導出來
1)復制一份新的文件,以xml結尾
2)右鍵顯示圖標
3)導出png圖片
五、activiti接口基礎api示例
1. 代碼創(chuàng)建流程
/**
* 部署流程
*/
@RequestMapping("createProcesses")
@ResponseBody
public void createProcesses() {
//使用獲取RepositoryService進行部署
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("static/bpmn/demo.bpmn")//添加bpmn資源
.addClasspathResource("static/bpmn/demo.png")//添加png資源
.name("員工請假審批流程")
.deploy();//部署流程
//輸出流程部署的信息
System.out.println("流程部署id:" + deployment.getId());
System.out.println("流程部署名稱:" + deployment.getName());
}
//結果:
//流程部署id:1fb480d0-0773-11ed-8dc3-005056c00001
//流程部署名稱:員工請假審批流程
執(zhí)行后可以去數(shù)據(jù)庫查看相關的表數(shù)據(jù)
act_re_deployment:查看相關的流程的創(chuàng)建
act_re_procdef:查看流程的定義
act_ge_bytearray:流程文件存儲
2. 查詢流程的定義
/**
* 查詢流程的定義
*/
@RequestMapping("searchProcess")
@ResponseBody
public void searchProcess() {
String key= "myLeave";
//獲取ProcessDefinitionQuery對象,用來查詢操作
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey(key)
.orderByProcessDefinitionVersion()//安裝版本信息
.desc()//倒序
.list();
//輸出流程定義的信息
for (ProcessDefinition processDefinition : list) {
System.out.println("流程定義的id:" + processDefinition.getId());
System.out.println("流程定義的name:" + processDefinition.getName());
System.out.println("流程定義的key:" + processDefinition.getKey());
System.out.println("流程定義的version:" + processDefinition.getVersion());
System.out.println("流程部署的id:" + processDefinition.getDeploymentId());
System.out.println("--------------------------------------------------");
}
}
//結果
//相同key,則自動提升版本
//流程定義的id:myLeave:2:f6844e42-0774-11ed-96b3-005056c00001
//流程定義的name:員工請假審批流程
//流程定義的key:myLeave
//流程定義的version:2
//流程部署的id:f66888df-0774-11ed-96b3-005056c00001
//--------------------------------------------------
//流程定義的id:myLeave:1:fc307169-0773-11ed-9b87-005056c00001
//流程定義的name:員工請假審批流程
//流程定義的key:myLeave
//流程定義的version:1
//流程部署的id:fc1a2a46-0773-11ed-9b87-005056c00001
//--------------------------------------------------
3. 刪除流程
/**
* 刪除流程
*/
@RequestMapping("deleteProcess")
@ResponseBody
public void deleteProcess() {
String id = "f66888df-0774-11ed-96b3-005056c00001";
//設置true,擇優(yōu)級聯(lián)刪除的效果。false如果已有實例,則會刪除錯誤
repositoryService.deleteDeployment(id, true);
}
4. 獲取流程里面的資源文件
/**
* 讀取數(shù)據(jù)庫中的資源文件
*/
@RequestMapping("searchProcesslFile")
@ResponseBody
public void searchProcesslFile() throws IOException {
String id = "myLeave";
//查詢器
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey(id)
.singleResult();
//獲取流程部署id
String deploymentId = processDefinition.getDeploymentId();
//通過repositoryService對象的相關方法來獲取圖片信息和bpmn信息
//png圖片
InputStream pngInput = repositoryService
.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
//bpmn 文件的流
InputStream bpmnInput = repositoryService
.getResourceAsStream(deploymentId, processDefinition.getResourceName());
//文件的保存
File filePng = new File("E:/學習/activiti/evection.png");
File fileBpmn = new File("E:/學習/activiti/evection.bpmn");
OutputStream pngOut = new FileOutputStream(filePng);
OutputStream bpmnOut = new FileOutputStream(fileBpmn);
//輸入流和輸出流的轉化
IOUtils.copy(pngInput, pngOut);
IOUtils.copy(bpmnInput, bpmnOut);
pngInput.close();
pngOut.close();
bpmnInput.close();
bpmnOut.close();
}
5. 創(chuàng)建流程實例
/**
* 創(chuàng)建流程實例
*/
@RequestMapping("addApplication")
@ResponseBody
public void addApplication() {
String businessKey = "myLeave";
//啟動一個流程實例
//ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(businessKey);
//啟動一個流程實例,設置業(yè)務id,長度最大255,通過processInstance.getBusinessKey()獲取
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(businessKey,"businessKey");
System.out.println("流程定義id:" + processInstance.getProcessDefinitionId());
System.out.println("流程實例id:" + processInstance.getId());
System.out.println("當前活動id:" + processInstance.getActivityId());
}
//結果:
//流程定義id:myLeave:2:a07c05cb-076f-11ed-afa5-005056c00001
//流程實例id:f6f5bf5a-0772-11ed-8dc3-005056c00001
//當前活動id:null
6. 查看流程底下存在哪些實例
/**
* 查詢流程下存在哪些實例
* 可通過.processInstanceId等相關屬性過濾
*/
@RequestMapping("searchProcessRunInstance")
@ResponseBody
public void searchProcessRunInstance() {
String key = "myLeave";
List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().processDefinitionKey(key).list();
//輸出流程定義的信息
for (ProcessInstance processInstance : list) {
System.out.println("流程實例id:" + processInstance.getProcessInstanceId());
System.out.println("所屬流程定義id:" + processInstance.getProcessDefinitionId());
System.out.println("是否完成:" + processInstance.isEnded());
System.out.println("是否暫停:" + processInstance.isSuspended());
System.out.println("當前活動標識:" + processInstance.getActivityId());
System.out.println("業(yè)務關鍵字:" + processInstance.getBusinessKey());
System.out.println("------------" );
}
}
//結果:
//流程實例id:906f1e33-0776-11ed-96b3-005056c00001
//所屬流程定義id:myLeave:2:f6844e42-0774-11ed-96b3-005056c00001
//是否完成:false
//是否暫停:false
//當前活動標識:null
//業(yè)務關鍵字:null
//------------
//流程實例id:fece74da-0773-11ed-9b87-005056c00001
//所屬流程定義id:myLeave:1:fc307169-0773-11ed-9b87-005056c00001
//是否完成:false
//是否暫停:false
//當前活動標識:null
//業(yè)務關鍵字:null
//------------
7. 根據(jù)流程和負責人查詢?nèi)蝿?/h4>
/**
* 查詢?nèi)蝿詹樵? * 也可以不加過濾條件,查詢出全部
*/
@RequestMapping("searchTask")
@ResponseBody
public void searchTask() {
String assignee = "worker";
String key = "myLeave";
//根據(jù)流程的key和任務負責人 查詢?nèi)蝿?/span>
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee(assignee)
.list();
//輸出當前用戶具有的任務
for (Task task : list) {
System.out.println("流程實例id:" + task.getProcessDefinitionId());
System.out.println("任務id:" + task.getId());
System.out.println("任務負責人:" + task.getAssignee());
System.out.println("任務名稱:" + task.getName());
}
}
//結果:
//流程實例id:myLeave:2:a07c05cb-076f-11ed-afa5-005056c00001
//任務id:2da138fa-0772-11ed-a901-005056c00001
//任務負責人:worker
//任務名稱:創(chuàng)建請假流程
8. 處理流程
/**
* 根據(jù)流程的key和任務負責人 處理任務
*/
@RequestMapping("solveTask")
@ResponseBody
public void solveTask() {
String assignee = "worker";
String key = "myLeave";
//根據(jù)流程的key和任務負責人 查詢?nèi)蝿?/span>
Task task = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee(assignee)
.singleResult();
//完成任務,跳到下一個流程
taskService.complete(task.getId());
}
/**
* 查詢?nèi)蝿詹樵? * 也可以不加過濾條件,查詢出全部
*/
@RequestMapping("searchTask")
@ResponseBody
public void searchTask() {
String assignee = "worker";
String key = "myLeave";
//根據(jù)流程的key和任務負責人 查詢?nèi)蝿?/span>
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee(assignee)
.list();
//輸出當前用戶具有的任務
for (Task task : list) {
System.out.println("流程實例id:" + task.getProcessDefinitionId());
System.out.println("任務id:" + task.getId());
System.out.println("任務負責人:" + task.getAssignee());
System.out.println("任務名稱:" + task.getName());
}
}
//結果:
//流程實例id:myLeave:2:a07c05cb-076f-11ed-afa5-005056c00001
//任務id:2da138fa-0772-11ed-a901-005056c00001
//任務負責人:worker
//任務名稱:創(chuàng)建請假流程
/**
* 根據(jù)流程的key和任務負責人 處理任務
*/
@RequestMapping("solveTask")
@ResponseBody
public void solveTask() {
String assignee = "worker";
String key = "myLeave";
//根據(jù)流程的key和任務負責人 查詢?nèi)蝿?/span>
Task task = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee(assignee)
.singleResult();
//完成任務,跳到下一個流程
taskService.complete(task.getId());
}
act_ru_execution:任務操作
act_ru_task:目前需要處理的任務表
9. 流程歷史信息查看
/**
* 流程歷史信息查看
* 即時刪除了流程,但是流程的歷史信息還是會被保存下來,存在hi**表中
* 也可以不加過濾條件,查詢出全部
*/
@RequestMapping("searchHistoricActivityInstance")
@ResponseBody
public void searchHistoricActivityInstance() {
String id = "myLeave:1:fc307169-0773-11ed-9b87-005056c00001";
//獲取actinst表的查詢對象
HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
//查詢actinst表,根據(jù)流程id查詢
HistoricActivityInstanceQuery historicActivityInstanceQuery1 = historicActivityInstanceQuery.processDefinitionId(id);
//查詢actinst表,根據(jù)流程實例id查詢
//historicActivityInstanceQuery.processInstanceId(流程實例id);
//排序
historicActivityInstanceQuery1.orderByHistoricActivityInstanceStartTime().desc();
//獲取查詢結果
List<HistoricActivityInstance> list = historicActivityInstanceQuery1.list();
//輸出查詢結果
for (HistoricActivityInstance hi : list) {
System.out.println(hi.getActivityId());
System.out.println(hi.getActivityName());
System.out.println(hi.getActivityType());
System.out.println(hi.getAssignee());
System.out.println(hi.getProcessDefinitionId());
System.out.println(hi.getProcessInstanceId());
}
}
//結果:
//_4
//部門經(jīng)理審批
//userTask
//manager
//myLeave:1:fc307169-0773-11ed-9b87-005056c00001
//fece74da-0773-11ed-9b87-005056c00001
//_3
//創(chuàng)建請假流程
//userTask
//worker
//myLeave:1:fc307169-0773-11ed-9b87-005056c00001
//fece74da-0773-11ed-9b87-005056c00001
//_2
//StartEvent
//startEvent
//null
//myLeave:1:fc307169-0773-11ed-9b87-005056c00001
//fece74da-0773-11ed-9b87-005056c00001
10. 單個流程全部實例掛起
/**
* 全部流程實例掛起和激活
*/
@RequestMapping("allLockOrOpenPeocess")
@ResponseBody
public void allLockOrOpenPeocess() {
String id = "myLeave";
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey(id)
.singleResult();
//獲取流程的狀態(tài)
boolean suspended = processDefinition.isSuspended();
String pdId = processDefinition.getId();
//如果激活就掛起,掛起就激活
if (suspended) {
//表示當前是掛起的,需要激活。
//參數(shù):流程定義id、是否激活、激活時間
repositoryService.activateProcessDefinitionById(pdId, true, null);
System.out.println("流程定義:" + pdId + ",已激活");
} else {
//激活狀態(tài),則需要掛起
//參數(shù):流程定義id、是否掛起、掛起時間
repositoryService.suspendProcessDefinitionById(pdId, true, null);
System.out.println("流程定義:" + pdId + ",已掛起");
}
}
11. 單個實例掛起和激活
/**
* 單個流程實例掛起和激活
*/
@RequestMapping("singleLockOrOpenPeocess")
@ResponseBody
public void singleLockOrOpenPeocess() {
//task表的proc_inst_id
String id = "dc609b81-082e-11ed-a65d-005056c00001";
//獲取實例對象
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(id)
.singleResult();
//獲取狀態(tài)
boolean suspended = processInstance.isSuspended();
String pdId = processInstance.getId();
if (suspended) {
//表示當前是掛起的,需要激活
runtimeService.activateProcessInstanceById(pdId);
System.out.println("流程定義:" + pdId + ",已激活");
} else {
//激活狀態(tài),則需要掛起
runtimeService.suspendProcessInstanceById(pdId);
System.out.println("流程定義:" + pdId + ",已掛起");
}
}
六、activiti接口進階(變量啟動)
-
流程變量
Global變量:這個是流程變量的默認作用域,表示是一個完整的流程實例。Global變量名不能重復,如果重復則會被后面的覆蓋。
Local變量:Local變量只針對一個任務或者一個執(zhí)行實例,變量名可相同,互不影響。
ps1:如果設置了流程變量,就必須復制,否則將會報錯導致流程結束。
ps2:如果連線分支不設置條件,默認走sequenceFlow id(可在xml查看)小的那條線。
-
畫分支圖,并且設置流程審批人變量,依次設置為 a s s i g n e e 0 、 {assignee0}、 assignee0、{assignee1}、 a s s i g n e e 2 、 {assignee2}、 assignee2、{assignee3}
-
啟動流程,并且創(chuàng)建實例(帶變量)
/** * 啟動流程(創(chuàng)建新的申請流程實例列表) */ @RequestMapping("addApplication") @ResponseBody public void addApplication() { Map<String,Object> variables=new HashMap<>(); Map<String ,Object> evention=new HashMap<>(); evention.put("num",2); variables.put("evention",evention); variables.put("assignee0","申請人"); variables.put("assignee1","部門經(jīng)理"); variables.put("assignee2","總經(jīng)理"); variables.put("assignee3","財務人事"); String key = "myLeave1"; ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key,variables); }
-
依次調(diào)用solveTask方法,可以發(fā)現(xiàn)最終走的分支是num小于3的分支,即不經(jīng)過總經(jīng)理審批。
-
也可以在每次執(zhí)行時,重新設置本地變量
ps:這里需要留意,7.1.0.M1版本的activiti無法直接在complete時覆蓋全局和本地變量,只能通過設置本地變量覆蓋。
/** * 啟動流程(創(chuàng)建新的申請流程實例列表) */ @RequestMapping("addApplication") @ResponseBody public void addApplication() { Map<String,Object> variables=new HashMap<>(); Map<String ,Object> evention=new HashMap<>(); evention.put("num",2); variables.put("evention",evention); variables.put("assignee0","申請人"); variables.put("assignee1","部門經(jīng)理"); variables.put("assignee2","總經(jīng)理"); variables.put("assignee3","財務人事"); String key = "myLeave1"; ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key,variables); }
/** * 根據(jù)流程的key和任務負責人 處理任務 */ @RequestMapping("solveTask") @ResponseBody public void solveTask() { String assignee = "申請人"; String id = "myLeave1"; //根據(jù)流程的key和任務負責人 查詢?nèi)蝿?/span> Task task = taskService.createTaskQuery() .processDefinitionKey(id) .taskAssignee(assignee) .singleResult(); //完成任務,跳到下一個流程 Map<String,Object> variables=new HashMap<>(); Map<String ,Object> evention=new HashMap<>(); evention.put("num",2); variables.put("evention",evention); variables.put("assignee0","申請人1"); variables.put("assignee1","部門經(jīng)理1"); variables.put("assignee2","總經(jīng)理1"); variables.put("assignee3","財務人事1"); taskService.setVariablesLocal(task.getId(),variables); taskService.complete(task.getId()); }
/** * 根據(jù)流程的key和任務負責人 處理任務 */ @RequestMapping("solveTaskForVariables") @ResponseBody public void solveTaskForVariables() { String assignee = "部門經(jīng)理1"; String id = "myLeave1"; //根據(jù)流程的key和任務負責人 查詢?nèi)蝿?/span> Task task = taskService.createTaskQuery() .processDefinitionKey(id) .taskAssignee(assignee) .singleResult(); //完成任務,跳到下一個流程 Map<String,Object> variables=new HashMap<>(); Map<String ,Object> evention=new HashMap<>(); evention.put("num",2); variables.put("evention",evention); variables.put("assignee0","申請人2"); variables.put("assignee1","部門經(jīng)理2"); variables.put("assignee2","總經(jīng)理2"); variables.put("assignee3","財務人事2"); taskService.setVariablesLocal(task.getId(),variables); taskService.complete(task.getId()); }
然后查詢當前任務
/** * 根據(jù)流程的key查詢存在哪些任務 */ @RequestMapping("searchTaskByKey") @ResponseBody public void searchTaskByKey() { String key = "myLeave1"; //根據(jù)流程的key和任務負責人 查詢?nèi)蝿?/span> List<Task> tasks = taskService.createTaskQuery() .processDefinitionKey(key) .list(); for (Task task : tasks) { System.out.println(task.getId()); System.out.println(task.getName()); System.out.println(task.getAssignee()); System.out.println("--------------"); } } //結果 //3c18d52e-0841-11ed-b1d5-005056c00001 //財務部審批 //財務人事2 //--------------
七、activiti網(wǎng)關
1. 排他網(wǎng)關
-
概念:用來在流程中實現(xiàn)決策。 當流程執(zhí)行到這個網(wǎng)關,所有分支都會判斷是否為true,如果為ture則執(zhí)行。如果多個為true,則執(zhí)行id值小的。如果沒 有位true的,則拋出異常
-
流程圖
2. 并行網(wǎng)關
-
概念:并行網(wǎng)關允許將流程分成多條分支,也可以把多條分支匯聚到一起。并行網(wǎng)關的線上面,寫上條件也沒有用,在并行網(wǎng)關的后面分支都要執(zhí)行完成之后,才會走下一個任務,不然,只要有一個分支沒有完成,后面的任務就不會走
-
流程圖
3. 包含網(wǎng)關
-
概念:包含網(wǎng)關可以看做是排他網(wǎng)關和并行網(wǎng)關的結合體。和排他網(wǎng)關一樣,你可以在外出順序流上定義條件,包含網(wǎng)關會解析它們,不定義則默認放行。 但是主要的區(qū)別是包含網(wǎng)關可以選擇多于一條順序流,這和并行網(wǎng)關一樣。這也是用的最多的網(wǎng)關。
-
流程圖
八、組任務流程
-
概念
即任務的下一個處理人不再是一個具體的人員,而是一組候選人。候選人可以主動拾取任務,然后辦理。
-
流程圖,即再流程的第二步,經(jīng)理或總經(jīng)理需要拾取任務才能進行處理
-
代碼實現(xiàn)
由于activiti需要整合Security框架,所以需要做好權限配置,這里是簡單做了個lisi用戶的配置
package activiti.config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.ComponentScan; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextImpl; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Component; import java.util.Collection; @Component public class SecurityUtil { private Logger logger = LoggerFactory.getLogger(SecurityUtil.class); @Autowired @Qualifier("myUserDetailsService") private UserDetailsService userDetailsService; public void logInAs(String username) { UserDetails user = userDetailsService.loadUserByUsername(username); if (user == null) { throw new IllegalStateException("User " + username + " doesn't exist, please provide a valid user"); } logger.info("> Logged in as: " + username); SecurityContextHolder.setContext( new SecurityContextImpl( new Authentication() { @Override public Collection<? extends GrantedAuthority> getAuthorities() { return user.getAuthorities(); } @Override public Object getCredentials() { return user.getPassword(); } @Override public Object getDetails() { return user; } @Override public Object getPrincipal() { return user; } @Override public boolean isAuthenticated() { return true; } @Override public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { } @Override public String getName() { return user.getUsername(); } })); org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username); } }
package activiti.config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @Configuration public class SpringSecurityConfiguration { private Logger logger = LoggerFactory.getLogger(SpringSecurityConfiguration.class); @Bean public UserDetailsService myUserDetailsService() { InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager(); //這里添加用戶,后面處理流程時用到的任務負責人,需要添加在這里 String[][] usersGroupsAndRoles = { {"lisi", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"}, {"system", "password", "ROLE_ACTIVITI_USER"}, {"admin", "password", "ROLE_ACTIVITI_ADMIN"}, }; for (String[] user : usersGroupsAndRoles) { List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length)); logger.info("> Registering new user: " + user[0] + " with the following Authorities[" + authoritiesStrings + "]"); inMemoryUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]), authoritiesStrings.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList()))); } return inMemoryUserDetailsManager; } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
查找并且拾取任務文章來源:http://www.zghlxwxcb.cn/news/detail-645863.html
/** * 根據(jù)流程的key和候選人拾取任務 * 由于是測試,所以返回單個任務。正常應該是列表展示所有候選任務,然后選擇拾取。 */ @RequestMapping("claimTask") @ResponseBody public void claimTask() { String taskCandidateUser = "lisi"; String id = "myLeave5"; //根據(jù)流程的key和任務負責人 查詢?nèi)蝿?/span> Task task = taskService.createTaskQuery() .processDefinitionKey(id) .taskCandidateUser(taskCandidateUser) .singleResult(); if(task!=null){ taskService.claim(task.getId(),taskCandidateUser); } }
lisi處理任務文章來源地址http://www.zghlxwxcb.cn/news/detail-645863.html
/** * 根據(jù)流程的key和任務負責人 處理任務 */ @RequestMapping("solveTask") @ResponseBody public void solveTask() { String assignee = "lisi"; String id = "myLeave5"; //根據(jù)流程的key和任務負責人 查詢?nèi)蝿?/span> Task task = taskService.createTaskQuery() .processDefinitionKey(id) .taskAssignee(assignee) .singleResult(); //完成任務,跳到下一個流程 taskService.complete(task.getId()); }
到了這里,關于activiti7入門教程的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!