推薦:Spring微服務(wù)分布式架構(gòu):“某滴出行”項目實戰(zhàn)+面試匯總(附全套面試題MD文檔+項目源碼+白皮書)
背景
使用flowable自帶的flowable-ui制作流程圖
使用springboot開發(fā)流程使用的接口完成流程的業(yè)務(wù)功能
flowable-ui部署運行
flowable-6.6.0 運行 官方demo
參考文檔:https://flowable.com/open-source/docs/bpmn/ch14-Applications/
1县钥、從官網(wǎng)下載flowable-6.6.0 : https://github.com/flowable/flowable-engine/releases/download/flowable-6.6.0/flowable-6.6.0.zip
2秀姐、將壓縮包中的 flowable-6.6.0\wars\flowable-ui.war 丟到Tomcat中跑起來
3、打開http://localhost:8080/flowable-ui 用賬戶:admin/test 登錄
4若贮、進入APP.MODELER創(chuàng)建流程省有,之后可以導(dǎo)出流程到項目中使用,或者配置
apache-tomcat-9.0.37\webapps\flowable-ui\WEB-INF\classes\flowable-default.properties連接本地數(shù)據(jù)庫
注意:需要將java驅(qū)動jar(mysql-connector-java-5.1.45.jar)復(fù)制到 apache-tomcat-9.0.37\webapps\flowable-rest\WEB-INF\lib這樣創(chuàng)建的流程后端程序就能直接使用
繪制流程圖
根據(jù)業(yè)務(wù)需要在 flowable-ui>APP.MODELER里面繪制流程圖谴麦,示例如上圖蠢沿。先解釋一些概念。
事件(event)通常用于為流程生命周期中發(fā)生的事情建模匾效,圖里是【開始舷蟀、結(jié)束】兩個圈。
順序流(sequence flow)是流程中兩個元素間的連接器。圖里是【箭頭線段】野宜。
網(wǎng)關(guān)(gateway)用于控制執(zhí)行的流向扫步。圖里是【菱形(中間有X)】
用戶任務(wù)(user task)用于對需要人工執(zhí)行的任務(wù)進行建模。圖里是【矩形】匈子。
簡單的工作流大概就這些元素(還有很多這里就不擴展了)河胎。下面描述一下工作流是如何流動的。
首先啟動了工作流后虎敦,由【開始】節(jié)點自動流向【學(xué)生】節(jié)點仿粹,等待該任務(wù)執(zhí)行。任務(wù)被分配的學(xué)生用戶執(zhí)行后流向 【老師】節(jié)點原茅,再次等待該任務(wù)執(zhí)行吭历。被分配的老師用戶執(zhí)行后流向 【網(wǎng)關(guān)】,網(wǎng)關(guān)以此檢查每個出口擂橘,流向符合條件的任務(wù)晌区,比如這里老師執(zhí)行任務(wù)時是同意,就流向【校長】節(jié)點通贞,等待該任務(wù)執(zhí)行朗若。執(zhí)行后跟老師類似,同意后就流向【結(jié)束】節(jié)點昌罩,整個流程到此結(jié)束哭懈。
繪圖細(xì)節(jié):
1、保留流程模型
2茎用、順序流可以設(shè)置流條件來限制流動遣总,比如上面的網(wǎng)關(guān)出口就設(shè)置了條件
3、任務(wù)需要分配任務(wù)的執(zhí)行用戶轨功,可以分配到候選組旭斥,也可以直接分配到候選人
最后導(dǎo)出工作流文件
文件內(nèi)容
<?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-insmtece" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.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.flowable.org/processdef">
<process id="leave_approval" name="請假審批" isExecutable="true">
<startEvent id="start" name="開始" flowable:initiator="startuser" flowable:formFieldValidation="true"></startEvent>
<userTask id="stu_task" name="學(xué)生" flowable:candidateGroups="stu_group" flowable:formFieldValidation="true"></userTask>
<sequenceFlow id="flow1" sourceRef="start" targetRef="stu_task"></sequenceFlow>
<userTask id="te_task" name="老師" flowable:candidateGroups="te_group" flowable:formFieldValidation="true"></userTask>
<exclusiveGateway id="getway1" name="網(wǎng)關(guān)1"></exclusiveGateway>
<userTask id="mte_task" name="校長" flowable:candidateGroups="mte_group" flowable:formFieldValidation="true"></userTask>
<exclusiveGateway id="getway2" name="網(wǎng)關(guān)2"></exclusiveGateway>
<endEvent id="end" name="結(jié)束"></endEvent>
<sequenceFlow id="flow1" name="請假" sourceRef="stu_task" targetRef="te_task" skipExpression="${command=='agree'}"></sequenceFlow>
<sequenceFlow id="flow3_1" name="同意" sourceRef="getway1" targetRef="mte_task">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${command=='agree'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow2" name="審批" sourceRef="te_task" targetRef="getway1"></sequenceFlow>
<sequenceFlow id="flow3_2" name="拒絕" sourceRef="getway1" targetRef="stu_task">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${command=='refuse'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow4" name="審批" sourceRef="mte_task" targetRef="getway2"></sequenceFlow>
<sequenceFlow id="flow4_1" name="同意" sourceRef="getway2" targetRef="end" skipExpression="${command=='free'}">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${command=='agree'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow4_2" name="拒絕" sourceRef="getway2" targetRef="stu_task">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${command=='refuse'}]]></conditionExpression>
</sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_leave_approval">
這里先省略
</bpmndi:BPMNDiagram>
</definitions>
【完整文件】:leave_approval.bpmn20.xml
4、bpmn文件導(dǎo)入
如果需要古涧,可以把這個流程文件下載下來垂券,直接導(dǎo)入使用
后臺項目搭建
后臺項目基于jdk8,使用springboot框架
spring 版本
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
項目依賴pom.xml
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.6.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
項目配置application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/flowable?useSSL=false&characterEncoding=UTF-8&serverTimezone=GMT%2B8
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
數(shù)據(jù)庫
1羡滑、Flowable的所有數(shù)據(jù)庫表都以ACT_開頭菇爪。第二部分是說明表用途的兩字符標(biāo)示符。服務(wù)API的命名也大略符合這個規(guī)則柒昏。
2凳宙、ACT_RE_: 'RE’代表repository。帶有這個前綴的表包含“靜態(tài)”信息昙楚,例如流程定義與流程資源(圖片近速、規(guī)則等)诈嘿。
3、ACT_RU_: 'RU’代表runtime削葱。這些表存儲運行時信息奖亚,例如流程實例(process instance)、用戶任務(wù)(user task)析砸、變量(variable)昔字、作業(yè)(job)等。Flowable只在流程實例運行中保存運行時數(shù)據(jù)首繁,并在流程實例結(jié)束時刪除記錄作郭。這樣保證運行時表小和快。
4弦疮、ACT_HI_: 'HI’代表history夹攒。這些表存儲歷史數(shù)據(jù),例如已完成的流程實例胁塞、變量咏尝、任務(wù)等。
5啸罢、ACT_GE_: 通用數(shù)據(jù)编检。在多處使用。
1)通用數(shù)據(jù)表(2個)
act_ge_bytearray:二進制數(shù)據(jù)表扰才,如流程定義允懂、流程模板、流程圖的字節(jié)流文件衩匣;
act_ge_property:屬性數(shù)據(jù)表(不常用)蕾总;
2)歷史表(8個,HistoryService接口操作的表)
act_hi_actinst:歷史節(jié)點表舵揭,存放流程實例運轉(zhuǎn)的各個節(jié)點信息(包含開始谤专、結(jié)束等非任務(wù)節(jié)點);
act_hi_attachment:歷史附件表午绳,存放歷史節(jié)點上傳的附件信息(不常用);
act_hi_comment:歷史意見表映之;
act_hi_detail:歷史詳情表拦焚,存儲節(jié)點運轉(zhuǎn)的一些信息(不常用);
act_hi_identitylink:歷史流程人員表杠输,存儲流程各節(jié)點候選赎败、辦理人員信息,常用于查詢某人或部門的已辦任務(wù)蠢甲;
act_hi_procinst:歷史流程實例表僵刮,存儲流程實例歷史數(shù)據(jù)(包含正在運行的流程實例);
act_hi_taskinst:歷史流程任務(wù)表,存儲歷史任務(wù)節(jié)點搞糕;
act_hi_varinst:流程歷史變量表勇吊,存儲流程歷史節(jié)點的變量信息;
3)用戶相關(guān)表(4個窍仰,IdentityService接口操作的表)
act_id_group:用戶組信息表汉规,對應(yīng)節(jié)點選定候選組信息;
act_id_info:用戶擴展信息表驹吮,存儲用戶擴展信息针史;
act_id_membership:用戶與用戶組關(guān)系表;
act_id_user:用戶信息表碟狞,對應(yīng)節(jié)點選定辦理人或候選人信息啄枕;
4)流程定義、流程模板相關(guān)表(3個族沃,RepositoryService接口操作的表)
act_re_deployment:部屬信息表频祝,存儲流程定義、模板部署信息竭业;
act_re_procdef:流程定義信息表智润,存儲流程定義相關(guān)描述信息,但其真正內(nèi)容存儲在act_ge_bytearray表中未辆,以字節(jié)形式存儲窟绷;
act_re_model:流程模板信息表,存儲流程模板相關(guān)描述信息咐柜,但其真正內(nèi)容存儲在act_ge_bytearray表中兼蜈,以字節(jié)形式存儲;
5)流程運行時表(6個拙友,RuntimeService接口操作的表)
act_ru_task:運行時流程任務(wù)節(jié)點表为狸,存儲運行中流程的任務(wù)節(jié)點信息韭邓,重要含滴,常用于查詢?nèi)藛T或部門的待辦任務(wù)時使用;
act_ru_event_subscr:監(jiān)聽信息表秕噪,不常用牍蜂;
act_ru_execution:運行時流程執(zhí)行實例表漾根,記錄運行中流程運行的各個分支信息(當(dāng)沒有子流程時,其數(shù)據(jù)與act_ru_task表數(shù)據(jù)是一一對應(yīng)的)鲫竞;
act_ru_identitylink:運行時流程人員表辐怕,重要,常用于查詢?nèi)藛T或部門的待辦任務(wù)時使用从绘;
act_ru_job:運行時定時任務(wù)數(shù)據(jù)表寄疏,存儲流程的定時任務(wù)信息是牢;
act_ru_variable:運行時流程變量數(shù)據(jù)表,存儲運行中的流程各節(jié)點的變量信息陕截;
# 流程引擎API與服務(wù)
引擎API是與Flowable交互的最常用手段驳棱。總?cè)肟邳c是ProcessEngine艘策。
1蹈胡、RepositoryService很可能是使用Flowable引擎要用的第一個服務(wù)。這個服務(wù)提供了管理與控制部署(deployments)與流程定義(process
definitions)的操作朋蔫。管理靜態(tài)信息罚渐, 2、RuntimeService用于啟動流程定義的新流程實例驯妄。
3荷并、IdentityService很簡單。它用于管理(創(chuàng)建青扔,更新源织,刪除,查詢……)組與用戶微猖。
4谈息、FormService是可選服務(wù)。也就是說Flowable沒有它也能很好地運行凛剥,而不必犧牲任何功能侠仇。
5、HistoryService暴露Flowable引擎收集的所有歷史數(shù)據(jù)犁珠。要提供查詢歷史數(shù)據(jù)的能力逻炊。
6、ManagementService通常在用Flowable編寫用戶應(yīng)用時不需要使用犁享。它可以讀取數(shù)據(jù)庫表與表原始數(shù)據(jù)的信息余素,也提供了對作業(yè)(job)的查詢與管理操作。
7炊昆、DynamicBpmnService可用于修改流程定義中的部分內(nèi)容桨吊,而不需要重新部署它。例如可以修改流程定義中一個用戶任務(wù)的辦理人設(shè)置凤巨,或者修改一個服務(wù)任務(wù)中的類名屏积。
接下來使用之前的請假流程圖,上代碼
代碼
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.idm.api.Group;
import org.flowable.idm.api.User;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;
/**
* TestFlowable
*
* @Author
* @Date: 2021/10/17 23:35
* @Version 1.0
*/
@Slf4j
public class TestFlowable {
@Autowired
private RepositoryService repositoryService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private HistoryService historyService;
@Autowired
private org.flowable.engine.TaskService taskService;
@Autowired
private org.flowable.engine.IdentityService identityService;
public void createDeploymentZip() {
/*
* @Date: 2021/10/17 23:38
* Step 1: 部署xml(壓縮到zip形式磅甩,直接xml需要配置相對路徑,麻煩姥卢,暫不用)
*/
try {
File zipTemp = new File("f:/leave_approval.bpmn20.zip");
ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipTemp));
Deployment deployment = repositoryService
.createDeployment()
.addZipInputStream(zipInputStream)
.deploy();
log.info("部署成功:{}", deployment.getId());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
/*
* @Date: 2021/10/17 23:40
* Step 2: 查詢部署的流程定義
*/
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leave_approval").list();
List<ProcessDefinition> pages = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leave_approval").listPage(1, 30);
/*
* @Date: 2021/10/17 23:40
* Step 3: 啟動流程卷要,創(chuàng)建實例
*/
String processDefinitionKey = "leave_approval";//流程定義的key,對應(yīng)請假的流程圖
String businessKey = "schoolleave";//業(yè)務(wù)代碼渣聚,根據(jù)自己的業(yè)務(wù)用
Map<String, Object> variablesDefinition = new HashMap<>();//流程變量,可以自定義擴充
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variablesDefinition);
log.info("啟動成功:{}", processInstance.getId());
/*
* @Date: 2021/10/17 23:40
* Step 4: 查詢指定流程所有啟動的實例列表
* 列表僧叉,或 分頁 刪除
*/
List<Execution> executions = runtimeService.createExecutionQuery().processDefinitionKey("leave_approval").list();
List<Execution> executionPages = runtimeService.createExecutionQuery().processDefinitionKey("leave_approval").listPage(1, 30);
// runtimeService.deleteProcessInstance(processInstanceId, deleteReason); //刪除實例
/*
* @Date: 2021/10/17 23:40
* Step 5: 學(xué)生查詢可以操作的任務(wù),并完成任務(wù)
*/
String candidateGroup = "stu_group"; //候選組 xml文件里面的 flowable:candidateGroups="stu_group"
List<Task> taskList = taskService.createTaskQuery().taskCandidateGroup(candidateGroup).orderByTaskCreateTime().desc().list();
for (Task task : taskList) {
// 申領(lǐng)任務(wù)
taskService.claim(task.getId(), "my");
// 完成
taskService.complete(task.getId());
}
/*
* @Date: 2021/10/17 23:40
* Step 6: 老師查詢可以操作的任務(wù),并完成任務(wù)
*/
String candidateGroupTe = "te_group"; //候選組 xml文件里面的 flowable:candidateGroups="te_group"
List<Task> taskListTe = taskService.createTaskQuery().taskCandidateGroup(candidateGroupTe).orderByTaskCreateTime().desc().list();
for (Task task : taskListTe) {
// 申領(lǐng)任務(wù)
taskService.claim(task.getId(), "myte");
// 完成
Map<String, Object> variables = new HashMap<>();
variables.put("command","agree"); //攜帶變量奕枝,用于網(wǎng)關(guān)流程的條件判定,這里的條件是同意
taskService.complete(task.getId(), variables);
}
/*
* @Date: 2021/10/18 0:17
* Step 7: 歷史查詢瓶堕,因為一旦流程執(zhí)行完畢隘道,活動的數(shù)據(jù)都會被清空,上面查詢的接口都查不到數(shù)據(jù)郎笆,但是提供歷史查詢接口
*/
// 歷史流程實例
List<HistoricProcessInstance> historicProcessList = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("leave_approval").list();
// 歷史任務(wù)
List<HistoricTaskInstance> historicTaskList = historyService.createHistoricTaskInstanceQuery().processDefinitionKey("leave_approval").list();
// 實例歷史變量 , 任務(wù)歷史變量
// historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId);
// historyService.createHistoricVariableInstanceQuery().taskId(taskId);
// *****************************************************分隔符********************************************************************
// *****************************************************分隔符********************************************************************
// 可能還需要的API
// 移動任務(wù)谭梗,人為跳轉(zhuǎn)任務(wù)
// runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId)
// .moveActivityIdTo(currentActivityTaskId, newActivityTaskId).changeState();
// 如果在數(shù)據(jù)庫配置了分組和用戶,還會用到
List<User> users = identityService.createUserQuery().list(); //用戶查詢宛蚓,用戶id對應(yīng)xml 里面配置的用戶
List<Group> groups = identityService.createGroupQuery().list(); //分組查詢激捏,分組id對應(yīng)xml 里面配置的分組 如 stu_group,te_group 在表里是id的值
// 另外凄吏,每個查詢后面都可以拼條件远舅,內(nèi)置恁多查詢,包括模糊查詢痕钢,大小比較都有
}
}