乐趣区

关于java:Spring-Boot-flowable-快速实现工作流好用到爆Activiti-可以扔了

背景

应用 flowable 自带的 flowable-ui 制作流程图
应用 springboot 开发流程应用的接口实现流程的业务性能

flowable-ui 部署运行

flowable-6.6.0 运行 官网 demo

参考文档:

https://flowable.com/open-sou…

1、从官网下载 flowable-6.6.0 : https://github.com/flowable/f…

2、将压缩包中的 flowable-6.6.0\wars\flowable-ui.war 丢到 Tomcat 中跑起来

3、关上 http://localhost:8080/flowabl… 用账户:admin/test 登录

4、进入 APP.MODELER 创立流程,之后能够导出流程到我的项目中应用,或者配置

apache-tomcat-9.0.37\webapps\flowable-ui\WEB-INF\classes\flowable-default.properties 连贯本地数据库

留神:须要将 java 驱动 jar(mysql-connector-java-5.1.45.jar)复制到 apache-tomcat-9.0.37\webapps\flowable-rest\WEB-INF\lib 这样创立的流程后端程序就能间接应用

绘制流程图

依据业务须要在 flowable-ui>APP.MODELER 外面绘制流程图,示例如上图。先解释一些概念。

事件(event)通常用于为流程生命周期中产生的事件建模,图里是【开始、完结】两个圈。

程序流(sequence flow)是流程中两个元素间的连接器。图里是【箭头线段】。

网关(gateway)用于管制执行的流向。图里是【菱形(两头有 X)】

用户工作(user task)用于对须要人工执行的工作进行建模。图里是【矩形】。

简略的工作流大略就这些元素(还有很多这里就不扩大了)。上面形容一下工作流是如何流动的。

首先启动了工作流后,由【开始】节点主动流向【学生】节点,期待该工作执行。工作被调配的学生用户执行后流向【老师】节点,再次期待该工作执行。被调配的老师用户执行后流向【网关】,网关以此查看每个进口,流向符合条件的工作,比方这里老师执行工作时是批准,就流向【校长】节点,期待该工作执行。执行后跟老师相似,批准后就流向【完结】节点,整个流程到此结束。

绘图细节:

1、保留流程模型

2、程序流能够设置流条件来限度流动,比方下面的网关进口就设置了条件

3、工作须要分配任务的执行用户,能够调配到候选组,也能够间接调配到候选人

最初导出工作流文件

文件内容

<?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-insmtece" 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="leave_approval" name="销假审批" isExecutable="true">
    <startEvent id="start" name="开始" flowable:initiator="startuser" flowable:formFieldValidation="true"></startEvent>
    <userTask id="stu_task" name="学生" flowable:candidateGroups="stu_group" flowable:formFieldValidation="true"></userTask>
    <sequenceFlow id="flow1" sourceRef="start" targetRef="stu_task"></sequenceFlow>
    <userTask id="te_task" name="老师" flowable:candidateGroups="te_group" flowable:formFieldValidation="true"></userTask>
    <exclusiveGateway id="getway1" name="网关 1"></exclusiveGateway>
    <userTask id="mte_task" name="校长" flowable:candidateGroups="mte_group" flowable:formFieldValidation="true"></userTask>
    <exclusiveGateway id="getway2" name="网关 2"></exclusiveGateway>
    <endEvent id="end" name="完结"></endEvent>
    <sequenceFlow id="flow1" name="销假" sourceRef="stu_task" targetRef="te_task" skipExpression="${command=='agree'}"></sequenceFlow>
    <sequenceFlow id="flow3_1" name="批准" sourceRef="getway1" targetRef="mte_task">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${command=='agree'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow2" name="审批" sourceRef="te_task" targetRef="getway1"></sequenceFlow>
    <sequenceFlow id="flow3_2" name="回绝" sourceRef="getway1" targetRef="stu_task">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${command=='refuse'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow4" name="审批" sourceRef="mte_task" targetRef="getway2"></sequenceFlow>
    <sequenceFlow id="flow4_1" name="批准" sourceRef="getway2" targetRef="end" skipExpression="${command=='free'}">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${command=='agree'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow4_2" name="回绝" sourceRef="getway2" targetRef="stu_task">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${command=='refuse'}]]></conditionExpression>
    </sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_leave_approval">
    这里先省略
  </bpmndi:BPMNDiagram>
</definitions>

【残缺文件】:leave_approval.bpmn20.xml

4、bpmn 文件导入

如果须要,能够把这个流程文件下载下来,间接导入应用

后盾我的项目搭建

后盾我的项目基于 jdk8,应用 springboot 框架

Spring Boot 根底就不介绍了,举荐下这个实战教程:
https://github.com/javastacks…

spring 版本

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.0.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

我的项目依赖 pom.xml

<dependency>
    <groupId>org.flowable</groupId>
    <artifactId>flowable-spring-boot-starter</artifactId>
    <version>6.6.0</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.45</version>
</dependency>

我的项目配置 application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/flowable?useSSL=false&characterEncoding=UTF-8&serverTimezone=GMT%2B8
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: 123456

数据库

1、Flowable 的所有数据库表都以 ACT_结尾。第二局部是阐明表用处的两字符标示符。服务 API 的命名也大略合乎这个规定。

2、ACT_RE_: ‘RE’代表 repository。带有这个前缀的表蕴含“动态”信息,例如流程定义与流程资源(图片、规定等)。

3、ACT_RU_: ‘RU’代表 runtime。这些表存储运行时信息,例如流程实例(process instance)、用户工作(user task)、变量(variable)、作业(job)等。Flowable 只在流程实例运行中保留运行时数据,并在流程实例完结时删除记录。这样保障运行时表小和快。

4、ACT_HI_: ‘HI’代表 history。这些表存储历史数据,例如已实现的流程实例、变量、工作等。

5、ACT_GE_: 通用数据。在多处应用。

1)通用数据表(2 个)

  • act_ge_bytearray:二进制数据表,如流程定义、流程模板、流程图的字节流文件;
  • act_ge_property:属性数据表(不罕用);

2)历史表(8 个,HistoryService 接口操作的表)

  • act_hi_actinst:历史节点表,寄存流程实例运行的各个节点信息(蕴含开始、完结等非工作节点);
  • act_hi_attachment:历史附件表,寄存历史节点上传的附件信息(不罕用);
  • act_hi_comment:历史意见表;
  • act_hi_detail:历史详情表,存储节点运行的一些信息(不罕用);
  • act_hi_identitylink:历史流程人员表,存储流程各节点候选、办理人员信息,罕用于查问某人或部门的已办工作;
  • act_hi_procinst:历史流程实例表,存储流程实例历史数据(蕴含正在运行的流程实例);
  • act_hi_taskinst:历史流程工作表,存储历史工作节点;
  • act_hi_varinst:流程历史变量表,存储流程历史节点的变量信息;

3)用户相干表(4 个,IdentityService 接口操作的表)

  • act_id_group:用户组信息表,对应节点选定候选组信息;
  • act_id_info:用户扩大信息表,存储用户扩大信息;
  • act_id_membership:用户与用户组关系表;
  • act_id_user:用户信息表,对应节点选定办理人或候选人信息;

4)流程定义、流程模板相干表(3 个,RepositoryService 接口操作的表)

  • act_re_deployment:部属信息表,存储流程定义、模板部署信息;
  • act_re_procdef:流程定义信息表,存储流程定义相干形容信息,但其真正内容存储在 act_ge_bytearray 表中,以字节模式存储;
  • act_re_model:流程模板信息表,存储流程模板相干形容信息,但其真正内容存储在 act_ge_bytearray 表中,以字节模式存储;

5)流程运行时表(6 个,RuntimeService 接口操作的表)

  • act_ru_task:运行时流程工作节点表,存储运行中流程的工作节点信息,重要,罕用于查问人员或部门的待办工作时应用;
  • act_ru_event_subscr:监听信息表,不罕用;
  • act_ru_execution:运行时流程执行实例表,记录运行中流程运行的各个分支信息(当没有子流程时,其数据与 act_ru_task 表数据是一一对应的);
  • act_ru_identitylink:运行时流程人员表,重要,罕用于查问人员或部门的待办工作时应用;
  • act_ru_job:运行时定时工作数据表,存储流程的定时工作信息;
  • act_ru_variable:运行时流程变量数据表,存储运行中的流程各节点的变量信息;

流程引擎 API 与服务

引擎 API 是与 Flowable 交互的最罕用伎俩。总入口点是 ProcessEngine。

1、RepositoryService 很可能是应用 Flowable 引擎要用的第一个服务。这个服务提供了治理与管制部署 (deployments) 与流程定义 (process definitions) 的操作。治理动态信息,

2、RuntimeService 用于启动流程定义的新流程实例。

3、IdentityService 很简略。它用于治理(创立,更新,删除,查问……)组与用户。

4、FormService 是可选服务。也就是说 Flowable 没有它也能很好地运行,而不用就义任何性能。

5、HistoryService 裸露 Flowable 引擎收集的所有历史数据。要提供查问历史数据的能力。

6、ManagementService 通常在用 Flowable 编写用户利用时不须要应用。它能够读取数据库表与表原始数据的信息,也提供了对作业 (job) 的查问与治理操作。

7、DynamicBpmnService 可用于批改流程定义中的局部内容,而不须要重新部署它。例如能够批改流程定义中一个用户工作的办理人设置,或者批改一个服务工作中的类名。

接下来应用之前的销假流程图,上代码

import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.idm.api.Group;
import org.flowable.idm.api.User;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

/**
 * TestFlowable
 *
 * @Author
 * @Date: 2021/10/17 23:35
 * @Version 1.0
 */
@Slf4j
public class TestFlowable {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private org.flowable.engine.TaskService taskService;

    @Autowired
    private org.flowable.engine.IdentityService identityService;

    public void createDeploymentZip() {
        /*
         * @Date: 2021/10/17 23:38
         * Step 1: 部署 xml(压缩到 zip 模式,间接 xml 须要配置相对路径,麻烦,暂不必)*/
        try {File zipTemp = new File("f:/leave_approval.bpmn20.zip");
            ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipTemp));
            Deployment deployment = repositoryService
                    .createDeployment()
                    .addZipInputStream(zipInputStream)
                    .deploy();
            log.info("部署胜利:{}", deployment.getId());
        } catch (FileNotFoundException e) {e.printStackTrace();
        }
        /*
         * @Date: 2021/10/17 23:40
         * Step 2: 查问部署的流程定义
         */
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leave_approval").list();
        List<ProcessDefinition> pages = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leave_approval").listPage(1, 30);

        /*
         * @Date: 2021/10/17 23:40
         * Step 3: 启动流程,创立实例
         */
        String processDefinitionKey = "leave_approval";// 流程定义的 key, 对应销假的流程图
        String businessKey = "schoolleave";// 业务代码,依据本人的业务用
        Map<String, Object> variablesDefinition = new HashMap<>();// 流程变量,能够自定义裁减
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variablesDefinition);
        log.info("启动胜利:{}", processInstance.getId());
        /*
         * @Date: 2021/10/17 23:40
         * Step 4: 查问指定流程所有启动的实例列表
         * 列表,或 分页 删除
         */
        List<Execution> executions = runtimeService.createExecutionQuery().processDefinitionKey("leave_approval").list();
        List<Execution> executionPages = runtimeService.createExecutionQuery().processDefinitionKey("leave_approval").listPage(1, 30);
//        runtimeService.deleteProcessInstance(processInstanceId, deleteReason); // 删除实例

        /*
         * @Date: 2021/10/17 23:40
         * Step 5: 学生查问能够操作的工作, 并实现工作
         */
        String candidateGroup = "stu_group"; // 候选组 xml 文件外面的 flowable:candidateGroups="stu_group"
        List<Task> taskList = taskService.createTaskQuery().taskCandidateGroup(candidateGroup).orderByTaskCreateTime().desc().list();
        for (Task task : taskList) {
            // 申领工作
            taskService.claim(task.getId(), "my");
            // 实现
            taskService.complete(task.getId());
        }

        /*
         * @Date: 2021/10/17 23:40
         * Step 6: 老师查问能够操作的工作, 并实现工作
         */
        String candidateGroupTe = "te_group"; // 候选组 xml 文件外面的 flowable:candidateGroups="te_group"
        List<Task> taskListTe = taskService.createTaskQuery().taskCandidateGroup(candidateGroupTe).orderByTaskCreateTime().desc().list();
        for (Task task : taskListTe) {
            // 申领工作
            taskService.claim(task.getId(), "myte");
            // 实现
            Map<String, Object> variables = new HashMap<>();
            variables.put("command","agree"); // 携带变量,用于网关流程的条件断定,这里的条件是批准
            taskService.complete(task.getId(), variables);
        }
        /*
         * @Date: 2021/10/18 0:17
         * Step 7: 历史查问,因为一旦流程执行结束,流动的数据都会被清空,下面查问的接口都查不到数据,然而提供历史查问接口
         */
        // 历史流程实例
        List<HistoricProcessInstance> historicProcessList = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("leave_approval").list();
        // 历史工作
        List<HistoricTaskInstance> historicTaskList = historyService.createHistoricTaskInstanceQuery().processDefinitionKey("leave_approval").list();
        // 实例历史变量 , 工作历史变量
        // historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId);
        // historyService.createHistoricVariableInstanceQuery().taskId(taskId);
        // ***************************************************** 分隔符 ********************************************************************
        // ***************************************************** 分隔符 ********************************************************************
        // 可能还须要的 API
        // 挪动工作,人为跳转工作
        // runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId)
        //       .moveActivityIdTo(currentActivityTaskId, newActivityTaskId).changeState();

        // 如果在数据库配置了分组和用户,还会用到
        List<User> users = identityService.createUserQuery().list();    // 用户查问,用户 id 对应 xml 外面配置的用户
        List<Group> groups = identityService.createGroupQuery().list(); // 分组查问,分组 id 对应 xml 外面配置的分组 如 stu_group,te_group 在表里是 id 的值

        // 另外,每个查问前面都能够拼条件,内置恁多查问,包含含糊查问,大小比拟都有
    }
}

参考资料

【1】分享牛 Flowable 文档汉化:https://github.com/qiudaoke/f…

【2】猫七姑娘 flowable-6.6.0 运行官网 demo

【3】华格瑞沙 https://www.cnblogs.com/yangj…

版权申明:本文为 CSDN 博主「cy 谭」的原创文章,遵循 CC 4.0 BY-SA 版权协定,转载请附上原文出处链接及本申明。\
链接:https://blog.csdn.net/zhan107…

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿(2022 最新版)

2. 劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4. 别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

退出移动版