Camunda流程引擎多版本,如何优雅融入SpringBoot 框架,解决版本冲突问题

Camunda平台是一个轻量级、开源的业务流程管理平台。在性能、功能上优于其它开源流程框架,非常适合引入项目做二次开发。要在项目中引入Camunda流程引擎,那么我们就应该对流程引擎了解,不便能避免很多未知的问题,还能更好地发挥其作用。
一、Camunda 流程引擎版本介绍
    Camunda 是基于JAVA 语言开发,从7.0到目前最新版本 7.16 ,每一次版本的更新,流程引擎会增加一些新功能,也会优化现有性能。

 

二、SpringBoot 集成 Camunda版本对照
Camunda 与 Spring Boot 的集成,主要是因为每个版本的 Camunda Boot Starter  基于特定版本的  Spring Boot 开发,并绑定了特定版本的 Camunda BPM
注意:
从7.13.0版开始,Camunda BPM及其兼容的Spring Boot Starter始终共享同一版本。 另外,Spring Boot Starter中使用的Camunda BPM版本不再需要被覆盖。 只需选择与您要使用的Camunda BPM版本类似的Starter版本。
Spring Boot Starter version
Camunda BPM version
Spring Boot version
1.0.0* 
7.3.0 
1.2.5.RELEASE 
1.1.0* 
7.4.0 
1.3.1.RELEASE 
1.2.0* 
7.5.0 
1.3.5.RELEASE 
1.2.1* 
7.5.0 
1.3.6.RELEASE 
1.3.0* 
7.5.0 
1.3.7.RELEASE 
2.0.0** 
7.6.0 
1.4.2.RELEASE 
2.1.x** 
7.6.0 
1.5.3.RELEASE 
2.2.x** 
7.7.0 
1.5.6.RELEASE 
2.3.x 
7.8.0 
1.5.8.RELEASE 
3.0.x 
7.9.0 
2.0.x.RELEASE 
3.1.x 
7.10.0 
2.0.x.RELEASE 
3.2.x 
7.10.0 
2.1.x.RELEASE 
3.3.1+ 
7.11.0 
2.1.x.RELEASE 
3.4.x 
7.12.0 
2.2.x.RELEASE 
7.13.x
7.13.3+*** 
7.13.x
7.13.3+ 
2.2.x.RELEASE 
三、SpringBoot 集成Camunda  示例
   网上已经有很多关于 Spring Boot 集成的示例 Camunda,但很多引入太直接,并不是很理想,不但容易出现版本冲突问题,而且不便于POM文件的管理,我这里推荐大家使用官网推荐大家基于BOM的方式引入Camunda。
Camunda 现在最新版本是7.16.0,在我的项目中使用的是7.15.0
项目版本准备:
Spring Boot: 2.3.7.RELEASE
Camunda: 7.15.0
在我的项目是父子结构,父POM文件中定义了 Spring Boot 的版本,下面是POM文件:
<?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.hx</groupId>
    <artifactId>hx-fixSystem</artifactId>
    <packaging>pom</packaging>
    <version>2.0</version>
    <name>hx-fixSystem 管理系统</name>
    <modules>
        <!— Camunda 流程引擎模块 -->
        <module>hx-bpm</module>
    </modules>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.7.RELEASE</version>
    </parent>


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>11</java.version>
        <jedis.version>2.9.0</jedis.version>
        <log4jdbc.version>1.16</log4jdbc.version>
        <swagger.version>2.7.0</swagger.version>
        <fastjson.version>1.2.54</fastjson.version>
        <druid.version>1.1.22</druid.version>
        <commons-pool2.version>2.5.0</commons-pool2.version>
        <mapstruct.version>1.3.1.Final</mapstruct.version>
    </properties>


    <dependencies>
        <!--Spring boot start-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</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-security</artifactId>
        </dependency>
        <!-- spring cache -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--Spring boot end-->


        <!--spring2.0集成redis所需common-pool2-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>${commons-pool2.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>


        <!--监控sql日志-->
        <dependency>
            <groupId>org.bgee.log4jdbc-log4j2</groupId>
            <artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
            <version>${log4jdbc.version}</version>
        </dependency>


        <!-- RESTful APIs swagger2 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>


        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>1.6.2</version>
        </dependency>


        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>1.6.2</version>
        </dependency>

    
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>1.9.6</version>
        </dependency>


        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>23.0</version>
        </dependency>

        <!--Mysql依赖包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- druid数据源驱动 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>


        <!--lombok插件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <optional>true</optional>
        </dependency>
   
    </dependencies>


    <repositories>
        <repository>
            <id>public</id>
            <name>aliyun nexus</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
        </repository>
    </repositories>


    <pluginRepositories>
        <pluginRepository>
            <id>public</id>
            <name>aliyun nexus</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>


</project>
下面是Camunda 流程引擎模块的POM文件:
<?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">
    <parent>
        <artifactId>hx-fixSystem</artifactId>
        <groupId>com.hx</groupId>
        <version>2.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>hx-bpm</artifactId>
    <name>流程引擎</name>
    <description>流程引擎相关操作</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

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

    <dependencies>

        <!--Spring boot 集成camunda-->
        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter</artifactId>
        </dependency>


        <!--camunda Rest 接口-->
        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter-rest</artifactId>
        </dependency>


        <!--camunda webapp 页面操作流程-->
        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter-webapp</artifactId>
        </dependency>


        <!--外部任务客户端-->
        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter-external-task-client</artifactId>
        </dependency>


        <!--连接器-->
        <dependency>
            <groupId>org.camunda.bpm</groupId>
            <artifactId>camunda-engine-plugin-connect</artifactId>
        </dependency>


        <!--Spin和Json  Rest Http中解析; parse http response variable with camunda-spin-->
        <dependency>
            <groupId>org.camunda.bpm</groupId>
            <artifactId>camunda-engine-plugin-spin</artifactId>
        </dependency>
        <dependency>
            <groupId>org.camunda.spin</groupId>
            <artifactId>camunda-spin-dataformat-json-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>org.camunda.spin</groupId>
            <artifactId>camunda-spin-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.camunda.spin</groupId>
            <artifactId>camunda-spin-dataformat-all</artifactId>
        </dependency>


        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.3.0</version>
        </dependency>


        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.0</version>
        </dependency>


        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>3.3.0</version>
        </dependency>


        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.2</version>
        </dependency>


        <dependency>
            <groupId>org.simpleframework</groupId>
            <artifactId>simple-xml</artifactId>
            <version>2.7.1</version>
        </dependency>


        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>qrcode-utils</artifactId>
            <version>1.1</version>
        </dependency>


        <dependency>
            <groupId>com.cronutils</groupId>
            <artifactId>cron-utils</artifactId>
            <version>9.0.2</version>
        </dependency>


        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.4.13</version>
        </dependency>

        <!-- 服务注册-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.1.4.RELEASE</version>
        </dependency>


        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-commons</artifactId>
            <version>2.2.5.RELEASE</version>
            <scope>compile</scope>
        </dependency>


        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-openfeign-core</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>


        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.2.3.RELEASE</version>
        </dependency>


        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
            <version>10.2.0</version>
        </dependency>


    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
            </plugin>
        </plugins>
    </build>
</project>

在POM文件中引入 Camunda 依赖,按上面红色字体的方式引入,不但固定了版本,而且在下面的具体功能模块引入时,就可以不用加版本号,它们会自动按上面定好的版本引入对应依赖。
就这样一个 流程引擎项目就可以正常运转了。
四:Camunda 引擎自带的 组件式服务
Camunda 流程引擎功能很强大,做了很多封装工作,提供了很多’开箱’ 即用的组件式服务,直接调用现存的API,不用写什么代码就能把一般的流程跑起来。
下面就介绍几个重要组件:
组件名称
功能
RuntimeService
运行时服务。 提供了流程的发起、删除、挂起、激活、获取参数、删除参数等方法。
发起流程实例有 20个方法 
最常用的根据流程定义ID(),流程定义KEY方法,启动成功后返回流程示例。
ProcessInstance startProcessInstanceById(String processDefinitionId)
ProcessInstance startProcessInstanceByKey(String processDefinitionKey);
删除流程实例 15个方法
其中删除有 6个方法 (有返回);其余的为直接删除,没有返回
获取活动实例 节点 ,活动节点实例各 1个
向在给定执行中等待的活动实例发送外部触发器   3个
获取参数 17个方法
添加参数及值  8个方法
删除参数 4个方法
挂起流程实例 3个方法
激活流程实例  3个方法
还有其它一些方法没使用,占时还不明白用途
TaskService
任务服务。 提供了流程中任务的产生、删除、完成、委托、认领、设置参数、获取参数方法
其中常用的方法有:
Task newTask();
void deleteTask(String taskId);
void claim(String taskId, String userId); 
void complete(String taskId);
void delegateTask(String taskId, String userId);
void setAssignee(String taskId, String userId);
void setOwner(String taskId, String userId);
void setPriority(String taskId, int priority);
void setVariable(String taskId, String variableName, Object value);
  Object getVariable(String taskId, String variableName);
void removeVariable(String taskId, String variableName);
  Comment createComment(String taskId, String processInstanceId, String message);
List<Comment> getProcessInstanceComments(String processInstanceId);
HistoryService
历史服务。 对流程中已经完成的节点任务、参数的查询服务,历史流程。
其中常用的方法有:
HistoricProcessInstanceQuery createHistoricProcessInstanceQuery();
NativeHistoricActivityInstanceQuery createNativeHistoricActivityInstanceQuery();
IdentityService
权限服务。  想着的权限设置
对于以上的组件,在项目中直接引用即可使用,示例如下。
@Resource
private RuntimeService runtimeService;


@Resource
private TaskService taskService;


@Resource
private FormService formService;


@Resource
private HistoryService historyService;
如何部署一个流程代码:
/**
*  file 为上传流程图的文件,
*
*  name 设定流程的名字
*/

@Override
public void bpmnModelDeployFile(MultipartFile file, String name) {
    if(file == null){
        throw new ApiException("流程文件不能为空!");
    }

    try {
        repositoryService.createDeployment()
                //.tenantId(String.valueOf(tenantId))
                .name(name) // 流程名字
                .source("公司的流程") // 来源
                .addInputStream(file.getOriginalFilename(), file.getInputStream())
                .deploy();

    } catch (Exception e) {
        throw new ApiException("流程部署失败".concat(e.getMessage()));
    }
}
启动流程:
/**
*  key 为定义流程的KEY
*
*  WorkflowVariableDto 为参数对象
*   返回 流程实例ID
*/

@Override
public String startProcess(String key, WorkflowVariableDto dto) {

    List<String> tenantIds = new ArrayList<>(Arrays.asList(dto.getTenantIds().split(",")));

    // 设置流程发起人
    if (StringUtils.isNotBlank(dto.getStartUser())) {
        identityService.setAuthentication(dto.getStartUser(), new ArrayList<>(), tenantIds);
    }

    // 启动流程实例
    ProcessInstance instance = runtimeService.startProcessInstanceByKey(key, dto.getBusinessId());

    try {
        // 获取当前任务,会签可能会有多个
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(instance.getProcessInstanceId()).list();

        if (CollectionUtils.isNotEmpty(tasks)) {
            tasks.forEach(t -> {
                // 为当前任务分派用户
                if (StringUtils.isNotBlank(dto.getAssignee())) {
                    taskService.setAssignee(t.getId(), dto.getAssignee());
                }
                // 为当前任务添加候选用户
                if (StringUtils.isNotBlank(dto.getCandidateUsers())) {
                    List<String> users = WorkflowVariableDto.getIdListByStr(dto.getCandidateUsers());
                    users.forEach(u -> taskService.addCandidateUser(t.getId(), u));
                }
                // 为当前任务添加候选组
                if (StringUtils.isNotBlank(dto.getCandidateGroups())) {
                    List<String> groups = WorkflowVariableDto.getIdListByStr(dto.getCandidateGroups());
                    groups.forEach(g -> taskService.addCandidateGroup(t.getId(), g));
                }
            });
        }

    } catch (Exception e) {
        throw new ApiException("发起流程失败:".concat(e.getMessage()));
    }
    return instance.getProcessInstanceId();
}
完成任务:
/**
*  taskId 为任务ID
*  WorkflowVariableDto  为参数对象
*
*/

@Override
public void completeTask(String taskId, WorkflowVariableDto dto) {
    try {
        // 获取完成前任务
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if(ObjectUtils.isEmpty(task)){
            log.info("没有查找到当前任务:{}", taskId);
            return ;
        }

        // 完成任务填写的备注
        if(StringUtils.isNotBlank(dto.getReason()) && StringUtils.isNotBlank(task.getProcessInstanceId())){
            taskService.createComment(task.getId(), task.getProcessInstanceId(), dto.getReason());
        }

        // 完成当前任务
        taskService.complete(taskId, dto.getVariables());
    } catch (Exception e) {
        throw new ApiException("完成任务失败:".concat(e.getMessage()));
    }
}
驳回任务:
/**
* 驳回并返回到起点
* @param processInstanceId 流程实例ID
* @param taskId 任务ID
* @param reason 原因
*/
@Override
public boolean reject(String processInstanceId, String taskId, String reason, int step){
    Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).taskId(taskId).singleResult();
    if(task != null){
        ActivityInstance activityInstance = runtimeService.getActivityInstance(processInstanceId);
        if(activityInstance != null){
            List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
                                                                                        .processInstanceId(processInstanceId)
                                                                                        .executionId(task.getExecutionId())
                                                                                        .activityType("userTask")
                                                                                        .finished()
                                                                                        .orderByHistoricActivityInstanceEndTime()
                                                                                        .desc().list();

            historicActivityInstanceList = historicActivityInstanceList.stream().filter(it -> !it.getActivityId().equals(task.getTaskDefinitionKey())).collect(Collectors.toList());

            if(historicActivityInstanceList.size() > 0){
                HistoricActivityInstance first = historicActivityInstanceList.get(step);
                String toActId = first.getActivityId();
                String assignee = first.getAssignee();

                Map<String, Object> taskVariable = new HashMap<>();
                //设置当前处理人
                taskVariable.put("assignee", assignee)

                // 填写拒绝的原因
                taskService.createComment(task.getId(), processInstanceId, reason);

                runtimeService.createProcessInstanceModification(processInstanceId)
                        //关闭相关任务
                        .cancelActivityInstance(getInstanceIdForActivity(activityInstance, task.getTaskDefinitionKey()))
                        .setAnnotation("进行了驳回到"+ step + "任务节点操作")
                        //启动目标活动节点
                        .startBeforeActivity(toActId)
                        //流程的可变参数赋值
                        .setVariables(taskVariable)
                        .execute();

                List<Task> _taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).list();

                if(ObjectUtils.isNotEmpty(_taskList)){
                    for(Task item: _taskList){
                        if(item.getTaskDefinitionKey().equals(toActId)){
                            taskService.setAssignee(item.getId(), assignee);
                            return true;
                        }
                    }
                }
            }
        }
    }
    return false;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

周周的JAVA技术栈

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

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

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

打赏作者

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

抵扣说明:

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

余额充值