JDK21和 Flowable 7.0.0

一.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": []
		}
	]
}
  • 11
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 目前的最新版本的Flowable 6.x系列和7.x系列都支持JDK 17。如果你想在JDK 17上运行Flowable,你可以按照以下步骤进行: 1. 在POM文件中添加以下依赖: ``` <dependency> <groupId>org.flowable</groupId> <artifactId>flowable-spring-boot-starter</artifactId> <version>${flowable-version}</version> </dependency> ``` 2. 在Spring Boot应用程序的主类上添加以下注释:`@EnableProcessApplication` 3. 确保你的JDK版本为JDK 17。 4. 运行你的Spring Boot应用程序。 注意:如果你使用的是Flowable 6.x系列,你需要使用6.6.0及以上版本;如果你使用的是Flowable 7.x系列,你需要使用7.0.0及以上版本。同时,你需要使用支持JDK 17的Spring Boot版本。 希望这可以帮助到你! ### 回答2: 在JDK 17下运行Flowable是可以的。Flowable是Reactive Streams的一个实现,它提供了一种用于处理异步数据流(流)的编程模型。通过使用Flowable,我们可以更好地处理大量数据或需要异步处理的任务。 要在JDK 17中运行Flowable,首先需要确保Flowable API及其依赖项正常安装在项目中。可以通过使用构建工具(如Maven或Gradle)将Flowable库添加为项目的依赖项来实现。 在代码中,我们可以创建一个Flowable对象并定义操作符(operators)来处理流。例如,我们可以使用map操作符对流中的元素进行转换,使用filter操作符筛选出特定的元素等等。然后,我们可以通过使用订阅(subscribe)方法来订阅Flowable并开始处理数据流。 在运行时,JDK 17提供了对Flowable的支持,它能够识别Flowable的异步特性,并根据需要进行线程调度和处理。这意味着我们可以使用JDK 17的优化功能,如垃圾收集器和并行处理能力,来更高效地处理Flowable流。 总结而言,JDK 17兼容Flowable并提供了强大的功能,可以帮助我们处理异步数据流。尽管Flowable是Reactive Streams的一部分,但它仍然可以在JDK 17中使用,并且可以充分利用JDK 17的优化能力。 ### 回答3: JDK 17 是Java Development Kit(Java开发工具包)的一个版本,而Flowable是一个开源的用于处理业务流程的框架。 Flowable 是一个轻量级的、可扩展的企业级流程引擎,它使用Java语言编写,通过提供一系列的API和工具,可以帮助开发人员建立和管理复杂的业务流程。Flowable提供了流程的定义、执行和监控能力,同时还提供了包括任务管理、用户认证等功能。 要在JDK 17上运行Flowable,需要遵循以下步骤: 1. 确保你已经安装了JDK 17并设置了正确的环境变量。 2. 下载Flowable的最新版本,可以从官方网站或者Maven仓库中获取。 3. 在项目中添加Flowable的依赖,可以通过Maven或者Gradle进行配置。 4. 创建一个Java类,在其中编写使用Flowable的代码逻辑。 5. 在代码中,引用Flowable的API进行流程的定义和执行,例如创建一个流程实例、启动流程、查询任务等。 6. 运行代码,可以通过命令行、IDE或者其他工具执行。 需要注意的是,JDK 17使用了一些新的语言特性和功能,可能与旧版本的JDK有些不兼容。因此,在将Flowable迁移到JDK 17上之前,需要对代码进行一些修改和调整,以适应新版本的Java。此外,也需要确保Flowable的版本兼容JDK 17。 总结来说,要在JDK 17上运行Flowable,需要先安装JDK 17,然后配置Flowable的依赖并编写相应的代码。在运行时,需要注意版本兼容性和语言特性的使用,以确保顺利运行Flowable框架。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猪悟道

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值