首页 > 其他分享 >Springboot整合Flowable入门-学习笔记

Springboot整合Flowable入门-学习笔记

时间:2024-08-08 18:23:41浏览次数:14  
标签:Springboot Flowable list 流程 定义 任务 实例 ID 入门

目录

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>

标签:Springboot,Flowable,list,流程,定义,任务,实例,ID,入门
From: https://blog.csdn.net/TinpeaV/article/details/141020574

相关文章

  • 云消息队列 RabbitMQ 版入门训练营,解锁对比开源优势与零基础实战
    消息队列面向应用提供解耦、削峰填谷、异步通知等特性,是分布式架构中不可或缺的基础服务。随着业务增长,企业对消息队列的性能和稳定性要求不断提高,同时有优化资源和运维成本的需求。云消息队列RabbitMQ版严格遵循AMQP0-9-1协议,并通过架构优化避免了消息积压导致的内存泄漏......
  • Java毕业设计 基于Springboot+Vue的电影院剧院订票选座管理系统(源码+lw+部署文档+讲
    文末获取资源,收藏关注不迷路文章目录项目介绍功能需求技术介绍项目界面关键代码目录项目介绍随着经济的发展和信息技术的普及,国内许多企业都面临了重大的挑战。企业的管理流程、战略规划如果不能进行调整,极有可能面临淘汰的风险。特别是郑州大剧院,面对大量的会员和......
  • 【Python】excel常用函数操作Python实现,办公入门首选
    常见的Excel函数,在Python中的如何实现:VLOOKUP:可以使用merge或map函数来实现类似的功能。IF:可以使用numpy库的where函数来实现类似的功能。SUMIF:可以使用pandas的query函数来筛选数据,然后使用sum函数来计算总和。COUNTIF:类似于SUMIF,可以使用query函数来筛选数据,然......
  • SpringBoot属性配置方式
    问题:如果我们需要修改端口号为其他的端口号,那么我们可以在.yml文件中通过serverport直接对端口进行修改。但是如果我们交给运维或者客户的是一个jar包而不是项目的源文件,他们没有办法直接修改这些属性,这时候就需要SpringBoot属性配置相关的知识了。我们之前学习的是在reso......
  • springboot 集成阿里云短信服务,教你轻松实现短信发送功能
    springboot如何发送短信功能在SpringBoot中实现手机号发送短信功能,一般可以通过以下步骤:一、选择短信服务提供商这里使用了阿里云短信服务的SDK来发送短信。阿里云官网:https://www.aliyun.com/1.1开通短信服务进入短信服务控制台,依照如下步骤进行申请1.2新......
  • 25届计算机毕设选题推荐-基于springboot的小区停车场管理系统的分析与设计
    博主介绍:✌十余年IT大项目实战经验、在某机构培训学员上千名、专注于本行业领域✌技术范围:Java实战项目、Python实战项目、微信小程序/安卓实战项目、爬虫+大数据实战项目、Nodejs实战项目、PHP实战项目、.NET实战项目、Golang实战项目。主要内容:系统功能设计、开题报告......
  • 【CSS入门】第二课 - margin外边距
    这一小节,我们说一下margin外边距。怎么理解这个外边距呢,比如小张和小丽站在一起,紧紧排着站。试想一下,如果他俩冬天都穿着羽绒服和夏天穿着短袖,是不是占据的空间会不一样呢。那么回到HTML网页开发商来说,如果两个元素,他们加一些外边距,占的空间也会不一样,而且会使两个元素的距离也......
  • 【深度学习与NLP】——快速入门Pytorch基本语法
    目录Pytorch基本语法1.1认识Pytorch1.1.1什么是Pytorch1.1.2Pytorch的基本元素操作1.1.3 Pytorch的基本运算操作1.1.4 关于TorchTensor和Numpyarray之间的相互转换1.1.5小节总结1.2Pytorch中的autograd1.2.1关于torch.Tensor1.2.2关于Tensor的操作1.2.3......
  • 网络安全入门教程(非常详细)从零基础入门到精通,看完这一篇就够了_网络安全教程
    学前感言:1.这是一条坚持的道路,三分钟的热情可以放弃往下看了.2.多练多想,不要离开了教程什么都不会了.最好看完教程自己独立完成技术方面的开发.3.有时多google,baidu,我们往往都遇不到好心的大神,谁会无聊天天给你做解答.4.遇到实在搞不懂的,可以先放放,以后再来解决.......
  • 2024最新版IntelliJ IDEA安装教程(非常详细)从零基础入门到精通,看完这一篇就够了_idea20
    IDEA的使用IDEA的简单介绍IDEA的主要优势IDEA的卸载IDEA的安装第一个程序:HelloWorld结束语IDEA的简单介绍IDEA全称IntelliJIDEA,是Java语言对的集成开发环境,IDEA在业界被认为是公认最好的Java开发工具。IDEA的主要优势✅功能强大①强大的整合能力。比如:GitMavenSp......