SpringBoot 集成 Activiti 7 工作流引擎

一. 版本信息

  1. IntelliJ IDEA 2023.3.6
  2. JDK 17
  3. Activiti 7

二. IDEA依赖插件安装

安装BPM流程图插件,如果IDEA的版本超过2020,则不支持actiBPM插件。我的IDEA是2023版本我装的是 Activiti BPMN visualizer 插件。

  1. 在Plugins 搜索 Activiti BPMN visualizer 安装
  2. 创建BPMN文件

  3. 使用视图模式打开bpmn.xml

三. 创建SpringBoot 集成 activiti7

  1. 使用 IDEA 创建SpringBoot项目

  2. 设置项目参数

  3. 在 pom.xml 依赖配置文件中添加(Mysql,Lombok,activiti7)依赖

    <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>3.3.4</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com</groupId>
        <artifactId>activiti-demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>activiti-demo</name>
        <description>activiti-demo</description>
        <properties>
            <java.version>17</java.version>
        </properties>
        <dependencies>
            <!-- web依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!-- mysql依赖 -->
            <dependency>
                <groupId>com.mysql</groupId>
                <artifactId>mysql-connector-j</artifactId>
                <version>8.2.0</version>
            </dependency>
    
            <!-- lombok依赖 -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
    
            <!-- mybatis数据访问层 -->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
                <version>3.5.7</version>
            </dependency>
    
            <!-- activiti7 工作流引擎依赖  -->
            <dependency>
                <groupId>org.activiti</groupId>
                <artifactId>activiti-spring-boot-starter</artifactId>
                <version>7.1.0.M6</version>
            </dependency>
    
            <!-- 模块测试依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <excludes>
                            <exclude>
                                <groupId>org.projectlombok</groupId>
                                <artifactId>lombok</artifactId>
                            </exclude>
                        </excludes>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
  4. 创建本地连接的数据库
    创建数据库 activiti

    CREATE DATABASE `activiti` /*!40100 DEFAULT CHARACTER SET utf8 */;
    

    创建数据库表 user

    -- activiti.`user` definition
    
    CREATE TABLE `user` (
      `ID` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
      `NAME` varchar(100) DEFAULT NULL COMMENT '名称',
      `AGE` varchar(100) DEFAULT NULL COMMENT '年龄',
      `CREATED_BY` varchar(32) DEFAULT NULL COMMENT '创建人名称',
      `CREATED_TIME` datetime DEFAULT NULL COMMENT '创建时间',
      `CREATED_ID` varchar(32) DEFAULT NULL COMMENT '创建人ID',
      `UPDATED_BY` varchar(32) DEFAULT NULL COMMENT '更新人名称',
      `UPDATED_TIME` datetime DEFAULT NULL COMMENT '更新时间',
      `UPDATED_ID` varchar(32) DEFAULT NULL COMMENT '更新人ID',
      PRIMARY KEY (`ID`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表';
    

    添加一条测试数据

    INSERT INTO activiti.`user`
    (ID, NAME, AGE, CREATED_BY, CREATED_TIME, CREATED_ID, UPDATED_BY, UPDATED_TIME, UPDATED_ID)
    VALUES(1, '小王', '24', NULL, NULL, NULL, NULL, NULL, NULL);
    
  5. 添加 application.yml 配置文件

    spring:
      application:
        name: activiti-demo
      datasource:
        #url切换数据库之后如果对应数据库名称和路径有变动,需要修改url
        url: jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: root
        driver-class-name: com.mysql.cj.jdbc.Driver
    
  6. 添加 activiti.cfg.xml 配置文件(文件名不能随便改)

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans [
            <!ELEMENT beans (bean)*>
            <!ATTLIST beans
                    xmlns CDATA #REQUIRED
                    xmlns:xsi CDATA #REQUIRED
                    xsi:schemaLocation CDATA #REQUIRED>
            <!ELEMENT bean (property)*>
            <!ATTLIST bean
                    id CDATA #REQUIRED
                    class CDATA #REQUIRED>
            <!ELEMENT property (#PCDATA)>
            <!ATTLIST property
                    name CDATA #REQUIRED
                    value CDATA #REQUIRED>
            ]>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!-- processEnqine Activiti 的流程引擎 -->
        <bean id="processEngineConfiguration"
              class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
            <property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="jdbcUrl"
                      value="jdbc:mysql://localhost:3306/activiti?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai&amp;useSSL=false&amp;nullCatalogMeansCurrent=true"/>
            <property name="jdbcUsername" value="root"/>
            <property name="jdbcPassword" value="root"/>
    
            <!-- activiti 数据库表处理策略 -->
            <!-- databaseSchemaUpdate 属性的值可以设置为以下几种 -->
            <!-- none:这是默认值,表示不对数据库模式做任何变更,应用程序启动时不会检查数据库表结构是否与实体类匹配-->
            <!-- true:设置为 true 时,Spring会在应用程序启动时检查数据库表结构,并在发现不匹配时自动创建或修改表结构以匹配实体类定义。这相当于执行了数据库迁移-->
            <!-- create:与 true 类似,但 create 会在每次启动时删除并重新创建表,这可能会导致数据丢失,因此使用时需要谨慎-->
            <!-- create-drop:在每次启动应用程序时创建表,在关闭应用程序时删除表。这通常用于测试环境-->
            <!-- validate:在启动时验证数据库表结构是否与实体类定义匹配,如果不匹配则抛出异常,但不会自动进行任何更改-->
            <property name="databaseSchemaUpdate" value="true"/>
    
        </bean>
    </beans>
    
  7. 启动SpringBoot项目成功

  8. 开始添加一个查询数据测试接口(Controller,Service,Mapper,Entity)
    Controller类

    package com.activitidemo.act.controller;
    
    
    import com.activitidemo.act.entity.UserEntity;
    import com.activitidemo.act.service.impl.UserServiceImp;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import jakarta.annotation.Resource;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * <p>
     *  前端控制器
     * </p>
     *
     * @author ningbeibei
     * @since 2024-09-26
     */
    @RestController
    @RequestMapping("/user-entity")
    public class UserController {
    
        @Resource
        private UserServiceImp userService;
    
        @PostMapping("/user")
        public Object getUser(@RequestBody UserEntity user){
            QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id",user.getId());
            return userService.getBaseMapper().selectList(queryWrapper);
        }
    
    }
    

    Service 类

    package com.activitidemo.act.service;
    
    import com.activitidemo.act.entity.UserEntity;
    import com.baomidou.mybatisplus.extension.service.IService;
    
    /**
     * @author ningbeibei
     * @since 2024-09-26
     */
    public interface UserService extends IService<UserEntity> {
    
    }
    
    
    package com.activitidemo.act.service.impl;
    
    import com.activitidemo.act.mapper.UserMapper;
    import com.activitidemo.act.service.UserService;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import org.springframework.stereotype.Service;
    import com.activitidemo.act.entity.UserEntity;
    
    /**
     * <p>
     * 服务实现类
     * </p>
     *
     * @author ningbeibei
     * @since 2024-09-26
     */
    @Service
    public class UserServiceImp extends ServiceImpl<UserMapper, UserEntity> implements UserService {
    }
    

    Mapper 类

    package com.activitidemo.act.mapper;
    
    import com.activitidemo.act.entity.UserEntity;
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import org.apache.ibatis.annotations.Mapper;
    
    /**
     * <p>
     *  Mapper 接口
     * </p>
     *
     * @author ningbeibei
     * @since 2024-09-26
     */
    @Mapper
    public interface UserMapper extends BaseMapper<UserEntity> {
    
    }
    
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.activitidemo.act.entity.UserEntity">
    
    </mapper>
    

    Entity 类

    package com.activitidemo.act.entity;
    
    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableName;
    import lombok.Getter;
    import lombok.Setter;
    
    import java.io.Serializable;
    import java.time.LocalDateTime;
    
    /**
     * @author ningbeibei
     * @since 2024-09-26
     */
    @Getter
    @Setter
    @TableName("user")
    public class UserEntity implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        @TableField("ID")
        private Integer id;
    
        @TableField("NAME")
        private String name;
    
        @TableField("AGE")
        private int age;
    
        @TableField("CREATED_BY")
        private String createdBy;
    
        @TableField("CREATED_TIME")
        private LocalDateTime createdTime;
    
        @TableField("CREATED_ID")
        private String createdId;
    
        @TableField("UPDATED_BY")
        private String updatedBy;
    
        @TableField("UPDATED_TIME")
        private LocalDateTime updatedTime;
    
        @TableField("UPDATED_ID")
        private String updatedId;
    
    
    }
    

    目录结构

  9. 使用Postman接口测试工具,测试接口是否正常

四. Activiti 使用步骤

Activiti 主要流程操作步骤:

  1. **定义流程:**按照BPMN的规范,使用流程定义工具,用流程符号把整个流程描述出来。
  2. **部署流程:**把画好的流程定义文件,加载到数据库中,生成表的数据。
  3. **启动流程:**使用 java 代码来操作数据库表中的内容。
  4. **处理任务:**操作流程当中的各个任务。

1. 定义流程

2. 初始库表、定义、部署、操作任务代码

创建测试类

测试代码:

package com.activitidemo;

import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.FileCopyUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

@SpringBootTest
class ActivitiDemoApplicationTests {


    // 创建 ProcessEngine 对象
//    private ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();




//    /**
//     * 初始化数据库表:第一种方式
//     */
//    @Test
//    public void testInitOne() {
//        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        System.err.println("processEngine = " + processEngine);
//    }


    /**
     * 初始化数据库表
     * 通过读取 activiti.cfg.xml 配置文件
     */
    @Test
    public void testInitTwo() {
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        System.err.println("processEngine = " + processEngine);
    }

    /**
     * 流程部署
     */
    @Test
    public void testDeploy() {
        // 创建 ProcessEngine 对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取 repositoryService 对象
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 进行部署
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("process/leave.bpmn20.xml")
                .addClasspathResource("process/leave.bpmn20.png")
                .name("请假流程")
                .deploy();
        // 输出部署的一些信息
        System.out.println("流程部署ID:" + deployment.getId());
        System.out.println("流程部署名称:" + deployment.getName());
        System.out.println("流程部署成功");
    }

        /**
     * 启动流程实例
     */
    @Test
    public void testStartProcess() {
        // 创建 ProcessEngine 对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取 runtimeService 对象
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 1.根据流程定义的key启动流程实例,这个key是在定义bpmn的时候设置的
        ProcessInstance instance = runtimeService.startProcessInstanceByKey("leave");
        // 2.根据流程定义id启动流程实例
//        ProcessInstance instance = runtimeService.startProcessInstanceById("leave:1:4");

        // 获取流程实例的相关信息
        System.out.println("流程定义的id = " + instance.getProcessDefinitionId());
        System.out.println("流程实例的id = " + instance.getId());
        System.out.println("启动流程成功 ");
    }



    /**
     * 查询待办任务
     */
    @Test
    public void testSelectTodoTaskList() {
        String assignee = "李四";
        // 创建 ProcessEngine 对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取指定用户审核任务
        TaskService taskService = processEngine.getTaskService();
        // 使用面对对象方式查询数据库
        List<Task> tasks = taskService.createTaskQuery()
                .processDefinitionKey("leave")
                .taskAssignee(assignee)
                // 返回多个结果
                .list();
        // 只返回一个结果
        // .singleResult();

        // 自定义 sql 查询
        // taskService.createNativeTaskQuery();

        // 获取流程实例的相关信息
        for (Task task : tasks) {
            System.out.println("流程定义的id = " + task.getProcessDefinitionId());
            System.out.println("流程实例的id = " + task.getProcessInstanceId());
            System.out.println("任务id = " + task.getId());
            System.out.println("任务名称 = " + task.getName());
        }
    }


    /**
     * 指定用户去完成任务待办:多人审批在这操作,改变审核人名称就行了
     */
    @Test
    public void testCompleteTask() {
        String assignee = "李四";
        // 创建 ProcessEngine 对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取指定用户审核任务
        TaskService taskService = processEngine.getTaskService();
        List<Task> tasks = taskService.createTaskQuery()
                .processDefinitionKey("leave")
                .taskAssignee(assignee)
                .list();
        if (tasks != null && !tasks.isEmpty()){
            // 当前流程图所限制,只能做审核同意的动作
            for (Task task : tasks) {
                taskService.complete(task.getId());
            }
        }
    }


    /**
     * 审批添加备注
     */
    @Test
    public void testAddComment() {
        String assignee = "张三";
        // 创建 ProcessEngine 对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取指定用户审核任务
        TaskService taskService = processEngine.getTaskService();
        List<Task> tasks = taskService.createTaskQuery()
                .processDefinitionKey("leave")
                .taskAssignee(assignee)
                .list();
        if (tasks != null && !tasks.isEmpty()) {
            // 当前流程图所限制,只能做审核同意的动作
            for (Task task : tasks) {
                // 添加备注
                taskService.addComment(task.getId(), task.getProcessInstanceId(), assignee + "表示同意");
                taskService.complete(task.getId());
            }
        }
    }


    /**
     * 查询审批历史
     */
    @Test
    public void testSelectHistoryTask() {
        String processInstanceId = "2501";
        String assignee = "张三";
        // 创建 ProcessEngine 对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 查看历史信息
        HistoryService historyService = processEngine.getHistoryService();
        // 获取指定用户审核任务
        TaskService taskService = processEngine.getTaskService();
        // 获取历史审核信息
        List<HistoricActivityInstance> userTask = historyService.createHistoricActivityInstanceQuery()
                .activityType("userTask")
                // 指定实例的id
                .processInstanceId(processInstanceId)
                .taskAssignee(assignee)
                .finished()
                .list();

        for (HistoricActivityInstance instance : userTask) {
            System.out.println("任务名称 = " + instance.getActivityName());
            System.out.println("任务开始时间 = " + instance.getStartTime());
            System.out.println("任务结束时间 = " + instance.getEndTime());
            System.out.println("任务耗时 = " + instance.getDurationInMillis());
            // 获取审批批注信息
            List<Comment> taskComments = taskService.getTaskComments(instance.getTaskId());
            if (!taskComments.isEmpty()){
                System.out.println("审批批注 = " + taskComments.get(0).getFullMessage());
            }
        }
    }


    /**
     * 查询流程相关信息
     */
    @Test
    public void testDefinitionQuery() {
        // 创建 ProcessEngine 对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取仓库服务
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 获取流程定义集合
        List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("leave")
                // 最新的一个版本
                .latestVersion()
                .list();
        // 遍历集合
        for (ProcessDefinition definition : processDefinitionList) {
            System.out.println("流程定义id = " + definition.getId());
            System.out.println("流程定义名称 = " + definition.getName());
            System.out.println("流程定义key = " + definition.getKey());
            System.out.println("流程定义版本 = " + definition.getVersion());
            System.out.println("流程部署id = " + definition.getDeploymentId());
            System.out.println("===============");
        }
    }


    /**
     * 资源文件下载
     */
    @Test
    public void testDownloadResource() throws IOException {
        // 创建 ProcessEngine 对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取仓库服务
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 获取流程定义集合
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("leave")
                // 按照版本降序
                .orderByProcessDefinitionVersion()
                // 降序
                .desc()
                .list();

        // 获取最新那个
        ProcessDefinition definition = list.get(0);
        // 获取部署id
        String deploymentId = definition.getDeploymentId();

        // 获取bpmn的输入流
        InputStream bpmnInputStream = repositoryService.getResourceAsStream(deploymentId, definition.getResourceName());
        // 获取png的输入流
//        InputStream pngInputStream = repositoryService.getResourceAsStream(deploymentId, definition.getDiagramResourceName());

        String resourcePath = "C:/Users/ASUS/Desktop/" + File.separator + definition.getResourceName();
        File file = new File(resourcePath);
        if (!file.exists()) {
            file.getParentFile().mkdirs();
        }

        String diagramResourcePath = "C:/Users/ASUS/Desktop/" + File.separator + definition.getDiagramResourceName();
        file = new File(diagramResourcePath);
        if (!file.exists()) {
            file.getParentFile().mkdirs();
        }

        //复制文件
        FileCopyUtils.copy(bpmnInputStream, Files.newOutputStream(Paths.get(resourcePath)));
//        FileCopyUtils.copy(pngInputStream, Files.newOutputStream(Paths.get(diagramResourcePath)));
    }


    /**
     * 删除已经部署的流程定义
     */
    @Test
    public void testDeleteDeploy() {
        // 删除已经部署的流程定义
        String deploymentId = "45001";
        // 创建 ProcessEngine 对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取仓库服务
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 删除流程定义,如果改流程定义已有流程实例启动,则会报错
//        repositoryService.deleteDeployment(deploymentId);
        // 设置 true,级联删除流程定义,即使有启动的实例也可以删除
        repositoryService.deleteDeployment(deploymentId, true);
    }


    /**
     * 启动流程,需要进行 BusinessKey 绑定流程实例
     */
    @Test
    public void testStartBindBusinessKey() {
        String businessKey = "1";
        // 创建 ProcessEngine 对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 根据流程定义的key启动流程实例,这个key是在定义bpmn的时候设置的
        // 在启动流程的时候将业务key加进去
        ProcessInstance instance = runtimeService.startProcessInstanceByKey("leave", businessKey);
        // 获取流程实例的相关信息
        System.out.println("流程定义id = " + instance.getProcessDefinitionId());
        System.out.println("流程实例id = " + instance.getId());
        System.out.println("业务标识 = " + instance.getBusinessKey());
    }


    /**
     * 跑到下一个节点,需要进行审批了,此时需要获取 BusinessKey 进而获取请假单信息
     */
    @Test
    public void testGetBusinessKey() {
        // 1、获取李四的待办信息
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        List<Task> task = taskService.createTaskQuery()
                .taskAssignee("李四")
                .processDefinitionKey("leave")
                .list();

        // 2、获取 businessKey
        // 获取流程实例id
        String processInstanceId = task.get(1).getProcessInstanceId();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        String businessKey = processInstance.getBusinessKey();

        System.out.println("业务标识 = " + businessKey);
    }


    /**
     * 流程定义挂起与激活
     */
    @Test
    public void testSuspendAllProcessInstance() {
        // 创建 ProcessEngine 对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取仓库服务
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 获取流程定义对象
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("leave")
                .singleResult();
        boolean suspended = processDefinition.isSuspended();
        // 输出流程定义状态
        System.out.println("流程定义状态:" + (suspended ? "已挂起" : "已激活"));
        String processDefinitionId = processDefinition.getId();

        if (suspended) {
            repositoryService.activateProcessDefinitionById(processDefinitionId, true, null);
            System.out.println("流程id:" + processDefinitionId + "已激活");
        } else {
            repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null);
            System.out.println("流程id:" + processDefinitionId + "已挂起");
        }
    }


    /**
     * 流程实例挂起与激活
     */
    @Test
    public void testProcessInstance() {
        // 创建 ProcessEngine 对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 获取流程定义对象
        List<ProcessInstance> processInstanceList = runtimeService.createProcessInstanceQuery()
                .processDefinitionKey("leave")
                .list();

        // 遍历集合
        for (ProcessInstance processInstance  : processInstanceList) {
            boolean suspended = processInstance.isSuspended();
            // 输出流程定义状态
            System.out.println("流程实例状态:" + processInstance + "," + (suspended ? "已挂起" : "已激活"));
            String processDefinitionId = processInstance.getId();

            if (suspended) {
                runtimeService.activateProcessInstanceById(processDefinitionId);
                System.out.println("流程实例id:" + processDefinitionId + "已激活");
            } else {
                runtimeService.suspendProcessInstanceById(processDefinitionId);
                System.out.println("流程实例id:" + processDefinitionId + "已挂起");
            }
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

分布式版本管理工具——Git关联远程仓库(github+gitee)

Git远程仓库&#xff08;Github&#xff09;的基本使用 一、前言二、Git远程仓库介绍三、演示1. 关联github远程仓库2. 关联gitee&#xff08;码云&#xff09;远程仓库3. 重命名远程仓库名4. 移除远程仓库 四、结束语 一、前言 古之立大事者&#xff0c;不惟有超世之才&#x…

python-leetcode-删除有序数组中的重复项 II

80. 删除有序数组中的重复项 II - 力扣&#xff08;LeetCode&#xff09; class Solution:def removeDuplicates(self, nums: List[int]) -> int:n len(nums)if n < 2:return n # 如果长度小于等于 2&#xff0c;直接返回长度k 2 # 指针 k 指向下一个有效位置&#x…

欧科云链OKLink:比特币与以太坊“双重启动”将如何撬动市场?

近日&#xff0c;OKLink 与 137Labs 联合举办 X Space&#xff0c;围绕宏观经济环境、政策及机构投资的影响等话题&#xff0c;分享如何把握 Web3 中的潜在机会与辨别风险。OKG Research 首席研究员 Hedy、BuilderRocket Accelerator 研究合伙人 Vivienna、VC 分析员 Bunny、BU…

【Linux】Socket编程-UDP构建自己的C++服务器

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Linux 目录 一&#xff1a;&#x1f525; UDP 网络编程 &#x1f98b; 接口讲解&#x1f98b; V1 版本 - echo server&#x1f98b; V2 版本 - DictServer&#x1f98b; V3 版本 - 简单聊天室 二&a…

创建型设计模式、结构型设计模式与行为型设计模式 上下文任务通用方案 设计模式 大全

设计模式&#xff08;Design Pattern&#xff09;是一种面向对象编程思想&#xff0c;分为创建型模式、结构型模式与行为型模式三大类&#xff0c;提供在特定上下文中解决常见任务通用方案&#xff0c;旨在让程序&#xff08;软件&#xff09;具有更好特点&#xff0c;如降低耦…

如何查看下载到本地的大模型的具体大小?占了多少存储空间:Llama-3.1-8B下载到本地大概15GB

这里介绍一下tree命令&#xff0c;可以方便的查看文件目录结构和文件大小。 命令行tree的具体使用&#xff0c;请参考笔者的另一篇博客&#xff1a;深入了解 Linux tree 命令及其常用选项&#xff1a;Linux如何显示目录结构和文件大小&#xff0c;一言以蔽之&#xff0c;sudo a…

MySQL线上事故:使用`WHERE`条件`!=xxx`无法查询到NULL数据

前言 在一次 MySQL 的线上查询操作中&#xff0c;因为 ! 的特性导致未能正确查询到为 NULL 的数据&#xff0c;险些引发严重后果。本文将详细解析 NULL 在 SQL 中的行为&#xff0c;如何避免类似问题&#xff0c;并提供实际操作建议。 1. 为什么NULL会查询不到&#xff1f; 在…

4G报警器WT2003H-16S低功耗语音芯片方案开发-实时音频上传

一、引言 在当今社会&#xff0c;安全问题始终是人们关注的重中之重。无论是家庭、企业还是公共场所&#xff0c;都需要一套可靠的安全防护系统来保障人员和财产的安全。随着科技的飞速发展&#xff0c;4G 报警器应运而生&#xff0c;为安全防范领域带来了全新的解决方案。…

U盘格式化工具合集:6个免费的U盘格式化工具

在日常使用中&#xff0c;U盘可能会因为文件系统不兼容、数据损坏或使用需求发生改变而需要进行格式化。一个合适的格式化工具不仅可以清理存储空间&#xff0c;还能解决部分存储问题。本文为大家精选了6款免费的U盘格式化工具&#xff0c;并详细介绍它们的功能、使用方法、优缺…

玩转OCR | 腾讯云智能结构化OCR初次体验

目录 一、什么是OCR&#xff08;需要了解&#xff09; 二、产品概述与核心优势 产品概述 智能结构化能做什么 举例说明&#xff08;选看&#xff09; 1、物流单据识别 2、常见证件识别 3、票据单据识别 4、行业材料识别 三、产品特性 高精度 泛化性 易用性 四、…

基于微信小程序的校园自助打印系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了多年的设计程序开发&#xff0c;开发过上千套设计程序&#xff0c;没有什么华丽的语言&#xff0c;只有实…

driftingblues6_vh靶机

首先把靶机换成NAT模式 使用 arp-scan 命令扫描网段内存活的主机&#xff0c;以获取靶机ip地址 arp-scn -l 尝试访问ip 使用御剑扫描子域名&#xff0c;尝试访问robots.txt文件 通过访问文件我们发现了一个/textpattern/textpattern目录 访问一下目录发现了登录页面 他还给了…

STM32使用UART发送字符串与printf输出重定向

首先我们先看STM32F103C8T6的电路图 由图可知&#xff0c;其PA9和PA10引脚分别为UART的TX和RX(注意&#xff1a;这个电路图是错误的&#xff0c;应该是PA9是X而PA9是RX&#xff0c;我们看下图的官方文件可以看出)&#xff0c;那么接下来我们应该找到该引脚的定义是什么&#xf…

数据库自增 id 过大导致前端时数据丢失

可以看到&#xff0c;前端响应参数是没有丢失精度的 但是在接受 axios 请求参数时出现了精度丢失 解决方案一&#xff1a;改变 axios 字符编码 axios.defaults.headers[Content-Type] application/json;charsetUTF-8; 未解决 解决方案二&#xff1a;手动使用 json.parse() …

SpringBoot教程(三十二) SpringBoot集成Skywalking链路跟踪

SpringBoot教程&#xff08;三十二&#xff09; | SpringBoot集成Skywalking链路跟踪 一、Skywalking是什么&#xff1f;二、Skywalking与JDK版本的对应关系三、Skywalking下载四、Skywalking 数据存储五、Skywalking 的启动六、部署探针 前提&#xff1a; Agents 8.9.0 放入 …

闻泰科技涨停-操盘训练营实战-选股和操作技术解密

如上图&#xff0c;闻泰科技&#xff0c;今日涨停&#xff0c;这是前两天分享布局的一个潜伏短线的标的。 选股思路&#xff1a; 1.主图指标三条智能辅助线粘合聚拢&#xff0c;即将选择方向 2.上图红色框住部分&#xff0c;在三线聚拢位置&#xff0c;震荡筑底&#xff0c;…

计算机体系结构期末复习3:GPU架构及控制流问题

目录 一、GPU设计思路 1.简化流水线、增加核数 2.单指令多线程&#xff08;SIMT&#xff09; 3.同时驻留大量线程 4.总思路&#xff1a;多线程单指令多线程 二、GPU的控制流问题 1.什么是控制流问题 2.怎么应对分支分歧 一、GPU设计思路 1.简化流水线、增加核数 2.单指…

面试241228

面试可参考 1、cas的概念 2、AQS的概念 3、redis的数据结构 使用场景 不熟 4、redis list 扩容流程 5、dubbo 怎么进行服务注册和调用&#xff0c;6、dubbo 预热 7如何解决cos上传的安全问题kafka的高并发高吞吐的原因ES倒排索引的原理 spring的 bean的 二级缓存和三级缓存 spr…

2024 年发布的 Android AI 手机都有什么功能?

大家好&#xff0c;我是拭心。 2024 年是 AI 快速发展的一年&#xff0c;这一年 AI 再获诺贝尔奖&#xff0c;微软/苹果/谷歌等巨头纷纷拥抱 AI&#xff0c;多款强大的 AI 手机进入我们的生活。 今年全球 16% 的智能手机出货量为 AI 手机&#xff0c;到 2028 年&#xff0c;这…

SimForge HSF 案例分享|复杂仿真应用定制——UAVSim无人机仿真APP(技术篇)

导读 「神工坊」核心技术——「SimForge HSF高性能数值模拟引擎」支持工程计算应用的快速开发、自动并行&#xff0c;以及多域耦合、AI求解加速&#xff0c;目前已实现航发整机数值模拟等多个系统级高保真数值模拟应用落地&#xff0c;支持10亿阶、100w核心量级的高效求解。其低…