Springboot 集成Activiti 7

686 阅读9分钟

title:Springboot 集成Activiti 7 author: 果味怪叔叔

Springboot 集成Activiti 7

[TOC]

一、 Activiti简介:sailboat:

Activiti 是一个工作流引擎,它可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言 BPMN2.0 进行定义,业务流程按照预先定义的流程进行执行,实现了系统的流程由 Activiti 进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统的健壮性,同时也减少了系统开发维护成本。

官方网站:www.activiti.org/ [ppnMwD0.png

二、 环境准备:cactus:

2.1 Eclipse 安装组件Activiti

击Help-install new software

ppnMza8.png

2.2 点击Add

ppnQ9Pg.png

2.3 填写name和location

Name:Activiti BPMN 2.0 designer

Location:activiti.org/designer/up… (插件更新地址)

ppnQP2j.png

2.4 勾选如图所示,点击next

ppnQeaT.png

2.5 点击next

ppnQMRJ.png

2.6 勾选接受 点击finish

ppnQ1MR.png

2.7 install anyway

ppnQJZ6.png

2.8 重启eclipse

ppnQtIO.png

2.9 点击File-New-Other

ppnQUiD.png

2.10 验证安装成功的标识

ppnQwzd.png

三、 Springboot 集成Activiti :flags:

3.1 在Eclipse 绘制 流程图

3.2 springboot 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 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>2.7.9</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.yongliang.activiti</groupId>
    <artifactId>boot-activiti</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>boot-activiti</name>
    <description>boot-activiti</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <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>

        <!--springboot 集成activiti-->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter</artifactId>
            <version>7.1.0.M5</version>
        </dependency>
        <dependency>
            <groupId>org.activiti.dependencies</groupId>
            <artifactId>activiti-dependencies</artifactId>
            <version>7.1.0.M5</version>
            <type>pom</type>
        </dependency>
        <!-- 生成流程图 -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-image-generator</artifactId>
            <version>7.1.0.M5</version>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </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>

3.3 springboot application.yml 配置文件参数修改

server:
  port: 8090
spring:
  application:
    name: boot-activiti
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/activiti3?useUnicode=true&useSSL=false&serverTimezone=UTC&characterEncoding=UTF8&nullCatalogMeansCurrent=true
    username: root
    password: zyl00712
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      # 等待连接池分配连接的最大时间(毫秒),超过这个时长还没有可用的连接,则会抛出SQLException
      connection-timeout: 30000
      # 最小连接数
      minimum-idle: 5
      # 最大连接数
      maximum-pool-size: 20
      #自动提交
      auto-commit: true
      # 连接超时的最大时长(毫秒),超时则会被释放(retired)
      idle-timeout: 600000
      #  连接池的名字
      pool-name: DataSourceHikariCP
      # 连接池的最大生命时长(毫秒),超时则会被释放(retired)
      max-lifetime: 18000000
  # activiti7配置
  activiti:
    # 自动部署验证设置:true-开启(默认)、false-关闭
    check-process-definitions: false
    # 保存历史数据
    history-level: full
    # 检测历史表是否存在
    db-history-used: true
    # 关闭自动部署
    deployment-mode: never-fail
    # 对数据库中所有表进行更新操作,如果表不存在,则自动创建
    # create_drop:启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)
    # drop-create:启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
    database-schema-update: true
    # 解决频繁查询SQL问题
    async-executor-activate: false



3.3 启动服务

3.3.1 初始化数据表

修改配置文件后,进行项目启动,项目启动成功会自动生成 25 张数据表

-- ----------------------------
-- 修复Activiti7的M4版本缺失字段Bug
-- ----------------------------
alter table ACT_RE_DEPLOYMENT add column PROJECT_RELEASE_VERSION_ varchar(255) DEFAULT NULL;
alter table ACT_RE_DEPLOYMENT add column VERSION_ varchar(255) DEFAULT NULL;

3.3.2 数据表解读

Activiti 使用到的表都是 ACT_ 开头的,表名的第二部分表示用途。

ACT_GE_ (GE) 表示 general 全局通用数据及设置,各种情况都使用的数据。 ACT_HI_ (HI) 表示 history 历史数据表,包含着程执行的历史相关数据。 ACT_RE_ (RE) 表示 repository 存储,包含的是静态信息。 ACT_RU_ (RU) 表示 runtime 运行时,运行时的流程变量,用户任务,变量,职责(job)等运行时数据。Activiti 只存储实例执行期间的运行时数据,当流程实例结束时,将删除这些记录

3.3.3 全局通用数据(ACT_GE_*)

表名解释
ACT_GE_BYTEARRAY二进制数据表,存储通用的流程定义和流程资源。
ACT_GE_PROPERTY系统相关属性,属性数据表存储整个流程引擎级别的数据。

3.3.4 历史数据表(ACT_HI_*)

表名解释
ACT_HI_ACTINST历史节点表
ACT_HI_ATTACHMENT历史附件表
ACT_HI_COMMENT历史意见表
ACT_HI_DETAIL历史详情表,提供历史变量的查询
ACT_HI_IDENTITYLINK历史流程人员表
ACT_HI_PROCINST历史流程实例表
ACT_HI_TASKINST历史任务实例表
ACT_HI_VARINST历史变量表

3.3.5 静态信息表(ACT_RE_*)

表名解释
ACT_RE_DEPLOYMENT部署信息表
ACT_RE_MODEL流程设计模型部署表
ACT_RE_PROCDEF流程定义数据表

3.3.6 运行数据(ACT_RU_*)

表名解释
ACT_RU_DEADLETTER_JOB无法执行工作表: 如果一个任务执行了很多次,都无法执行,那么这个任务会写到
ACT_RU_EVENT_SUBSCR运行时事件 throwEvent、catchEvent 时间监听信息表
ACT_RU_EXECUTION运行时流程执行实例
ACT_RU_IDENTITYLINK运行时流程人员表,主要存储任务节点与参与者的相关信息
ACT_RU_INTEGRATION运行时积分表
ACT_RU_JOB运行时定时任务数据表
ACT_RU_SUSPENDED_JOB暂停的工作,流程中有一个定时任务,如果把这个任务停止工作了,这个任务会在act_ru_suspended_job中写入数据
ACT_RU_TASK运行时任务节点表
ACT_RU_TIMER_JOB运行时定时器作业表
ACT_RU_VARIABLE运行时流程变量数据表

3.3.7其它表

表名解释
ACT_EVT_LOG事件日志
ACT_PROCDEF_INFO流程定义的动态变更信息

3.5 快速部署

流程部署方式分为两种:自动部署与手动部署

  • 自动部署

自动部署:将 bpmn 文件放入 resources 资源目录下的 processes 文件夹中,项目启动时则进行自动部署。

  • 手动部署

新建测试类,并编写流程部署测试方法。

  • 新增springboot 配置类SpringSecurityConfiguration
package com.yongliang.activiti.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName: SpringSecurityConfiguration
 * @Description:
 * @Author: zhangyongliang
 * @Date: 2023/3/9 12:12
 * @Version: V2.3
 */
@Slf4j
@Configuration
public class SpringSecurityConfiguration {
    @Bean
    public UserDetailsService myUserDetailsService() {
        InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
        //这里添加用户,后面处理流程时用到的任务负责人,需要添加在这里
        String[][] usersGroupsAndRoles = {
                {"jack", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
                {"rose", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
                {"tom", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
                {"other", "password", "ROLE_ACTIVITI_USER", "GROUP_otherTeam"},
                {"system", "password", "ROLE_ACTIVITI_USER"},
                {"admin", "password", "ROLE_ACTIVITI_ADMIN"},
        };
        for (String[] user : usersGroupsAndRoles) {
            List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length));
            log.info("> Registering new user: " + user[0] + " with the following Authorities[" + authoritiesStrings + "]");
            inMemoryUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]), authoritiesStrings.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList())));
        }
        return inMemoryUserDetailsManager;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

  • 新增SpringSecurity 工具类SecurityUtil
package com.yongliang.activiti.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;

import java.util.Collection;

/**
 * @ClassName: SecurityUtil
 * @Description:
 * @Author: zhangyongliang
 * @Date: 2023/3/9 12:11
 * @Version: V2.3
 */
@Slf4j
@Component
public class SecurityUtil {
    @Autowired
    @Qualifier("myUserDetailsService")
    private UserDetailsService userDetailsService;


    public void logInAs(String username) {
        UserDetails user = userDetailsService.loadUserByUsername(username);
        if (user == null) {
            throw new IllegalStateException("User " + username + " doesn't exist, please provide a valid user");
        }
        log.info("> Logged in as: " + username);
        SecurityContextHolder.setContext(
                new SecurityContextImpl(
                        new Authentication() {

                            private static final long serialVersionUID = -1927273629176390730L;

                            @Override
                            public Collection<? extends GrantedAuthority>
                            getAuthorities() {
                                return user.getAuthorities();
                            }

                            @Override
                            public Object getCredentials() {
                                return user.getPassword();
                            }

                            @Override
                            public Object getDetails() {
                                return user;
                            }

                            @Override
                            public Object getPrincipal() {
                                return user;
                            }

                            @Override
                            public boolean isAuthenticated() {
                                return true;
                            }

                            @Override
                            public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
                            }

                            @Override
                            public String getName() {
                                return user.getUsername();
                            }
                        }));
        org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);
    }

}

3.5.1 流程部署

import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.InputStream;
import java.util.List;
import java.util.zip.ZipInputStream;

@SpringBootTest
public class DeploymentTest {

    @Autowired
    private RepositoryService repositoryService;

    /**
     * 流程部署
     */
    @Test
    public void initDeployment() {
        String fileName = "bpmn/Part1_Deployment.bpmn20.xml";
        Deployment deployment = this.repositoryService.createDeployment()
                .addClasspathResource(fileName)
                .name("流程部署测试")
                .deploy();
        System.out.println("流程部署名称:" + deployment.getName());
    }

    /**
     * 流程部署(Zip包)
     */
    @Test
    public void initDeploymentByZip() {
        InputStream inputStream = this.getClass()
                .getClassLoader()
                .getResourceAsStream("bpmn/Part1_Deployment.zip");
        assert inputStream != null;
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        Deployment deployment = this.repositoryService.createDeployment()
                .addZipInputStream(zipInputStream)
                .name("流程部署测试(Zip包)")
                .deploy();
        System.out.println("流部署名称:" + deployment.getName());
    }

    /**
     * 查询流程部署列表
     */
    @Test
    public void listDeployments() {
        List<Deployment> deployments = this.repositoryService.createDeploymentQuery().list();
        if (!deployments.isEmpty()) {
            deployments.forEach(deployment -> {
                System.out.println("Id:" + deployment.getId());
                System.out.println("Name:" + deployment.getName());
                System.out.println("DeploymentTime:" + deployment.getDeploymentTime());
                System.out.println("Key:" + deployment.getKey());
            });
        }
    }

    /**
     * 删除对流程实例、历史流程实例和作业的给定部署和级联删除
     */
    @Test
    public void deleteDeployment() {
        String deploymentId = "4c97f9ce-4774-11ed-930a-e4a8dfd43d4a";
        this.repositoryService.deleteDeployment(deploymentId, false);
    }
}

涉及数据表:act_re_deployment、act_re_procdef、act_ge_bytearray

act_re_deployment 和 act_re_procdef 属于一对多关系,即:一次部署可以部署多个流程定义,而只会在 act_re_deployment 生成一条记录

3.5.2 流程定义

import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.CollectionUtils;

import java.util.List;

@SpringBootTest
public class ProcessDefinitionTest {

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ProcessRuntime processRuntime; //新API 管理流程实例
    @Autowired
    private TaskRuntime taskRuntime; //新API 管理运行任务

    /**
     * 查询流程定义列表
     */
    @Test
    public void listProcessDefinitions() {
        List<ProcessDefinition> processDefinitions = this.repositoryService.createProcessDefinitionQuery()
                .list();
        if (!CollectionUtils.isEmpty(processDefinitions)) {
            processDefinitions.forEach(processDefinition -> {
                System.out.println("Name:" + processDefinition.getName());
                System.out.println("Key:" + processDefinition.getKey());
                System.out.println("ResourceName:" + processDefinition.getResourceName());
                System.out.println("DeploymentId:" + processDefinition.getDeploymentId());
                System.out.println("Version:" + processDefinition.getVersion());
            });
        }
    }
    
        /**
     * 查询流程的定义  新API方式查询
     */
    @Test
    public void test02() {
        securityUtil.logInAs("system");
        Page<ProcessDefinition> processDefinitionPage = processRuntime.processDefinitions(Pageable.of(0, 10));
        System.out.println("可用的流程定义数量:" + processDefinitionPage.getTotalItems());
        for (ProcessDefinition processDefinition : processDefinitionPage.getContent()) {
            System.out.println("流程定义:" + processDefinition);
        }
    }
}

3.5.3 流程实例

注意:流程定义(ProcessDefinition)与流程实例(ProcessInstance)是一对多关系

import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SpringBootTest
public class ProcessInstanceTest {
@Autowired
private RuntimeService runtimeService;
@Autowired
private ProcessRuntime processRuntime; //新API 管理流程实例
@Autowired
private TaskRuntime taskRuntime; //新API 管理运行任务
    
    /**
     * 启动流程实例 新API方式
     */
    @Test
    public void test04() {
        securityUtil.logInAs("system");

        ProcessInstance processInstance = processRuntime.start(ProcessPayloadBuilder.start()
                .withProcessDefinitionKey("my-evection")
                .withName("出差申请单")
                .withBusinessKey("1001")
                .build()
        );
        System.out.println("实例启动ID为:" + processInstance.getId());

    }

/**
 * 初始化流程实例
 */
@Test
public void initProcessInstance() {
    // 流程定义KEY
    String processDefinitionKey = "Part1_Deployment";
    // 业务表KEY(用于把业务数据与Activiti7流程数据相关联)
    String businessKey = "4208169753200945";
    // 参数
    Map<String, Object> variables = new HashMap<>(16);
    ProcessInstance processInstance = this.runtimeService
            .startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
    System.out.println("流程实例ID:" + processInstance.getProcessInstanceId());
}

/**
 * 查询流程实例
 */
@Test
public void getProcessInstance() {
    String processInstanceId = "354709ac-477f-11ed-abfa-e4a8dfd43d4a";
    ProcessInstance processInstance = this.runtimeService.createProcessInstanceQuery()
            .processInstanceId(processInstanceId)
            .singleResult();
    System.out.println("ProcessInstanceId:" + processInstance.getProcessInstanceId());
    System.out.println("ProcessDefinitionId:" + processInstance.getProcessDefinitionId());
    System.out.println("isEnded:" + processInstance.isEnded());
    System.out.println("isSuspended:" + processInstance.isSuspended());
}

/**
 * 查询流程实例列表
 */
@Test
public void listProcessInstances() {
    List<ProcessInstance> processInstanceList = this.runtimeService.createProcessInstanceQuery().list();
    if (!CollectionUtils.isEmpty(processInstanceList)) {
        processInstanceList.forEach(processInstance -> {
            System.out.println("ProcessInstanceId:" + processInstance.getProcessInstanceId());
            System.out.println("ProcessDefinitionId:" + processInstance.getProcessDefinitionId());
            System.out.println("isEnded:" + processInstance.isEnded());
            System.out.println("isSuspended:" + processInstance.isSuspended());
        });
    }
}

/**
 * 挂起流程实例
 */
@Test
public void suspendProcessInstance() {
    String processInstanceId = "354709ac-477f-11ed-abfa-e4a8dfd43d4a";
    this.runtimeService.suspendProcessInstanceById(processInstanceId);
}

/**
 * 激活流程实例
 */
@Test
public void activeProcessInstance() {
    String processInstanceId = "354709ac-477f-11ed-abfa-e4a8dfd43d4a";
    this.runtimeService.activateProcessInstanceById(processInstanceId);
}

/**
 * 删除流程实例
 */
    @Test
    public void deleteProcessInstance() {
        String processInstanceId = "354709ac-477f-11ed-abfa-e4a8dfd43d4a";
        String reason = "测试删除流程实例";
        this.runtimeService.deleteProcessInstance(processInstanceId, reason);
    }
}

涉及数据表:act_hi_actinst、act_hi_taskinst、act_hi_identitylink、act_hi_procinst、act_ru_execution、act_ru_identitylink、act_ru_task

3.5.4 任务管理

  • Assignee:执行人/代理人
  • Candidate Users:候选人
  • Candidate Groups:候选组
  • Due Date:任务到期时间
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SpringBootTest
public class TaskTest {

    @Autowired
    private TaskService taskService;
    @Autowired
    private ProcessRuntime processRuntime; //新API 管理流程实例
    @Autowired
    private TaskRuntime taskRuntime; //新API 管理运行任务
    
        /**
     * 任务查询、拾取及完成操作
     */
    @Test
    public void test05() {
        securityUtil.logInAs("jack");
        Page<Task> taskPage = taskRuntime.tasks((Pageable.of(0, 10)));
        System.out.println("拾取任务数量为:" + taskPage.getTotalItems());
        if (taskPage.getTotalItems() > 0) {
            for (Task task : taskPage.getContent()) {
                // 拾取任务
                taskRuntime.claim(TaskPayloadBuilder.claim().withAssignee("jack").withTaskId(task.getId()).build());
                taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(task.getId()).build());
                System.out.println("任务:" + task);
            }
            Page<Task> taskPage2 = taskRuntime.tasks(Pageable.of(0, 10));
            if (taskPage2.getTotalItems() > 0) {
                System.out.println("查询任务:" + taskPage2.getContent());
            }

        }
    }

    /**
     * 查询任务列表
     */
    @Test
    public void listTasks() {
        List<Task> taskList = this.taskService.createTaskQuery().list();
        if (!CollectionUtils.isEmpty(taskList)) {
            taskList.forEach(task -> {
                System.out.println("Id:" + task.getId());
                System.out.println("Name:" + task.getName());
                System.out.println("Assignee:" + task.getAssignee());
            });
        }
    }

    /**
     * 查询我的代办任务
     */
    @Test
    public void listTasksByAssignee() {
        String assignee = "admin";
        List<Task> taskList = this.taskService.createTaskQuery()
                .taskAssignee(assignee)
                .list();
        if (!CollectionUtils.isEmpty(taskList)) {
            taskList.forEach(task -> {
                System.out.println("Id:" + task.getId());
                System.out.println("Name:" + task.getName());
                System.out.println("Assignee:" + task.getAssignee());
            });
        }
    }

    /**
     * 完成任务
     */
    @Test
    public void completeTask() {
        String taskId = "354b9d90-477f-11ed-abfa-e4a8dfd43d4a";
        Map<String, Object> variables = new HashMap<>(16);
        this.taskService.complete(taskId, variables);
    }
        /**
     * @ClassName BootActivitiApplicationTests
     * @Description: 完成流程任务
     * @Author: zhangyongliang
     * @Date: 2023/3/9 16:02
     * @Version: V2.3
     */
    @Test
    public void test08() {
        securityUtil.logInAs("tom");
        Page<Task> page = taskRuntime.tasks(Pageable.of(0, 10));
        if (page != null && page.getTotalItems() > 0) {
            page.getContent().forEach(task -> {
                taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(task.getId()).build());
                System.out.println("完成流程任务结束");
            });
        }
    }

    /**
     * 拾取任务
     */
    @Test
    public void claimTask() {
        String taskId = "16beabc1-479f-11ed-9c3a-e4a8dfd43d4a";
        String userId = "jason";
        Task task = this.taskService.createTaskQuery().taskId(taskId).singleResult();
        taskService.claim(taskId, userId);
    }

    /**
     * 归还任务
     */
    @Test
    public void returnTask() {
        String taskId = "16beabc1-479f-11ed-9c3a-e4a8dfd43d4a";
        Task task = this.taskService.createTaskQuery().taskId(taskId).singleResult();
        // 归还任务
        taskService.unclaim(taskId);
    }

    /**
     * 交办任务
     */
    @Test
    public void handoverTask() {
        String taskId = "16beabc1-479f-11ed-9c3a-e4a8dfd43d4a";
        String userId = "jack";
        Task task = this.taskService.createTaskQuery().taskId(taskId).singleResult();
        // 交办任务
        taskService.setAssignee(taskId, userId);
    }
}

3.5.5 历史任务

import org.activiti.engine.HistoryService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.CollectionUtils;

import java.util.List;

@SpringBootTest
public class HistoricTest {

    @Autowired
    private HistoryService historyService;

    /**
     * 根据用户名查询历史记录
     */
    @Test
    public void listHistoricTasksByAssignee() {
        String assignee = "admin";
        List<HistoricTaskInstance> historicTasks = this.historyService.createHistoricTaskInstanceQuery()
                .orderByHistoricTaskInstanceEndTime()
                .asc()
                .taskAssignee(assignee)
                .list();
        if (!CollectionUtils.isEmpty(historicTasks)) {
            historicTasks.forEach(historicTaskInstance -> {
                System.out.println("Id:" + historicTaskInstance.getId());
                System.out.println("ProcessInstanceId:" + historicTaskInstance.getProcessInstanceId());
                System.out.println("Name:" + historicTaskInstance.getName());
            });
        }
    }

    /**
     * 根据流程实例ID查询历史
     */
    @Test
    public void listHistoricTasksByProcessInstanceId() {
        String processInstanceId = "0f8a9b00-479e-11ed-af85-e4a8dfd43d4a";
        List<HistoricTaskInstance> historicTasks = this.historyService.createHistoricTaskInstanceQuery()
                .orderByHistoricTaskInstanceEndTime()
                .asc()
                .processInstanceId(processInstanceId)
                .list();
        if (!CollectionUtils.isEmpty(historicTasks)) {
            historicTasks.forEach(historicTaskInstance -> {
                System.out.println("Id:" + historicTaskInstance.getId());
                System.out.println("ProcessInstanceId:" + historicTaskInstance.getProcessInstanceId());
                System.out.println("Name:" + historicTaskInstance.getName());
            });
        }
    }
}

3.5.6 UEL 表达式

  • 表达式以 ${ 开始;} 结束,例如:${day > 100}
  • 支持逻辑运算:${username == “admin” and password == “123456”}
  • 支持变量(变量名必须小写)与实体类赋值

涉及数据表:act_hi_varinst、act_ru_variable

3.5.7 网关分类

  • 并行网关 有开始-有结束

ppn1S3Q.png

  • 排他网关

ppn19js.png

  • 包容网关

注意:包容网关是并行网关的一种衍生,所以也是成对出现

ppn1ENT.png

  • 事件网关

evection-event.png