SpringBoot融合Activiti7(报表引擎)完全版

原创
小哥 3年前 (2022-12-26) 阅读数 90 #大杂烩

Spring Boot 集成 Activiti7(工作流引擎)完整版本

介绍

Activiti 是一个 工作流引擎 它可以从业务系统中提取复杂的业务流程,并使用专门的建模语言。 BPMN2.0 业务流程是根据预定义的流程定义和执行的,使系统的流程能够由 Activiti 管理,减少业务系统因流程变化而产生的工作量,从而升级系统,从而提高系统的鲁棒性,同时也降低了系统开发和维护的成本。(salvio修改)
升级新api (ProcessRuntime) 和(TaskRuntime)
官方网站:https://www.activiti.org/

环境搭建

安装插件

File -> Settings -> Plugins -> Activiti BPMN visualizer

引入依赖


    
    
        org.activiti
        activiti-spring-boot-starter
        7.1.0.M4
        
            
                org.mybatis
                mybatis
            
        
    
    
        org.activiti.dependencies
        activiti-dependencies
        7.1.0.M4
        pom
    
    
    
        org.activiti
        activiti-image-generator
        7.1.0.M4
    

1234567891011121314151617181920212223242526

配置文件

spring:
  # 数据源配置
  datasource:
  driver-class-name: com.mysql.cj.jdbc.Driver
  url: jdbc:mysql://127.0.0.1:3306/activiti?useUnicode=true&useSSL=false&serverTimezone=UTC&characterEncoding=UTF8&nullCatalogMeansCurrent=true
  username: "root"
  password: "88888888"
  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
123456789101112131415161718192021222324252627282930313233343536373839

初始化数据表

修改配置文件后,启动项目,如果成功启动,将自动生成项目。 25 数据表如下:

注意:7.1.0.M4 版本自动生成的表字段不完整,因此需要执行以下操作。SQL:

-- ----------------------------
-- 修复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;
12345

数据表解释

Activiti 所使用的表格均为 ACT_ 在开头,表名的第二部分表示目的。

  • ACT_GE_ ( GE ) 表示 general 全球通用数据和设置,各种情况下使用的数据。
  • ACT_HI_ ( HI ) 表示 history 历史数据表,包含与程序执行相关的历史数据。
  • ACT_RE_ ( RE ) 表示 repository 存储,其中包含静态信息。
  • ACT_RU_ ( RU ) 表示 runtime 运行时、运行时过程变量、用户任务、变量、责任(job)以及其他运行时数据。Activiti 在实例执行期间仅存储运行时数据,并在流程实例结束时删除这些记录 (salvio修改)

全球通用数据(ACT_GE_*)

表名

解释

ACT_GE_BYTEARRAY

存储通用流程定义和流程资源的二进制数据表。

ACT_GE_PROPERTY

与系统相关的属性,属性数据表存储整个流程引擎级别的数据。

历史数据表(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

历史变量表

静态信息表(ACT_RE_*)

表名

解释

ACT_RE_DEPLOYMENT

部署信息表

ACT_RE_MODEL

流程设计模型部署表

ACT_RE_PROCDEF

工艺定义数据表

操作数据(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

运行时过程变量数据表

其它表

表名

解释

ACT_EVT_LOG

事件日志

ACT_PROCDEF_INFO

流程定义的动态更改信息

快速入门

流程部署

流程部署有两种类型:自动部署和手动部署。

自动部署 :将 bpmn 文件放入 resources 在资源目录下 processes 文件夹,该文件夹在项目启动时自动部署。(salvio修改)

spring:
  # activiti7配置
  activiti:
    # 自动部署验证设置:true-打开(默认),false-关闭
    check-process-definitions: true
    # 保存历史数据
    history-level: full
    # 检查历史记录表是否存在
    db-history-used: true
    # 关闭SpringAutoDeployment
    deployment-mode: never-fail
    # 更新数据库中的所有表,如果表不存在,将自动创建该表。
    database-schema-update: true
    # 解决频繁查询SQL问题
    async-executor-activate: false
123456789101112131415

手动部署 :创建新的测试类并编写流程部署测试方法。

自定流程

  1. 创建 *.bpmn20.xml 文件:New -> New Activity 6.x BPMN 2.x file
  2. 流程设计页面:已选择 *.bpmn20.xml 文件,右键单击 view BPMN(Activity ) Diagram

    <?xml version="1.0" encoding="UTF-8"?>

    12345678910111213141516171819202122232425262728293031

单元测试

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 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);
    }
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071

涉及的数据表:act_re_deployment、act_re_procdef、act_ge_bytearray

act_re_deployment 和 act_re_procdef 这是一对多的关系,即一次可以部署多个流程定义,但只能在 act_re_deployment 生成记录(salvio修改)

流程定义

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;

    /**
     * 查询流程定义列表
     */
    @Test
    public void listProcessDefinitions() {
        List 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());
            });
        }
    }
}
123456789101112131415161718192021222324252627282930313233

流程实例

注:流程定义(ProcessDefinition)和流程实例(ProcessInstance)是一对多的关系(salvio修改)

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;

    /**
     * 初始化进程实例
     */
    @Test
    public void initProcessInstance() {
        // 流程定义KEY
        String processDefinitionKey = "Part1_Deployment";
        // 业务表KEY(用于比较业务数据Activiti7过程数据关联)
        String businessKey = "4208169753200945";
        // 参数
        Map 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 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);
    }
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192

涉及的数据表:act_hi_actinst、act_hi_taskinst、act_hi_identitylink、act_hi_procinst、act_ru_execution、act_ru_identitylink、act_ru_task(salvio修改)

任务管理

  • 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;
    
    /**
     * 查询任务列表
     */
    @Test
    public void listTasks() {
        List 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 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 variables = new HashMap<>(16);
        this.taskService.complete(taskId, variables);
    }
    
    /**
     * 拾取任务
     */
    @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);
    }

    } 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394

涉及的数据表:act_hi_actinst、act_hi_taskinst、act_hi_identitylink、act_hi_procinst、act_ru_execution、act_ru_identitylink、act_ru_task(salvio修改)

历史记录

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 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 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());
            });
        }
    }
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455

UEL表达式

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

涉及的数据表:act_hi_varinst、act_ru_variable

BPMN2.0网关

并行网关(Parallel gateway)

注意:并行网关有开始和结束。

专用网关(Exclusive gateway)

非独占网关(Inclusive gateway)

注意:包含网关是并行网关的派生,因此它们也成对出现。

事件网关(Event gateway)

待续(salvio修改)
版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除