Springboot整合Flowable入门-学习笔记

news2024/11/13 20:39:57

目录

1、定义流程(画图)

2、Springboot部署流程

3、Springboot删除所有流程

4、Springboot根据 流程部署ID 查询 流程定义ID

5、Springboot启动(发起)流程

6、Springboot查询任务

6.1全部任务

6.2我的任务(代办任务)

7、springboot审批任务

1、审批通过

2、驳回

8、Springboot流程状态管理

1、流程定义

1、挂起《流程定义》

2、激活《流程定义》

2、流程实例

1、挂起《流程实例》

2、激活《流程实例》

9、资源

1.单元测试代码

2.xml代码


看了很多文档,总结一个完整的工作流包含以下步骤:

  • 定义流程: 创建一个BPMN 2.0格式的流程定义文件。
  • 部署流程: 将流程定义文件部署到Flowable引擎中。
  • 启动流程实例: 使用部署好的流程定义启动一个新的流程实例。
  • 执行任务: 查询和完成流程实例中的任务

ps:我使用的工具是 IDEA2019, 环境JDK8,Springboot版本2.5.15,Flowable版本6.8.0

大家先搞懂一个概念:是先有 流程定义 才会有 流程实例

1、定义流程(画图)

现在有很多优秀的画BPMN2.0开源系统。

我这里使用的是IDEA的插件:Flowable BPMN visualizer

安装好插件之后,在资源目录创建一个processes(flowable默认读取resources/processes下的流程文件)

创建BPMN文件

创建BPMN视图

开始画图:(整个流程必须是有一个起点,一个任务,一个终点)

我这里画一个请假流程:(开始-人事审核-主管审核-结束)

用户任务(UserTask)属性解释:

  • id:

    • 描述: User Task的唯一标识符。
    • 示例: id="sid-bb849ec0-1482-4057-a447-c8d68adc9ca2"
  • name:

    • 描述: User Task的显示名称。
    • 示例: name="人事审核"
  • assignee:

    • 描述: 指定执行此任务的单个用户。
    • 示例: flowable:assignee="cpw"    
  • candidateUsers:

    • 描述: 任务的候选用户列表。这些用户都有资格完成任务。
    • 示例: flowable:candidateUsers="cpw,zhangsan,lisi" (通过逗号隔开)
  • candidateGroups:

    • 描述: 任务的候选用户组列表。这些用户组中的用户都有资格完成任务。
    • 示例: flowable:candidateGroups="managers" 
  • formKey:

    • 描述: 指定与任务关联的表单的键,用于在任务执行时显示相应的表单。
    • 示例: flowable:formKey="approveForm"
  • dueDate:

    • 描述: 任务的到期日期,可以是一个具体日期或相对时间表达式。
    • 示例: flowable:dueDate="${now() + 5 days}"
  • priority:

    • 描述: 任务的优先级,数值越高表示优先级越高。
    • 示例: flowable:priority="50"
  • documentation:

    • 描述: 任务的文档说明,可以提供任务的详细描述。
    • 示例: <documentation>This task requires approval from the manager.</documentation>
  • extensions:

    • 描述: 自定义属性,可以添加额外的配置。例如,自定义表单字段或执行特定操作

连接节点

点击一个图案 按住拖动右上角的箭头进行连线

好了,完整的一个图出来了、完整的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">
  <process id="flowDemo" name="flowDemo" isExecutable="true">
    <startEvent id="sid-bb849ec0-1482-4057-a447-c8d68adc9ca2" name="开始"/>
    <userTask id="sid-c30c0960-a986-4cd6-80e2-bae02d6af707" name="人事审核" flowable:assignee="cpw"></userTask>
    <userTask id="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39" name="主管审核" flowable:assignee="zhuguan"/>
    <endEvent id="sid-712aab8a-a060-4363-b3eb-cd3fa9215808"/>
    <sequenceFlow id="sid-2c879163-8816-4dd7-89bb-bf1a4485fef4" sourceRef="sid-bb849ec0-1482-4057-a447-c8d68adc9ca2" targetRef="sid-c30c0960-a986-4cd6-80e2-bae02d6af707"/>
    <sequenceFlow id="sid-2fca88ff-d597-430c-a5e9-edfefbdd2569" sourceRef="sid-c30c0960-a986-4cd6-80e2-bae02d6af707" targetRef="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39"/>
    <sequenceFlow id="sid-e8b6c848-1c54-4fdb-a8b0-e085d715c906" sourceRef="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39" targetRef="sid-712aab8a-a060-4363-b3eb-cd3fa9215808"/>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_flowDemo">
    <bpmndi:BPMNPlane bpmnElement="flowDemo" id="BPMNPlane_flowDemo">
      <bpmndi:BPMNShape id="shape-d460f24b-1aac-4028-b625-929601acd3c0" bpmnElement="sid-bb849ec0-1482-4057-a447-c8d68adc9ca2">
        <omgdc:Bounds x="-375.0" y="-37.25" width="30.0" height="30.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-ad3ec780-dd25-42f1-8e53-6ed0608d5b91" bpmnElement="sid-c30c0960-a986-4cd6-80e2-bae02d6af707">
        <omgdc:Bounds x="-282.75" y="-62.25" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-2a1947d2-0365-4dd8-8083-9bdaa7bea300" bpmnElement="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39">
        <omgdc:Bounds x="-134.25" y="-62.25" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-c748377a-bdcd-4892-b001-3621cf05589a" bpmnElement="sid-712aab8a-a060-4363-b3eb-cd3fa9215808">
        <omgdc:Bounds x="15.625" y="-37.25" width="30.0" height="30.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-a51efb51-2d88-4eae-9ffe-baa2e50cd0e5" bpmnElement="sid-2c879163-8816-4dd7-89bb-bf1a4485fef4">
        <omgdi:waypoint x="-345.0" y="-22.25"/>
        <omgdi:waypoint x="-282.75" y="-22.25"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-69253e56-2532-4829-b515-d27caeeb275a" bpmnElement="sid-2fca88ff-d597-430c-a5e9-edfefbdd2569">
        <omgdi:waypoint x="-182.75" y="-22.25"/>
        <omgdi:waypoint x="-134.25" y="-22.25"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-86a73120-1957-453e-b988-7f2ede9f75dc" bpmnElement="sid-e8b6c848-1c54-4fdb-a8b0-e085d715c906">
        <omgdi:waypoint x="-34.25" y="-22.25"/>
        <omgdi:waypoint x="-10.011603" y="-22.25"/>
        <omgdi:waypoint x="15.625" y="-22.25"/>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

2、Springboot部署流程

有两种使用Flowable类的方法:

第一种是使用ProcessEngine,它里面包含了所有flowable的核心类,我们可以查看源码:

第二种是直接使用***Service

有哪些Service可以查看flowable的jar包下engine里的Serivce类

现在开始部署流程:(使用Springboot单元测试)

@SpringBootTest
@DisplayName("流程测试")
public class UnitTest {

    //第一种方法使用ProcessEngine
    @Resource
    private ProcessEngine processEngine;

    //第二种方法使用若干个 ***Service
    //@Autowired
    //private RuntimeService runtimeService;
    //@Autowired
    //private RepositoryService repositoryServiceService;


    @DisplayName("部署流程")
    @Test
    void deployFlow(){
        Deployment deploy = processEngine.getRepositoryService().createDeployment() //创建部署对象
                .addClasspathResource("processes/flowDemo.bpmn20.xml") // 默认是在resources/processes下寻找,当然你可以自定义目录
                .name("第一个Flowable案例") //设置流程的名字
                .deploy(); //deploy部署流程

        System.out.println("部署流程ID为:"+deploy.getId()); //获取到当前流程的ID

    }
}

运行结果:获取到部署成功的流程的ID

部署成功之后会涉及到以下数据表

ACT_GE_BYTEARRAY

  • 描述: 存储二进制数据,如流程定义的BPMN XML文件,PNG图片和其他附加数据。

ACT_RE_DEPLOYMENT

  • 描述: 存储流程部署的信息。每次部署一个新版本的流程定义时,会在此表中创建一条记录。

ACT_RE_PROCDEF

  • 描述: 存储流程定义的元数据,包括流程的ID、版本、名称和相关的部署ID。

部署成功之后查看 ACT_RE_DEPLOYMENT 表,你会发现创建的两条数据

因为项目启动时会自动部署flowable默认位置下的流程文件,所以会出现两个流程,这时候我们可以关闭自动部署。

可以根据你的需求加上以下配置:

flowable:
  # 关闭定时任务
  async-executor-activate: true
  # 将databaseSchemaUpdate设置为true。如果Flowable发现数据库的结构与应用所需的结构不一致的时候,会自动帮你更新或者新增表或者表结构。
  database-schema-update: true
  # 项目启动时会自动部署默认位置下的流程文件,false表示不检查,true表示检查,默认为true
  check-process-definitions: false

也可以根据需求更改存放路径和后缀名:
flowable.process-definition-location-prefix:classpath*:/processes/
flowable.process-definition-location-suffixes: **.bpmn20.xml,**.bpmn,

3、Springboot删除所有流程

    @DisplayName("删除全部流程")
    @Test
    void deleteAllFlowable(){

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();

        // 删除所有流程定义
        repositoryService.createProcessDefinitionQuery().list().forEach(pd ->
                repositoryService.deleteDeployment(pd.getDeploymentId(), true)
        );

        System.out.println("删除成功");

    }

4、Springboot根据 流程部署ID 查询 流程定义ID

注意:一个 流程部署ID 可以对应多个 流程定义ID

    @DisplayName("根据 流程部署ID 查询 流程定义ID ")
    @Test
    void selectProcessByDeployId(){
        String deployId = "dd77ca7c-554e-11ef-93dc-581122450312";//从上一个流程获取到的部署ID
        List<ProcessDefinition> list = processEngine.getRepositoryService().createProcessDefinitionQuery().deploymentId(deployId).list();
        for (ProcessDefinition processDefinition : list) {
            System.out.println("deployId对应的流程定义ID为:"+processDefinition.getId());
        }

    }

运行结果:

流程定义ID由流程定义的name和一串uuid组成。

5、Springboot启动(发起)流程

启动流程有很多种方法,主要使用的是两种:一种是根据 流程定义的ID,一种是根据流程定义的KEY(标识)

最好是使用 流程定义ID(随机生成),因为KEY就是流程定义的名字可能会重复(实际业务中注意新增流程的时候,如果选择KEY来查询流程,记得做唯一判断)

PS:前面关于部署和定义使用的是RepositoryService,接下来操作流程则使用RuntimeService

    @DisplayName("启动流程")
    @Test
    void startProcess(){
        // 前面关于部署和定义使用的是RepositoryService,接下来操作流程则使用RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // act_re_procdef(流程定义)表中的id
        String processId = "flowDemo:1:dd9eb36f-554e-11ef-93dc-581122450312";
        runtimeService.startProcessInstanceById(processId);
        //String processKey = "flowDemo";
        //runtimeService.startProcessInstanceByKey(processKey);
        System.out.println("启动流程成功");
    }

运行结果

启动流程后下面的表发生变化:

  • 流程实例表 (ACT_RU_EXECUTION)

    • 记录流程实例的当前状态和运行时信息。
    • 启动流程后,新增一条记录,记录新流程实例的信息。
  • 任务表 (ACT_RU_TASK)

    • 记录运行时任务的信息。
    • 如果启动流程后有用户任务,会在这个表中新增一条或多条任务记录。
  • 历史流程实例表 (ACT_HI_PROCINST)

    • 记录历史流程实例的信息。
    • 启动流程后,新增一条记录,用于记录历史流程实例的信息。
  • 历史任务表 (ACT_HI_TASKINST)

    • 记录历史任务的信息。
    • 如果启动流程后有用户任务,会在这个表中新增历史任务记录。
  • 历史活动实例表 (ACT_HI_ACTINST)

    • 记录历史活动实例的信息。
    • 启动流程后,每个活动节点(如任务、网关等)都会在这个表中新增一条记录。
  • 任务参与者表 (ACT_RU_IDENTITYLINK)

    • 记录任务的参与者信息。
    • 如果启动的流程涉及到任务分配,会在这个表中新增记录

6、Springboot查询任务

PS:涉及到任务则使用TaskService方法

6.1全部任务

    @DisplayName("全部任务查询")
    @Test
    void findAllTask(){
        List<Task> list = processEngine.getTaskService().createTaskQuery().list();
        for (Task task : list) {
            System.out.println("任务ID:"+task.getId()+"---任务名称:"+task.getName()+"---任务当前办理人:"+task.getAssignee());
        }
    }

运行结果:

6.2我的任务(代办任务)

    @DisplayName("我的(代办)任务查询")
    @Test
    void findMyTask(){
        //任务查询 通过TaskService来实现
        TaskService taskService = processEngine.getTaskService();
        List<Task> list = taskService.createTaskQuery().taskAssignee("cpw").list(); //流程设置的  用户任务的办理人--人事
        //List<Task> list = taskService.createTaskQuery().taskAssignee("zhuguan").list(); //流程设置的  用户任务的办理人--主管
        for (Task task : list) {
            System.out.println("任务ID:"+task.getId()+"---任务名称:"+task.getName()+"---任务当前办理人:"+task.getAssignee());
        }
    }

7、springboot审批任务

发起流程之后,会从开始节点流到人事审核节点

根据上面查询到的任务ID进行操作:

1、审批通过

    @DisplayName("任务审批通过")
    @Test
    void completeTask(){
        //任务相关操作通过TaskService来实现
        TaskService taskService = processEngine.getTaskService();
        String taskId = "df2f8b51-5559-11ef-8d43-581122450312";
        taskService.complete(taskId);
        System.out.println("审批通过");
    }

运行结果:

此时流程就会跑到:人事审核节点跑到了主管审核节点

验证:这时候我们查询一下主管的代办任务,就会发现任务跑到主管这里来了

    @DisplayName("我的(代办)任务查询")
    @Test
    void findMyTask(){
        //任务查询 通过TaskService来实现
        TaskService taskService = processEngine.getTaskService();
        //List<Task> list = taskService.createTaskQuery().taskAssignee("cpw").list(); //流程设置的  用户任务的办理人--人事
        List<Task> list = taskService.createTaskQuery().taskAssignee("zhuguan").list(); //流程设置的  用户任务的办理人--主管
        for (Task task : list) {
            System.out.println("任务ID:"+task.getId()+"---任务名称:"+task.getName()+"---任务当前办理人:"+task.getAssignee());
        }
    }

审批任务影响以下表:

ACT_RU_TASK

  • 操作: 删除任务记录。

  • 描述: 当任务完成后,任务记录会从该表中删除。这个表存储的是正在运行的任务。

ACT_RU_IDENTITYLINK

  • 操作: 删除相关任务的身份链接记录。

  • 描述: 当任务完成后,相关的用户和组的身份链接记录会从该表中删除。这个表存储的是任务与用户/组之间的关系,如任务的分配者、候选人和参与者。

ACT_HI_TASKINST

  • 操作: 插入或更新任务历史记录。

  • 描述: 当任务完成后,会在该表中插入一条新的历史任务实例记录,或者更新现有的任务实例记录,以反映任务的完成时间和状态。

ACT_HI_ACTINST

  • 操作: 插入或更新活动历史记录。

  • 描述: 当任务完成后,会在该表中插入一条新的历史活动实例记录,或者更新现有的活动实例记录,以反映任务的完成。

ACT_HI_IDENTITYLINK

  • 操作: 插入或更新身份链接历史记录。

  • 描述: 当任务完成后,与任务相关的身份链接信息会在该表中插入新的历史记录或者更新现有的记录。

-----------------------------------------------------------------------------------------------------------------------

主管再次审批,则就到了结束节点即任务完成,act_ru表(流程运行实例表)相关的记录就会被完善

PS:注意在人事审核节点的时候任务审批通过之后,将会生成新的任务ID流向主管审核

2、驳回

我们再部署第二个流程来进行驳回操作,接下来重复简单讲解(因为上面的已经说完了)

部署流程:

查询流程:

发起流程:

查询我的任务:

审核任务:

好了,终于又回到主管审核节点~  重头戏来了~

驳回:

根据业务驳回可以是驳回到上一个节点,或者是驳回到起点重新开始。

这里讲一下驳回到起点重新开始。

1、在查询任务的时候,我们加上查询当前任务的流程实例ID

    @DisplayName("我的(代办)任务查询")
    @Test
    void findMyTask(){
        //任务查询 通过TaskService来实现
        TaskService taskService = processEngine.getTaskService();
        //List<Task> list = taskService.createTaskQuery().taskAssignee("cpw").list(); //流程设置的  用户任务的办理人--人事
        List<Task> list = taskService.createTaskQuery().taskAssignee("zhuguan").list(); //流程设置的  用户任务的办理人--主管
        for (Task task : list) {
            System.out.println("任务ID:"+task.getId()+"---任务名称:"+task.getName()+"---任务当前办理人:"+task.getAssignee()+"---任务的流程实例ID:"+task.getProcessInstanceId());
        }
    }

2、根据实例ID获取到流程实例,然后根据流程实例获取到流程定义,然后取消当前流程实例,重新启动新的流程实例 (驳回流程)

以下是运行的过程的参数变化:

运行结果:

验证:看看流程是否从 主管审核 退回到起点 人事审核 

ok兄弟们,驳回成功

    @DisplayName("任务驳回")
    @Test
    void rejectTask(){

        String processInstanceId = "9cd07051-555d-11ef-ba69-581122450312";
        RuntimeService runtimeService = processEngine.getRuntimeService();
        RepositoryService repositoryService = processEngine.getRepositoryService();

        // 获取当前流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        System.out.println("获取当前流程实例:"+processInstance);
        // 获取流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(processInstance.getProcessDefinitionId()).singleResult();
        System.out.println("获取当前流程定义:"+processDefinition);
        // 取消当前流程实例
        runtimeService.deleteProcessInstance(processInstanceId, "驳回流程");
        System.out.println("取消流程实例ID:"+processInstanceId);
        // 启动新的流程实例
        runtimeService.startProcessInstanceById(processDefinition.getId());
        System.out.println("流程ID:"+processDefinition.getId()+"启动成功!!!");
    }

8、Springboot流程状态管理

重要的事情说三遍:是先有 流程定义 才会有 流程实例 才会有  流程任务

PS:操作流程使用RepositoryService方法

1、流程定义

查询所有的流程定义

    @DisplayName("查询流程定义状态")
    @Test
    void selectProcessDefinition(){
        List<ProcessDefinition> list = processEngine.getRepositoryService().createProcessDefinitionQuery().list();
        for (ProcessDefinition processDefinition : list) {
            //流程定义是否挂起 false为否(fasle表示该流程定义的状态为:激活)  true为是(true表示该流程定义的状态为:挂起)
            System.out.println("流程定义的ID:"+processDefinition.getId()+"---流程定义的Name:"+processDefinition.getName()+"---该流程定义是否挂起:"+processDefinition.isSuspended());
        }
    }

运行结果:

processDefinition.isSuspended()查询流程定义是否挂起 
false为否(fasle表示该流程定义的状态为:激活)  
true为是(true表示该流程定义的状态为:挂起)

由此可以判断这两个《流程定义》都是激活状态

1、挂起《流程定义》

当一个流程定义被挂起时,新的流程实例将不能基于该流程定义启动,但已经运行的流程实例不受影响。

挂起流程定义主要有两种方法,一种是通过id 另一种是通过key,这里使用id来演示

    @DisplayName("挂起流程定义")
    @Test
    void stopProcessDefinition(){
        String processDefinitionId = "flowDemo2:1:82ce3927-555c-11ef-859f-581122450312";
        processEngine.getRepositoryService().suspendProcessDefinitionById(processDefinitionId);
        System.out.println("流程定义ID为:"+processDefinitionId+"挂起成功!");
    }

运行结果:

检验:

第一种检验方法:

第二种方法:

当流程定义被挂起时,我们来测试一下新的流程实例能不能启动?

2、激活《流程定义》

当一个挂起的流程定义被激活时,新的流程实例可以基于该流程定义启动。

跟挂起流程定义同理,激活流程定义也是主要通过两种方法来激活(ID,KEY)

我们继续使用ID来激活:

    @DisplayName("激活流程定义")
    @Test
    void startProcessDefinition(){
        String processDefinitionId = "flowDemo2:1:82ce3927-555c-11ef-859f-581122450312";
        processEngine.getRepositoryService().activateProcessDefinitionById(processDefinitionId);
        System.out.println("流程定义ID为:"+processDefinitionId+"激活成功!");
    }

运行结果:

检验:

好了,我好兄弟又激活回来了,我们来看看能否发起新的流程实例?

成功!

2、流程实例

操作流程实例使用RuntimeService方法

查询所有在运行的流程实例:

    @DisplayName("查询流程实例状态")
    @Test
    void selectProcessInstance(){
        List<ProcessInstance> list = processEngine.getRuntimeService().createProcessInstanceQuery().list();
        for (ProcessInstance processInstance : list) {
            //processDefinition.isSuspended()查询流程定义是否挂起 false为否(fasle表示该流程定义的状态为:激活)  true为是(true表示该流程定义的状态为:挂起)
            System.out.println("流程实例的ID:"+processInstance.getId()+"---流程实例的Name:"+processInstance.getName()+"---该流程实例是否挂起:"+processInstance.isSuspended());
        }
    }

运行结果:

1、挂起《流程实例》

当一个流程实例被挂起时,该实例中的任务将不能被执行,不能继续进行下一步的操作。

    @DisplayName("挂起流程实例")
    @Test
    void stopProcessInstance(){
        String processInstanceId = "93012f42-5569-11ef-bb69-581122450312";
        processEngine.getRuntimeService().suspendProcessInstanceById(processInstanceId);
        System.out.println("流程实例ID为:"+processInstanceId+"挂起成功!");
    }

检验:

找到该挂起的流程实例下的用户任务,看看能否作业?

2、激活《流程实例》

当一个挂起的流程实例被激活时,该实例可以继续执行,进行下一步的操作。

    @DisplayName("激活流程实例")
    @Test
    void startProcessInstance(){
        String processInstanceId = "93012f42-5569-11ef-bb69-581122450312";
        processEngine.getRuntimeService().activateProcessInstanceById(processInstanceId);
        System.out.println("流程实例ID为:"+processInstanceId+"激活成功!");
    }

运行结果:

检验:

那兄弟们再执行一下该流程实例的任务看看

OKOK 审批通过!!

完结撒花~~~~

----------------------------------------------------------------------------------------------------------------------------

9、资源

1.单元测试代码

附上全部测试代码:


@SpringBootTest
@DisplayName("流程测试")
public class UnitTest {

    //第一种方法使用ProcessEngine
    @Resource
    private ProcessEngine processEngine;

    //第二种方法使用若干个 ***Service
    //@Autowired
    //private RuntimeService runtimeService;
    //@Autowired
    //private RepositoryService repositoryServiceService;


    @DisplayName("部署流程")
    @Test
    void deployFlow(){
        Deployment deploy = processEngine.getRepositoryService().createDeployment() //创建部署对象
                .addClasspathResource("processes/flowDemo2.bpmn20.xml") // 默认是在resources/processes下寻找,当然你可以自定义目录
                .name("第二个Flowable案例") //设置流程的名字
                .deploy(); //deploy部署流程

        System.out.println("流程部署ID为:"+deploy.getId()); //获取到当前流程的ID

    }

    @DisplayName("根据 流程部署ID 查询 流程定义ID ")
    @Test
    void selectProcessByDeployId(){
        String deployId = "82aa5d74-555c-11ef-859f-581122450312";//从上一个流程获取到的部署ID
        List<ProcessDefinition> list = processEngine.getRepositoryService().createProcessDefinitionQuery().deploymentId(deployId).list();
        for (ProcessDefinition processDefinition : list) {
            System.out.println("deployId对应的流程定义ID为:"+processDefinition.getId());
        }

    }


    @DisplayName("启动流程")
    @Test
    void startProcess(){
        // 前面关于部署和定义使用的是RepositoryService,接下来操作流程则使用RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // act_re_procdef(流程定义)表中的id
        String processId = "flowDemo2:1:82ce3927-555c-11ef-859f-581122450312";
        runtimeService.startProcessInstanceById(processId);
        //String processKey = "flowDemo";
        //runtimeService.startProcessInstanceByKey(processKey);
        System.out.println("启动流程成功");
    }

    @DisplayName("全部任务查询")
    @Test
    void findAllTask(){
        List<Task> list = processEngine.getTaskService().createTaskQuery().list();
        for (Task task : list) {
            System.out.println("任务ID:"+task.getId()+"---任务名称:"+task.getName()+"---任务办理人:"+task.getAssignee());
        }
    }

    @DisplayName("我的(代办)任务查询")
    @Test
    void findMyTask(){
        //任务查询 通过TaskService来实现
        TaskService taskService = processEngine.getTaskService();
        List<Task> list = taskService.createTaskQuery().taskAssignee("cpw").list(); //流程设置的  用户任务的办理人--人事
        //List<Task> list = taskService.createTaskQuery().taskAssignee("zhuguan").list(); //流程设置的  用户任务的办理人--主管
        for (Task task : list) {
            System.out.println("任务ID:"+task.getId()+"---任务名称:"+task.getName()+"---任务当前办理人:"+task.getAssignee()+"---任务的流程实例ID:"+task.getProcessInstanceId());
        }
    }

    @DisplayName("任务审批通过")
    @Test
    void completeTask(){
        //任务相关操作通过TaskService来实现
        TaskService taskService = processEngine.getTaskService();
        String taskId = "93043c87-5569-11ef-bb69-581122450312";
        taskService.complete(taskId);
        System.out.println("审批通过");
    }

    @DisplayName("任务驳回")
    @Test
    void rejectTask(){

        String processInstanceId = "9cd07051-555d-11ef-ba69-581122450312";
        RuntimeService runtimeService = processEngine.getRuntimeService();
        RepositoryService repositoryService = processEngine.getRepositoryService();

        // 获取当前流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        System.out.println("获取当前流程实例:"+processInstance);
        // 获取流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(processInstance.getProcessDefinitionId()).singleResult();
        System.out.println("获取当前流程定义:"+processDefinition);
        // 取消当前流程实例
        runtimeService.deleteProcessInstance(processInstanceId, "驳回流程");
        System.out.println("取消流程实例ID:"+processInstanceId);
        // 启动新的流程实例
        runtimeService.startProcessInstanceById(processDefinition.getId());
        System.out.println("流程ID:"+processDefinition.getId()+"启动成功!!!");
    }

    @DisplayName("查询流程定义状态")
    @Test
    void selectProcessDefinition(){
        List<ProcessDefinition> list = processEngine.getRepositoryService().createProcessDefinitionQuery().list();
        for (ProcessDefinition processDefinition : list) {
            //processDefinition.isSuspended()查询流程定义是否挂起 false为否(fasle表示该流程定义的状态为:激活)  true为是(true表示该流程定义的状态为:挂起)
            System.out.println("流程定义的ID:"+processDefinition.getId()+"---流程定义的Name:"+processDefinition.getName()+"---该流程定义是否挂起:"+processDefinition.isSuspended());
        }
    }


    @DisplayName("挂起流程定义")
    @Test
    void stopProcessDefinition(){
        String processDefinitionId = "flowDemo2:1:82ce3927-555c-11ef-859f-581122450312";
        processEngine.getRepositoryService().suspendProcessDefinitionById(processDefinitionId);
        System.out.println("流程定义ID为:"+processDefinitionId+"挂起成功!");
    }

    @DisplayName("激活流程定义")
    @Test
    void startProcessDefinition(){
        String processDefinitionId = "flowDemo2:1:82ce3927-555c-11ef-859f-581122450312";
        processEngine.getRepositoryService().activateProcessDefinitionById(processDefinitionId);
        System.out.println("流程定义ID为:"+processDefinitionId+"激活成功!");
    }

    @DisplayName("查询流程实例状态")
    @Test
    void selectProcessInstance(){
        List<ProcessInstance> list = processEngine.getRuntimeService().createProcessInstanceQuery().list();
        for (ProcessInstance processInstance : list) {
            //processDefinition.isSuspended()查询流程定义是否挂起 false为否(fasle表示该流程定义的状态为:激活)  true为是(true表示该流程定义的状态为:挂起)
            System.out.println("流程实例的ID:"+processInstance.getId()+"---流程实例的Name:"+processInstance.getName()+"---该流程实例是否挂起:"+processInstance.isSuspended());
        }
    }

    @DisplayName("挂起流程实例")
    @Test
    void stopProcessInstance(){
        String processInstanceId = "93012f42-5569-11ef-bb69-581122450312";
        processEngine.getRuntimeService().suspendProcessInstanceById(processInstanceId);
        System.out.println("流程实例ID为:"+processInstanceId+"挂起成功!");
    }

    @DisplayName("激活流程实例")
    @Test
    void startProcessInstance(){
        String processInstanceId = "93012f42-5569-11ef-bb69-581122450312";
        processEngine.getRuntimeService().activateProcessInstanceById(processInstanceId);
        System.out.println("流程实例ID为:"+processInstanceId+"激活成功!");
    }



    @DisplayName("删除全部流程")
    @Test
    void deleteAllFlowable(){

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 删除所有流程定义
        repositoryService.createProcessDefinitionQuery().list().forEach(pd ->
                repositoryService.deleteDeployment(pd.getDeploymentId(), true)
        );
        System.out.println("删除成功");

    }


}

2.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">
  <process id="flowDemo" name="flowDemo" isExecutable="true">
    <startEvent id="sid-bb849ec0-1482-4057-a447-c8d68adc9ca2" name="开始"/>
    <userTask id="sid-c30c0960-a986-4cd6-80e2-bae02d6af707" name="人事审核" flowable:assignee="cpw"></userTask>
    <userTask id="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39" name="主管审核" flowable:assignee="zhuguan"/>
    <endEvent id="sid-712aab8a-a060-4363-b3eb-cd3fa9215808"/>
    <sequenceFlow id="sid-2c879163-8816-4dd7-89bb-bf1a4485fef4" sourceRef="sid-bb849ec0-1482-4057-a447-c8d68adc9ca2" targetRef="sid-c30c0960-a986-4cd6-80e2-bae02d6af707"/>
    <sequenceFlow id="sid-2fca88ff-d597-430c-a5e9-edfefbdd2569" sourceRef="sid-c30c0960-a986-4cd6-80e2-bae02d6af707" targetRef="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39"/>
    <sequenceFlow id="sid-e8b6c848-1c54-4fdb-a8b0-e085d715c906" sourceRef="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39" targetRef="sid-712aab8a-a060-4363-b3eb-cd3fa9215808"/>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_flowDemo">
    <bpmndi:BPMNPlane bpmnElement="flowDemo2" id="BPMNPlane_flowDemo">
      <bpmndi:BPMNShape id="shape-d460f24b-1aac-4028-b625-929601acd3c0" bpmnElement="sid-bb849ec0-1482-4057-a447-c8d68adc9ca2">
        <omgdc:Bounds x="-375.0" y="-37.25" width="30.0" height="30.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-ad3ec780-dd25-42f1-8e53-6ed0608d5b91" bpmnElement="sid-c30c0960-a986-4cd6-80e2-bae02d6af707">
        <omgdc:Bounds x="-282.75" y="-62.25" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-2a1947d2-0365-4dd8-8083-9bdaa7bea300" bpmnElement="sid-fc70937d-9773-4db8-acb3-a3af3e6ccb39">
        <omgdc:Bounds x="-133.5509" y="-62.9491" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-c748377a-bdcd-4892-b001-3621cf05589a" bpmnElement="sid-712aab8a-a060-4363-b3eb-cd3fa9215808">
        <omgdc:Bounds x="15.625" y="-37.25" width="30.0" height="30.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-a51efb51-2d88-4eae-9ffe-baa2e50cd0e5" bpmnElement="sid-2c879163-8816-4dd7-89bb-bf1a4485fef4">
        <omgdi:waypoint x="-345.0" y="-22.25"/>
        <omgdi:waypoint x="-282.75" y="-22.25"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-69253e56-2532-4829-b515-d27caeeb275a" bpmnElement="sid-2fca88ff-d597-430c-a5e9-edfefbdd2569">
        <omgdi:waypoint x="-182.75" y="-22.25"/>
        <omgdi:waypoint x="-133.5509" y="-22.9491"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-86a73120-1957-453e-b988-7f2ede9f75dc" bpmnElement="sid-e8b6c848-1c54-4fdb-a8b0-e085d715c906">
        <omgdi:waypoint x="-33.550903" y="-22.9491"/>
        <omgdi:waypoint x="-10.011603" y="-22.25"/>
        <omgdi:waypoint x="15.625" y="-22.25"/>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1997233.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu怎么进入救援模式或单用户模式

进入救援模式&#xff08;Rescue Mode&#xff09;或单用户模式&#xff08;Single User Mode&#xff09;的方法取决于你所使用的Linux发行版。以下是通用的步骤&#xff0c;适用于大多数基于GRUB引导的系统&#xff0c;如Ubuntu、Debian、CentOS等&#xff1a; 重启你的系统。…

【Python第三方库】Requests全面解析

文章目录 安装基本用法测试网站发送GET请求发送POST请求更多请求请求参数请求头其他常用请求属性处理响应响应状态码响应内容 处理超时处理异常 requests 是一个非常流行的 Python HTTP 库&#xff0c;用于发送所有类型的 HTTP 请求。它简洁易用&#xff0c;能够处理复杂的请求…

DAMA学习笔记(十三)-大数据和数据科学

1.引言 大数据不仅指数据的量大&#xff0c;也指数据的种类多&#xff08;结构化的和非结构化的&#xff0c;文档、文件、音频、视频、流数据等&#xff09;&#xff0c;以及数据产生的速度快。数据科学家是指从从数据中探究、研发预测模型、机器学习模型、规范性模型和分析方法…

数据结构与算法基础篇--有向无环

. - 力扣&#xff08;LeetCode&#xff09; 力扣-207题 要判定一个图是否为有向无环图&#xff08;DAG, Directed Acyclic Graph&#xff09;&#xff0c;可以使用拓扑排序&#xff08;Topological Sort&#xff09;的方法。如果一个有向图存在拓扑排序&#xff0c;那么它就是…

【MySQL】事务——事务的引入、事务的概念、什么是事务、为什么会出现事务、事务的版本支持、事务的提交方式、事务常见操作方式

文章目录 MySQL1. 事务的引入2. 事务的概念2.1 什么是事务2.2 为什么会出现事务2.3 事务的版本支持2.4 事务的提交方式2.5 事务常见操作方式2.5.1 测试事务开始和回滚2.5.2 测试未commit事务回滚2.5.3 测试commit事务持久化2.5.4 测试begin事务不受自动提交影响2.5.5 测试单条S…

【C++】模板(相关知识点讲解 + STL底层涉及的模板应用)

目录 模板是什么&#xff1f; 模板格式 模板本质 函数模板 格式介绍 显式实例化 模板参数匹配原则 类模板 类模板的实例化 非类型模板参数 模板特化——概念 函数模板特化 类模板的特化 全特化 半特化 偏特化 三种类特化例子&#xff08;放一起比较&#xff09;…

在 CentOS 7 上安装 Redmine 的详细步骤及 20 个经典用法

目录 1. 引言 2. 安装步骤 2.1 更新系统 2.2 安装依赖包 2.3 安装 MariaDB 数据库 2.4 配置 MariaDB 2.5 安装 Ruby 2.6 安装 Redmine 2.7 配置 Redmine 2.8 安装 Bundler 和必要的 Gems 2.9 生成密钥并迁移数据库 2.10 配置 Apache 2.11 启动 Apache 并设置开机自…

1712系列 嵌入式电源系统

1712系列 嵌入式电源系统 2/3/4/5G&共享站点快速部署 简述 1712A 300A嵌入式电源系统采用模块化设计、组合式结构&#xff0c;由控制器、整流模块、交流配电单元、直流配电单元等组成。该系统将交流电转换成稳定的-48V直流电&#xff0c;用于铁塔、移动、电信、联通等公司…

修改nacos实力权重或者对某实例下线报错

在Nacos控制台进行上述操作&#xff0c;错误信息 caused: errCode: 500, errMsg: do metadata operation failed ;caused: com.alibaba.nacos.consistency.exception.ConsistencyException: The Raft Group [naming_instance_metadata] did not find the Leader node;caused:…

sql注入大总结【万字详解】

文章目录 数据库的架构sql注入概念正常语句正常回显页面在页面中使用sql语句 跨库查询sql文件读写影响条件复现读写的路径的问题 sql注入请求分类sql注入请求类型sql注入请求方式&#xff1a;sql注入数据请求格式 数据库的增删改查数据库查询数据库添加数据库删除数据库修改 盲…

【python函数】读文件(返回str数据)

大家好&#xff0c;我是一名_全栈_测试开发工程师&#xff0c;已经开源一套【自动化测试框架】和【测试管理平台】&#xff0c;欢迎大家关注我&#xff0c;和我一起【分享测试知识&#xff0c;交流测试技术&#xff0c;趣聊行业热点】。 一、函数说明&#xff1a; 使用的函数&a…

STM32IIC与SPI详解

单片机里的通信协议其实蛮多的&#xff0c;IIC&#xff1b;SPI&#xff1b;MQTT&#xff1b;CAN&#xff1b;包括串口也是一种通信协议。而串口通信虽然实现了全双工&#xff0c;但需要至少三根线&#xff0c;为了节省这一根线的成本&#xff0c;于是IIC诞生了。 目录 一.IIC…

【产业前沿】树莓集团如何以数字媒体产业园为引擎,加速产业升级?

在数字化转型的浪潮中&#xff0c;树莓集团以敏锐的洞察力和前瞻性的战略眼光&#xff0c;将数字媒体产业园打造成为产业升级的强劲引擎。这一创新举措不仅为传统行业插上了数字的翅膀&#xff0c;更为整个产业链注入了新的活力与可能。 树莓集团深知&#xff0c;数字媒体产业园…

【人工智能】AI最终会取代程序员吗?

1. 前言 到 2030 年&#xff0c;40% 的编程任务将实现自动化。这个令人难以置信的统计数据凸显了人工智能在软件工程中日益增长的影响力&#xff0c;并引发了一个问题&#xff1a;人工智能会彻底接管软件工程吗&#xff1f; 人工智能技术正在蓬勃发展&#xff0c;有望实现大量…

【实战】Spring Security Oauth2自定义授权模式接入手机验证

文章目录 前言技术积累Oauth2简介Oauth2的四种模式授权码模式简化模式密码模式客户端模式自定义模式 实战演示1、mavan依赖引入2、自定义手机用户3、自定义手机用户信息获取服务4、自定义认证令牌5、自定义授权模式6、自定义实际认证提供者7、认证服务配置8、Oauth2配置9、资源…

C语言程序设计-[11] 循环结构嵌套

1、循环结构嵌套形式 上面三种循环语句结构可以相互嵌套&#xff0c;组合非常灵活。循环嵌套需要记住最重要的一点&#xff1a;”外循环执行一次&#xff0c;内循环要完整执行一遍”&#xff0c;要通过实例加深对这一句话的理解。 注1&#xff1a;一个循环结构由四个要素构成&…

Java设计模式-建造者模式-一次性理解透

1. 建造者模式简介 今天我们将研究 Java 中的建造者模式&#xff08;Builder 模式&#xff09;。Builder 设计模式是一种创建型设计模式&#xff0c;也被称为生成器模式&#xff0c;类似于工厂模式和抽象工厂模式。 该模式用于创建复杂对象&#xff0c;允许用户创建不同类型的…

【Python】PyWebIO 初体验:用 Python 写网页

目录 前言1 使用方法1.1 安装 Pywebio1.2 输出内容1.3 输入内容 2 示例程序2.1 BMI 计算器2.2 Markdown 编辑器2.3 聊天室2.4 五子棋 前言 前两天正在逛 Github&#xff0c;偶然看到一个很有意思的项目&#xff1a;PyWebIo。 这是一个 Python 第三方库&#xff0c;可以只用 P…

100 Exercises To Learn Rust 挑战!准备篇

公司内部的学习会非常活跃&#xff01;我也参与了Rust学习会&#xff0c;并且一直在研究rustlings。最近&#xff0c;我发现了一个类似于rustlings的新教程网站&#xff1a;Welcome - 100 Exercises To Learn Rust。 rustlings是基于Rust的权威官方文档《The Rust Programming…

汽车免拆诊断案例 | 2010款劳斯莱斯古斯特车中央信息显示屏提示传动系统故障

故障现象  一辆2010款劳斯莱斯古斯特车&#xff0c;搭载N74发动机&#xff0c;累计行驶里程约为11万km。车主反映&#xff0c;起动发动机后组合仪表和中央信息显示屏均提示传动系统故障。用故障检测仪检测&#xff0c;发现发动机控制模块2&#xff08;DME2&#xff09;中存储…