参考文章:

Spring Boot 项目集成camunda流程引擎_springboot集成camunda-CSDN博客

camunda流程引擎 API 接口介绍_camunda接入-CSDN博客

Camunda部署方式

使用camunda开源工作流引擎有:通过docker运行、使用springboot集成、部署camunda发行包、基于源代码编译运行等多种方式。

文本重点介绍如何在Spring Boot应用程序中如何集成Camunda Platform开源流程平台,这也是项目中最为常见的一种使用方式。


部署Camunda工作流引擎(springboot方式)

1、创建新的 Maven 项目

项目名称命名为camunda7-springboot

2、添加 Camunda 平台和 Spring Boot 依赖项

本示例要使用camunda流程引擎、web界面、Rest服务接口

我们使用camunda7.19.0版本,该版本支持jdk8和springboot2。camunda和springboot版本的依赖对应关系,查看官方文档说明

Spring Boot Version Compatibility | docs.camunda.org

<?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>

    <groupId>com.camunda</groupId>
    <artifactId>camunda7-springboot</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <camunda.spring-boot.version>7.19.0</camunda.spring-boot.version>
        <spring-boot.version>2.7.9</spring-boot.version>
    </properties>

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

    <dependencies>
        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter-webapp</artifactId>
            <version>${camunda.spring-boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter-rest</artifactId>
            <version>${camunda.spring-boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.6</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>3.4.7</version>
            </plugin>
            <!--指定JDK编译版本 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

3、配置 Spring Boot 项目

在项目中src/main/resources新建application.yaml

server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/camunda719?characterEncoding=UTF-8&useUnicode=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
camunda:
  bpm:
    database:
      type: mysql
      schema-update: true
    auto-deployment-enabled: false # 自动部署 resources 下的 bpmn文件
    admin-user:
      id: demo
      password: demo

这里我们设置了schema-update: true,启动会自动创建脚本,初始化后,我们在设置为false

创建一个数据库,否则启动会会找不到库

此配置将导致以下结果:

  1. 将创建具有提供的密码和名字的管理员用户“demo”
  2. 使用mysql数据库,启动时自动创建数据库,合计49张表

4、编写Spring Boot启动类

接下来,我们添加一个带有 main 方法的应用程序类,该方法将成为启动 Spring Boot 应用程序的入口点。该类上有@SpringBootApplication注解,它隐含地添加了几个方便的功能(自动配置、组件扫描等 - 参见 Spring Boot 文档)。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;
 
@SpringBootApplication
public class Camunda7Application {
    public static void main(String... args) {
        ConfigurableApplicationContext application =  SpringApplication.run(Camunda7Application.class, args);
        Environment env = application.getEnvironment();
        String port = env.getProperty("server.port");
        String path = env.getProperty("server.servlet.context-path");
        if (path == null || "".equals(path)) {
            path = "/";
        }
        System.out.println("\n----------------------------------------------------------\n" +
                "\tCamunda7Application is running!\n" +
                "\tPort:\t" + port + "\n" +
                "\tPath:\t" + path + "\n" +
                "----------------------------------------------------------");
    }
}

5、启动Spring Boot工程

现在,当您在浏览器中打开 http://localhost:8080/ 时,您可以使用我们之前配置的登录名和密码“demo/demo”来访问 Camunda Web 应用程序。

能正常登录访问这个界面,表示基于springboot集成camunda成功了。


部署BPMN设计器

下载地址:https://downloads.camunda.cloud/release/camunda-modeler/5.19.0/camunda-modeler-5.19.0-win-x64.zip

下载流程设计器后camunda-modeler后,只需将下载内容解压缩到您选择的文件夹中即可。

成功解压缩后,对于 Windows 用户运行Camunda Modeler.exe,对于 Mac 用户或 Linux 用户运行.sh文件,启动流程建模器

设计BPMN流程

新建一个模板,选择Camunda7

设置两个人工任务节点,配置流程处理人为demo用户

点击左下角可查看xml内容

发布BPMN流程

点击流程设计器左下方的发布流程按钮,直接发布到springboot项目里面


Camunda控制台测试

查看流程定义相关信息

现在,当您在浏览器中打开 http://localhost:8080/camunda/app/ ,您可以使用我们之前配置的登录名和密码“demo/demo”来访问 Camunda Web 应用程序

开启实例

访问首页,然后选择任务列表

http://localhost:8080/camunda/app/

我们点击开启实例选项,选择刚才流程定义key,点击start

因为我们用户名就是demo,所有在任务列表可以看到了

此时,我看打开mysql数据库表,查看camunda数据库表里的数据:打开流程定义发布表act_re_deployment,看到我们刚刚发布的这个流动定义模型

打开流程实例历史表act_hi_procinst,看到我们刚刚发起的这个流程实例数据。

打开流程待办任务表act_ru_task,多了一条demo用户待处理的任务。

通过Camunda Rest接口测试

以上我们通过camunda的web界面进行了发起流程测试验证,下面我们通过Camunda REST API的方式进行测试验证。Camunda Platform REST API官方说明文档:Camunda Platform REST API

查询流程定义

http://127.0.0.1:8080/engine-rest/process-definition

发起流程实例

http://127.0.0.1:8080/engine-rest/process-definition/key/{key}/start

发起调用

反参

我们再查看任务列表,可以看到已经成功创建实例,并开始第一个任务了

查询待办任务

通过上面接口得知,流程当前流转到了人工节点上,那么需要查询待办任务:返回所有的流程待办任务列表

完成待办提交流程

完成待办任务,提交流程往下走,提交流程的rest服务接口为:


通过Java API接口测试

上面介绍了通过Camunda Web控制台界面和Camunda提供的rest接口两种方式,来调用流程引擎服务。以下介绍第三种方式,即Java编码方式,直接调用Camunda提供的Service接口。

我们自己开发一个RestController服务类,类里注入RuntimeService和TaskService的SpringBean,然后调用这两个类的API接口,实现发起流程和查询待办的逻辑。

直接使用刚才的springboot项目,里面集成knife4j

        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>3.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

这里需要加下面配置,否则集成knife4j会报错

spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

添加配置类

@Configuration
@EnableSwagger2
public class SwaggerConfig {
 
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.camunda.controller")) // 扫描的包路径
                .paths(PathSelectors.any())
                .build();
    }
 
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Knife4j Demo API")
                .description("Spring Boot 2 with Knife4j Example")
                .version("1.0")
                .build();
    }
}

添加controller和反参封装类

@RestController
@RequestMapping("/test")
@Api(tags = "测试模块")
public class TestController {

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private TaskService taskService;

    /**
     * 通过流程定义key,发起一个流程实例
     * @param processKey 流程定义key
     * @return 流程实例ID
     */
    @ApiOperation(value = "通过流程定义key,发起一个流程实例")
    @GetMapping(value = "/startProcessInstanceByKey/{processKey}")
    public R<?> startProcessInstanceByKey(@PathVariable("processKey") String processKey) {
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(processKey);
        return R.ok(instance.getRootProcessInstanceId());
    }
 
    @ApiOperation(value = "查询某个用户的待办任务")
    @GetMapping(value = "/getTaskByAssignee/{assignee}")
    public R<?> getTaskByAssignee(@PathVariable("assignee") String assignee) {
        List<TaskEntity> taskList = (List)taskService.createTaskQuery().taskAssignee(assignee).list();
        StringBuffer sb = new StringBuffer();
        List<Map<String,String>> list = new ArrayList<>();
        for (TaskEntity task : taskList) {
            Map<String,String> map = new HashMap<>();
            map.put("待办任务ID", task.getId());
            map.put("流程实例ID", task.getProcessInstanceId());
            list.add(map);
        }
        return R.okList(list,list.size());
    }
}
@Data
public class R<T> implements Serializable
{
    private static final long serialVersionUID = 1L;

    /** 成功 */
    public static final int SUCCESS = 200;

    /** 失败 */
    public static final int FAIL = 500;

    public static final String SUCCESS_MSG = "成功";

    public static final String FAIL_MSG = "失败";

    private int code;

    private String msg;

    private T data;

    private long total;

    public static <T> R<T> ok()
    {
        return restResult(SUCCESS,SUCCESS_MSG, null);
    }

    public static <T> R<T> ok(String msg,T data) {
        return restResult(SUCCESS,msg,data);
    }

    public static <T> R<T> ok(T data)
    {
        return restResult(SUCCESS, SUCCESS_MSG,data);
    }

    public static <T> R<T> okMsg(String msg) {
        return restResult(SUCCESS,msg,null);
    }

    public static <T> R<T> okList(T data,long total) {
        return restResult(SUCCESS,SUCCESS_MSG,data,total);
    }

    public static <T> R<T> fail()
    {
        return restResult(FAIL,FAIL_MSG,  null);
    }

    public static <T> R<T> fail(String msg)
    {
        return restResult(FAIL,msg,null);
    }

    public static <T> R<T> fail(T data)
    {
        return restResult(FAIL, FAIL_MSG,data);
    }

    public static <T> R<T> fail(int code, String msg)
    {
        return restResult( code, msg,null);
    }

    public static <T> R<T> fail(String msg,T data)
    {
        return restResult(FAIL, msg, data);
    }


    private static <T> R<T> restResult(int code, String msg,T data)
    {
        R<T> apiResult = new R<>();
        apiResult.setCode(code);
        apiResult.setData(data);
        apiResult.setMsg(msg);
        return apiResult;
    }


    private static <T> R<T> restResult(int code, String msg,T data, long total) {
        R<T> apiResult = new R<>();
        apiResult.setCode(code);
        apiResult.setMsg(msg);
        apiResult.setData(data);
        apiResult.setTotal(total);
        return apiResult;
    }

    public static <T> Boolean isFail(R<T> ret)
    {
        return !isSuccess(ret);
    }

    public static <T> Boolean isSuccess(R<T> ret)
    {
        return R.SUCCESS == ret.getCode();
    }

    public static R<?> toR(int rows) {
        return rows > 0 ? R.ok() : R.fail();
    }

    public static R<?> toR(boolean result) {
        return result ? R.ok() : R.fail();
    }
}

使用knife4j测试一下,查询待办任务,可以看到也返回了demo用户的待办任务数据,说明通过直接调用camunda的API接口RuntimeService和TaskService也是成功的。

Logo

更多推荐