SpringBoot集成Camunda工作流引擎样例demo

前言

在项目中需要用到工作流引擎来设计部分业务流程,框架选型最终选择了Camunda7。本文将介绍如何在Spring Boot项目中集成Camunda流程引擎,并提供一个完整的业务流程的样例demo。

整合Camunda流程引擎

版本

SpringBoot:2.6.14

Camunda:7.18.0

Camunda-modeler:5.13.0

添加依赖

在Spring Boot项目中添加Camunda的依赖,可以使用Maven或Gradle等构建工具。以下是一个Maven的依赖示例:

<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.6.14</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>

      <dependency>
        <groupId>org.camunda.bpm</groupId>
        <artifactId>camunda-bom</artifactId>
        <version>7.18.0</version>
        <scope>import</scope>
        <type>pom</type>
      </dependency>
    </dependencies>
  </dependencyManagement>

<dependencies>
    <dependency>
      <groupId>org.camunda.bpm.springboot</groupId>
      <artifactId>camunda-bpm-spring-boot-starter-rest</artifactId>
    </dependency>
    <dependency>
      <groupId>org.camunda.bpm.springboot</groupId>
      <artifactId>camunda-bpm-spring-boot-starter-webapp</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.41</version>
    </dependency>
  </dependencies>

Application xml配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/camunda?serverTimezone=Asia/Shanghai
    username: root
    password: 123456

camunda.bpm:
  webapp:
    # 设置管理控制台的访问上下文
    application-path: /workflow
  auto-deployment-enabled: false
  admin-user:
    # 配置登录管理控制台的用户
    id: admin
    password: admin
    firstName: admin
  filter:
    create: All tasks
  database:
    #数据库类型
    type: mysql
    #是否自动更新表信息
    schema-update: true
#logging:
#  level:
    #配置日志,这样在开发过程中就能看到每步执行的SQL语句了
#    '[org.camunda.bpm.engine.impl.persistence.entity]': debug

注*:提前创建好数据库camunda(数据库名可改成自己的数据库名),首次启动服务数据库camunda中会自动生成相关表结构和数据,如果报错如下,说明数据源下已经存在act_*相关的表,所以不会再次生成。

### Cause: java.sql.SQLSyntaxErrorException: Table 'camunda2.act_ge_property' doesn't exist

创建BPMN流程案例

 demo1.bpmn

<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_03yaiy9" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.13.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.19.0">
  <bpmn:process id="demo1" name="审批退回" isExecutable="true">
    <bpmn:startEvent id="StartEvent_1" name="审批流程">
      <bpmn:outgoing>Flow_01ndo4p</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:sequenceFlow id="Flow_01ndo4p" sourceRef="StartEvent_1" targetRef="Activity_1gko2k5" />
    <bpmn:sequenceFlow id="Flow_1tl602a" sourceRef="Activity_1gko2k5" targetRef="Activity_15pxhgv" />
    <bpmn:endEvent id="Event_0hdfd5c">
      <bpmn:incoming>Flow_1xy7g6r</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="Flow_1xy7g6r" sourceRef="Activity_15pxhgv" targetRef="Event_0hdfd5c" />
    <bpmn:userTask id="Activity_1gko2k5" name="提交申请">
      <bpmn:extensionElements>
        <camunda:formData>
          <camunda:formField id="name" label="名称" type="string" />
          <camunda:formField id="age" label="年龄" type="long" />
        </camunda:formData>
      </bpmn:extensionElements>
      <bpmn:incoming>Flow_01ndo4p</bpmn:incoming>
      <bpmn:outgoing>Flow_1tl602a</bpmn:outgoing>
    </bpmn:userTask>
    <bpmn:userTask id="Activity_15pxhgv" name="审批">
      <bpmn:incoming>Flow_1tl602a</bpmn:incoming>
      <bpmn:outgoing>Flow_1xy7g6r</bpmn:outgoing>
    </bpmn:userTask>
  </bpmn:process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="demo1">
      <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
        <dc:Bounds x="179" y="99" width="36" height="36" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="175" y="142" width="45" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_0hdfd5c_di" bpmnElement="Event_0hdfd5c">
        <dc:Bounds x="592" y="99" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_1jipdur_di" bpmnElement="Activity_1gko2k5">
        <dc:Bounds x="270" y="77" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_0kbrp5d_di" bpmnElement="Activity_15pxhgv">
        <dc:Bounds x="430" y="77" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="Flow_01ndo4p_di" bpmnElement="Flow_01ndo4p">
        <di:waypoint x="215" y="117" />
        <di:waypoint x="270" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_1tl602a_di" bpmnElement="Flow_1tl602a">
        <di:waypoint x="370" y="117" />
        <di:waypoint x="430" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_1xy7g6r_di" bpmnElement="Flow_1xy7g6r">
        <di:waypoint x="530" y="117" />
        <di:waypoint x="592" y="117" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>

demo2.bpmn

<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0zgtpwl" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.13.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.19.0">
  <bpmn:process id="qjlc" name="请假流程" isExecutable="true">
    <bpmn:startEvent id="StartEvent_1">
      <bpmn:outgoing>Flow_0jsyu31</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:sequenceFlow id="Flow_0jsyu31" sourceRef="StartEvent_1" targetRef="Activity_0tjwb9m" />
    <bpmn:sequenceFlow id="Flow_01p9vvr" sourceRef="Activity_0tjwb9m" targetRef="Activity_09tuiqf" />
    <bpmn:sequenceFlow id="Flow_0isdipx" sourceRef="Activity_09tuiqf" targetRef="Gateway_0nk0jwh" />
    <bpmn:endEvent id="Event_0wmdaqi">
      <bpmn:incoming>Flow_0b2trtt</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="Flow_0zu2a2p" sourceRef="Activity_0c6x52o" targetRef="Gateway_0xhl1us" />
    <bpmn:userTask id="Activity_0tjwb9m" name="请假">
      <bpmn:extensionElements>
        <camunda:formData>
          <camunda:formField id="name" label="名称" type="string" />
          <camunda:formField id="sj" label="时间" type="date" />
        </camunda:formData>
      </bpmn:extensionElements>
      <bpmn:incoming>Flow_0jsyu31</bpmn:incoming>
      <bpmn:incoming>Flow_0nk9gqk</bpmn:incoming>
      <bpmn:outgoing>Flow_01p9vvr</bpmn:outgoing>
    </bpmn:userTask>
    <bpmn:userTask id="Activity_0c6x52o" name="人事">
      <bpmn:incoming>Flow_15re4jy</bpmn:incoming>
      <bpmn:outgoing>Flow_0zu2a2p</bpmn:outgoing>
    </bpmn:userTask>
    <bpmn:userTask id="Activity_09tuiqf" name="经理">
      <bpmn:extensionElements>
        <camunda:formData>
          <camunda:formField id="qjr" label="请假人" type="string" />
          <camunda:formField id="json" label="内容" type="string" />
        </camunda:formData>
      </bpmn:extensionElements>
      <bpmn:incoming>Flow_01p9vvr</bpmn:incoming>
      <bpmn:incoming>Flow_0ot47ia</bpmn:incoming>
      <bpmn:outgoing>Flow_0isdipx</bpmn:outgoing>
    </bpmn:userTask>
    <bpmn:exclusiveGateway id="Gateway_0xhl1us" name="判断">
      <bpmn:incoming>Flow_0zu2a2p</bpmn:incoming>
      <bpmn:outgoing>Flow_0b2trtt</bpmn:outgoing>
      <bpmn:outgoing>Flow_0ot47ia</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:sequenceFlow id="Flow_0b2trtt" name="通过" sourceRef="Gateway_0xhl1us" targetRef="Event_0wmdaqi">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${pd2=='通过'}</bpmn:conditionExpression>
    </bpmn:sequenceFlow>
    <bpmn:sequenceFlow id="Flow_0ot47ia" name="退回" sourceRef="Gateway_0xhl1us" targetRef="Activity_09tuiqf">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${pd2!='通过'}</bpmn:conditionExpression>
    </bpmn:sequenceFlow>
    <bpmn:exclusiveGateway id="Gateway_0nk0jwh" name="判断">
      <bpmn:incoming>Flow_0isdipx</bpmn:incoming>
      <bpmn:outgoing>Flow_15re4jy</bpmn:outgoing>
      <bpmn:outgoing>Flow_0nk9gqk</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:sequenceFlow id="Flow_15re4jy" name="通过" sourceRef="Gateway_0nk0jwh" targetRef="Activity_0c6x52o">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${pd=='通过'}</bpmn:conditionExpression>
    </bpmn:sequenceFlow>
    <bpmn:sequenceFlow id="Flow_0nk9gqk" name="退回" sourceRef="Gateway_0nk0jwh" targetRef="Activity_0tjwb9m">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${pd!='通过'}</bpmn:conditionExpression>
    </bpmn:sequenceFlow>
  </bpmn:process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="qjlc">
      <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
        <dc:Bounds x="152" y="199" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_0wmdaqi_di" bpmnElement="Event_0wmdaqi">
        <dc:Bounds x="1252" y="199" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_1iqqjo3_di" bpmnElement="Activity_0tjwb9m">
        <dc:Bounds x="250" y="177" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_1ytibhn_di" bpmnElement="Activity_0c6x52o">
        <dc:Bounds x="780" y="177" width="100" height="80" />
        <bpmndi:BPMNLabel />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_05y4k6q_di" bpmnElement="Activity_09tuiqf">
        <dc:Bounds x="430" y="177" width="100" height="80" />
        <bpmndi:BPMNLabel />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Gateway_0xhl1us_di" bpmnElement="Gateway_0xhl1us" isMarkerVisible="true">
        <dc:Bounds x="1045" y="192" width="50" height="50" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="1058.5" y="168" width="23" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Gateway_0nk0jwh_di" bpmnElement="Gateway_0nk0jwh" isMarkerVisible="true">
        <dc:Bounds x="625" y="192" width="50" height="50" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="639" y="249" width="23" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="Flow_0jsyu31_di" bpmnElement="Flow_0jsyu31">
        <di:waypoint x="188" y="217" />
        <di:waypoint x="250" y="217" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_01p9vvr_di" bpmnElement="Flow_01p9vvr">
        <di:waypoint x="350" y="217" />
        <di:waypoint x="430" y="217" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0isdipx_di" bpmnElement="Flow_0isdipx">
        <di:waypoint x="530" y="217" />
        <di:waypoint x="625" y="217" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0zu2a2p_di" bpmnElement="Flow_0zu2a2p">
        <di:waypoint x="880" y="217" />
        <di:waypoint x="1045" y="217" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0b2trtt_di" bpmnElement="Flow_0b2trtt">
        <di:waypoint x="1095" y="217" />
        <di:waypoint x="1252" y="217" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="1163" y="199" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0ot47ia_di" bpmnElement="Flow_0ot47ia">
        <di:waypoint x="1070" y="242" />
        <di:waypoint x="1070" y="380" />
        <di:waypoint x="480" y="380" />
        <di:waypoint x="480" y="260" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="765" y="362" width="21" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_15re4jy_di" bpmnElement="Flow_15re4jy">
        <di:waypoint x="675" y="217" />
        <di:waypoint x="780" y="217" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="717" y="199" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0nk9gqk_di" bpmnElement="Flow_0nk9gqk">
        <di:waypoint x="650" y="192" />
        <di:waypoint x="650" y="100" />
        <di:waypoint x="300" y="100" />
        <di:waypoint x="300" y="177" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="465" y="82" width="21" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>

demo3

<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0h3vbuf" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.13.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.19.0">
  <bpmn:process id="zdsp" name="自动审批" isExecutable="true">
    <bpmn:startEvent id="StartEvent_1">
      <bpmn:outgoing>Flow_0edugib</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:sequenceFlow id="Flow_0edugib" sourceRef="StartEvent_1" targetRef="Activity_0pvheo9" />
    <bpmn:sequenceFlow id="Flow_0fcxiem" sourceRef="Activity_0pvheo9" targetRef="Activity_08s87r4" />
    <bpmn:endEvent id="Event_16ew4n3">
      <bpmn:incoming>Flow_0uzct3z</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="Flow_0uzct3z" sourceRef="Activity_08s87r4" targetRef="Event_16ew4n3" />
    <bpmn:serviceTask id="Activity_0pvheo9" name="自动审批" camunda:class="com.ph.workflow.task.ATask">
      <bpmn:extensionElements>
        <camunda:executionListener delegateExpression="${monitorExecution}" event="start" />
      </bpmn:extensionElements>
      <bpmn:incoming>Flow_0edugib</bpmn:incoming>
      <bpmn:outgoing>Flow_0fcxiem</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:userTask id="Activity_08s87r4" name="人工审批" camunda:assignee="${userName}">
      <bpmn:incoming>Flow_0fcxiem</bpmn:incoming>
      <bpmn:outgoing>Flow_0uzct3z</bpmn:outgoing>
    </bpmn:userTask>
  </bpmn:process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="zdsp">
      <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
        <dc:Bounds x="179" y="99" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_1yjbweb_di" bpmnElement="Activity_0pvheo9">
        <dc:Bounds x="270" y="77" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_16ew4n3_di" bpmnElement="Event_16ew4n3">
        <dc:Bounds x="682" y="99" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_1meixwq_di" bpmnElement="Activity_08s87r4">
        <dc:Bounds x="460" y="77" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="Flow_0edugib_di" bpmnElement="Flow_0edugib">
        <di:waypoint x="215" y="117" />
        <di:waypoint x="270" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0uzct3z_di" bpmnElement="Flow_0uzct3z">
        <di:waypoint x="560" y="117" />
        <di:waypoint x="682" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0fcxiem_di" bpmnElement="Flow_0fcxiem">
        <di:waypoint x="370" y="117" />
        <di:waypoint x="460" y="117" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>

完整的业务流程样例demo代码Controller

import com.alibaba.fastjson.JSONObject;
import org.camunda.bpm.engine.*;
import org.camunda.bpm.engine.history.HistoricActivityInstance;
import org.camunda.bpm.engine.history.HistoricTaskInstance;
import org.camunda.bpm.engine.impl.RepositoryServiceImpl;
import org.camunda.bpm.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.camunda.bpm.engine.impl.pvm.process.ActivityImpl;
import org.camunda.bpm.engine.repository.Deployment;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/workflow")
public class CamundaController {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private IdentityService identityService;

    /**
     * 查询已部署的流程定义列表
     */
    @GetMapping("/deployed-cases")
    public List<String> getDeployedCases() {
        // and convert it to a list of WorkflowCase objects
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
                .list();
        return list.stream().map(e -> e.getId() + "," + e.getName() + "," + e.getVersion()).collect(Collectors.toList());
    }

    /**
     * 部署流程案例
     *
     * @param file BPMN文件
     * @param name 流程名称
     */
    @PostMapping("/deploy-case")
    public String deployCase(@RequestParam("file") MultipartFile file, @RequestParam("name") String name) {
        try (InputStream is = file.getInputStream()) {
            // 获取文件的名称
            String originalFilename = file.getOriginalFilename();

            Deployment deployment = repositoryService.createDeployment()
                    .addInputStream(originalFilename, is)
                    .name(name)
                    .deploy();
            return deployment.getId();
        } catch (Exception e) {
            return e.getMessage();
        }
    }

    /**
     * 启动流程实例
     *
     * @param caseId 流程定义id
     */
    @PostMapping("/start-case/{caseId}")
    public String startCase(@PathVariable(value = "caseId") String caseId, @RequestBody String json) {

        Map map = new HashMap();
        if (json != null && !"".equals(json)) {
            map = JSONObject.parseObject(json, Map.class);
        }
        // 部署流程
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(caseId, map);
        return processInstance.getId();
    }

    /**
     * 查询正在执行的任务列表
     *
     * @param caseId 流程实例id
     */
    @GetMapping("/active-tasks")
    public List<String> getActiveTasks(@RequestParam(value = "caseId", required = false) String caseId) {
        List<Task> list = taskService.createTaskQuery().processInstanceId(caseId).list();
        // Implement the logic here
        return list.stream().map(e -> {
            return "任务id:" + e.getId() + ", 实例id:" + e.getProcessInstanceId() + ",流程定义id:" + e.getProcessDefinitionId();
        }).collect(Collectors.toList());
    }

    /**
     * 审批通过任务
     *
     * @param taskId 任务id
     * @param json   参数json字符串
     */
    @PostMapping("/approve-task/{taskId}")
    public String approveTask(@PathVariable("taskId") String taskId, @RequestBody String json) {
        if (json != null && !"".equals(json)) {
            Map map = JSONObject.parseObject(json, Map.class);
            taskService.setVariables(taskId, map);
        }
        taskService.complete(taskId);
        return "Task approved successfully";
    }

    /**
     * 查询历史流程案例列表
     *
     * @param caseId 流程实例id
     */
    @GetMapping("/historical-cases")
    public List<HistoricTaskInstance> getHistoricalCases(@RequestParam(value = "caseId", required = false) String caseId) {
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(caseId).list();
        return list;
    }

    /**
     * 查询流程实例参数列表
     *
     * @param taskId 任务id
     */
    @GetMapping("/task-variables")
    public Map<String, Object> getVariables(@RequestParam(value = "taskId", required = false) String taskId) {
        Map<String, Object> variables = taskService.getVariables(taskId);
        return variables;
    }

    /**
     * 回退
     *
     * @param processInstanceId 流程实例id
     */
    @PostMapping("/rollback/{instanceId}")
    public String rollback(@PathVariable("instanceId") String processInstanceId) {

        Task activeTask = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .active()
                .singleResult();
        HistoricTaskInstance taskInstance = historyService.createHistoricTaskInstanceQuery()
                .taskId(activeTask.getId())
                .singleResult();

        // 获取流程定义
        ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(taskInstance.getProcessDefinitionId());

        // 获取当前活动
        ActivityImpl currentActivity = processDefinitionEntity.findActivity(taskInstance.getTaskDefinitionKey());

        // 获取起始活动
        List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
                .activityType("userTask")
                .processInstanceId(processInstanceId)
                .finished()
                .orderByHistoricActivityInstanceEndTime()
                .desc()
                .list();
        if (historicActivityInstances.size() == 0) {
            return "没有历史活动";
        }
        ActivityImpl lastActivity = processDefinitionEntity.findActivity(historicActivityInstances.get(0).getActivityId());

        // 退回至起点
        runtimeService.createProcessInstanceModification(processInstanceId)
                .cancelAllForActivity(currentActivity.getActivityId())
                .startBeforeActivity(lastActivity.getActivityId())
                .setAnnotation("退回")
                .execute();
        return "Rollback successful";
    }

    /**
     * 删除流程案例
     *
     * @param caseId 流程定义id
     */
    @DeleteMapping("/delete-case/{caseId}")
    public String deleteCase(@PathVariable(value = "caseId") String caseId) {
        repositoryService.deleteProcessDefinition(caseId);
        return "successful";
    }
}

监听类代码

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.springframework.stereotype.Component;

@Component("monitorExecution")
public class MonitorExecution implements JavaDelegate {

    @Override
    public void execute(DelegateExecution delegateExecution) throws Exception {
        String processInstanceId = delegateExecution.getProcessInstanceId();
        System.out.println("自动执行: " + processInstanceId);
    }
}




--------------------------------------------------------------------



import org.camunda.bpm.engine.delegate.*;

public class ATask implements ExecutionListener, JavaDelegate {

    @Override
    public void execute(DelegateExecution delegateExecution) throws Exception {
        System.out.println("待发布....");
    }

    @Override
    public void notify(DelegateExecution delegateExecution) throws Exception {

    }

}

以下步骤:

  1. 创建一个简单的审批流程demo1.bpmn。
  2. 部署流程定义。
  3. 启动流程实例。
  4. 查询任务列表。
  5. 完成任务。
  6. 验证流程是否已完成。
  7. 删除流程定义。

结论

本文介绍了如何在Spring Boot项目中集成Camunda流程引擎,并提供了一个完整的业务流程的样例demo。希望这篇文章对您有所帮助。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Boot是一个用于创建独立的、基于Spring的应用程序的框架。规则引擎是一种用于管理和执行业务规则的工具。在Spring Boot集成规则引擎可以帮助我们更方便地管理和执行业务规则。 下面是一个简单的Spring Boot集成规则引擎的示例: 1. 首先,需要在pom.xml文件中添加规则引擎的依赖。例如,可以使用Drools规则引擎,添加以下依赖: ```xml <dependency> <groupId>org.kie</groupId> <artifactId>kie-api</artifactId> <version>7.59.0.Final</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-core</artifactId> <version>7.59.0.Final</version> </dependency> ``` 2. 创建规则文件。在src/main/resources目录下创建一个规则文件,例如rules.drl,编写业务规则。 3. 创建一个规则引擎配置类。在Spring Boot应用程序中创建一个配置类,例如RuleEngineConfig.java,配置规则引擎的相关信息。 ```java @Configuration public class RuleEngineConfig { @Bean public KieContainer kieContainer() { KieServices kieServices = KieServices.Factory.get(); KieFileSystem kieFileSystem = kieServices.newKieFileSystem(); Resource resource = kieServices.getResources().newClassPathResource("rules.drl"); kieFileSystem.write(resource); KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem); kieBuilder.buildAll(); KieModule kieModule = kieBuilder.getKieModule(); return kieServices.newKieContainer(kieModule.getReleaseId()); } @Bean public KieSession kieSession() { return kieContainer().newKieSession(); } } ``` 4. 创建一个业务类。在Spring Boot应用程序中创建一个业务类,例如RuleService.java,使用规则引擎执行业务规则。 ```java @Service public class RuleService { @Autowired private KieSession kieSession; public void executeRules(Object fact) { kieSession.insert(fact); kieSession.fireAllRules(); } } ``` 5. 在控制器中使用规则引擎。在Spring Boot应用程序的控制器中使用规则引擎执行业务规则。 ```java @RestController public class RuleController { @Autowired private RuleService ruleService; @PostMapping("/execute") public void executeRules(@RequestBody Object fact) { ruleService.executeRules(fact); } } ``` 这样,当调用`/execute`接口时,规则引擎将会执行相应的业务规则。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值