流程设计器flowable-ui
flowable-ui Docker镜像地址
#创建网络
docker network create my_net
#生成容器实例
docker run -d --network=my_net --restart=always -p 8002:8080 --privileged=true -e TZ=Asia/Shanghai --name myFlowableUi flowable/flowable-ui:6.8.0
访问地址:http://localhost:8002/flowable-ui
用户名及密码:admin test
表结构讲解
工作流程的相关操作都是操作存储在对应的表结构中,为了能更好的弄清楚Flowable的实现原理和细节,我们有必要先弄清楚Flowable的相关表结构及其作用。在Flowable中的表结构在初始化的时候会创建五类表结构,具体如下:
- ACT_RE :'RE'表示 repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
- ACT_RU:'RU'表示 runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Flowable只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
- ACT_HI:'HI'表示 history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
- ACT_GE: GE 表示 general。 通用数据, 用于不同场景下
- ACT_ID: ’ID’表示identity(组织机构)。这些表包含标识的信息,如用户,用户组,等等。
表分类 | 表名 | 解释 |
---|---|---|
一般数据 | ||
[ACT_GE_BYTEARRAY] | 通用的流程定义和流程资源 | |
[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_MODEL] | 模型信息 | |
[ACT_RE_PROCDEF] | 已部署的流程定义 | |
运行实例表 | ||
[ACT_RU_EVENT_SUBSCR] | 运行时事件 | |
[ACT_RU_EXECUTION] | 运行时流程执行实例 | |
[ACT_RU_IDENTITYLINK] | 运行时用户关系信息,存储任务节点与参与者的相关信息 | |
[ACT_RU_JOB] | 运行时作业 | |
[ACT_RU_TASK] | 运行时任务 | |
[ACT_RU_VARIABLE] | 运行时变量表 | |
用户用户组表 | ||
[ACT_ID_BYTEARRAY] | 二进制数据表 | |
[ACT_ID_GROUP] | 用户组信息表 | |
[ACT_ID_INFO] | 用户信息详情表 | |
[ACT_ID_MEMBERSHIP] | 人与组关系表 | |
[ACT_ID_PRIV] | 权限表 | |
[ACT_ID_PRIV_MAPPING] | 用户或组权限关系表 | |
[ACT_ID_PROPERTY] | 属性表 | |
[ACT_ID_TOKEN] | 记录用户的token信息 | |
[ACT_ID_USER] | 用户表 |
Service总览
service名称 | service作用 |
---|---|
RepositoryService | Flowable的资源管理类 |
RuntimeService | Flowable的流程运行管理类 |
TaskService | Flowable的任务管理类 |
HistoryService | Flowable的历史管理类 |
ManagerService | Flowable的引擎管理类 |
简单介绍:
RepositoryService
是activiti的资源管理类,提供了管理和控制流程发布包和流程定义的操作。使用工作流建模工具设计的业务流程图需要使用此service将流程定义文件的内容部署到计算机。
除了部署流程定义以外还可以:查询引擎中的发布包和流程定义。
暂停或激活发布包,对应全部和特定流程定义。 暂停意味着它们不能再执行任何操作了,激活是对应的反向操作。获得多种资源,像是包含在发布包里的文件, 或引擎自动生成的流程图。
获得流程定义的pojo版本, 可以用来通过java解析流程,而不必通过xml。
RuntimeService
Activiti的流程运行管理类。可以从这个服务类中获取很多关于流程执行相关的信息
TaskService
Activiti的任务管理类。可以从这个类中获取任务的信息。
HistoryService
Flowable的历史管理类,可以查询历史信息,执行流程时,引擎会保存很多数据(根据配置),比如流程实例启动时间,任务的参与者, 完成任务的时间,每个流程实例的执行路径,等等。 这个服务主要通过查询功能来获得这些数据。
ManagementService
Activiti的引擎管理类,提供了对Flowable 流程引擎的管理和维护功能,这些功能不在工作流驱动的应用程序中使用,主要用于 Flowable 系统的日常维护。
idea开发插件
插件名称:Flowable BPMN visualizer
插件地址:plugins.jetbrains.com/plugin/1431…
监听器说明
任务监听器:TaskListener
TaskListener 顾名思义它是针对任务的事件监听器,它可以监听任务的创建、分配、完成等事件。TaskListener 的事件类型和执行时机是与任务相关的,它可以访问任务相关的信息,并可以对任务进行操作(例如设置任务的执行人 、 指定任务的代理人 、 发送通知等),因此通常用于处理与任务相关的事件。
<userTask id="createBill" name="创建请假单" flowable:candidateUsers="${dagongzai}">
<extensionElements>
<flowable:taskListener event="create" delegateExpression="${my03TaskListener}"/><!-- 事务中,执行的任务监听器 -->
<flowable:taskListener event="create" delegateExpression="${my03TransactionCommittedTaskListener}" onTransaction="committed"/><!-- 事务提交后,执行的任务监听器 -->
<flowable:taskListener event="create" delegateExpression="${my03TransactionRolledBackTaskListener}" onTransaction="rolled-back"/><!-- 事务回滚后,执行的任务监听器 -->
</extensionElements>
</userTask>
import com.gjw.go.common.log
import org.flowable.task.service.delegate.DelegateTask
import org.flowable.task.service.delegate.TaskListener
import org.springframework.stereotype.Component
@Component
class My03TaskListener : TaskListener {
override fun notify(delegateTask: DelegateTask) {
log.info("事务中执行的 任务监听器")
}
}
import com.gjw.go.common.log
import org.flowable.bpmn.model.Task
import org.flowable.engine.TaskService
import org.flowable.engine.delegate.TransactionDependentTaskListener
import org.springframework.stereotype.Component
/**
* 事务提交后 执行的任务监听器
*/
@Component
class My03TransactionCommittedTaskListener : TransactionDependentTaskListener {
override fun notify(
processInstanceId: String?,
executionId: String?,
task: Task?,
executionVariables: MutableMap<String, Any>?,
customPropertiesMap: MutableMap<String, Any>?
) {
log.info("事务提交后 任务监听器 processId: " + processInstanceId + ",任务ID=" + task!!.id)
}
}
/**
* 事务回滚后 执行的任务监听器
*/
@Component
class My03TransactionRolledBackTaskListener(
private val taskService: TaskService
) : TransactionDependentTaskListener {
override fun notify(
processInstanceId: String,
executionId: String,
task: Task?,
executionVariables: MutableMap<String, Any>?,
customPropertiesMap: MutableMap<String, Any>?
) {
log.info("事务回滚 任务监听器 processId: $processInstanceId,executionId: $executionId")
}
}
执行监听器:ExecutionListener
ExecutionListener 是针对整个流程实例的事件监听器,它可以监听流程实例启动、结束、活动开始、活动结束、连线选择等事件。ExecutionListener 的事件类型和执行时机都是固定的,它不能直接访问任务相关的信息(例如任务的候选人、任务的执行者等),因此通常用于处理与流程实例相关的事件。
流程事件监听器:FlowableEventListener
事件枚举类: org.flowable.common.engine.api.delegate.event.FlowableEngineEventType
监听整个流程的开始、结束等;
网关说明
包容网关
并行网关
排他网关 exclusiveGateway
需求
1、动态设置下一个审批节点审批用户
核心配置:任务监听器, 通过任务监听器自定义指派
<!--直属老师审批-->
<userTask id="teacherCheck" name="直属教师审批" flowable:assignee="${jiaoshi}" flowable:formFieldValidation="true">
<documentation>直属老师进行审批</documentation>
<extensionElements>
<!--任务监听器:在任务创建前设置流程变量,动态设置直属老师信息及候选审批用户等-->
<flowable:taskListener event="create" class="com.gjw.go.flowable.task.listener.FlowTaskListener"></flowable:taskListener>
<modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>
</userTask>
package com.gjw.go.flowable.task.listener;
import lombok.extern.slf4j.Slf4j;
import org.flowable.task.service.delegate.DelegateTask;
import org.flowable.task.service.delegate.TaskListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* 任务监听器,在具体任务中配置并动态修改生成任务的参数
*/
@Slf4j
public class FlowTaskListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
log.info("**************任务监听器 start");
log.info("getEventName= {}",delegateTask.getEventName());
log.info("getName= {}",delegateTask.getName());
log.info("getId= {}",delegateTask.getId());
log.info("getVariables= {}",delegateTask.getVariables());
log.info("delegateTask.getProcessDefinitionId()= {}",delegateTask.getProcessDefinitionId());
Map<String,Object> variablesMap = delegateTask.getVariables();
if(Objects.equals(variablesMap.get("employee"),"寒冬")){
List<String> users = new ArrayList<>();
users.add("admin1");
users.add("admin2");
users.add("admin3");
users.add("admin4");
delegateTask.addCandidateUsers(users);//给该节点添加候选审批用户
delegateTask.setAssignee("xiangcunlaoshi");//设置受让人
System.out.println("进入自定义逻辑 ");
}
log.info("**************任务监听器 end");
}
}
2023-请假流程.bpmn20.xml
<?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" exporter="Flowable Open Source Modeler" exporterVersion="6.8.0">
<process id="holidayFlowable" name="2023-请假流程" isExecutable="true">
<documentation>2023年新版请假流程</documentation>
<!--流程事件监听器 优先级高于 任务监听器-->
<extensionElements>
<flowable:eventListener events="TASK_ASSIGNED" class="com.gjw.go.flowable.task.listener.MyFlowableEventListener"></flowable:eventListener>
<flowable:eventListener events="TASK_CREATED" class="com.gjw.go.flowable.task.listener.MyFlowableEventListener"></flowable:eventListener>
</extensionElements>
<!--流程开始-->
<startEvent id="startEvent1"></startEvent>
<sequenceFlow id="sid-A9B1B8F5-F233-4ED2-962A-6AD3DFB90DB7" sourceRef="startEvent1" targetRef="javaService"></sequenceFlow>
<!--Java服务任务-->
<serviceTask id="javaService" name="调用java服务" flowable:class="com.gjw.go.flowable.task.listener.ToUpperCaseFieldInjected">
<extensionElements>
<flowable:field name="text" expression="${jiaoshi}" />
</extensionElements>
</serviceTask>
<sequenceFlow sourceRef="javaService" targetRef="teacherCheck"></sequenceFlow>
<!--直属老师审批-->
<userTask id="teacherCheck" name="直属教师审批" flowable:assignee="${jiaoshi}" flowable:formFieldValidation="true">
<documentation>直属老师进行审批</documentation>
<extensionElements>
<!--执行监听器-->
<flowable:executionListener event="start" class="com.gjw.go.flowable.task.listener.FlowExecutionListener">
<flowable:field name="fieldName">
<!--执行监听器上的字段注入-->
<flowable:string><![CDATA[dept]]></flowable:string>
<flowable:string></flowable:string>
<flowable:expression></flowable:expression>
</flowable:field>
</flowable:executionListener>
<!--任务监听器:在任务创建前设置流程变量,动态设置直属老师信息及候选审批用户等-->
<flowable:taskListener event="create" class="com.gjw.go.flowable.task.listener.FlowTaskListener"></flowable:taskListener>
<modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>
</userTask>
<sequenceFlow id="sid-35534B9A-A1C4-4429-B91D-096B9CFD70F2" sourceRef="teacherCheck" targetRef="sid-CE7A6ED1-0F56-440F-8F19-0A815FD7D0CF"></sequenceFlow>
<!--排他网关-->
<exclusiveGateway id="sid-CE7A6ED1-0F56-440F-8F19-0A815FD7D0CF"></exclusiveGateway>
<sequenceFlow id="sid-E775E55F-3A3B-49C6-93B0-5B5E54B5941A" sourceRef="sid-CE7A6ED1-0F56-440F-8F19-0A815FD7D0CF" targetRef="refusedSendEmail">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${!approved}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="sid-74AE5A71-27E3-4691-8EBB-A34FB66FE0BF" sourceRef="sid-CE7A6ED1-0F56-440F-8F19-0A815FD7D0CF" targetRef="sid-3B97B2FD-93AE-4D23-B15D-1C7B29A03259">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${approved}]]></conditionExpression>
</sequenceFlow>
<!--拒绝并发邮件通知-->
<serviceTask id="refusedSendEmail" name="审批未通过发送邮件通知" flowable:class="com.gjw.go.flowable.SendRejectionMail">
<documentation>拒绝并发送邮件通知</documentation>
</serviceTask>
<sequenceFlow id="sid-861DCE16-83F6-40D2-8FF3-944495A39A24" sourceRef="refusedSendEmail" targetRef="sid-364A4056-2170-4E7E-A68C-17A630E06310"></sequenceFlow>
<!--流程结束-->
<endEvent id="sid-364A4056-2170-4E7E-A68C-17A630E06310"></endEvent>
<!--老师审核通过到校长审批-->
<userTask id="sid-3B97B2FD-93AE-4D23-B15D-1C7B29A03259" name="校长进行审批" flowable:assignee="${xiaozhang}">
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>
</userTask>
<sequenceFlow id="sid-A4396BF2-DCA8-4633-B6DD-3D5E2073AF7C" sourceRef="sid-3B97B2FD-93AE-4D23-B15D-1C7B29A03259" targetRef="sid-206D3454-335C-4448-9043-BFE6CED5E8DE"></sequenceFlow>
<!--流程结束-->
<endEvent id="sid-206D3454-335C-4448-9043-BFE6CED5E8DE"></endEvent>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_holidayFlowable">
<bpmndi:BPMNPlane bpmnElement="holidayFlowable" id="BPMNPlane_holidayFlowable">
<bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
<omgdc:Bounds height="30.0" width="30.0" x="90.0" y="145.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="teacherCheck" id="BPMNShape_teacherCheck">
<omgdc:Bounds height="80.0" width="100.0" x="165.0" y="120.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-CE7A6ED1-0F56-440F-8F19-0A815FD7D0CF" id="BPMNShape_sid-CE7A6ED1-0F56-440F-8F19-0A815FD7D0CF">
<omgdc:Bounds height="40.0" width="40.0" x="310.0" y="140.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="refusedSendEmail" id="BPMNShape_refusedSendEmail">
<omgdc:Bounds height="80.0" width="100.0" x="450.0" y="255.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-3B97B2FD-93AE-4D23-B15D-1C7B29A03259" id="BPMNShape_sid-3B97B2FD-93AE-4D23-B15D-1C7B29A03259">
<omgdc:Bounds height="80.0" width="100.0" x="600.0" y="120.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-206D3454-335C-4448-9043-BFE6CED5E8DE" id="BPMNShape_sid-206D3454-335C-4448-9043-BFE6CED5E8DE">
<omgdc:Bounds height="28.0" width="28.0" x="755.0" y="146.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-364A4056-2170-4E7E-A68C-17A630E06310" id="BPMNShape_sid-364A4056-2170-4E7E-A68C-17A630E06310">
<omgdc:Bounds height="28.0" width="28.0" x="595.0" y="281.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sid-A9B1B8F5-F233-4ED2-962A-6AD3DFB90DB7" id="BPMNEdge_sid-A9B1B8F5-F233-4ED2-962A-6AD3DFB90DB7" flowable:sourceDockerX="15.0" flowable:sourceDockerY="15.0" flowable:targetDockerX="50.0" flowable:targetDockerY="40.0">
<omgdi:waypoint x="119.94999848995758" y="160.0"></omgdi:waypoint>
<omgdi:waypoint x="164.9999999999917" y="160.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-74AE5A71-27E3-4691-8EBB-A34FB66FE0BF" id="BPMNEdge_sid-74AE5A71-27E3-4691-8EBB-A34FB66FE0BF" flowable:sourceDockerX="20.5" flowable:sourceDockerY="20.5" flowable:targetDockerX="36.5" flowable:targetDockerY="40.5">
<omgdi:waypoint x="349.4469046063378" y="160.5"></omgdi:waypoint>
<omgdi:waypoint x="600.0" y="160.5"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-35534B9A-A1C4-4429-B91D-096B9CFD70F2" id="BPMNEdge_sid-35534B9A-A1C4-4429-B91D-096B9CFD70F2" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="20.5" flowable:targetDockerY="20.5">
<omgdi:waypoint x="264.9499999999977" y="160.21623376623376"></omgdi:waypoint>
<omgdi:waypoint x="310.4130434782609" y="160.41304347826087"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-E775E55F-3A3B-49C6-93B0-5B5E54B5941A" id="BPMNEdge_sid-E775E55F-3A3B-49C6-93B0-5B5E54B5941A" flowable:sourceDockerX="20.5" flowable:sourceDockerY="20.5" flowable:targetDockerX="50.0" flowable:targetDockerY="40.0">
<omgdi:waypoint x="341.0655129891483" y="168.8841282894737"></omgdi:waypoint>
<omgdi:waypoint x="450.0" y="255.32448377581122"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-A4396BF2-DCA8-4633-B6DD-3D5E2073AF7C" id="BPMNEdge_sid-A4396BF2-DCA8-4633-B6DD-3D5E2073AF7C" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="14.0" flowable:targetDockerY="14.0">
<omgdi:waypoint x="699.9499999999878" y="160.0"></omgdi:waypoint>
<omgdi:waypoint x="755.0" y="160.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-861DCE16-83F6-40D2-8FF3-944495A39A24" id="BPMNEdge_sid-861DCE16-83F6-40D2-8FF3-944495A39A24" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="14.0" flowable:targetDockerY="14.0">
<omgdi:waypoint x="549.95" y="295.0"></omgdi:waypoint>
<omgdi:waypoint x="595.0" y="295.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
示例代码
对象初始化
ProcessEngine processEngine = null;
RuntimeService runtimeService = null;
TaskService taskService = null;
HistoryService historyService = null;
RepositoryService repositoryService = null;
@BeforeEach
public void test() {
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/flowable-learn2?serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("tiger")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
processEngine = cfg.buildProcessEngine();
runtimeService = processEngine.getRuntimeService();
taskService = processEngine.getTaskService();
historyService = processEngine.getHistoryService();
repositoryService = processEngine.getRepositoryService();
}
部署流程
// 部署流程 获取RepositoryService对象
Deployment deployment = repositoryService.createDeployment()// 创建Deployment对象
.addClasspathResource("2023年出差流程.bpmn20.xml") // 添加流程部署文件
.name("2023年出差流程") // 设置部署流程的名称
.deploy(); // 执行部署操作
System.out.println("deployment.getId() = " + deployment.getId());
System.out.println("deployment.getName() = " + deployment.getName());
System.out.println("deployment.getKey() = " + deployment.getKey());
发起流程
//启动的流程变量
Map<String, Object> variables = new HashMap<>();
variables.put("zuzhang", Arrays.asList("组长1", "组长2", "组长3"));
variables.put("chejian", Arrays.asList("车间主任1", "车间主任2", "车间主任3"));
variables.put("caiwu", Arrays.asList("财务1", "财务2", "财务3"));
variables.put("zongjingli", Arrays.asList("总经理1", "总经理2", "总经理3"));
variables.put("parentProcessId", "A0001");
variables.put("num", 1000);
ProcessInstance holidayRequest = runtimeService
.startProcessInstanceByKey("流程定义KEY", "业务KEY", variables);
任务审批
Map<String, Object> variables = new HashMap<>();
variables.put("变量KEY", "变量值");
taskService.complete("任务ID", variables);
流程实例删除
//此删除不会清除历史记录,只是将流程结束,并设置删除原因
runtimeService.deleteProcessInstance("45001", "终止");
//此删除相关历史数据会被删除(只能删除已完成的流程实例)
historyService.deleteHistoricProcessInstance("2501");
historyService.createHistoricProcessInstanceQuery().deleted();
删除历史任务
//方式一:未完成的任务 不能进行删除
String taskId = "57504";
historyService.deleteHistoricTaskInstance(taskId);
//方式二:
historyService.createHistoricProcessInstanceQuery()
.taskId(taskId)
.finished()
.delete();
节点回退
参考网址:blog.csdn.net/qh870754310…
runtimeService.createChangeActivityStateBuilder()
.processInstanceId("25001")
.moveActivityIdTo("sid-CC04EA90-362D-431B-ACF0-556B2E85254E","sid-5AE4B702-3503-46AE-B81F-5D96F00EDD7A")
//.moveActivityIdsToSingleActivityId(Arrays.asList("sid-602CE508-641C-43C7-8001-065A32DA56A5"), "sid-C9093C97-1EBC-4CA0-B6E1-791230846996")
.changeState();
关闭流程
runtimeService.deleteProcessInstance("流程ID", "关闭原因");
修改流程变量
runtimeService.setVariable("流程ID","变量KEY", "变量值")
taskService!!.setVariable("任务ID", "变量KEY", "变量值")
任务候选人及受让人管理
//给任务添加候选人
taskService.addCandidateUser(taskId,assigneeId)
//删除任务的候选人
taskService.deleteCandidateUser("任务ID","候选人ID")
//设置任务的受让人
taskService.setAssignee("任务ID","受让人ID")
//清除任务的受让人
taskService.setAssignee("任务ID",null)
通过程序代码定义流程
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.StartEvent;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.repository.Deployment;
public class CreateProcessDefinition {
public static void main(String[] args) {
// 创建流程引擎配置
ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createStandaloneInMemoryProcessEngineConfiguration();
// 创建流程引擎
ProcessEngine processEngine = configuration.buildProcessEngine();
// 创建流程定义
BpmnModel bpmnModel = new BpmnModel();
Process process = new Process();
process.setId("my-process");
process.setName("我的流程");
bpmnModel.addProcess(process);
// 创建开始事件
StartEvent startEvent = new StartEvent();
startEvent.setId("startEvent");
process.addStartEvent(startEvent);
// 创建用户任务
UserTask userTask = new UserTask();
userTask.setId("userTask");
userTask.setName("用户任务");
process.addTask(userTask);
// 连接开始事件和用户任务
startEvent.connectTo(userTask);
// 部署流程定义
Deployment deployment = processEngine.getRepositoryService()
.createDeployment()
.addBpmnModel("my-process.bpmn20.xml", bpmnModel)
.deploy();
}
}
查询任务详情
//进行中的任务详情
val task = taskService!!.createTaskQuery()
.includeProcessVariables()
.includeTaskLocalVariables()
.includeIdentityLinks()
.taskId("任务ID").singleResult()
//历史任务详情
historyService.createHistoricTaskInstanceQuery()
.includeProcessVariables()
.taskId("任务ID")
.singleResult()
查询进行中的流程实例
List<ProcessInstance> list = runtimeService.createProcessInstanceQuery()
.processDefinitionKey("流程定义key")
.list();
System.out.println("查询进行中的流程实例");
for (ProcessInstance processInstance : list){
System.out.println("getId = "+ processInstance.getId());
System.out.println("getProcessInstanceId = "+ processInstance.getProcessInstanceId());
System.out.println("getName = "+ processInstance.getName());
System.out.println("getStartUserId = "+ processInstance.getStartUserId());
System.out.println("**********************");
}
查询历史流程实例
List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery()
.includeProcessVariables().list();
System.out.println("查询历史流程实例");
System.out.println(JSON.toJSONString(list));
查询历史实例的审核历史
List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
.processInstanceId("50001")
.orderByHistoricTaskInstanceStartTime().desc()
//.includeProcessVariables()
//.finished()
.list();
System.out.println("查询流程实例历史审核任务 任务数:="+list.size());
list.forEach(item->{
System.out.println("********************");
System.out.println("getId = "+item.getId());
System.out.println("getName = "+item.getName());
System.out.println("getTaskDefinitionKey = "+item.getTaskDefinitionKey());
System.out.println("getAssignee = "+item.getAssignee());
//System.out.println("getIdentityLinks = "+JSON.toJSONString(item.getIdentityLinks()));
System.out.println("getFormKey = "+item.getFormKey());
//System.out.println("getProcessVariables = "+JSON.toJSONString(item.getProcessVariables()));
System.out.println("getCreateTime = "+item.getCreateTime());
System.out.println("getEndTime = "+item.getEndTime());
System.out.println("getTime = "+item.getTime());
System.out.println("getExecutionId = "+item.getExecutionId());
System.out.println("getDeleteReason = "+item.getDeleteReason());
});
查询待处理任务信息
List<Task> list = taskService.createTaskQuery()
.includeProcessVariables()
.includeIdentityLinks()
.processDefinitionKey("流程定义key")
.list();
System.out.println("查询待处理任务信息****");
list.forEach(task -> {
System.out.println("*****************");
System.out.println("getId =" + task.getId());
System.out.println("getName =" + task.getName());
System.out.println("getProcessInstanceId =" + task.getProcessInstanceId());
System.out.println("getProcessDefinitionId =" + task.getProcessDefinitionId());
System.out.println("getTaskDefinitionId =" + task.getTaskDefinitionId());
System.out.println("getTaskDefinitionKey =" + task.getTaskDefinitionKey());
System.out.println("getAssignee =" + task.getAssignee());
System.out.println("getProcessVariables =" + JSON.toJSONString(task.getProcessVariables()));
System.out.println("getIdentityLinks =" + JSON.toJSONString(task.getIdentityLinks()));
});
自定义流程
{
"processName": "流程名",
"processKey": "请假流程_v1",
"instanceListener": "com.go.flow.MyProcessListener",
"nodes": [
{
"nodeId": "_start",
"nodeName": "开始节点",
"nodeType": "START",
"targetRef": "n_0"
},
{
"nodeId": "n_0",
"nodeName": "班主任审批",
"nodeType": "USER_TASK",
"formKey": "com.sx.flow.FormA1",
"targetRef": "n_1",
"assignee": "#user_1",
"candidateUsers": "#n_0_user",
"taskListener": "com.go.flow.MyTaskListener"
},
{
"nodeId": "n_1",
"nodeName": "班主任审批",
"nodeType": "USER_TASK",
"formKey": "com.sx.flow.FormA1",
"targetRef": "gateway_1",
"assignee": "#user_1",
"candidateUsers": "#n_1_user",
"taskListener": "com.go.flow.MyTaskListener"
},
{
"nodeId": "gateway_1",
"nodeName": "排他网关",
"nodeType": "PAI_TA_GATEWAY",
"flowConditions": [
{
"nodeId": "n_2",
"conExpression": "T(Integer).parseInt(#leaveDays) <= 7"
},
{
"nodeId": "n_3",
"conExpression": "T(Integer).parseInt(#leaveDays) > 7"
}
]
},
{
"nodeId": "n_2",
"nodeName": "总理审批(请假小于等于7天)",
"nodeType": "USER_TASK",
"formKey": "com.sx.flow.FormA1",
"targetRef": "_end",
"assignee": "#user_1",
"candidateUsers": "#n_2_user",
"taskListener": "com.go.flow.MyTaskListener"
},
{
"nodeId": "n_3",
"nodeName": "主席审批(请假大于7天)",
"nodeType": "USER_TASK",
"formKey": "com.sx.flow.FormA1",
"targetRef": "_end",
"assignee": "#user_1",
"candidateUsers": "#n_3_user",
"taskListener": "com.go.flow.MyTaskListener"
},
{
"nodeId": "_end",
"nodeName": "结束节点",
"nodeType": "END"
}
]
}