JDK21和 Flowable 7.0.0

2024-01-10

一.Flowable

Java语言实现的轻量级工作流框架

二.项目搭建

项目结构

在这里插入图片描述

1.依赖包

本测试项目包含了 drools 、dmn 等依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.example</groupId>
        <artifactId>flowable-test</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>flowable</artifactId>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.boot.version>3.1.3</spring.boot.version>
        <flowable.version>7.0.0</flowable.version>
        <drools.version>9.44.0.Final</drools.version>
    </properties>
    <!--    drools-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-bom</artifactId>
                <type>pom</type>
                <scope>import</scope>
                <version>${drools.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
        <!-- flowable -->
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter</artifactId>
            <version>${flowable.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter-actuator</artifactId>
            <version>${flowable.version}</version>
        </dependency>
        <!--        camel-->
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-camel</artifactId>
            <version>${flowable.version}</version>
        </dependency>
        <!--        dmn-->
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-dmn-engine</artifactId>
            <version>${flowable.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-dmn-engine-configurator</artifactId>
            <version>${flowable.version}</version>
        </dependency>
        <!--        mq jms-->
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-jms-spring-executor</artifactId>
            <version>${flowable.version}.M1</version>
            <exclusions>
                <exclusion>
                    <groupId>org.flowable</groupId>
                    <artifactId>flowable-spring</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-pool</artifactId>
            <version>6.0.1</version>
        </dependency>
        <!--        httpclient flowable http-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.14</version>
        </dependency>

        <dependency>
            <groupId>org.apache.camel.springboot</groupId>
            <artifactId>camel-spring-boot-starter</artifactId>
            <version>4.0.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- pgsql -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.6.0</version>
        </dependency>
        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.44</version>
        </dependency>
        <!--java script execution-->
        <dependency>
            <groupId>org.openjdk.nashorn</groupId>
            <artifactId>nashorn-core</artifactId>
            <version>15.4</version>
        </dependency>
        <!--        drools-->
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-engine</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-mvel</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-model-compiler</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-xml-support</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>
</project>

2.数据库

Flowable 默认使用 H2 数据库,但是可以通过修改配置文件来指定,本文使用的是 Postgres
创建一个名为 flowable 的库
Flowable 首次启动时默认会自动创建表
也可以通过官方SQL脚本手动创建表

在这里插入图片描述

3.资源文件

1.YML配置文件

server:
  port: 8086
  servlet.context-path: /flowable-rest

## 暴露 SpringBoot 除 shutdown 外的所有端点
management:
  server.port: 7291
  endpoints:
    web:
      exposure:
        include: "*"
    health:
      show-details: when_authorized
      roles: access-admin

spring:
  activemq:
    broker-url: tcp://localhost:61616
  application:
    name: flowable-rest
  banner:
    location: classpath:/org/flowable/spring/boot/flowable-banner.txt
  jmx:
    default-domain: ${spring.application.name}
  datasource:
    driver-class-name: org.postgresql.Driver
    url: jdbc:postgresql://127.0.0.1:5432/flowable
    username: postgres
    password: 123456
    ## 连接池
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      poolName: ${spring.application.name}
      maxLifetime: 600000
      idleTimeout: 300000
      minimumIdle: 10
      maximumPoolSize: 50
      connection-test-query: select 1

## java object serializable
rest:
  variables:
    allow:
      serializable=true:

flowable:
  process-definition-location-prefix: classpath*:/processes/
  process-definition-location-suffixes: "**.bpmn20.xml,**.bpmn,drools/**.drl,dmn/**.dmn.xml"
  database-schema-update: true
  async-executor-activate: true
  history-level: full
  rest:
    app:
      swagger-docs-enabled: true
      create-demo-definitions: true
      authentication-mode: verify-privilege
      admin:
        user-id: rest-admin
        password: test
        firstname: Rest
        lastname: Admin
  process:
    servlet:
      path: /service
  mail.server:
    default-from: xxxxxx@qq.com
    host: smtp.qq.com
    username: xxxxxx@qq.com
    password: xxxxxx
    s-s-l-port: 465
    use-ssl: true
    use-tls: false

logging:
  level:
    org.example.*: debug

2.Drools kbase

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">

    <!--
        name: kbase 名称全局唯一
        packages: 规则文件包目录
        default: 指定为默认 kbase
    -->
    <kbase name="my_kbase" packages="processes.drools.*" default="true">
        <!--
            name: ksession 名称 kbase 下唯一
            default: 指定为默认 ksession
            clockType: 时钟类型 系统时钟或测试的伪时钟
        -->
        <ksession name="my_ks" clockType="realtime" default="true"/>
    </kbase>
</kmodule>

3.Drools rule

MyBusinessRule.drl

package drools

rule "myBusiness_1"
    when
    then
        System.out.println("Step4_1 drools 9.44.0.Final");
end

rule "myBusiness_2"
    when
    then
        System.out.println("Step4_2 drools 9.44.0.Final");
end

rule "myBusiness_3"
    when
    then
        System.out.println("Step4_3 drools 9.44.0.Final");
end

4.DMN 决策表

MyDecision.dmn.xml

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/DMN/20180521/MODEL/"
             id="simple" name="Simple" namespace="http://activiti.org/dmn">
  <decision id="myDecision" name="Simple decision">
    <decisionTable id="myDecisionTest" hitPolicy="UNIQUE">
      <input id="inputId">
        <inputExpression id="inputExpression1" typeRef="number">
          <text>age</text>
        </inputExpression>
      </input>
      <output id="outputId" label="myResult" name="myResult" typeRef="string" />
      <rule>
        <inputEntry id="inputEntry_1">
          <text>&gt;18</text>
        </inputEntry>
        <outputEntry id="outputEntry_1">
          <text>'成年'</text>
        </outputEntry>
      </rule>
      <rule>
        <inputEntry id="inputEntry_2">
          <text>&lt;=18</text>
        </inputEntry>
        <outputEntry id="outputEntry_2">
          <text>'未成年'</text>
        </outputEntry>
      </rule>
    </decisionTable>
  </decision>
</definitions>

5.BPMN 流文件

leave_approval_process.bpmn20.xml

可通过下面 IDEA 插件查看流节点

<?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="leave_approval_process" name="leave_approval_process" isExecutable="true">
    <startEvent id="sid-a76e7b82-39bd-4838-b819-2628292d2c2c" name="Start"/>
    <userTask id="sid-604145ee-174b-4864-a973-934078a7d043" name="LineManager" flowable:assignee="admin">
      <extensionElements>
        <flowable:taskListener event="create" class="org.example.exp.listener.UserTaskListener"/>
      </extensionElements>
    </userTask>
    <sequenceFlow id="sid-4fcf06a4-ba36-486e-a058-d993513403d0" sourceRef="sid-a76e7b82-39bd-4838-b819-2628292d2c2c" targetRef="sid-604145ee-174b-4864-a973-934078a7d043"/>
    <serviceTask id="sid-501c9238-5da1-47f0-8f95-2f458010a970" name="QueryRemainingDays" flowable:delegateExpression="${queryRemainingDays}"/>
    <sequenceFlow id="sid-6a8c97f8-acc2-4a3e-9051-6c78f161365b" sourceRef="sid-604145ee-174b-4864-a973-934078a7d043" targetRef="sid-501c9238-5da1-47f0-8f95-2f458010a970"/>
    <endEvent id="sid-e6b42855-57d6-4e8d-96a7-f5b1a004ed3d"/>
    <scriptTask id="sid-354c035b-2e49-4f5f-88ca-ca1cfd0e27ff" name="VerifyScript" scriptFormat="JavaScript" flowable:autoStoreVariables="false">
      <extensionElements>
        <flowable:executionListener class="org.example.exp.listener.ScriptListener" event="end"/>
      </extensionElements>
      <script><![CDATA[execution.setVariable("sum",90);]]></script>
    </scriptTask>
    <sequenceFlow id="sid-0da818a4-ea4f-4f85-b9ad-e23e943fc2f0" sourceRef="sid-501c9238-5da1-47f0-8f95-2f458010a970" targetRef="sid-354c035b-2e49-4f5f-88ca-ca1cfd0e27ff"/>
    <businessRuleTask id="sid-42d7188c-58e7-46c1-994c-3004b8d44b6b" name="MyBusiness" flowable:rules="myBusiness_1,myBusiness_3"/>
    <sequenceFlow id="sid-1ec2477c-054e-4611-9c01-fcae871faee5" sourceRef="sid-354c035b-2e49-4f5f-88ca-ca1cfd0e27ff" targetRef="sid-42d7188c-58e7-46c1-994c-3004b8d44b6b"/>
    <receiveTask id="sid-myReceive" name="myReceive">
      <extensionElements>
        <flowable:executionListener event="end" class="org.example.exp.listener.ReceiveTaskListener"/>
      </extensionElements>
    </receiveTask>
    <sequenceFlow id="sid-2b9661b6-f462-41f9-98d2-556cd0a2c064" sourceRef="sid-42d7188c-58e7-46c1-994c-3004b8d44b6b" targetRef="sid-myReceive"/>
    <manualTask id="sid-5d7dd741-0f16-4100-a21f-3fc2b5808653" flowable:exclusive="true" name="myManualTask">
      <extensionElements>
        <flowable:executionListener event="start" class="org.example.exp.listener.ManualTaskListener"/>
      </extensionElements>
    </manualTask>
    <sequenceFlow id="sid-2bc20ebd-7970-44d9-b6c0-a8448cb91db3" sourceRef="sid-myReceive" targetRef="sid-5d7dd741-0f16-4100-a21f-3fc2b5808653"/>
    <!-- flowable 单独定义的节点类型 支持按 apache camel 路由规则进行调用 -->
    <serviceTask flowable:type="camel" id="sid-bb78a1a1-3bd8-411a-920b-63ae2eb06949" flowable:exclusive="true" name="CamelServiceTask">
      <extensionElements>
        <flowable:field name="camelContext">
          <flowable:string>camelContext</flowable:string>
        </flowable:field>
        <flowable:executionListener event="end" class="org.example.exp.listener.CamelListener"/>
      </extensionElements>
    </serviceTask>
    <sequenceFlow id="sid-e44ef6ef-5e78-4d6b-9fef-45a793579236" sourceRef="sid-5d7dd741-0f16-4100-a21f-3fc2b5808653" targetRef="sid-bb78a1a1-3bd8-411a-920b-63ae2eb06949"/>
    <serviceTask flowable:type="http" id="sid-fe09b981-5d42-4cca-a222-9b1256dea9f6" flowable:exclusive="true" name="HttpServiceTask">
      <extensionElements>
        <flowable:field name="requestUrl">
          <flowable:string>http://127.0.0.1:8088/view/hello</flowable:string>
        </flowable:field>
        <flowable:executionListener event="end" class="org.example.exp.listener.HttpListener"/>
        <flowable:field name="requestMethod">
          <flowable:string>GET</flowable:string>
        </flowable:field>
        <flowable:field name="saveResponseParameters">
          <flowable:string>true</flowable:string>
        </flowable:field>
        <flowable:field name="responseVariableName">
          <flowable:string>result</flowable:string>
        </flowable:field>
      </extensionElements>
    </serviceTask>
    <sequenceFlow id="sid-7ed37a45-da59-43d3-ae84-83f57ed56025" sourceRef="sid-bb78a1a1-3bd8-411a-920b-63ae2eb06949" targetRef="sid-fe09b981-5d42-4cca-a222-9b1256dea9f6"/>
    <serviceTask flowable:type="mail" id="sid-5796c07d-53d8-4bd4-a56a-ddff642c06e6" name="MailserviceTask">
      <extensionElements>
        <flowable:executionListener event="end" class="org.example.exp.listener.MailListener"/>
        <flowable:field name="to">
          <flowable:string>hongxu_1234@163.com</flowable:string>
        </flowable:field>
        <flowable:field name="subject">
          <flowable:string>【Flowable 测试】</flowable:string>
        </flowable:field>
        <flowable:field name="text">
          <flowable:string>Hello</flowable:string>
        </flowable:field>
      </extensionElements>
    </serviceTask>
    <sequenceFlow id="sid-d65dc071-03b3-44b1-b757-e78fc175cb50" sourceRef="sid-fe09b981-5d42-4cca-a222-9b1256dea9f6" targetRef="sid-5796c07d-53d8-4bd4-a56a-ddff642c06e6"/>
    <serviceTask flowable:type="dmn" id="sid-2f1cea1d-b3de-451e-8612-0247f27b3d30" flowable:exclusive="true" name="DmnServiceTask">
      <extensionElements>
        <flowable:executionListener event="start" class="org.example.exp.listener.DmnStartListener"/>
        <flowable:executionListener event="end" class="org.example.exp.listener.DmnEndListener"/>
        <flowable:field name="decisionTableReferenceKey">
          <flowable:string>myDecision</flowable:string>
        </flowable:field>
      </extensionElements>
    </serviceTask>
    <sequenceFlow id="sid-389b9aea-15c7-41ed-b509-80c7b90ef6a5" sourceRef="sid-5796c07d-53d8-4bd4-a56a-ddff642c06e6" targetRef="sid-2f1cea1d-b3de-451e-8612-0247f27b3d30"/>
    <serviceTask flowable:type="shell" id="sid-968bc676-cb2a-4e38-ab51-037f174addfb" flowable:exclusive="true" name="ShellServiceTask">
      <extensionElements>
        <flowable:executionListener event="end" class="org.example.exp.listener.ShellListener"/>
        <flowable:field name="outputVariable">
          <flowable:string>shellOutput</flowable:string>
        </flowable:field>
        <flowable:field name="command">
          <flowable:string>ls</flowable:string>
        </flowable:field>
      </extensionElements>
    </serviceTask>
    <sequenceFlow id="sid-285f6ce8-8b6c-4aa0-8a47-ffe9ddcd535f" sourceRef="sid-2f1cea1d-b3de-451e-8612-0247f27b3d30" targetRef="sid-968bc676-cb2a-4e38-ab51-037f174addfb"/>
    <serviceTask flowable:type="external-worker" id="sid-e3e82c89-44df-4beb-89d6-29a5819386d9" flowable:exclusive="true" name="ExternalWorkerTask" flowable:topic="my-external-worker" flowable:async="true">
      <extensionElements>
        <flowable:executionListener event="end" class="org.example.exp.listener.ExternalWorkerListener"/>
      </extensionElements>
    </serviceTask>
    <sequenceFlow id="sid-e7db60c3-6b77-42b1-8921-7c5b45cf2e52" sourceRef="sid-968bc676-cb2a-4e38-ab51-037f174addfb" targetRef="sid-e3e82c89-44df-4beb-89d6-29a5819386d9"/>
    <sequenceFlow id="sid-fa098a45-db8a-415f-96b2-6b1dc1cd3c26" sourceRef="sid-e3e82c89-44df-4beb-89d6-29a5819386d9" targetRef="sid-e6b42855-57d6-4e8d-96a7-f5b1a004ed3d"/>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_leave_approval_process">
    <bpmndi:BPMNPlane bpmnElement="leave_approval_process" id="BPMNPlane_leave_approval_process">
      <bpmndi:BPMNShape id="shape-678b7128-9f1c-4ebd-a546-3c1337b0ec0d" bpmnElement="sid-a76e7b82-39bd-4838-b819-2628292d2c2c">
        <omgdc:Bounds x="-700.0" y="-420.0" width="30.0" height="30.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-bc8d7db7-870a-4b22-89b6-66f91f51be7f" bpmnElement="sid-604145ee-174b-4864-a973-934078a7d043">
        <omgdc:Bounds x="-735.0" y="-340.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-04bdc7f3-62dd-49d6-8e1d-bf9ad723c114" bpmnElement="sid-4fcf06a4-ba36-486e-a058-d993513403d0">
        <omgdi:waypoint x="-685.0" y="-390.0"/>
        <omgdi:waypoint x="-685.0" y="-340.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="shape-1850c5f4-e021-4cfc-8f45-1ed25c94cf67" bpmnElement="sid-501c9238-5da1-47f0-8f95-2f458010a970">
        <omgdc:Bounds x="-560.0" y="-340.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-77901c58-dc34-403e-8bc1-ed63e71f442c" bpmnElement="sid-6a8c97f8-acc2-4a3e-9051-6c78f161365b">
        <omgdi:waypoint x="-635.0" y="-300.0"/>
        <omgdi:waypoint x="-560.0" y="-300.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="shape-27dba26e-e25e-42c7-99b1-4a487c854aba" bpmnElement="sid-e6b42855-57d6-4e8d-96a7-f5b1a004ed3d">
        <omgdc:Bounds x="-165.0" y="115.0" width="30.0" height="30.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-fa3bf5cf-c5da-4626-8def-332c1a2f12e9" bpmnElement="sid-354c035b-2e49-4f5f-88ca-ca1cfd0e27ff">
        <omgdc:Bounds x="-375.0" y="-340.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-757b6ea6-bd95-4eec-b301-c897a784ef2e" bpmnElement="sid-0da818a4-ea4f-4f85-b9ad-e23e943fc2f0">
        <omgdi:waypoint x="-460.0" y="-300.0"/>
        <omgdi:waypoint x="-375.0" y="-300.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="shape-3cf05ae4-6095-4ded-9107-577ddf81469d" bpmnElement="sid-42d7188c-58e7-46c1-994c-3004b8d44b6b">
        <omgdc:Bounds x="-205.0" y="-340.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-76ba8768-a486-4cb9-b9dc-1a12eaa0b600" bpmnElement="sid-1ec2477c-054e-4611-9c01-fcae871faee5">
        <omgdi:waypoint x="-275.0" y="-300.0"/>
        <omgdi:waypoint x="-205.0" y="-300.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="shape-48a1535c-18c4-4749-8e7c-44c5861ba53c" bpmnElement="sid-myReceive">
        <omgdc:Bounds x="-205.0" y="-195.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-33bc9ca7-a4ff-4d01-8dcd-f82789df32c1" bpmnElement="sid-2b9661b6-f462-41f9-98d2-556cd0a2c064">
        <omgdi:waypoint x="-155.0" y="-260.0"/>
        <omgdi:waypoint x="-155.0" y="-195.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="shape-9749617d-f42b-4300-8dd3-c7362c2fdcf0" bpmnElement="sid-5d7dd741-0f16-4100-a21f-3fc2b5808653">
        <omgdc:Bounds x="-375.0" y="-195.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-933e1c6d-abc2-4d32-8d86-66590f3a3fb5" bpmnElement="sid-2bc20ebd-7970-44d9-b6c0-a8448cb91db3">
        <omgdi:waypoint x="-205.0" y="-155.0"/>
        <omgdi:waypoint x="-275.0" y="-155.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="shape-5b38760c-f447-4bc4-8d91-e1203260de7b" bpmnElement="sid-bb78a1a1-3bd8-411a-920b-63ae2eb06949">
        <omgdc:Bounds x="-560.0" y="-195.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-8c7b7240-feae-424a-8533-7310817ad8ac" bpmnElement="sid-e44ef6ef-5e78-4d6b-9fef-45a793579236">
        <omgdi:waypoint x="-375.0" y="-155.0"/>
        <omgdi:waypoint x="-460.0" y="-155.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="shape-4999f21a-5c5a-4aeb-b3a1-d0970216e1ef" bpmnElement="sid-fe09b981-5d42-4cca-a222-9b1256dea9f6">
        <omgdc:Bounds x="-725.0" y="-195.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-c4376369-11d5-4a49-be3b-abc1d4664bb8" bpmnElement="sid-7ed37a45-da59-43d3-ae84-83f57ed56025">
        <omgdi:waypoint x="-560.0" y="-155.0"/>
        <omgdi:waypoint x="-625.0" y="-155.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="shape-7e4436fd-c2f0-4f78-8f8c-95705b65ab65" bpmnElement="sid-5796c07d-53d8-4bd4-a56a-ddff642c06e6">
        <omgdc:Bounds x="-725.0" y="-50.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-0c6a4753-80bb-4b01-9dd1-07a9ecc2eb26" bpmnElement="sid-d65dc071-03b3-44b1-b757-e78fc175cb50">
        <omgdi:waypoint x="-675.0" y="-115.0"/>
        <omgdi:waypoint x="-675.0" y="-50.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="shape-f1b0d350-1a0e-4db0-940c-0403056ad9ce" bpmnElement="sid-2f1cea1d-b3de-451e-8612-0247f27b3d30">
        <omgdc:Bounds x="-555.0" y="-50.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-e3edbe78-449d-4e20-8835-6e9d5923657f" bpmnElement="sid-389b9aea-15c7-41ed-b509-80c7b90ef6a5">
        <omgdi:waypoint x="-625.0" y="-10.0"/>
        <omgdi:waypoint x="-555.0" y="-10.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="shape-85558274-3c5f-4251-91fa-c7929e0b848d" bpmnElement="sid-968bc676-cb2a-4e38-ab51-037f174addfb">
        <omgdc:Bounds x="-375.0" y="-50.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-847326d8-1d9d-439a-b5fc-fc04d53b7ca5" bpmnElement="sid-285f6ce8-8b6c-4aa0-8a47-ffe9ddcd535f">
        <omgdi:waypoint x="-455.0" y="-10.0"/>
        <omgdi:waypoint x="-375.0" y="-10.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="shape-ac87169d-593d-4bfa-a0b7-370ae27e1181" bpmnElement="sid-e3e82c89-44df-4beb-89d6-29a5819386d9">
        <omgdc:Bounds x="-205.0" y="-50.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-d9f11d8b-1d81-43eb-b0ab-1c889868c2d2" bpmnElement="sid-e7db60c3-6b77-42b1-8921-7c5b45cf2e52">
        <omgdi:waypoint x="-275.0" y="-10.0"/>
        <omgdi:waypoint x="-205.0" y="-10.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-795e60ae-ca8d-4b57-97c1-44fd8d424451" bpmnElement="sid-ba0aefb1-778c-45d2-92f5-a448479b66cd">
        <omgdi:waypoint x="135.0" y="280.0"/>
        <omgdi:waypoint x="205.0" y="280.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-dda2b7be-0018-4e00-a39e-31244236942c" bpmnElement="sid-2acc642a-907d-47dd-bf42-07008e856a0e">
        <omgdi:waypoint x="255.0" y="320.0"/>
        <omgdi:waypoint x="255.0" y="420.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-52d51756-b205-4b41-8267-a8142e969843" bpmnElement="sid-fa098a45-db8a-415f-96b2-6b1dc1cd3c26">
        <omgdi:waypoint x="-155.0" y="30.0"/>
        <omgdi:waypoint x="-149.99998" y="114.99999"/>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

4.BPMN 流程图绘制插件

IDEA 插件:Flowable BPMN visualizer

安装好该插件后即可在 IDEA 中通过右键创建流程模板了

在这里插入图片描述

右键可以创建不同节点

在这里插入图片描述

右键用该插件打开上面 bpmn 配置文件,如下图,本配置包含了大部分 Flowable节点的简单测试实现

在这里插入图片描述

5.测试代码

1.启动类

package org.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class WflApp {

    public static void main(String[] args) {
        SpringApplication.run(WflApp.class,args);
        System.out.println("Hello world!");
    }
}

2.Flowable 配置

package org.example.config;

import org.example.exp.external.MyExternalWorker;
import org.flowable.common.engine.impl.EngineDeployer;
import org.flowable.common.engine.impl.history.HistoryLevel;
import org.flowable.dmn.engine.deployer.DmnDeployer;
import org.flowable.engine.impl.rules.RulesDeployer;
import org.flowable.job.service.JobServiceConfiguration;
import org.flowable.job.service.impl.asyncexecutor.DefaultJobManager;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.spring.boot.EngineConfigurationConfigurer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-02 下午 6:18
 */
@Configuration
public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {

    @Value("${flowable.async-executor-activate}")
    boolean asyncExecutorActivate;

    @Value("${flowable.history-level}")
    HistoryLevel historyLevel;

    @Override
    public void configure(SpringProcessEngineConfiguration engineConfiguration) {

        //设置字体
        engineConfiguration.setActivityFontName("宋体");
        engineConfiguration.setLabelFontName("宋体");
        engineConfiguration.setAnnotationFontName("宋体");


        //设置 RULE 依赖
        List<EngineDeployer> customPostDeployers = new ArrayList<>();
        customPostDeployers.add(new RulesDeployer());
        customPostDeployers.add(new DmnDeployer());
        engineConfiguration.setCustomPostDeployers(customPostDeployers);

        // JOB 执行器
        engineConfiguration.setAsyncExecutorActivate(asyncExecutorActivate);
        engineConfiguration.setHistoryLevel(historyLevel);

        //设置外部处理器
        engineConfiguration.addCustomJobHandler(new MyExternalWorker());

        //设置 JOB Manger
        String engineName = engineConfiguration.getEngineName();
        JobServiceConfiguration configuration = new JobServiceConfiguration(engineName);
        DefaultJobManager jobManager = new DefaultJobManager(configuration);
        engineConfiguration.setJobManager(jobManager);
    }
}

3.Camel 配置

1.Camel 配置
package org.example.config;

import jakarta.annotation.PostConstruct;
import org.apache.camel.CamelContext;
import org.example.router.CamelRouter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-08 下午 3:06
 */
@Component
public class MyCamelContext {

    @Autowired
    CamelContext camelContext;

    @PostConstruct
    public void init() throws Exception {
        camelContext.addRoutes(new CamelRouter());
        System.out.println();
    }
}

2.Camel Router 定义
package org.example.router;

import org.apache.camel.builder.RouteBuilder;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-08 下午 2:26
 */
public class CamelRouter extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        from("flowable://leave_approval_process:sid-bb78a1a1-3bd8-411a-920b-63ae2eb06949")
                .setBody(constant("hello world!"))
                .to("log:output");
    }
}

4.扩展类监听

1.外部工作类
package org.example.exp.external;

import org.flowable.common.engine.api.scope.ScopeTypes;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.bpmn.helper.ErrorPropagation;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.impl.util.CountingEntityUtil;
import org.flowable.job.service.JobHandler;
import org.flowable.job.service.impl.persistence.entity.JobEntity;
import org.flowable.variable.api.delegate.VariableScope;
import org.flowable.variable.service.VariableService;
import org.flowable.variable.service.impl.persistence.entity.VariableInstanceEntity;

import java.util.List;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-09 上午 10:07
 */
public class MyExternalWorker implements JobHandler {

    /**
     * 自定义实现覆盖默认实现
     */
    private static final String type = "async-continuation";

    /**
     * key 用于获取唯一的处理器 JobHandlers
     * @return
     */
    @Override
    public String getType() {
        return type;
    }

    /**
     * 定义一个异步任务 用于在流程外执行一些处理逻辑 弱关联性
     * @param job
     * @param configuration
     * @param variableScope
     * @param commandContext
     */
    @Override
    public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) {


        System.out.println("Step12 My External work take ...");

        ExecutionEntity executionEntity = (ExecutionEntity) variableScope;

        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
        VariableService variableService = processEngineConfiguration.getVariableServiceConfiguration().getVariableService();
        List<VariableInstanceEntity> jobVariables = variableService.findVariableInstanceBySubScopeIdAndScopeType(executionEntity.getId(), ScopeTypes.BPMN_EXTERNAL_WORKER);
        for (VariableInstanceEntity jobVariable : jobVariables) {
            executionEntity.setVariable(jobVariable.getName(), jobVariable.getValue());
            CountingEntityUtil.handleDeleteVariableInstanceEntityCount(jobVariable, false);
            variableService.deleteVariableInstance(jobVariable);
        }

        if (configuration != null && configuration.startsWith("error:")) {
            String errorCode;
            if (configuration.length() > 6) {
                errorCode = configuration.substring(6);
            } else {
                errorCode = null;
            }
            ErrorPropagation.propagateError(errorCode, executionEntity);
        } else {
            CommandContextUtil.getAgenda(commandContext).planTriggerExecutionOperation(executionEntity);
        }
    }
}

2.普通Java服务扩展
package org.example.exp.service;

import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
import org.springframework.stereotype.Component;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-04 下午 10:04
 */
@Component("queryRemainingDays")
public class QueryRemainingDays implements JavaDelegate {

    public void execute(DelegateExecution execution) {

        System.out.println("Step2 QueryRemainingDays ...");
    }
}

3.Camel Listener
package org.example.exp.listener;

import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-08 下午 2:54
 */
public class CamelListener implements ExecutionListener {

    @Override
    public void notify(DelegateExecution execution) {
        System.out.println("Step7 ServiceTask Camel ...");
    }
}
4.DmnEndListener
package org.example.exp.listener;

import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-09 上午 2:08
 */
public class DmnEndListener implements ExecutionListener {

    @Override
    public void notify(DelegateExecution execution) {
        Object object = execution.getVariable("myResult");
        System.out.println(String.format("Step10 ServiceTask Dmn End ... I'm %s",object));
    }
}
5.DmnStartListener
package org.example.exp.listener;

import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-08 下午 11:42
 */
public class DmnStartListener implements ExecutionListener {

    @Override
    public void notify(DelegateExecution execution) {
        execution.setVariable("age",20);
        System.out.println("Step10 ServiceTask Dmn ... ");
    }
}

6.ExternalWorkerListener
package org.example.exp.listener;

import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;

import java.util.List;
import java.util.Map;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-09 上午 10:31
 */
public class ExternalWorkerListener implements ExecutionListener {

    @Override
    public void notify(DelegateExecution execution) {

        System.out.println("Step12 ServiceTask ExternalWorker ...");
    }

}

7.HttpListener
package org.example.exp.listener;

import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-08 下午 5:10
 */
public class HttpListener implements ExecutionListener {

    @Override
    public void notify(DelegateExecution execution) {
        Object object = execution.getVariable("result");
        System.out.println(String.format("Step8 ServiceTask Http ... result : %s",object));
    }
}
8.MailListener
package org.example.exp.listener;

import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-08 下午 11:02
 */
public class MailListener implements ExecutionListener {

    @Override
    public void notify(DelegateExecution execution) {
        System.out.println("Step9 ServiceTask Mail ... ");
    }
}

9.ManualTaskListener
package org.example.exp.listener;

import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-08 下午 1:53
 */
public class ManualTaskListener implements ExecutionListener {

    @Override
    public void notify(DelegateExecution execution) {
        System.out.println("Step6 ManualTask ...");
    }
}
10.ReceiveTaskListener
package org.example.exp.listener;

import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-08 上午 11:59
 */
public class ReceiveTaskListener implements ExecutionListener {

    @Override
    public void notify(DelegateExecution execution) {
        System.out.println("Step5 ReceiveTask Trigger ...");
    }
}

11.ScriptListener
package org.example.exp.listener;

import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-05 下午 3:33
 */
public class ScriptListener implements ExecutionListener {

    @Override
    public void notify(DelegateExecution execution) {
        System.out.println(String.format("Step3 Script: Sum %s",execution.getVariable("sum")));
    }
}

12.ShellListener
package org.example.exp.listener;

import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-09 上午 9:42
 */
public class ShellListener implements ExecutionListener {

    @Override
    public void notify(DelegateExecution execution) {
        String output = (String) execution.getVariable("shellOutput");
        System.out.println(String.format("Step11 ServiceTask Shell ... output : %s",output.replace("\n"," ")));
    }
}

13.UserTaskListener
package org.example.exp.listener;

import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-05 上午 11:07
 */
public class UserTaskListener implements TaskListener {

    @Override
    public void notify(DelegateTask delegateTask) {
        System.out.println("Step1 Create ...");
    }
}

5.测试接口类

包含用户节点的查询和审批,接收节点的触发

package org.example.controller;

import com.alibaba.fastjson.JSONObject;
import jakarta.servlet.http.HttpServletResponse;
import org.example.exp.service.QueryRemainingDays;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author zhx & moon
 * @Since 1.8
 * @Date 2024-01-02 下午 6:21
 */
@RestController
@RequestMapping("/wfl")
public class ProcessController {

    @Autowired
    QueryRemainingDays queryRemainingDays;

    @Autowired
    RuntimeService runtimeService;

    @Autowired
    TaskService taskService;

    @Autowired
    RepositoryService repositoryService;

    @Autowired
    ProcessEngine engine;

    /**
     * 查询流程定义
     * @return
     */
    @GetMapping("/queryProcessDefinition")
    public List<String> queryProcessDefinition(){
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
        return list.stream().map(ProcessDefinition::getId).collect(Collectors.toList());
    }

    /**
     * 通过 ID 激活流程
     * @param id
     */
    @GetMapping("/active/{id}")
    public void active(@PathVariable("id") String id){

        if (!StringUtils.hasLength(id)){
            id = "leave_approval_process";
        }
        HashMap<String,Object> map = new HashMap<>();
        map.put("id","111");
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(id,map);
        System.out.println(String.format("instance id :%s ",instance.getId()));
    }

    /**
     * 获取任务
     * 可以根据候选人、组来查询
     * 认领 taskService.claim(t.getId(),"admin");
     * 转交 taskService.setAssignee(t.getId(),"admin");
     * 回退 taskService.setAssignee(t.getId(),null);
     */
    @GetMapping("/queryUserTask")
    public List<JSONObject> queryUserTask(){
        List<Task> list = taskService.createTaskQuery().list();
        List<JSONObject> result = new ArrayList<>(list.size());
        JSONObject object;
        for (Task t:list){
            object = new JSONObject();
            object.put("taskId",t.getId());
            object.put("userId",t.getAssignee());
            result.add(object);
        }
        return result;
    }

    /**
     * 认领和处理
     * @param taskId
     */
    @GetMapping("/claimAndComplete")
    public void claimAndComplete(@RequestParam("taskId") String taskId,@RequestParam("userCode") String userCode){

        //获取任务
        Task task = taskService.createTaskQuery().taskId(taskId).taskAssignee(userCode).singleResult();
        if (task!=null){
            //TODO 审批校验,通过或不通过
            //完成
            taskService.complete(taskId);
        }
    }

    /**
     * 等待任务:即任务执行到本节点会阻塞,如本节点前会进行一系列非常复杂的业务处理,需要人为或后台线程单独检测完成情况,并决定是否继续触发
     * @param receiveTaskId
     */
    @GetMapping("/receiveTaskHandler")
    public void receiveTaskHandler(@RequestParam("receiveTaskId") String receiveTaskId){

        //查找当前流实例
        List<Execution> list = runtimeService.createExecutionQuery().activityId(receiveTaskId).list();
        for (Execution execution:list){
            runtimeService.trigger(execution.getId());
        }
    }


    /**
     * 查询流实例
     * @return
     */
    @GetMapping("/queryProcessInstance/{key}")
    public List<JSONObject> queryProcessInstance(@PathVariable("key") String key){
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().processDefinitionKey(key).list();
        List<JSONObject> result = new ArrayList<>(list.size());
        JSONObject object;
        for (ProcessInstance instance:list){
            object = new JSONObject();
            object.put("key",instance.getProcessDefinitionKey());
            object.put("instanceId",instance.getProcessInstanceId());
            result.add(object);
        }

        return result;
    }

    /**
     * 批量删除实例
     * @param key
     */
    @DeleteMapping("/deleteProcessInstance/{key}")
    public void deleteProcessInstance(@PathVariable("key") String key){
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().processDefinitionKey(key).list();
        List<String> ids = list.stream().map(ProcessInstance::getId).collect(Collectors.toList());
        runtimeService.bulkDeleteProcessInstances(ids,"test");

    }

    /**
     * 绘制流程图
     * @param response
     * @param instanceId
     * @throws IOException
     */
    @GetMapping("/buildFlowChart")
    public void buildFlowChart(@RequestParam("instanceId") String instanceId,HttpServletResponse response) throws IOException {

        //查找实例
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
        if (null == pi){
            return;
        }
        //查找已执行节点
        List<Execution> executions = runtimeService.createExecutionQuery().processInstanceId(instanceId).list();
        List<String> act = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        for (Execution execution:executions){
            List<String> ids = runtimeService.getActiveActivityIds(execution.getId());
            act.addAll(ids);
        }
        //获取 bpmn 模型并绘制流程图
        BpmnModel model = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        ProcessEngineConfiguration engineConfiguration = engine.getProcessEngineConfiguration();
        ProcessDiagramGenerator generator = engineConfiguration.getProcessDiagramGenerator();
        InputStream in = generator.generateDiagram(model,"png",act,flows,engineConfiguration.getActivityFontName(),engineConfiguration.getLabelFontName(),engineConfiguration.getAnnotationFontName(),engineConfiguration.getClassLoader(),1.0,false);
        int length;
        byte[] bytes = new byte[4096];
        OutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            while ((length=in.read(bytes)) != -1){
                outputStream.write(bytes,0,length);
            }
            outputStream.flush();
            
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (null != in){
                in.close();
            }
            if (null != outputStream){
                outputStream.close();
            }
        }
    }
}

三.测试

1.测试

创建流实例、查询待审批节点、审批、触发接收节点

输出日志

在这里插入图片描述

2.导出流进度

接口:/flowable-rest/wfl/buildFlowChart?instanceId=0626e0cb-af11-11ee-9530-00155da1d269

在这里插入图片描述

3.Postman 配置文件

{
	"info": {
		"_postman_id": "a6e5c056-e06d-40d2-b499-6db72d51c413",
		"name": "Flowable",
		"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
		"_exporter_id": "29860655"
	},
	"item": [
		{
			"name": "启动流",
			"request": {
				"method": "GET",
				"header": [],
				"url": {
					"raw": "127.0.0.1:8086/flowable-rest/wfl/active/leave_approval_process",
					"host": [
						"127",
						"0",
						"0",
						"1"
					],
					"port": "8086",
					"path": [
						"flowable-rest",
						"wfl",
						"active",
						"leave_approval_process"
					]
				}
			},
			"response": []
		},
		{
			"name": "查询用户任务",
			"event": [
				{
					"listen": "test",
					"script": {
						"exec": [
							"pm.test(\"set token\",function(){\r",
							"    var json = pm.response.json()\r",
							"    pm.environment.set(\"instanceId\",json.get(0).taskId)\r",
							"});"
						],
						"type": "text/javascript"
					}
				}
			],
			"request": {
				"method": "GET",
				"header": [],
				"url": {
					"raw": "http://127.0.0.1:8086/flowable-rest/wfl/queryUserTask",
					"protocol": "http",
					"host": [
						"127",
						"0",
						"0",
						"1"
					],
					"port": "8086",
					"path": [
						"flowable-rest",
						"wfl",
						"queryUserTask"
					]
				}
			},
			"response": []
		},
		{
			"name": "用户审批",
			"request": {
				"method": "GET",
				"header": [],
				"url": {
					"raw": "http://127.0.0.1:8086/flowable-rest/wfl/claimAndComplete?taskId={{instanceId}}&userCode=admin",
					"protocol": "http",
					"host": [
						"127",
						"0",
						"0",
						"1"
					],
					"port": "8086",
					"path": [
						"flowable-rest",
						"wfl",
						"claimAndComplete"
					],
					"query": [
						{
							"key": "taskId",
							"value": "{{instanceId}}"
						},
						{
							"key": "userCode",
							"value": "admin"
						}
					]
				}
			},
			"response": []
		},
		{
			"name": "等待触发",
			"request": {
				"method": "GET",
				"header": [],
				"url": {
					"raw": "http://127.0.0.1:8086/flowable-rest/wfl/receiveTaskHandler?instanceId={{instanceId}}&receiveTaskId=sid-myReceive",
					"protocol": "http",
					"host": [
						"127",
						"0",
						"0",
						"1"
					],
					"port": "8086",
					"path": [
						"flowable-rest",
						"wfl",
						"receiveTaskHandler"
					],
					"query": [
						{
							"key": "instanceId",
							"value": "{{instanceId}}"
						},
						{
							"key": "receiveTaskId",
							"value": "sid-myReceive"
						}
					]
				}
			},
			"response": []
		},
		{
			"name": "查询流实例",
			"request": {
				"method": "GET",
				"header": [],
				"url": {
					"raw": "http://127.0.0.1:8086/flowable-rest/wfl/queryProcessInstance/leave_approval_process",
					"protocol": "http",
					"host": [
						"127",
						"0",
						"0",
						"1"
					],
					"port": "8086",
					"path": [
						"flowable-rest",
						"wfl",
						"queryProcessInstance",
						"leave_approval_process"
					]
				}
			},
			"response": []
		},
		{
			"name": "删除流实例",
			"request": {
				"method": "DELETE",
				"header": [],
				"url": {
					"raw": "http://127.0.0.1:8086/flowable-rest/wfl/deleteProcessInstance/leave_approval_process",
					"protocol": "http",
					"host": [
						"127",
						"0",
						"0",
						"1"
					],
					"port": "8086",
					"path": [
						"flowable-rest",
						"wfl",
						"deleteProcessInstance",
						"leave_approval_process"
					]
				}
			},
			"response": []
		},
		{
			"name": "根据实例绘制流显示进度",
			"request": {
				"method": "GET",
				"header": [],
				"url": {
					"raw": "http://127.0.0.1:8086/flowable-rest/wfl/buildFlowChart?instanceId={{instanceId}}",
					"protocol": "http",
					"host": [
						"127",
						"0",
						"0",
						"1"
					],
					"port": "8086",
					"path": [
						"flowable-rest",
						"wfl",
						"buildFlowChart"
					],
					"query": [
						{
							"key": "instanceId",
							"value": "{{instanceId}}"
						}
					]
				}
			},
			"response": []
		},
		{
			"name": "MQ 发数测试",
			"request": {
				"method": "GET",
				"header": [],
				"url": {
					"raw": "127.0.0.1:8085/test/topic?msg=abc",
					"host": [
						"127",
						"0",
						"0",
						"1"
					],
					"port": "8085",
					"path": [
						"test",
						"topic"
					],
					"query": [
						{
							"key": "msg",
							"value": "abc"
						}
					]
				}
			},
			"response": []
		}
	]
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JDK21和 Flowable 7.0.0 的相关文章

  • 工作流程引擎之flowable(集成springboot)

    0 背景 现状 公司各部门业务系统有各自的工作流引擎 也有cross function的业务在不同系统或OA系统流转 没有统一的去规划布局统一的BPM解决方案 近期由于一个项目引发朝着整合统一的BPM方案 特了解一下市面上比较主流的开源和收
  • MybatisPlus整合Flowable出现的坑

    MybatisPlus整合Flowable出现的坑 摘要 现在在项目中使用的MybatisPlus 最近研究了一下流程框架Flowable 看了很多技术文档博客 打算直接整合进去 先记录一下遇到的问题 问题 Description file
  • 规则引擎Drools使用 第一篇 规则引擎认知

    规则引擎有什么用呢 可以在那些实际场景使用呢 思考这样一个问题 申请信用卡 每个人去申请信用卡的时候 都会经过一遍核查 这个核查过程其实就可以当做是根据规则 去校验你的信息是否符合规则 只有符合规则的才可以申请信用卡 还记得以前自己写的那些
  • flowable流程实例笔记(1)

    RuntimeService 运行服务类 支持启动的方式 流程定义 从这里获取资源文件 执行实例 流程实例中执行的每个环节 流程实例 一个流程实例包括所有运行的节点 一个流程中流程实例只有一个 启动一个实例 public void star
  • Could not acquire change log lock. Currently locked by XXXXXX

    最近公司项目使用到了flowable 为了方便业务开发人员使用流程设计器画流程图 使用了flowable的原生流程设计器modeler 用docker部署非常方便 参考flowable流程设计器部署官网文档 用docker部署flowabl
  • Drools 中的 Mvel 方言是什么?

    我是流口水的新手 我正在创建规则 但出现编译时错误 字段不可见 我尝试检查 Jboss 示例 它们在哪里使用方言 mvel 它编译了 我听不懂方言 那么什么是dialect mvel mvel 或者MVFLEX 表达式语言 has a 丰富
  • java代码访问drools guvnor

    我们有一个项目要求通过Web应用程序访问guvnor 有人可以让我知道如何通过java代码访问guvnor吗 抵押贷款示例已经有一些示例代码 Drools Expert手册大概有详细解释 这是代码 private static Knowle
  • kie 工作台部署战争不工作(tomcat)

    我已经下载了 kie workbench 并解压kie drools wb distribution wars 6 2 0 Final tomcat7 war 我以前从未使用过 tomcat 但我想使用工作台 但似乎没有一个选项可以让工作台
  • Drools 6.0 在运行时动态加载规则

    我想在运行时加载 drl 文件 我发现的帖子包括这个one适用于 5 0 版本 但我不知道如何为 drools 6 0 版本执行此操作 在 Drools 6 中 您的规则包被部署到 Maven 提供了 KieScanner 您可以将其附加到
  • 将新规则文件添加到现有知识会话

    我想向现有的规则文件添加一个新的规则文件 或修改现有的规则文件 KieSession在运行时动态地 我找到了一个answer https stackoverflow com a 22208775 1925388关于这一点并尝试了那里提到的解
  • “StreamCorruptedException:无效的流标头”的可能原因

    我 尝试 使用 drools 来处理我的定价规则 但是当我尝试执行规则时 会引发以下异常 java lang RuntimeException KnowledgeAgent exception while trying to deseria
  • Spring-Drools 集成:引用的文件 (kie-spring.xsd) 包含错误

    我正在尝试将 drools 与 Spring 一起使用 春季版本4 01 Drools Kie 版本 6 0 1 我的 kie context xml 有以下错误 在 Eclipse 中 引用的文件包含错误 http drools org
  • Drools 在 where 子句中获取 List 的第一个元素

    是否可以从中获取列表的第一个元素whenDrools 中的条款 如果我不知道列表中的对象字段值 而我只想检索第一个元素 我该怎么做 rule TestRule1 dialect java when c Collection listCust
  • Drools - 使用累积来查找最小值和最大值

    我有一个流口水的问题 困扰我一段时间了 我想使用累积从 Item 对象列表 包含价格 中找出最低和最高价格 插入一个包含 Item 列表的 Member 对象 包含 Item 对象列表 groovy java source pseudo c
  • Guvnor规则编码

    我在 Excel 中有一个 Drools 决策表 规则中使用的一些字符串具有 字符 当我从这个决策表在 Guvnor 中构建规则包时 我在规则源中得到了错误的字符 例如 在电子表格中 gt rea de Lazer POR 在内置的 drl
  • 使用 cron 表达式流口水规则?

    我有一个要求 我只想在工作日触发规则 我有一些规则 如烟雾 温度 运动 您能否建议我如何根据我的要求制定规则 请给我一些示例 除了 cron 之外 还有其他更好的方法来根据时间触发规则吗 您可以在工作日或周末解雇规则 我也遇到过同样的要求
  • drools 中是否有任何 API 可以通过传递值来动态创建 drl 文件?

    我知道如何使用所有方法在 KIE 工作台中创建 DRL 文件 但我的问题是不使用 KIE 工作台 我们可以创建 drl使用我们所需的值进行文件 如果有任何可能性 请建议我 同样的方式建议我任何与此相关的 API 提前致谢 您可以使用Droo
  • 持久感知 KieSession 在事务期间不使用悲观锁

    我在用Drools with 春季启动2 3 我已经实现了持久意识KieSession 其中MySQL用于存储会话 我已经成功集成了默认的EntityManagerFactorySpring Boot 与 Drools 的结合 但我的问题是
  • 口水累积正在更新一个不相关的事实

    在 Drools 中使用累积时 会针对未更新的事实评估并触发规则 规则如下 rule WidgetsPerUser when user User accumulate Widget checkIsUser user widgetCount
  • OptaPlanner 的 Drools 规则不会与类路径上的 Spring Boot 开发工具一起触发,因此分数为零

    我让 optaplanner 与 drools 规则一起正常工作 突然 在我做了一些改变之后 Optaplanner 不再将我的事实放入 drools kSession 中 我进行了一些日志记录 发现 optaplanner 在我的解决方案

随机推荐

  • 基于机器学习的投资组合推荐系统+源代码+文档说明+演示视频

    文章目录 源码下载地址 项目介绍 界面预览 项目备注 毕设定制 咨询 源码下载地址 源码下载地址 点击这里下载源码 项目介绍 界面预览
  • AI大模型应用入门实战与进阶:如何训练自己的AI模型

    1 背景介绍 人工智能 Artificial Intelligence AI 是计算机科学的一个分支 旨在模拟人类智能的能力 包括学习 理解自然语言 识别图像和视频 进行决策等 随着数据量的增加和计算能力的提升 人工智能技术的发展得到了巨大
  • AI大模型应用入门实战与进阶:从AI模型应用到商业转化

    1 背景介绍 人工智能 AI 已经成为当今世界最热门的技术话题之一 其在各个领域的应用也不断拓展 大型AI模型是人工智能领域的核心 它们在自然语言处理 图像识别 语音识别等方面的表现力和性能都有着重要的作用 然而 如何将这些大型AI模型应用
  • gazebo(fortress) set the path of sdf file

    This method only satisfied with gazebo fortress not harmenic
  • 流程管理的未来:人工智能如何改变业务运行

    1 背景介绍 流程管理是企业在实现业务目标时所采取的一系列有序 连贯的活动 它涉及到许多领域 如生产 销售 研发 财务等 随着企业规模的扩大和市场竞争的激烈 流程管理的复杂性也不断增加 人工智能 AI 技术的发展为流程管理提供了新的机遇 有
  • 人工智能与模式识别的社会影响与应用

    1 背景介绍 人工智能 Artificial Intelligence AI 和模式识别 Pattern Recognition PR 是计算机科学领域的两个重要分支 人工智能研究如何让计算机具有类似人类智能的能力 如学习 推理 理解自然语
  • 线性代数在深度学习中的角色

    1 背景介绍 深度学习是一种人工智能技术 它主要通过神经网络来学习和模拟人类大脑的思维过程 线性代数是一门数学分支 它研究的是向量和矩阵的运算 在深度学习中 线性代数起着非常重要的作用 因为它为神经网络提供了数学模型和计算方法 在这篇文章中
  • 慢思维的力量:如何解决复杂问题

    1 背景介绍 在当今的快速发展和竞争激烈的环境中 我们需要更有效地解决复杂问题 这需要我们具备一种称为慢思维的思考方式 它可以帮助我们更好地理解问题 制定更好的解决方案 本文将介绍慢思维的核心概念 算法原理 具体操作步骤以及数学模型公式 并
  • 强化学习求解TSP(二):Qlearning求解旅行商问题TSP(提供Python代码)

    一 Qlearning简介 Q learning是一种强化学习算法 用于解决基于奖励的决策问题 它是一种无模型的学习方法 通过与环境的交互来学习最优策略 Q learning的核心思想是通过学习一个Q值函数来指导决策 该函数表示在给定状态下
  • 线性代数在数据挖掘中的应用

    1 背景介绍 线性代数是数学的一个分支 主要研究的是线性方程组和向量的相关概念和方法 在数据挖掘领域 线性代数的应用非常广泛 包括数据处理 特征提取 模型训练等方面 本文将从以下几个方面进行阐述 背景介绍 核心概念与联系 核心算法原理和具体
  • 6 - 数据备份与恢复|innobackupex

    数据备份与恢复 innobackupex 数据备份与恢复 数据备份相关概念 物理备份与恢复 逻辑备份 推荐 使用binlog日志文件实现对数据的时时备份 使用日志 恢复数据
  • 心灵与大脑的沟通:如何让大脑更好地理解我们的情感

    1 背景介绍 心理学和人工智能之间的界限已经不断模糊化 尤其是在情感智能方面 情感智能是一种新兴的人工智能技术 旨在让计算机更好地理解和回应人类的情感 这篇文章将探讨如何让大脑更好地理解我们的情感 以及在这个过程中涉及的核心概念 算法原理
  • AI大模型应用入门实战与进阶:Part 7 Transformer模型解析

    1 背景介绍 自从2020年的大模型如GPT 3等开始引起广泛关注 人工智能领域的研究和应用得到了重大推动 在这一波技术创新中 Transformer模型发挥着关键作用 这篇文章将深入探讨Transformer模型的核心概念 算法原理和实例
  • 强化学习求解TSP(一):Qlearning求解旅行商问题TSP(提供Python代码)

    一 Qlearning简介 Q learning是一种强化学习算法 用于解决基于奖励的决策问题 它是一种无模型的学习方法 通过与环境的交互来学习最优策略 Q learning的核心思想是通过学习一个Q值函数来指导决策 该函数表示在给定状态下
  • 如何成为一名数据科学家:必须掌握的技能和知识

    1 背景介绍 数据科学家是一种新兴的职业 它结合了计算机科学 统计学 数学和领域知识等多个领域的知识和技能 以解决实际问题 数据科学家的主要任务是收集 清洗 分析和解释大量数据 从中挖掘有价值的信息和知识 并将其应用于决策和预测 数据科学家
  • 机器智能与人类智能的竞争:技术创新的驱动力

    1 背景介绍 人工智能 Artificial Intelligence AI 和机器学习 Machine Learning ML 是最近几年最热门的技术领域之一 随着数据量的增加和计算能力的提高 机器学习技术的发展得到了极大的推动 机器学习
  • 电脑快速打开计算器的方法

    大家好 我是爱你三千遍斯塔克 我们平常在运算时 经常要要使用计算器 那么计算器有什么快速打开方法吗 这里有一些参考方法 可供大家进行参考 希望对大家有帮助 希望你喜欢我的内容 记得关注我哦 我会继续为大家带来更好的作 1 win R 打开运
  • 机器学习中的知识共享:模型与数据的交流与协作

    1 背景介绍 机器学习 Machine Learning 是一种通过数据学习模式和规律的计算机科学领域 在过去的几年里 机器学习技术在各个领域得到了广泛应用 如图像识别 自然语言处理 推荐系统等 随着数据规模的不断增长 单个机器学习模型的复
  • 人工智能与机器学习:未来的编程范式

    1 背景介绍 人工智能 Artificial Intelligence AI 和机器学习 Machine Learning ML 是现代计算机科学的重要领域之一 它们旨在让计算机能够自主地学习 理解和进化 以解决复杂的问题 随着数据量的增加
  • JDK21和 Flowable 7.0.0

    JDK21和 Flowable 7 0 0 一 Flowable 二 项目搭建 1 依赖包 2 数据库 3 资源文件 1 YML配置文件 2 Drools kbase