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 属性表示线指向的节点
流程图
<?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: 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>
表
一般数据
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 ( ) ) ;
}
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" ) ;
}
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 ( ) ) ;
}
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) ;
}
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<String, Object> variables) 流程执行中
void setVariable(String executionId, String variableName, Object value) void setVariableLocal(String executionId, String variableName, Object value) void setVariables(String executionId, Map<String, ? extends Object> variables) void setVariablesLocal(String executionId, Map<String, ? extends Object> 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>
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