【Flowable】使用UEL整合Springboot从0到1(四)

前言

在前面我们介绍了Springboot简单使用了foleable以及flowableUI的安装和使用,在之前我们分配任务的处理人的时候都是通过Assignee去指定固定的人的。这在实际业务中是不合适的,我们希望在流程中动态的去解析每个节点的处理人,当前flowable也支持这样去做。

一、 UEL表达式

Flowable使用UEL进行表达式解析。UEL代表Unified Expression Language,是EE6规范的一部分.Flowable支持两种UEL表达式: UEL-value 和UEL-method

  • UEL-value:值表达式 Value expression: 解析为一个值。默认情况下,所有流程变量都可以使用。
bash 复制代码
${userCode}
${isEndWorkFlag == true && isSnedEmailFlag == true}
# 这里userCode可以是任意值,员工号(编码),isEndWorkFlag和isSnedEmailFlag可以是boolean类型的值
  • UEL-method:将method方法注入到activiti的processEngineConfiguration的bean中。
bash 复制代码
${userService.findManagerUserCodeByEmpCode(empCode)}

# 这里userService就是我们spring当中的bean,这里先说明一下值表达式,后续整合spring的时候,在补充这块。

我们知道了UEL表达式之后,我们简单测试一下使用

二、使用FlowableUI绘制流程

绘制一个简单的流程,在分配人那里使用UEL表达式去指定节点处理人,绘制完成之后点击下载将流程下载下来,放置项目的resources下,这里有想尝试的可以直接使用如下MyHoliday.bpmn20.xml

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.7.2">
  <process id="MyHoliday" name="MyHoliday" isExecutable="true">
    <startEvent id="startEvent1" name="开始" flowable:formFieldValidation="true"></startEvent>
    <userTask id="sid-320C4AED-D9F4-4C53-B2B6-D4ACCBA155F5" name="直线审批" flowable:assignee="${firstAssigne}" flowable:formFieldValidation="true">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <sequenceFlow id="sid-422764E6-61F4-454A-BF08-9CF973E1E67D" sourceRef="startEvent1" targetRef="sid-320C4AED-D9F4-4C53-B2B6-D4ACCBA155F5"></sequenceFlow>
    <userTask id="sid-873E297E-9E6B-4F4E-AF6A-2E085F1806B1" name="部门审批" flowable:assignee="${deptAssigne}" flowable:formFieldValidation="true">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <sequenceFlow id="sid-A0869337-10D3-43BC-90C1-036C9719308E" sourceRef="sid-320C4AED-D9F4-4C53-B2B6-D4ACCBA155F5" targetRef="sid-873E297E-9E6B-4F4E-AF6A-2E085F1806B1"></sequenceFlow>
    <endEvent id="sid-CAB64925-F653-4167-8E12-ED956B723D2E" name="结束"></endEvent>
    <sequenceFlow id="sid-91D96B3A-3408-4504-A23D-8F0C2AFE19A7" sourceRef="sid-873E297E-9E6B-4F4E-AF6A-2E085F1806B1" targetRef="sid-CAB64925-F653-4167-8E12-ED956B723D2E"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_MyHoliday">
    <bpmndi:BPMNPlane bpmnElement="MyHoliday" id="BPMNPlane_MyHoliday">
      <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
        <omgdc:Bounds height="30.0" width="30.0" x="89.99999731779107" y="149.99999552965178"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-320C4AED-D9F4-4C53-B2B6-D4ACCBA155F5" id="BPMNShape_sid-320C4AED-D9F4-4C53-B2B6-D4ACCBA155F5">
        <omgdc:Bounds height="80.0" width="100.00000000000003" x="164.99999731779107" y="124.99999552965178"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-873E297E-9E6B-4F4E-AF6A-2E085F1806B1" id="BPMNShape_sid-873E297E-9E6B-4F4E-AF6A-2E085F1806B1">
        <omgdc:Bounds height="80.00000000000001" width="100.0" x="299.99999105930357" y="119.99999642372141"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-CAB64925-F653-4167-8E12-ED956B723D2E" id="BPMNShape_sid-CAB64925-F653-4167-8E12-ED956B723D2E">
        <omgdc:Bounds height="28.0" width="28.0" x="464.9999861419205" y="145.9999920725826"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="sid-91D96B3A-3408-4504-A23D-8F0C2AFE19A7" id="BPMNEdge_sid-91D96B3A-3408-4504-A23D-8F0C2AFE19A7" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.00000000000001" flowable:targetDockerX="14.0" flowable:targetDockerY="14.0">
        <omgdi:waypoint x="399.94999034668683" y="159.99999473723344"></omgdi:waypoint>
        <omgdi:waypoint x="464.99998600932435" y="159.99999254311274"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-A0869337-10D3-43BC-90C1-036C9719308E" id="BPMNEdge_sid-A0869337-10D3-43BC-90C1-036C9719308E" flowable:sourceDockerX="50.000000000000014" flowable:sourceDockerY="40.0" flowable:targetDockerX="50.0" flowable:targetDockerY="40.00000000000001">
        <omgdi:waypoint x="264.9499973177909" y="163.1481439230865"></omgdi:waypoint>
        <omgdi:waypoint x="299.9999910593035" y="161.8499961786801"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-422764E6-61F4-454A-BF08-9CF973E1E67D" id="BPMNEdge_sid-422764E6-61F4-454A-BF08-9CF973E1E67D" flowable:sourceDockerX="15.0" flowable:sourceDockerY="15.0" flowable:targetDockerX="50.000000000000014" flowable:targetDockerY="40.0">
        <omgdi:waypoint x="119.94999580774865" y="164.99999552965178"></omgdi:waypoint>
        <omgdi:waypoint x="164.9999973177828" y="164.99999552965178"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

三、部署流程

java 复制代码
    @Test
    public void testDeploy() {
        //1.获取ProcessEngine 对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2.获取RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //3.完成流程部署操作
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("MyHoliday.bpmn20.xml") //关联要部署的流程名称
                .name("请假流程")
                .deploy(); //部署流程


        System.out.println("id: " + deploy.getId());
        System.out.println("name: " + deploy.getName());
        System.out.println("key: " + deploy.getKey());

    }

注意:ProcessEngines.getDefaultProcessEngine();该获取方式会去加载resources下的 flowable.cfg.xml文件,该文件为数据库的一些配置以及启动配置信息:

xml 复制代码
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="processEngineConfiguration"
          class="org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="jdbcUrl" value="jdbc:mysql://xxxxxx/flowable?allowMultiQueries=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;useSSL=false&amp;serverTimezone=UTC&amp;nullCatalogMeansCurrent=true" />
        <property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver" />
        <property name="jdbcUsername" value="xxx" />
        <property name="jdbcPassword" value="xxx" />
        <!--是否自动创建表-->
        <property name="databaseSchemaUpdate" value="true" />
        <!---是否启用异步任务-->
        <property name="asyncExecutorActivate" value="false" />
    </bean>
</beans>

不想使用该方法的也可以使用之前文章中的示例去进行创建ProcessEngine对象,如下:

java 复制代码
 @Test
    public void testProcessEngine() {
        // 获取 ProcessEngineConfiguration 对象
        ProcessEngineConfiguration configuration = new StandaloneProcessEngineConfiguration();

        //配置相关的数据库连接信息
        configuration.setJdbcDriver("com.mysql.cj.jdbc.Driver");
        configuration.setJdbcUsername("xxxx");
        configuration.setJdbcPassword("xxxx");
        configuration.setJdbcUrl("jdbc:mysql://xxxxx/flowable?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai");
        //如果数据库中的表结构不存在就新建
        configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);

        //构建流程引擎对象
        ProcessEngine processEngine = configuration.buildProcessEngine();
        System.out.println("processEngine = " + processEngine);
    }

启动完成之后:
查询表ACT_RE_PROCDEF流程定义信息,上篇文章有介绍到flowable表的作用和注释,有兴趣的可以去看看。

这里

  • ID_:字段表示流程定义ID,可以理解成后续扩展版本控制的时候这个表示不同的版本号,
  • DEPLOYMENT_ID_:表示此次部署的ID

查询表:ACT_GE_BYTEARRAY 表的资源信息,可以看到我们绘制的xml文件一些信息

四、启动流程

java 复制代码
 @Test
    public void startTest() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();

        RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();


        Map<String, Object> variables = new HashMap<>();
		//部门处理人指定为张三处理firstAssigne为上述绘制指派人所填写的变量
        variables.put("firstAssigne", "张三");
        variables.put("deptAssigne", "李四");
		//MyHoliday:1:22504就是上面介绍到的 流程定义ID
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("MyHoliday:1:22504", variables);


        System.out.println("processInstance.getProcessInstanceId() = " + processInstance.getProcessInstanceId());
    }

启动完成之后:
查询表: ACT_RU_VARIABLE查询我们决策变量。

查询表:ACT_RU_TASK可以看到我们当前流程的任务处理到哪了

五、审批操作

java 复制代码
    @Test
    public void complete() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();

        TaskService taskService = defaultProcessEngine.getTaskService();
        taskService.setAssignee("25007", "张三");
        taskService.complete("25007");
    }

完成审批后可以看到act_ru_task表的节点达到部门审批了。

继续审批

java 复制代码
    @Test
    public void complete01() {
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = defaultProcessEngine.getTaskService();

        Task task = taskService.createTaskQuery()
                //流程实例ID很多地方可以拿ACT_RU_EXECUTION表中PROC_INST_ID_或者ACT_RU_TASK中的PROC_INST_ID_等等
                .processInstanceId("25001")
                .taskAssignee("李四")
                .singleResult();

        taskService.complete(task.getId());
    }

六、结束

经过上述操作,该流程已经完成了审批了。我们可以查询ACT_HI_ACTINST看到历史流程实例信息

本篇内容简单的介绍了一下从绘制流程到审批介绍的简单过程,如果有不正确或者不足的地方还恳请各位小伙伴给出一些建议。

相关推荐
提笔了无痕19 分钟前
什么是Redis的缓存问题,以及如何解决
数据库·redis·后端·缓存·mybatis
浪里行舟24 分钟前
国产OCR双雄对决?PaddleOCR-VL与DeepSeek-OCR全面解析
前端·后端
CodeCraft Studio32 分钟前
【能源与流程工业案例】KBC借助TeeChart 打造工业级数据可视化平台
java·信息可视化·.net·能源·teechart·工业可视化·工业图表
lang2015092838 分钟前
Spring Boot缓存机制全解析
spring boot·后端·缓存
摇滚侠39 分钟前
Spring Boot 3零基础教程,WEB 开发 默认页签图标 Favicon 笔记29
java·spring boot·笔记
lang2015092842 分钟前
Spring Boot SQL数据库全攻略
数据库·spring boot·sql
YSRM43 分钟前
Leetcode+Java+图论+最小生成树&拓扑排序
java·leetcode·图论
沐浴露z1 小时前
【JVM】详解 Class类文件的结构
java·jvm·class
桦说编程2 小时前
Java并发编程:两种控制并发度的实现方法及其比较
java·后端