Flowable工作流

625 阅读9分钟

官方文档

流程设计器flowable-ui

flowable-ui Docker镜像地址

hub.docker.com/r/flowable/…

#创建网络
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作用
RepositoryServiceFlowable的资源管理类
RuntimeServiceFlowable的流程运行管理类
TaskServiceFlowable的任务管理类
HistoryServiceFlowable的历史管理类
ManagerServiceFlowable的引擎管理类

简单介绍:

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…

监听器说明

参考:juejin.cn/post/722395…

任务监听器: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"
            }
        ]
    }