简单易懂的springboot整合Camunda 7工作流入门教程

news2024/10/5 21:09:26

简单易懂的Spring Boot整合Camunda7入门教程

因为关于Spring Boot结合Camunda7的教程在网上比较少,而且很多都写得有点乱,很多概念写得太散乱,讲解不清晰,导致看不懂,本人通过研究学习之后就写出了这篇教学文档。

介绍

Camunda是一个开源平台,专为开发人员设计,用以建模、执行和监控业务流程。它基于BPMN(Business Process Model and Notation,业务流程建模与标记)标准,允许组织自动化其业务流程。Camunda的核心组件包括流程引擎、任务管理器、用户界面组件和管理工具。

官方文档

为什么结合Spring Boot和Camunda?

  1. 简化开发:Spring Boot简化了Java应用的搭建过程,而Camunda则提供了强大的流程自动化工具。两者的结合可以帮助开发者快速搭建带有工作流的应用。
  2. 集成便利:Spring Boot和Camunda都有很好的生态支持,它们之间的集成相对简单,因为Camunda本身也支持Spring环境。
  3. 灵活性和可扩展性:Camunda允许在流程定义中嵌入自定义Java代码,这样可以轻松地与现有的Spring Boot应用集成,实现复杂的业务逻辑。

在这里插入图片描述

快速开始

添加依赖

环境为java17
添加依赖:

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

这个依赖包是Camunda与Spring Boot集成的基础,包含了启动Camunda BPM引擎所需的基本组件,如Camunda BPM Engine、Spring Integration以及Spring Boot自动配置。它使开发者能够快速启动Camunda BPM引擎,并提供默认配置选项。

  1. camunda-bpm-spring-boot-starter-rest

此依赖包提供了Camunda REST API的支持,允许通过HTTP请求访问Camunda BPM引擎的功能,如启动流程实例、查询状态、管理任务及部署定义。这使得前端应用或其他服务可以通过RESTful方式与Camunda交互。

  1. camunda-bpm-spring-boot-starter-webapp

这个依赖包用于创建集成Camunda Web客户端(如Cockpit)和任务列表(Tasklist)的Web应用程序,方便在浏览器中管理和监控Camunda流程。这提高了开发和运维的效率。

基础配置

# Camunda Engine自动配置
camunda:
  db:
    history: full

# camunda登录信息配置
camunda.bpm:
  auto-deployment-enabled: false  # 关闭自动部署,一开始测试的时候可以先不关闭,默认是自动部署
  admin-user:
    id: admin  #用户名
    password: 123456  #密码
    firstName: su
  filter:
    create: All tasks

至少要配置一个数据库项(mysql,pgsql都支持):

datasource:
  driver-class-name: org.postgresql.Driver
  username: 
  password:
  url: jdbc:postgresql:
jpa:
  hibernate:
    ddl-auto: update

resources下新建BPMN用于存放流程文件:

在这里插入图片描述

启动项目

配置好之后,启动项目,会自动配置好数据库和生成对应表

在这里插入图片描述

通过localhost:端口号/context-path(自己配置的,没有可以忽略)/camunda/app/,可以访问到内置web界面

输入用户名密码即为配置文件里面的 admin,123456

在这里插入图片描述

主控制台

登陆成功后,如下所示,具体的使用在下面介绍
在这里插入图片描述

  • Cockpit:这是Camunda的管理控制台,用于监视和调试流程实例。你可以在这里查看流程定义、流程实例、历史数据等。它是开发人员和管理员的主要工具,用于理解流程行为和诊断问题。
  • Tasklist:这是一个任务列表,用于查看和管理当前待办事项。对于那些需要完成任务的用户来说,这是一个重要的入口点。
  • Admin:这是Camunda的管理工具,用于管理用户、组、权限和数据库连接等。它提供了对系统设置的全面控制。

绘制流程图

下载

首先需要一个工具 Camunda Modeler 来画,下载地址:

https://camunda.com/download/modeler/

选择对应自己电脑的版本下载:

在这里插入图片描述

下载好后,解压双击打开程序:

在这里插入图片描述

新建流程图

在这里插入图片描述

最终绘制一个基础的任务审核流程图:
在这里插入图片描述

介绍

任务分类

介绍最常用的两种

用户任务 (User Task)

在这里插入图片描述

具体来说就是需要手动执行的任务,即需要我们这变写完业务代码后,调用代码,来提交当前任务,当前任务才会被完成,从而走到下一个流程

taskService.complete(taskId, variables);
系统任务(Service Task)

在这里插入图片描述

系统自动完成的任务,而结合springboot 也就是在springboot写好的执行流程,自动执行完成后走到下一个流程。

网关

分为这么几类,会根据我们传入的流程变量及设定的条件走

  • 排他网关(exclusive gateway)

这个网关只会走一个,我们走到这个网关时,会从上到下找第一个符合条件的任务往下走

  • 并行网关(Parallel Gateway)

这个网关不需要设置条件,会走所有的任务

  • 包含网关(Inclusive Gateway)

这个网关会走一个或者多个符合条件的任务

在这里插入图片描述

具体绘制方法

可以从左边直接拖过来,或者直接点击(具体自己尝试,很简单的)

开始

首先需要每个流程都需要有一个流程起点:
在这里插入图片描述

点击新建的流程点可以选择下一个节点是什么:
在这里插入图片描述

系统任务

系统任务推荐指定bean来实现java代码:
在这里插入图片描述

代码实现方法:

@Component
public class SignInDelegate implements JavaDelegate {

    @Override
    public void execute(DelegateExecution execution) throws Exception {
        //执行的系统任务流程
    }
    @Bean("指定的bean")
    public JavaDelegate signIn() {
        return this::execute; // 返回当前类的 execute 方法
    }
}

DelegateExecution是Camunda BPM引擎提供的一个接口,用于在流程执行过程中传递上下文信息。它在流程实例执行的过程中充当了一个中心角色,提供了访问流程变量、流程定义、活动实例以及其他与流程执行相关的功能的方法。

补充:右边有个展开,点一下就出来了

在这里插入图片描述

设定网关

设定网关表达式:

在这里插入图片描述

在上一个系统任务中设置传入对应变量,让流程能顺利通过网关:

@Component
public class SignInDelegate implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) throws Exception {
    //执行的系统任务流程
   // 设置流程变量,以至于能够顺利通过网关,如果没有设置的话会报错
   execution.setVariable("通过", true);
}
@Bean("指定的bean")
public JavaDelegate signIn() {
    return this::execute; // 返回当前类的 execute 方法
}

}
设定角色任务

在系统任务中指定对应的用户(受理人)来处理该事件:

在这里插入图片描述

@Component
public class SignInDelegate implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) throws Exception {
    //执行的系统任务流程
   // 设置流程变量,以至于能够顺利通过网关,如果没有设置的话会报错
   execution.setVariable("通过", true);
   execution.setVariable("指定的角色", "用户id或者唯一的用户名称");  //指定受理人
}
@Bean("指定的bean")
public JavaDelegate signIn() {
    return this::execute; // 返回当前类的 execute 方法
}

**注意:**Assignee只能是string类型,不能传入其他类型

完成角色任务

可以通过taskAssignee(“变量值(用户名或id)”) 来查找任务实例

可以通过task.setAssignee(“变量值(用户名或id)”);来修改当前实例的受理人

List<Task> tasks = taskService.createTaskQuery()
        .processDefinitionKey(processDefinitionKey)
        .taskAssignee(userId)
        //这里两个参数意思是从第几行开始,一共需要几行
        .listPage(pageNum, pageSize);

(如何获得当前节点任务实例ID的方法后面会讲)

通过某种方法获取到taskId(当前节点任务实例ID),通过这个id去查找任务,然后完成任务:

    // 完成任务
    @Override
    public String submitApproval(String taskId, boolean approval,String note) {
        // 获取任务
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null){
            return "不存在该任务";
        }
        // 执行业务流程

        // 设置审批结果
        runtimeService.setVariable(task.getExecutionId(), "审批情况", approval); //task.getExecutionId()是实例id,设定全局变量能够走到结束流程

        // 完成任务
        taskService.complete(taskId);

        return "审批已完成.";
    }
设定processDefinitionKey

rocessDefinitionKey是在使用Camunda BPM时的一个重要概念,它用于唯一标识一个流程定义。当您在Camunda Modeler中设计流程并通过BPMN 2.0标准定义了一个流程后,该流程会被赋予一个唯一的键值,这个键就是processDefinitionKey

什么是processDefinitionKey

processDefinitionKey是在流程定义文件(通常是.bpmn文件)中的属性,它用来唯一识别一个特定的流程定义。这个键通常对应于流程定义的ID,并且在流程定义部署到Camunda BPM引擎时会被使用。

在哪里定义?

在BPMN文件中,processDefinitionKey是在<process>元素上的id属性。虽然这不是一个强制性的属性,但在实践中,为了能够通过代码引用流程定义,通常会为其指定一个有意义的id

例如,在BPMN文件中:

<process id="myProcess" name="My Process">
  <!-- 流程节点定义 -->
</process>

在这个例子中,myProcess就是processDefinitionKey

在绘制流程图,点击空白处就能看到processDefinitionKey,可以自己指定,设定,程序是通过指定的processDefinitionKey来启动对应流程图实例的。

在这里插入图片描述

基本概念

工作流基础变量名词解释

processDefinitionKey(默认流程Key)

解释
processDefinitionKey是一个用来唯一标识某个流程定义的字符串。当你使用Camunda Modeler设计并保存一个流程图时,这个流程图会有一个对应的processDefinitionKey,它实际上就是流程定义文件中的<process>标签的id属性。

用途
当你需要在代码中启动一个流程实例时,就需要使用processDefinitionKey来告诉Camunda BPM引擎你想启动哪一个流程定义。例如,如果你想启动名为orderApproval的流程,就会使用orderApproval作为processDefinitionKey

processInstanceId(流程实例ID)

解释
当你启动一个流程定义时,Camunda BPM引擎会为这个特定的流程实例生成一个唯一的processInstanceId。这个ID用来唯一标识一个具体的流程实例,即使使用同一个流程定义启动多次,每次启动都会生成不同的processInstanceId

用途
使用processInstanceId可以查询特定流程实例的状态,查看流程实例的历史记录,或者继续处理流程实例中的下一步。

nodeId(节点ID)

解释
在BPMN流程定义中,流程由一系列的活动(节点)组成,如开始事件、任务、网关等。每个活动都有一个唯一的标识符,即nodeId

用途
nodeId用于标识流程中的各个活动。在流程执行过程中,可以用来追踪流程当前所处的位置,或者记录流程执行的历史轨迹。

taskId(任务ID)

解释
在流程定义中有许多任务需要用户完成,如审核任务、填写表单等。每个这样的任务都有一个唯一的taskId

用途
taskId用于标识特定的任务实例,用户可以通过taskId来查找和执行分配给他们的任务。

Assignee(受理人)

解释
在流程定义中,有些任务需要指定的用户来完成。Assignee是指定给某个任务的执行者,即谁负责完成这项任务。

用途
Assignee用于指派任务给具体的用户。只有被指派的用户才能看到任务并在任务列表中执行它。

BusinessKey(业务Key)

解释
BusinessKey是用来关联业务对象与流程实例的标识符。它可以用来存储业务相关的信息,以便于后续的流程处理。

用途
使用BusinessKey可以将业务数据关联到流程实例上,这样在流程执行过程中,可以方便地获取到业务相关的数据。比如说一个考勤流程,有人要申请考勤,那么就可以将这个人的唯一工作号码作为BusinessKey,方便查询和定位这个人的申请流程。

流程图讲解:

在这里插入图片描述

流程节点的类型及其意义
  1. 开始事件(Start Event)

    • 意义:标志着流程的开始。可以是普通开始事件、定时器开始事件等。
    • 用法:用于定义流程实例何时启动。例如,当接收到订单时,可以触发订单处理流程的开始事件。
  2. 结束事件(End Event)

    • 意义:标志着流程或分支的结束。可以是普通结束事件、取消结束事件等。
    • 用法:用于定义流程何时终止。例如,当订单处理完毕后,可以触发订单处理流程的结束事件。
  3. 任务(Task)

    • 意义:表示需要完成的工作。可以是用户任务、服务任务等。
    • 用法:用于定义需要执行的具体工作。例如,用户任务可能涉及人工审批,而服务任务则可以调用 Web 服务或执行脚本。
  4. 网关(Gateway)

    • 独占网关(Exclusive Gateway)
      • 意义:用于选择一条单一路径继续流程。
      • 用法:根据条件选择下一个活动。例如,根据订单金额决定是否需要额外审批。
    • 并行网关(Parallel Gateway)
      • 意义:允许多条路径同时进行。
      • 用法:同时执行多个并行任务。例如,同时发送邮件通知客户和更新库存系统。
    • 复杂网关(Complex Gateway)
      • 意义:用于更复杂的路由逻辑。
      • 用法:处理更复杂的流程分支逻辑。
  5. 事件子流程(Event Subprocess)

    • 意义:用于处理特定类型的事件。
    • 用法:可以嵌套在流程中,等待特定事件的发生再执行。
  6. 序列流(Sequence Flow)

    • 意义:连接两个节点,定义流程的流向。
    • 用法:用于定义节点之间的顺序关系。

Services API

当然可以,下面是经过优化后的讲解,旨在让新手更容易理解Camunda引擎中的各个服务及其功能:


Camunda 服务概述

在使用Camunda BPM引擎时,有几个核心服务可以帮助我们管理和执行流程。以下是这些服务的基本介绍以及它们的主要用途:

RepositoryService

简介:RepositoryService是你与Camunda引擎交互的第一个切入点。它主要用于管理流程定义的部署,包括上传流程定义文件(如BPMN文件)到引擎中。

主要功能

  • 部署和管理流程定义。
  • 查询已部署的流程定义和部署信息。
  • 挂起和激活流程定义,控制其是否可以被启动。
  • 检索流程定义中的文件和流程图。
RuntimeService

简介:RuntimeService是用于在流程执行期间与引擎交互的服务。它允许启动流程实例,并且可以查询正在执行的流程实例状态。

主要功能

  • 启动流程实例。
  • 存储和检索流程实例的变量。
  • 查询正在执行的流程实例和执行实例(指向流程实例当前位置的“令牌”)。
  • 处理流程实例的外部触发。
TaskService

简介:TaskService专注于管理流程中的任务,特别是那些需要人为干预的任务。

主要功能

  • 查询分配给用户的任务。
  • 创建新的任务,这些任务可以独立于任何流程实例。
  • 分配任务给用户或组。
  • 认领和完成任务。
IdentityService

简介:IdentityService提供了管理用户和组的功能,但请注意,核心引擎并不会在运行时验证用户身份。

主要功能

  • 创建、更新、删除和查询用户和组。
  • 尽管可以将任务分配给任何用户,但实际的身份验证和授权需在应用层实现。
FormService

简介:FormService是可选的,它支持流程中的表单功能,比如启动流程前展示的表单或任务完成时所需的表单。

主要功能

  • 管理和渲染开始表单和任务表单。
  • 表单数据与流程变量的交互。
HistoryService

简介:HistoryService提供了访问流程执行历史记录的功能。

主要功能

  • 查询流程实例的历史数据,如开始时间、执行用户、任务耗时等。
  • 数据持久化级别可配置。
ManagementService

简介:ManagementService提供了对数据库表元数据的访问,并支持作业的查询和管理。

主要功能

  • 检索数据库表和元数据信息。
  • 管理和查询作业,例如计时器作业。
FilterService

简介:FilterService允许创建和管理过滤器,用于简化常见的查询需求。

主要功能

  • 创建存储的查询,如任务查询。
  • Tasklist应用使用过滤器来筛选任务。
ExternalTaskService

简介:ExternalTaskService专门处理外部任务,即在流程引擎之外执行的工作项。

主要功能

  • 提供对流程外部任务的访问和管理。
  • 支持异步处理模式下的任务领取和完成。
Query API

简介:Camunda引擎提供了多种方式来查询数据。

主要功能

  • Java Queries:使用面向对象的API进行查询,适用于大多数场景。
  • Native Queries:直接构建SQL查询语句,适用于复杂或特定的需求。
示例

下面是一个查询任务的简单示例:

// Java 查询示例
List<Task> tasks = taskService.createTaskQuery()
  .taskAssignee("userOne")
  .processVariableValueEquals("orderId", "8888")
  .orderByDueDate().asc()
  .list();

// Native 查询示例
List<Task> tasks = taskService.createNativeTaskQuery()
  .sql("SELECT * FROM " + managementService.getTableName(Task.class) + " T WHERE T.NAME_ = #{taskName}")
  .parameter("taskName", "aOpenTask")
  .list();

Camunda 服务使用示例

在这里插入图片描述

进程过程中的变量数据

在Camunda BPM引擎中,流程实例变量(Process Instance Variables)是非常重要的概念,因为它们贯穿整个流程的生命周期,用于存储流程执行期间的数据。这些变量可以用来传递信息、控制流程逻辑、以及与其他系统集成。下面是一个关于流程变量从设置到使用的完整过程的讲解:

1. 定义变量

首先,在设计流程定义时,你需要考虑哪些数据需要在流程中传递。这些数据可以是输入参数、中间计算结果或者是输出结果。虽然在BPMN模型中没有直接定义变量的地方,但你可以通过流程节点的行为来隐式地定义变量。例如,你可以添加一个服务任务来设置初始变量。

2. 设置变量

一旦流程定义被部署,你就可以在启动流程实例时设置初始变量。这可以通过调用RuntimeServicestartProcessInstanceByKey方法来完成,并且可以传入一个Map类型的参数来设置初始变量。

Map类型是<String,Object>,也就是可以将定义的对象都能传进去

Map<String, Object> variables = new HashMap<>();
variables.put("orderId", "12345");
User user = new User();
variables.put("User",user)
runtimeService.startProcessInstanceByKey("orderApproval", variables);
3. 查询变量

在流程执行过程中,你可能需要查询某些变量的值。这可以通过RuntimeService提供的getVariablegetVariables方法来实现。

Object orderId = runtimeService.getVariable("processInstanceId", "orderId");
User user = (User) runtimeService.getVariable("processInstanceId", "User");
4. 修改变量

随着流程的推进,变量的值可能会发生变化。你可以通过服务任务中的脚本或服务调用来修改变量的值。修改变量可以通过setVariablesetVariables方法来完成。

runtimeService.setVariable("processInstanceId", "status", "approved");
5. 传递变量

变量不仅可以存储在流程实例中,还可以在流程节点之间传递。例如,当一个任务完成后,任务的结果可以作为变量传递给下一个任务或网关。

taskService.complete(taskId, variables);
6. 使用变量控制流程逻辑

流程中的某些决策点(如排他网关)可以根据变量的值来决定流程走向。例如,如果一个订单的金额超过一定阈值,则需要高级经理审批。

<exclusiveGateway id="approvalGateway">
    <conditionExpression xsi:type="tFormalExpression"
                         evaluatesToType="string">${amount > 1000}</conditionExpression>
</exclusiveGateway>
7. 变量的作用域

需要注意的是,流程变量有不同的作用域,包括流程实例级、执行级(如子流程)和任务级。不同作用域的变量可以在不同的上下文中访问。

8. 清理变量

当流程实例结束时,与之相关的变量也将不再可用。如果你需要长期存储某些数据,应该将其持久化到数据库或其他存储系统中。

示例场景

假设有一个订单审批流程,需要根据订单金额来决定审批流程。订单金额作为一个变量在流程开始时被设置,并在审批过程中被多个节点使用。

// 设置订单金额
Map<String, Object> variables = new HashMap<>();
variables.put("orderAmount", 1500);

// 启动流程实例
runtimeService.startProcessInstanceByKey("orderApproval", variables);

// 某个服务任务检查订单金额并修改状态
runtimeService.setVariable("processInstanceId", "approvalStatus", "pending");

// 用户完成任务时提交结果
Map<String, Object> completionVariables = new HashMap<>();
completionVariables.put("reviewResult", "approved");
taskService.complete(taskId, completionVariables);
通过变量查询任务

通过变量来查询任务或流程实例是Camunda BPM引擎中一个非常实用的功能。这使得开发者可以根据业务逻辑中的条件来动态查询流程的状态。以下是详细的步骤和示例,说明如何使用变量来查询任务或流程实例。

查询任务

假设你想要找到所有分配给了特定用户并且订单ID等于某特定值的任务,可以使用TaskService来执行这样的查询。

// 使用变量查询任务
List<Task> tasks = taskService.createTaskQuery()
    .taskAssignee("johnDoe") // 指定任务的分配者
    .processVariableValueEquals("orderId", "12345") // 使用变量值来过滤任务
    .list();

for (Task task : tasks) {
    System.out.println("Task ID: " + task.getId() + ", Name: " + task.getName());
}

在这个例子中,taskAssignee方法用来过滤分配给特定用户johnDoe的任务,而processVariableValueEquals方法则是根据流程实例中的变量orderId的值来进一步筛选任务。

查询流程实例

如果你需要根据变量来查询流程实例,可以使用RuntimeService来进行查询。例如,找出所有订单ID为特定值的流程实例。

// 使用变量查询流程实例
List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery()
    .variableValueEquals("orderId", "12345") // 使用变量值来过滤流程实例
    .list();

for (ProcessInstance instance : processInstances) {
    System.out.println("Process Instance ID: " + instance.getId() + ", Business Key: " + instance.getBusinessKey());
}

在这个例子中,variableValueEquals方法用来根据变量orderId的值来过滤流程实例。createProcessInstanceQuery方法创建了一个流程实例查询对象,然后通过这个对象可以指定查询条件。

更复杂的查询

如果你需要更复杂的查询条件,比如组合条件(AND/OR)、范围查询等,可以使用多个查询方法来组合条件。例如,你可以根据两个变量来查询任务:

List<Task> tasks = taskService.createTaskQuery()
    .taskAssignee("johnDoe")
    .processVariableValueEquals("orderId", "12345")
    .processVariableValueGreaterThan("amount", 1000)
    .list();

在这里,我们不仅根据orderId查询,而且还添加了一个额外的条件amount大于1000。

查询单一实例或任务

如果你只想获取单个结果而不是列表,可以使用singleResult方法代替list

Task singleTask = taskService.createTaskQuery()
    .taskAssignee("johnDoe")
    .processVariableValueEquals("orderId", "12345")
    .singleResult();

if (singleTask != null) {
    System.out.println("Found task: " + singleTask.getName());
} else {
    System.out.println("No task found.");
}

RepositoryService部署流程图

部署对象
        // 创建部署对象
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource(requestParam.getResourcePath()) // 添加资源路径
                .name(requestParam.getBpmnName()) // 设置部署名称
                .deploy(); // 部署流程定义

部署位置是相对于资源路径来说,比如:BPMN/名称.bpmn

在web中就可以看到部署的实例了:
在这里插入图片描述

在这里插入图片描述

删除部署对象
// 删除部署,默认情况下不会级联删除流程实例和Job
repositoryService.deleteDeployment(deploymentId);// deploymentId = deploy.getId()
获取流程实例
    @Override
    public String getBpmnModelInstance(String processDefinitionId) {
        // 获取流程模型实例
        BpmnModelInstance bpmnModelInstance = repositoryService.getBpmnModelInstance(processDefinitionId);

        if (ObjectUtil.isNotNull(bpmnModelInstance)) {
            // 获取模型中的所有用户任务
            Collection<UserTask> userTasks = bpmnModelInstance.getModelElementsByType(UserTask.class);
            // 获取模型定义
            Definitions definitions = bpmnModelInstance.getDefinitions();

            // 日志输出
            log.info("获取到流程模型实例:{}", bpmnModelInstance);
        }

        return null; // 返回提示信息,这里暂时返回null
    }

runtimeService开启流程实例

启动流程实例
Map<String, Object> paramMap = request.getVariables();

// businessKey用于查询用户对应业务的待办任务
org.camunda.bpm.engine.runtime.ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, request.getBusinessKey(), paramMap);

使用RuntimeService来启动一个新的流程实例,并传递业务键(businessKey)和流程变量(paramMap)。

拒绝流程实例
@Override
public String rejectProcessInstance(RejectInstanceRequest request) {
    String processInstanceId = request.getProcessInstanceId();
    ActivityInstance activity = runtimeService.getActivityInstance(processInstanceId);
    
    runtimeService.createProcessInstanceModification(processInstanceId)
            .cancelActivityInstance(activity.getId())
            .setAnnotation("驳回")
            .startBeforeActivity(request.getTargetNodeId())
            .execute();
    
    return "驳回成功";
}

使用RuntimeService来拒绝(即回退)一个流程实例,并将流程重定向到指定的活动节点。

  • .cancelActivityInstance(activity.getId()):取消当前活动实例。
  • .setAnnotation("驳回"):设置注释,用于标记此次操作的原因。
  • .startBeforeActivity(request.getTargetNodeId()):将流程实例重定向到指定的目标节点。
  • .execute():执行流程实例修改操作。
挂起实例

挂起流程实例是指暂停特定流程实例的执行,使其不能继续前进。你可以选择挂起单个流程实例,也可以挂起一组符合特定条件的流程实例。

    /**
     * 挂起流程定义
     *
     * @param processDefinitionId 流程定义ID
     * @return 提示信息
     */
    @Override
    public String suspendProcessDefinitionById(String processDefinitionId) {
        // 挂起流程定义
        repositoryService.suspendProcessDefinitionById(processDefinitionId); //也可以通过processDefinitionKey来挂起实例
        return "挂起成功";
    }

TaskService 操作详解

讲解TaskService中的“查询任务列表”和“完成任务”的操作。

查询任务列表
@Override
public List<Task> queryTasks(TaskQueryRequest request) {
    // 获取查询参数
    String assignee = request.getAssignee();
    String candidateGroup = request.getCandidateGroup();
    
    // 创建任务查询对象
    TaskQuery taskQuery = taskService.createTaskQuery()
        .taskAssignee(assignee) // 指定任务的分配者
    
    // 执行查询并返回任务列表
    List<Task> tasks = taskQuery.list();
    
    return tasks;
}
完成任务
@Override
public String completeTask(CompleteTaskRequest request) {
    // 获取任务ID和任务变量
    String taskId = request.getTaskId();
    Map<String, Object> taskVariables = request.getVariables();
    
    // 完成任务,并传递任务变量
    taskService.complete(taskId, taskVariables);
    
    return "任务完成";
}
示例

假设你需要查询分配给特定用户,并完成其中一个任务:

public class TaskQueryRequest {
    private String assignee;

    public TaskQueryRequest(String assignee) {
        this.assignee = assignee;
    }

    public String getAssignee() {
        return assignee;
    }

    public String getCandidateGroup() {
        return candidateGroup;
    }
}

public class CompleteTaskRequest {
    private String taskId;
    private Map<String, Object> variables;

    public CompleteTaskRequest(String taskId, Map<String, Object> variables) {
        this.taskId = taskId;
        this.variables = variables;
    }

    public String getTaskId() {
        return taskId;
    }

    public Map<String, Object> getVariables() {
        return variables;
    }
}

// 假设请求对象如下:
TaskQueryRequest queryRequest = new TaskQueryRequest("johnDoe");

// 查询任务
List<Task> tasks = taskService.queryTasks(queryRequest);

// 假设需要完成第一个任务
if (!tasks.isEmpty()) {
    Task task = tasks.get(0);
    CompleteTaskRequest completeRequest = new CompleteTaskRequest(task.getId(), Collections.singletonMap("result", "completed")); // 这是自己定义的方法
    
    // 完成任务
    String result = taskService.completeTask(completeRequest);
    System.out.println(result); // 输出 "任务完成"
}

文档md格式开源地址:springboot结合Camunda7简单快速入门教程文档
觉得写得不错的话,可以给个star(´・ω・`) 。

参考文章:
1.SpringBoot 优雅集成 Camunda 7以上 工作流引擎,保姆级教程!
2.Camunda修炼手册

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2190530.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

我的创作纪念日一年

目录 机缘 收获 日常 成就 憧憬 机缘 我之所以开始写CSDN博客&#xff0c;源于一段特殊的时光。去年此时&#xff0c;我独自待在实验室&#xff0c;周围的世界仿佛与我无关。没有旅游&#xff0c;没有与朋友的欢聚&#xff0c;情感的挫折和学业的压力如潮水般袭来。在这样的…

2025舜宇招聘【内推码】

【2025内推码】 DSwNQ9yu DSJXN8Mr 舜宇集团2025届全球校园招聘正式启动&#xff01;&#xff01;&#xff01; 专业需求&#xff1a;机械、自动化、电子、电气、通信、控制、测控、计算机、软件、物理、光学等专业&#xff1b; 工作地点&#xff1a;宁波余姚、浙江杭州、广东…

97. UE5 GAS RPG 实现闪电链技能(二)

书接上回&#xff0c;如果没有查看上一篇文章的同学推荐先看上一章&#xff0c;我们接着实现闪电链技能。 在上一章最后&#xff0c;我们实现了闪电链的第一条链&#xff0c;能够正确显示特效&#xff0c;接下来&#xff0c;我们先实现它的音效和一些bug修复。 我们在多端网络里…

(9)MATLAB瑞利衰落信道仿真2

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、瑞利衰落信道二、瑞利衰落信道建模三、仿真结果二、高斯随机变量和瑞利随机变量后续 前言 本文首先给出瑞利衰落信道模型&#xff0c;并根据瑞利衰落变量估…

乌班图基础设施安装之Mysql8.0+Redis6.X安装

简介&#xff1a;云服务器基础设施安装之 Mysql8.0Redis6.X 安装 Docker安装 # 按照依赖 yum install -y yum-utils device-mapper-persistent data lvm2 Docker Mirror 从去年开始. hub.docker.com[1] 在国内的访问速度极慢. 当时大家主要还是依赖国内的一些镜像源: 如中科…

【JNI】数组的基本使用

在上一期讲了基本类型的基本使用&#xff0c;这期来说一说数组的基本使用 HelloJNI.java&#xff1a;实现myArray函数&#xff0c;把一个整型数组转换为双精度型数组 public class HelloJNI { static {System.loadLibrary("hello"); }private native String HelloW…

AI编程工具的崛起:效率提升的未来在哪里?

你正在使用的编程工具会被淘汰吗&#xff1f;AI编程工具正在改变这一切&#xff01; 在日益忙碌的开发世界里&#xff0c;工具的选择决定了开发者的工作效率。在过去的十年里&#xff0c;从代码编辑器到版本控制工具&#xff0c;各种工具帮助开发者逐步优化了工作流程&#xf…

C/C++逆向:函数逆向分析-调用约定分析

在进行函数逆向分析时&#xff0c;分析其函数调用约定具有非常重要的作用&#xff0c;因为调用约定直接影响了函数的参数传递、返回值、栈管理、寄存器使用等多个方面&#xff0c;不同的编译器和平台可能有不同的默认调用约定&#xff0c;识别调用约定可以帮助判断代码是由哪种…

HTB:Mongod[WriteUP]

连接至HTB服务器并启动靶机 靶机IP&#xff1a;10.129.99.33 分配IP&#xff1a;10.10.16.12 1.How many TCP ports are open on the machine? 使用nmap对靶机进行全端口TCP脚本、服务扫描&#xff1a; nmap -sC -sV -T4 -p- {TARGET_IP} 可以看到靶机共开放TCP端口2个&…

LC108-将有序数组转化为二叉搜索树(二叉平衡树)

文章目录 1 题目2 思路3 ACM完整代码参考 1 题目 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡二叉搜索树 示例&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] 输出&#xff1a;[0,-3,9,-10,null,5] 解释&#xff1…

最佳语音识别 Whisper-large-v3-turbo 上线,速度更快(本地安装 )

Openai 上线语音模型whisper-large-v3-turbo 在本文中&#xff0c;我们将介绍 whisper-large-v3-turbo 以及 whisper-web&#xff08;一个直接在浏览器中进行ML语音识别的开源项目&#xff09;。 尽管近年来出现了许多音频和多模态模型&#xff0c;但Whisper 仍是生产级自动语音…

类型模板参数与非类型模板参数

在C中&#xff0c;模板参数分为两种类型&#xff1a;类型参数和非类型参数。类型参数是指定模板类型名称的参数&#xff0c;而非类型参数是指定模板整型常量的参数。 模板参数不限定于类型&#xff0c;普通值也可作为模板参数&#xff0c;但这里值的类型只能是整形家族&#x…

Qt教程(001):Qt概述与安装

文章目录 一、Qt概述1.1 什么是Qt1.2 Qt优点1.3 Qt发展史1.4 支持的平台1.5 成功案例1.6 下载安装1.7 QtCreator介绍 一、Qt概述 1.1 什么是Qt Qt是一个跨平台的C图形用户界面应用程序框架。它为应用程序开发者提供建立艺术级图形界面所需的所有功能。它是完全面向对象的&…

快乐数(c语言)

1.「快乐数」 定义为&#xff1a;对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。如果这个过程 结果为 1&#xff0c;那么这个数就是快乐数。如果 n 是 快乐数 就返…

打卡第三天 P5729 【深基5.例7】工艺品制作

今天是我打卡第三天&#xff0c;做个入门题吧(#^.^#) 题目描述 输入格式 输出格式 输出一个整数表示答案。 输入输出样例 输入 #1 4 4 4 1 1 1 1 2 2 2 输出 #1 56 说明/提示 C&#xff1a; #include<bits/stdc.h> using namespace std; long long a[100][100][1…

【ubuntu】修改用户名、主机名、主文件夹名、登录名、密码

目录 1.他们是什么 2.修改方法 2.1 修改用户密码 2.2 修改主机名 2.2.1 切换到root用户 2.2.2 修改名称 2.3 修改用户名 主文件夹名 登录名 2.2.1 sudoers 2.2.2 passwd 2.2.3 shadow 2.2.4 group 2.2.5 修改主文件夹名 3.重启 1.他们是什么 &#xff08;1&#xf…

初识 C 语言(2)

目录 一、sigined 和 unsigned1. unsigned 二、数据类型的取值范围三、变量的分类1. 局部变量2. 全局变量3. 全局变量和局部变量名称冲突 四、算数操作符1. 加法操作符&#xff08;&#xff09;2. 减法操作符&#xff08;-&#xff09;3. 乘法操作符&#xff08;\*&#xff09;…

认知杂谈96《反人性与顺人性》

内容摘要&#xff1a; 成长常被视为反人性的&#xff0c;因为它意味着要离开舒适区&#xff0c;面对挑战。然而&#xff0c;在与人共事时&#xff0c;顺应人性同样重要&#xff0c;它要求我们理解他人的需求和动机。为了平衡成长与顺应人性&#xff0c;我们应设定清晰目标&…

封装el-upload组件,用于上传图片和视频

使用环境 vue3element-ui plus 需要根据后端返回结构修改的函数&#xff1a;onPreview onRemove onSuccess 组件使用 基本使用 源代码&#xff1a; <script setup> import AutoUploadFile from /components/auto-upload-file/index.vue function change(urls){console.…

hdfs伪分布式集群搭建

1 准备 vmware 虚拟三台centos系统的节点三台机器安装好jdk环境关闭防火墙&#xff08;端口太多&#xff0c;需要的自行去开关端口&#xff09;hadoop压缩包解压至三台服务器 可在一台节点上配置完成后克隆为三台节点 2 host修改 vi /etc/hosts在每个节点上添加三台机器的i…