flowable
插件
依赖
< dependency>
< groupId> org.flowable groupId>
< artifactId> flowable-engine artifactId>
< version> 6.5.0 version>
dependency>
< dependency>
< groupId> mysql groupId>
< artifactId> mysql-connector-java artifactId>
< version> 8.0.18 version>
dependency>
xml标签
- 表示一个完整的工作流程 - 工作流中起点位置 - 工作流中结束位置 - 代表一个任务审核节点 - flowable:assignee 属性,这表示这个节点该由谁来处理 - 服务任务,在具体的实现中,这个任务可以做任何事情 - 逻辑判断节点 - 链接各个节点的线条 - sourceRef 属性表示线的起始节点 - targetRef 属性表示线指向的节点
流程图
< 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: 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 = " process1" name = " process1" isExecutable = " true" >
< startEvent id = " start" name = " start" />
< userTask id = " apply" name = " apply" flowable: assignee= " 10001" />
< sequenceFlow id = " edge_1" sourceRef = " start" targetRef = " apply" name = " edge_1" />
< exclusiveGateway id = " gateway" name = " gateway" />
< sequenceFlow id = " edge_2" sourceRef = " apply" targetRef = " gateway" name = " edge_2" />
< sequenceFlow id = " agree" sourceRef = " gateway" targetRef = " holiday_system" name = " agree" >
< conditionExpression xsi: type= " tFormalExpression" > ${approved} conditionExpression>
sequenceFlow>
< sequenceFlow id = " rejected" sourceRef = " gateway" targetRef = " e_mail" name = " rejected" >
< conditionExpression xsi: type= " tFormalExpression" > !${approved} conditionExpression>
sequenceFlow>
< endEvent id = " refuse_end" name = " refuse_end" />
< sequenceFlow id = " edge_5" sourceRef = " e_mail" targetRef = " refuse_end" name = " edge_5" />
< userTask id = " holiday_apply" name = " holiday_apply" />
< sequenceFlow id = " edge_3" sourceRef = " holiday_system" targetRef = " holiday_apply" name = " edge_3" />
< endEvent id = " agree_end" name = " agree_end" />
< sequenceFlow id = " edge_4" sourceRef = " holiday_apply" targetRef = " agree_end" name = " edge_4" />
< serviceTask id = " e_mail" flowable: exclusive= " true" name = " e_mail" flowable: class= " com.sws.flowable.SendEmail" />
< serviceTask id = " holiday_system" flowable: exclusive= " true" name = " holiday_system" flowable: class= " com.sws.flowable.CallExternalSystem" />
process>
< bpmndi: BPMNDiagram id = " BPMNDiagram_process1" >
< bpmndi: BPMNPlane bpmnElement = " process1" id = " BPMNPlane_process1" >
< bpmndi: BPMNShape id = " shape-cf32fcf2-b052-4374-82b8-a8c1c4bf85d5" bpmnElement = " start" >
< omgdc: Bounds x = " -225.0" y = " -85.0" width = " 30.0" height = " 30.0" />
bpmndi: BPMNShape>
< bpmndi: BPMNShape id = " shape-0e717dd9-30ac-4c4c-b055-a3bf5d6bfecf" bpmnElement = " apply" >
< omgdc: Bounds x = " -75.0" y = " -110.0" width = " 100.0" height = " 80.0" />
bpmndi: BPMNShape>
< bpmndi: BPMNEdge id = " edge-eed13fc9-0ffb-4bff-a0aa-e285d8b7d7f9" bpmnElement = " edge_1" >
< omgdi: waypoint x = " -195.0" y = " -70.0" />
< omgdi: waypoint x = " -74.99999" y = " -70.0" />
bpmndi: BPMNEdge>
< bpmndi: BPMNShape id = " shape-a4f56a19-2439-44d3-b8a3-b775ad52e2a4" bpmnElement = " gateway" >
< omgdc: Bounds x = " 130.0" y = " -89.99999" width = " 40.0" height = " 40.0" />
bpmndi: BPMNShape>
< bpmndi: BPMNEdge id = " edge-d5f2fe06-7a50-4973-8511-72fa8925cbec" bpmnElement = " edge_2" >
< omgdi: waypoint x = " 25.0" y = " -70.0" />
< omgdi: waypoint x = " 130.0" y = " -69.99999" />
bpmndi: BPMNEdge>
< bpmndi: BPMNEdge id = " edge-8753897d-4678-4e99-b9ce-642f43e7f525" bpmnElement = " agree" >
< omgdi: waypoint x = " 170.0" y = " -69.99999" />
< omgdi: waypoint x = " 260.0" y = " -70.0" />
bpmndi: BPMNEdge>
< bpmndi: BPMNEdge id = " edge-2b5a2ac0-1286-4d5f-af1e-48e998ce9f1b" bpmnElement = " rejected" >
< omgdi: waypoint x = " 150.0" y = " -50" />
< omgdi: waypoint x = " 150.0" y = " 80.0" />
< omgdi: waypoint x = " 250" y = " 80" />
bpmndi: BPMNEdge>
< bpmndi: BPMNShape id = " shape-7a97d6b5-57ba-41bc-8dc1-717aab6aa854" bpmnElement = " refuse_end" >
< omgdc: Bounds x = " 460.0" y = " 65.0" width = " 30.0" height = " 30.0" />
bpmndi: BPMNShape>
< bpmndi: BPMNEdge id = " edge-27898ca3-1476-4654-9004-a8bc78995894" bpmnElement = " edge_5" >
< omgdi: waypoint x = " 349.99997" y = " 80.00001" />
< omgdi: waypoint x = " 460.0" y = " 80.0" />
bpmndi: BPMNEdge>
< bpmndi: BPMNShape id = " shape-ef7ac29e-8c1f-4c49-8f8d-6a78163eeebd" bpmnElement = " holiday_apply" >
< omgdc: Bounds x = " 470.0" y = " -109.99999" width = " 100.0" height = " 80.0" />
bpmndi: BPMNShape>
< bpmndi: BPMNEdge id = " edge-c2087a6f-f798-43ba-916c-cca48749601c" bpmnElement = " edge_3" >
< omgdi: waypoint x = " 360.0" y = " -69.99999" />
< omgdi: waypoint x = " 470.0" y = " -69.99999" />
bpmndi: BPMNEdge>
< bpmndi: BPMNShape id = " shape-36c2a15b-54c0-4418-ba70-a04be63c2db4" bpmnElement = " agree_end" >
< omgdc: Bounds x = " 675.0" y = " -85.0" width = " 30.0" height = " 30.0" />
bpmndi: BPMNShape>
< bpmndi: BPMNEdge id = " edge-04236214-6d53-4358-a229-43b194cc81ae" bpmnElement = " edge_4" >
< omgdi: waypoint x = " 570.0" y = " -69.99999" />
< omgdi: waypoint x = " 675.0" y = " -70.0" />
bpmndi: BPMNEdge>
< bpmndi: BPMNShape id = " shape-df0c0f71-78a2-42df-90c5-51fa6b518cc0" bpmnElement = " e_mail" >
< omgdc: Bounds x = " 250.0" y = " 40.0" width = " 100.0" height = " 80.0" />
bpmndi: BPMNShape>
< bpmndi: BPMNShape id = " shape-a2af75ca-9706-423d-97b6-94121cea7903" bpmnElement = " holiday_system" >
< omgdc: Bounds x = " 260.0" y = " -109.99999" width = " 100.0" height = " 80.0" />
bpmndi: BPMNShape>
bpmndi: BPMNPlane>
bpmndi: BPMNDiagram>
definitions>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
表
一般数据
act_ge_bytearry
通用流程定义和流程资源,流程资源表,流程部署的bpmn文件和png图片 id_
rev_
name_
deployment_id_
bytes_
generated_
act_ge_property
流程历史记录
act_hi_actinst
act_hi_attachment
act_hi_comment
act_hi_detail
act_hi_identitylink
act_hi_procinst
act_hi_taskinst
act_hi_varinst
流程定义表
act_re_deployment
act_re_procdef
act_re_model
运行实例表
act_ru_event_subscr
act_ru_execution
act_ru_identitylink
act_ru_task
act_ru_job
act_ru_variable
概念&类型
ProcessEngineConfiguration
工作流引擎配置 ProcessEngine
流程引擎对象
RepositoryService
ProcessDefinition
RuntimeService
运行时服务,可以启动流程实例 ProcessInstance
TaskService HistoryService ManagementService
Activity
Execution
流程的执行线路 通过Execution可以获得当前ProcessInstance当前执行到哪个Activity Task
test
public void testProcessEngine ( ) {
ProcessEngineConfiguration configuration = new StandaloneProcessEngineConfiguration ( ) ;
configuration. setJdbcDriver ( "com.mysql.cj.jdbc.Driver" ) ;
configuration. setJdbcUsername ( "root" ) ;
configuration. setJdbcPassword ( "123456" ) ;
configuration. setJdbcUrl ( "jdbc:mysql://localhost:3306/flowable?characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true" ) ;
configuration. setDatabaseSchemaUpdate ( ProcessEngineConfiguration . DB_SCHEMA_UPDATE_TRUE ) ;
ProcessEngine processEngine = configuration. buildProcessEngine ( ) ;
}
流程部署
act_re_deployment
act_re_procdef
act_ge_bytearry
public void testDeploy ( ) {
ProcessEngine processEngine = configuration. buildProcessEngine ( ) ;
RepositoryService repositoryService = processEngine. getRepositoryService ( ) ;
Deployment deploy = repositoryService. createDeployment ( )
. addClasspathResource ( "process1.bpmn20.xml" )
. name ( "请求流程" )
. deploy ( ) ;
System . out. println ( deploy. getId ( ) ) ;
System . out. println ( deploy. getName ( ) ) ;
}
@Test
public void testDeployQuery ( ) {
ProcessEngine processEngine = configuration. buildProcessEngine ( ) ;
RepositoryService repositoryService = processEngine. getRepositoryService ( ) ;
ProcessDefinition processDefinition = repositoryService. createProcessDefinitionQuery ( )
. deploymentId ( "2501" )
. singleResult ( ) ;
System . out. println ( "processDefinition.getId() = " + processDefinition. getId ( ) ) ;
System . out. println ( "processDefinition.getName() = " + processDefinition. getName ( ) ) ;
System . out. println ( "processDefinition.getDeploymentId() = " + processDefinition. getDeploymentId ( ) ) ;
System . out. println ( "processDefinition.getDescription() = " + processDefinition. getDescription ( ) ) ;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
ProcessEngine processEngine = configuration. buildProcessEngine ( ) ;
RepositoryService repositoryService = processEngine. getRepositoryService ( ) ;
ProcessDefinition processDefinition = repositoryService. createProcessDefinitionQuery ( )
. deploymentId ( "xxx" )
. singleResult ( ) ;
boolean suspended = processDefintion. isSuspended ( ) ;
if ( suspended) {
repositoryService. activateProcessDefinitionById ( "xxx" ) ;
} else {
repositoryService. suspendProcessDefinitionByKey ( "xxx" ) ;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
public void testDelete ( ) {
ProcessEngine processEngine = configuration. buildProcessEngine ( ) ;
RepositoryService repositoryService = processEngine. getRepositoryService ( ) ;
repositoryService. deleteDeployment ( "xxx" ) ;
}
启动流程实例
act_ru_deadletter_job
act_ru_event_subscr
act_ru_history_job
act_ru_job
act_ru_suspended_job
act_ru_timer_job
act_ru_execution
act_ru_variable
act_ru_task
act_ru_identitylink
public void testRunProcess ( ) {
ProcessEngine processEngine = configuration. buildProcessEngine ( ) ;
RuntimeService runtimeService = processEngine. getRuntimeService ( ) ;
Map < String , Object > variables = new HashMap < > ( ) ;
variables. put ( "employee" , "张三" ) ;
variables. put ( "nrOfHolidays" , 3 ) ;
variables. put ( "description" , "工作累了,想出去玩玩" ) ;
ProcessInstance processInstance = runtimeService
. startProcessInstanceByKey ( "process1" , variables) ;
System . out. println ( "流程定义的ID:" + processInstance. getProcessDefinitionId ( ) ) ;
System . out. println ( "流程实例的ID:" + processInstance. getId ( ) ) ;
System . out. println ( "当前活动的ID:" + processInstance. getActivityId ( ) ) ;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
public void testQueryTask ( ) {
ProcessEngine processEngine = configuration. buildProcessEngine ( ) ;
TaskService taskService = processEngine. getTaskService ( ) ;
List < Task > list = taskService. createTaskQuery ( )
. processDefinitionKey ( "process1" )
. taskAssignee ( "10001" )
. list ( ) ;
for ( Task task : list) {
System . out. println ( "task.getProcessDefinitionId() = " + task. getProcessDefinitionId ( ) ) ;
System . out. println ( "task.getId() = " + task. getId ( ) ) ;
System . out. println ( "task.getAssignee() = " + task. getAssignee ( ) ) ;
System . out. println ( "task.getName() = " + task. getName ( ) ) ;
}
}
public class SendEmail implements JavaDelegate {
@Override
public void execute ( DelegateExecution delegateExecution) {
System . out. println ( "拒绝" ) ;
}
}
public void testCompleteTask ( ) {
ProcessEngine processEngine = configuration. buildProcessEngine ( ) ;
TaskService taskService = processEngine. getTaskService ( ) ;
Task task = taskService. createTaskQuery ( )
. processDefinitionKey ( "process1" )
. taskAssignee ( "10001" )
. singleResult ( ) ;
Map < String , Object > variables = new HashMap < > ( ) ;
variables. put ( "approved" , false ) ;
taskService. complete ( task. getId ( ) , variables) ;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
public void testQueryHistory ( ) {
ProcessEngine processEngine = configuration. buildProcessEngine ( ) ;
HistoryService historyService = processEngine. getHistoryService ( ) ;
List < HistoricActivityInstance > list = historyService. createHistoricActivityInstanceQuery ( )
. processDefinitionId ( "process1:2:10004" )
. finished ( )
. orderByHistoricActivityInstanceEndTime ( ) . asc ( )
. list ( ) ;
for ( HistoricActivityInstance historicActivityInstance : list) {
System . out. println ( historicActivityInstance. getActivityId ( ) + " took " + historicActivityInstance. getDurationInMillis ( ) + " milliseconds" ) ;
}
}
变量
流程创建时
ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map variables) 流程执行中
void setVariable(String executionId, String variableName, Object value) void setVariableLocal(String executionId, String variableName, Object value) void setVariables(String executionId, Map variables) void setVariablesLocal(String executionId, Map variables)
用户维护
表
表
ACT_ID_USER
ACT_ID_GROUP
ACT_ID_MEMBERSHIP
act_id_bytearry
act_id_info
act_id_priv
act_id_priv_mapping
act_id_property
act_id_token
test
public void createUser ( ) {
ProcessEngine processEngine = configuration. buildProcessEngine ( ) ;
IdentityService identityService = processEngine. getIdentityService ( ) ;
User user = identityService. newUser ( "111112222222" ) ;
user. setFirstName ( "111" ) ;
user. setLastName ( "222" ) ;
user. setEmail ( "1221122121@qq.com" ) ;
identityService. saveUser ( user) ;
}
public void createGroup ( ) {
ProcessEngine processEngine = configuration. buildProcessEngine ( ) ;
IdentityService identityService = processEngine. getIdentityService ( ) ;
Group group = identityService. newGroup ( "111" ) ;
group. setName ( "aaaa" ) ;
group. setType ( "bbb" ) ;
identityService. saveGroup ( group) ;
}
public void userGroup ( ) {
ProcessEngine processEngine = configuration. buildProcessEngine ( ) ;
IdentityService identityService = processEngine. getIdentityService ( ) ;
Group group = identityService. createGroupQuery ( ) . groupId ( "111" ) . singleResult ( ) ;
List < User > list = identityService. createUserQuery ( ) . list ( ) ;
for ( User user : list) {
identityService. createMembership ( user. getId ( ) , group. getId ( ) ) ;
}
}
流程设置组
flowable:candidateGroups=“${group1}”
IdentityService identityService = processEngine. getIdentityService ( ) ;
Group group = identityService. createGroupQuery ( ) . groupId ( "group1" ) . singleResult ( ) ;
RuntimeService runtimeService = processEngine. getRuntimeService ( ) ;
Map < String , Object > variables = new HashMap < > ( ) ;
variables. put ( "group1" , group. getId ( ) ) ;
runtimeService. startProcessInstanceById ( "xxx" , variables) ;
登录人查询
IdentityService identityService = processEngine. getIdentityService ( ) ;
Group group = identityService. createGroupQuery ( ) . groupMember ( "xxxx" ) . singleResult ( ) ;
TaskService taskService = processEngine. getTaskService ( ) ;
List < Task > list = taskService. createTaskQuery ( )
. processDefinitionId ( "xxxxx" )
. taskCandidateGroup ( group. getId ( ) )
. list ( ) ;
拾取任务
String userId = "xxxx" ;
IdentityService identityService = processEngine. getIdentityService ( ) ;
Group group = identityService. createGroupQuery ( ) . groupMember ( userId) . singleResult ( ) ;
TaskService taskService = processEngine. getTaskService ( ) ;
Task task = taskService. createTaskQuery ( )
. processDefinitionId ( "xxxxxxx" )
. taskCandidateGroup ( group. getId ( ) )
. singleResult ( ) ;
if ( task != null ) {
taskService. claim ( task. getId ( ) , userId) ;
System . out. println ( "任务拾取成功" ) ;
}
归还任务
String userId = "xxxx" ;
IdentityService identityService = processEngine. getIdentityService ( ) ;
Group group = identityService. createGroupQuery ( ) . groupMember ( userId) . singleResult ( ) ;
TaskService taskService = processEngine. getTaskService ( ) ;
Task task = taskService. createTaskQuery ( )
. processDefinitionId ( "xxxxxxx" )
. taskAssignee ( "xxx" )
. singleResult ( ) ;
if ( task != null ) {
taskService. unclaim ( task. getId ( ) ) ;
System . out. println ( "任务归还" ) ;
}
交接任务
String userId = "xxxx" ;
IdentityService identityService = processEngine. getIdentityService ( ) ;
Group group = identityService. createGroupQuery ( ) . groupMember ( userId) . singleResult ( ) ;
TaskService taskService = processEngine. getTaskService ( ) ;
Task task = taskService. createTaskQuery ( )
. processDefinitionId ( "xxxxxxx" )
. taskAssignee ( "xxx" )
. singleResult ( ) ;
if ( task != null ) {
taskService. setAssignee ( task. getId ( ) , "xxx" ) ;
System . out. println ( "交接任务" ) ;
}
完成任务
String userId = "xxxx";
// 根据当前登录的用户找到对应的组
IdentityService identityService = processEngine.getIdentityService();
// 当前用户所在的组
Group group = identityService.createGroupQuery().groupMember(userId).singleResult();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionId("xxxxxxx")
.taskCandidateGroup(group.getId())
.singleResult();
if(task != null) {
taskService.complete(task.getId());
System.out.println("完成Task");
}
监听器
public class MyTaskListener implements TaskListener{
public void notify(DelegateTask delegateTask){
// delegateTask.getName()
// delegateTask.getEventName()
}
}
网关
排他网关
按照所有出口顺序流定义的顺序对它们进行计算 选择第一个条件计算为true的顺序流 当没有设置条件时,认为顺序流为true 并行网关
fork分支
并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。 join汇聚
所有到达并行网关,在此等待的进入分支 直到所有进入顺序流的分支都到达以后, 流程就会通过汇聚网关。 包含网关
事件网关
事件
springboot整合
依赖
< parent>
< groupId> org.springframework.boot groupId>
< artifactId> spring-boot-starter-parent artifactId>
< version> 2.3.4.RELEASE version>
parent>
< dependencies>
< dependency>
< groupId> org.springframework.boot groupId>
< artifactId> spring-boot-starter-web artifactId>
dependency>
< dependency>
< groupId> org.flowable groupId>
< artifactId> flowable-spring-boot-starter artifactId>
< version> 6.3.0 version>
dependency>
< dependency>
< groupId> mysql groupId>
< artifactId> mysql-connector-java artifactId>
< version> 5.1.45 version>
dependency>
dependencies>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
application.yml
flowable :
async- executor- activate: false
database- schema- update: true
自动部署
resources/process/xxx.xml
手动部署
Deployment deploy = repositoryService. createDeployment ( )
. addClasspathResource ( "process1.bpmn20.xml" )
. name ( "请求流程" )
. deploy ( ) ;
mysql
docker run -d -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=123456 -v F:\\docker\\mysql\\conf:/etc/mysql/conf.d -v F:\\docker\\mysql\\data:/var/lib/mysql -v F:\\docker\\mysql\\mysql-file:/var/lib/mysql-files mysql