activiti7执行流程详解

2023-11-07

什么是工作流?

官方定义:工作流是将一组任务组织起来以完成某个经营过程:定义了任务的触发顺序和触发条件,每个任务可以由一个或多个软件系统完成,也可以由一个或一组人完成,还可以由一个或多个人与软件系统协作完。

我的理解:工作流就是针对程序的业务流程进行自动化管理、执行的流。让业务的执行过程根据我们预定义好的规则不断地触发和执行。它最明显的体现就是在项目中的一些审批操作,比如说员工请假、订单审核等等类似一种的操作时业务在当前操作完成后自动的跳转进行下一操作

配置Activiti7建表

2010年5月份启动,目前使用最广泛的工作流引擎。使用activiti可以将复杂的业务流程进行抽离,业务流程按照预先定义好的规则执行。将业务流程交给activiti去管理使得当业务发生变更时不需要去大量得改动程序,降低了维护成本。

activiti使用专门的建模语言BPMN进行定义,BPMN就是一组定义好的符号语言,使用这些符号来模拟整个复杂业务的执行流程

activiti的配置文件:实际上也是利用spring来配置的xml文件,其中主要配置的就是一个数据源以及注册引擎配置类Bean实例,通过流程引擎配置类ProcefssEngineConfiguration,我这里使用的是druid连接池,然后将连接池引入到ProcefssEngineConfiguration中

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/contex http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

  <!--数据源配置druid -->
  <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
    <property name="url"
              value="jdbc:mysql://localhost:3306/activiti?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC" />
    <property name="username" value="root" />
    <property name="password" value="123456" />
  </bean>
  <!--activiti单独运行的ProcessEngine配置对象(processEngineConfiguration),使用单独启动方式 默认情况下:bean的id=processEngineConfiguration -->
<!--默认创建时  该id名必须不可变 processEngineConfiguration-->
  <bean id="processEngineConfiguration"
 class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
    <!--代表数据源 -->
    <property name="dataSource" ref="dataSource"></property>
    <!--代表是否生成表结构 -->
    <property name="databaseSchemaUpdate" value="true" />
  </bean>
</beans>

第一次使用activiti需要去生成如下25张数据表,我们只需要通过获取ProcessEngine就可以自动创建

public void test01(){
  // 创建activiti表  后期有ProcessEngine帮助我们管理  
  // 默认创建方式
  ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
  System.out.println(processEngine);
  // 自定义创建方式
  ProcessEngineConfiguration processEngineConfigurationFromResource =
                ProcessEngineConfiguration
.createProcessEngineConfigurationFromResource("自定义文件名","自定义bean名");
}

自定义创建方式,更加灵活。activiti的配置文件命名以及processEngineConfiguration的id命名都可以自定义

databaseSchemaUpdate是指activiti的表生成策略,true标识如果数据库中已经存在则直接使用,如果不存在则先创建再使用

activiti核心组件PageEngine

activiti的核心就是ProcessEngine,就是工作流引擎。那么通过ProcessEngine可以调用不同的service接口,这些接口都封装了操作activiti生成表的方法,可以对于activiti生成的25张数据表进行不同的操作,如下:

在这里插入图片描述

像repositoryService就是用于部署流程服务,Runtime就是运行时服务,每个Service都对应有自己的数据表。我们在调用每个服务实例的方法实际上都是在操作数据库中的activiti生成的表。

activiti流程体验

activiti的使用步骤:
1、定义流程:按照BPMN使用流程定义符号对整个流程进行抽象建模
2、部署流程:将构建好的BPMN文件加载到数据库中生成表数据
3、启动流程:使用Java程序操作数据库表内容

下面我们用员工的请假审批流程做演示

1、对流程进行抽象建模在这里插入图片描述

每个步骤都有自己对应的操作,以及对应的负责人。

2、流程任务部署

// 流程任务部署
@Test
public void deploymentTest(){
  // (1)创建流程引擎 加载配置文件 默认加载activiti.cfg.xml文件
  ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
  // (2)获取repositoryService
  RepositoryService repositoryService = engine.getRepositoryService();
  // (3)通过repositoryService创建部署流程
  Deployment deploy = repositoryService.createDeployment()
    // (4) 添加资源文件
    .addClasspathResource("bpmn/test.bpmn20.xml")
    .addClasspathResource("bpmn/diagram.png")
    .name("员工请假审批流程")
    // (5)部署
    .deploy();
  // 查看当前流程的id、名称
  System.out.println("申请流程实例ID="+deploy.getId());
  System.out.println("申请流程示例名称="+deploy.getName());
}

下面启动一项任务流程实例,即对应项目中有员工申请了请假操作时的流程

// 启动流程实例
@Test
public void testProcess(){
  // 1. 创建ProcessEngine
  ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
  // 2. 获取RunTimeService运行时服务
  RuntimeService service = engine.getRuntimeService();
  // 3. 根据流程定义的id启动流程  我这里时test
  ProcessInstance instance = service.startProcessInstanceByKey("test");
  // 输出内容
  System.out.println("流程定义ID="+instance.getProcessDefinitionId());
  System.out.println("流程实例ID="+instance.getId());
  System.out.println("当前活动ID="+instance.getActivityId());
}

在项目开发中,如果某一用户或者是员工想要请假,那么就会为其启动一项任务流程。启动一项任务流程之后,activiti就会在对应的运行服务表中做出一些记录。启动流程之后也就对应着我们的BPMN图走到了第二步:经理审批

那么这个时候我们通过经理这个角色就可以查询到此时经理需要处理的任务流程,如下:查询个人待处理业务

// 查询个人待执行的任务
@Test
public void testGetPersonalTaskList(){
// 1. 获取引擎
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 2. 获取TaskService
TaskService taskService = engine.getTaskService();
// 3. 根据条件查询  以及任务负责人 查询任务
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey("forLeave")  // 任务
.taskAssignee("zhangsan")   // 负责人
.list();
for (Task task : list) {
System.out.println("流程实例ID==="+task.getProcessInstanceId());
System.out.println("任务ID==="+task.getId());
System.out.println("任务负责人==="+task.getAssignee());
System.out.println("任务名称==="+task.getName());
}
}

上述程序只是查询到了某一角色的待完成任务:部门主管审批,下面是具体操作来使该角色完成任务,同样是使用流程引擎获取TaskService

@Test
public void complete(){
  // 获取流程引擎
  ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
  // 获取任务TaskService
  TaskService taskService = engine.getTaskService();
  // 根据任务id完成任务  将上述查询道道的待完成任务id传入
  taskService.complete("2504");
}

该角色任务完成后将会跳转至下一步骤:部门经理审批。可以通过act_ru_task查看,该表就是对应某一项任务的执行状态,每一步的负责人通过之后就会跳转至下一项。同样的也可以通过act_hi_taskinst该表来查看某一项任务的执行进度,在对应的数据后会有该步骤的开始时间,如果已完成则会有完成结束时间

那么在实际项目中,我们可以首先通过获取某个角色的待完成任务放在页面上,该角色如果审批通过,那么可以将它点击通过的任务id作为形参传入上述complete方法中,以此完成该角色审批任务

下面执行部门经理审批,完成所有步骤

// 继续完成部门经理审批
@Test
public void completeTask(){
  // 获取流程引擎
  ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
  // 获取任务TaskService
  TaskService taskService = engine.getTaskService();
  // 查询部门经理lisi待完成得请假审批任务  并获取该任务对象
  Task task = taskService.createTaskQuery()
    .processDefinitionKey("forLeave")
    .taskAssignee("lisi")
// 获取单个任务  如果有多个任务则要用list();
    .singleResult();
  // 让李四完成任务 根据任务id完成任务  将上述查询到的待完成任务id传入
  taskService.complete(task.getId());
}

processDefinitionKey当中得key也就是参数就是需要查询得任务流程的id,就是构建BPMN点击空白界面时出现的id。完成所有任务后再次查看act_ru_task运行任务表会发现刚刚执行任务流程已经被删除,这是因为任务已经结束。

我们可以查看act_hi_actinst历史任务实例表,会发现该表中拥有本次任务流程的全部步骤以及详细信息
在这里插入图片描述
可以看到各个步骤开始及完成的时间以及负责人等详细信息

zip方式批量部署流程任务

// zip批量部署任务
@Test
public void deployPrecessZip(){
  // 获取流程引擎
  ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
  // 获取部署repositoryService
  RepositoryService service = engine.getRepositoryService();
  // 批量部署流程
  // 先读取文件
  InputStream inputStream = this.getClass()
    .getClassLoader()
    .getResourceAsStream("bpmn/bpmn.zip");
  // 将文件转换为zip流
  ZipInputStream zipInputStream = new ZipInputStream(inputStream);
  // 将zip流形式的文件交给service去读
  Deployment deploy = service.createDeployment()
    .addZipInputStream(zipInputStream)
    .deploy();
  System.out.println("部署的任务流程名称=="+deploy.getName());
  System.out.println("部署的任务流程ID=="+deploy.getId());
}

流程定义查询

流程定义查询,实际上就是查询指定的全部任务最终以list集合展示,比如在界面上需要展示当前所有申请了请假的员工的请假任务执行流程

// 查询流程定义  与上述查询某角色个人待执行任务类似
@Test
public void queryPrecessDefinition(){
  // 获取引擎
  ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
  // 获取repositoryService
  RepositoryService service = engine.getRepositoryService();
  // 获取query查询实例
  ProcessDefinitionQuery query = service.createProcessDefinitionQuery();
  // 查询当前所有流程定义
  List<ProcessDefinition> leave = query.processDefinitionKey("forLeave")   // key
    .orderByProcessDefinitionVersion() // 版本号
    .desc()   // 倒叙
    .list();//  返回集合
  // 信息打印
  for (ProcessDefinition processDefinition : leave) {
    System.out.println("流程定义ID=="+processDefinition.getId());
    System.out.println("流程定义Name=="+processDefinition.getName());
    System.out.println("流程定义key=="+processDefinition.getKey());
    System.out.println("流程定义版本=="+processDefinition.getVersion());
  }
}

其实流程定义查询主要查询的就是act_re_procdef这个表中的数据

流程定义删除(删除部署)

先看程序

// 删除部署根据部署ID
@Test
public void deletedDeployment(){
  ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
  RepositoryService service = engine.getRepositoryService();
  service.deleteDeployment("1");
}

流程定义的部署就是将流程任务的各种数据信息存放到数据库中的各个表上,那么删除部署的时候自然就会将所有相关的部署信息全部删除。就是你在部署的时候操作了那些表,那么删除部署的时候就还是操作这些表,将数据全部清空。

但是,如果当前流程启动了并且还未执行完毕。那么此时再根据部署ID去删除时是不会成功的,必须要删除就只能通过级联删除

级联删除

service.deleteDeployment("5001"); 
service.deleteDeployment("5001",true);

上述两种都是根据部署ID删除流程任务,第二种方式就是调用了deleteDeployment的重载方法,如果将第二个参数设置为true则表示打开级联删除。默认为false

流程资源下载

使用activiti提供的api进行下载:需要导入依赖

<!--  activiti提供的下载资源工具  -->
<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.11.0</version>
</dependency>

下载的具体步骤:

// 流程资源下载
@Test
public void uploadResource() throws IOException {
  // 获取流程引擎
  ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
  // 获取RepositoryService
  RepositoryService service = engine.getRepositoryService();
  // 通过流程定义信息获取部署ID
  ProcessDefinition leave = service.createProcessDefinitionQuery()
    .processDefinitionKey("forLeave")
    .singleResult();
  // 获取部署ID
  String deploymentId = leave.getDeploymentId();
  // 读取资源(png和bpmn)
  // 获取bpmn资源
  String pngName = leave.getDiagramResourceName();
  // 获取图片
  String bpmnName = leave.getResourceName();
  // 通过部署ID和名字获取图片资源
  // 获取 图片输入流
  InputStream pngInput = service.getResourceAsStream(deploymentId, pngName);
  // 获取bpmn资源输入流
  InputStream bpmnInput = service.getResourceAsStream(deploymentId, bpmnName);
  // 构造输出流
  File file1 = new File("E:/emo01.png");
  File file2 = new File("E:/emo02.bpmn");
  FileOutputStream fileOutputStream = new FileOutputStream(file1);
  FileOutputStream fileOutputStream2 = new FileOutputStream(file2);
  // 转换输入输出流
  IOUtils.copy(pngInput,fileOutputStream);
  IOUtils.copy(bpmnInput,fileOutputStream2);
  // 关闭流
  fileOutputStream2.close();
  fileOutputStream.close();
  bpmnInput.close();
  pngInput.close();
}

流程历史信息查看

// 查看历史流程信息
@Test
public void queryHistoryInstance(){
  // 获取引擎
  ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
  // 获取历史服务 HistoryService
  HistoryService historyService = engine.getHistoryService();
  // 创建查询
  List<HistoricActivityInstance> list = historyService
    .createHistoricActivityInstanceQuery()
    .processInstanceId("12501")
    .orderByHistoricActivityInstanceStartTime()
    .asc() // 升序
    .list();
  // 输出查看
  for (HistoricActivityInstance hi : list) {
    System.out.println("该步骤ID=="+hi.getActivityId());
    System.out.println("该步骤Name=="+hi.getActivityName());
    System.out.println("任务ID=="+hi.getProcessDefinitionId());
    System.out.println("流程ID=="+hi.getProcessInstanceId());
    System.out.println("<-------------------------------------->");
  }
}

上述输出语句,Activity表示某一流程的具体某一步骤。每一个步骤都会有自己的ID以及开始和结束时间。
ProcessDefinitionID任务ID就是表示当前流程属于某一种业务的具体实例,可以是请假审批或者报销申请等。
ProcessInstance流程ID就是表示流程实例ID比如具体的某一项请假业务或者报销业务
ProcessInstance > ProcessDefinition > Activity
而流程历史信息查看实际上就是查询了act_hi_actinst表

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

activiti7执行流程详解 的相关文章

随机推荐

  • Codeforces Round 881 (Div. 3) 题解

    目录 A Sasha and Array Coloring 题意 思路 代码 B Long Long 题意 思路 代码 C Sum in Binary Tree 题意 思路 代码 D Apple Tree 树形dp 题意 思路 代码 E T
  • 2022年C语言程序设计题库习集带答案(史上最全版)

    C语言程序设计 试题一 一 填空题 1 C语言中基本的数据类型有 2 C语言中普通整型变量的类型说明符为 在内存中占 字节 有符号普通整型的数据范围是 3 整数 35在机内的补码表示为 4 执行下列语句int a 8 a a a a 后 a
  • springboot集成微信app支付

    一 准备工作 以下信息需要自行开通和申请 public static final String APP ID app的id 需要app应用 public static final String KEY api密钥 商户账户信息里面去获取 p
  • 一个mysql语句报错引发的故事

    昨天在自己的本上装了mysql 打算练习sql语句 在创建表的时候报了错 Invalid default value for sex 就是说我sql语句中有个性别的默认值设置是无效的 性别用的是enum数据类型 出错原因是因为数据库的编码不
  • 【Python字典】

    字典类型的基本概念 通过任意键信息查找一组数据中值信息的过程叫映射 Python语言中通过字典实现映射 Python语言中的字典可 以通过大括号 建立 建立模式如下 lt 键1 gt lt 值1 gt lt 键2 gt lt 值2 gt l
  • C++11--包装器与可变参数摸板

    文章目录 可变参数模板 递归函数方式展开参数包 函数包装器 举个例子 bind函数 举个例子 可变参数模板 C 11的新特性可变参数模板能够让我们创建可以接受可变参数的函数模板和类模板 Args是一个模板参数包 args是一个函数形参参数包
  • 【人脸检测】 Tinaface复现(数据集准备、测试与评估)

    转载自 https blog csdn net qq 35975447 article details 110430390 人脸检测 Tinaface复现 数据集准备 测试与评估 参考 TinaFace Strong but Simple
  • Linux服务篇之DNS服务器搭建

    文章目录 一 DNS介绍 1 DNS简介 2 DNS工作原理 3 DNS的资源记录 二 实验 1 DNS正向解析实验 2 反向解析 3 主从服务器配置 三 总结 一 DNS介绍 1 DNS简介 DNS 全称 Domain Name Syst
  • 关于load过高的几种情况

    Linux 中 load啥意思 Load 在 Linux 系统中通常是指系统的负载情况 也称为系统负荷 它指的是系统正在运行的进程数量以及这些进程对系统资源的使用情况 例如 CPU 内存 磁盘 I O 等 Linux 系统的负载通常由三个数
  • osgEarth的Rex引擎原理分析(九十四)rex引擎如何显示瓦片的边界

    目标 八十八 中的问题171 效果图如下 思路 在文章 osgEarth的Rex引擎原理分析 九十一 晕眩图的制作与实现 的基础上 判断纹理坐标的范围 在边界处用特殊颜色即可 着色器代码如下 if oe layer tilec s lt 0
  • unity3D学习之API_Transform 位置

    一 定义 Transform 表示物体的位置 旋转和缩放而且每个对象必备的组件 场景中的每一个物体都有一个Transform 用于储存并操控物体的位置 旋转和缩放 每一个Transform可以有一个父级 允许你分层次应用位置 旋转和缩放 可
  • Qt的事件循环机制

    所有例程和PPT下载 https download csdn net download simonyucsdy 12311712 问题1 Qt中常见的事件有哪些 答 鼠标事件 QMouseEvent 键盘事件 QKeyEvent 绘制事件
  • SAP/FICO/BAPI_ACC_DOCUMENT_POST-外币凭证金额和本位币误差问题处理

    场景 通过BAPI ACC DOCUMENT POST创建USD币别凭证SAP会自动带出CNY本位币金额 本位币金额是USD通过SAP配置的汇率计算出来的 有时候会有误差 想要实现的功能 凭证金额和本位币金额都有外部系统传入设置不需要SAP
  • SQL视图的使用场景/案例

    背景原因 一方面 在一个项目的实际开发过程中牵涉到复杂业务的时候 我们不可避免的需要使用中间表来进行数据连接 一方面 采用Hibernate进行主外键进行关联 多对多 多对一 一对一等 采用主外键关联在数据的操作过程中具有很强的耦合性 尤其
  • gitlab配置ssh密钥及简单使用

    gitlab安装可参考https blog whsir com post 1419 html 演示环境 当前系统Centos6 9 使用IP192 168 0 80 修改gitlab仓库地址 编辑gitlab yml文件 vim opt g
  • 关于安卓调试的log系统

    在安卓系统下 对应用程序的调试 有一个特有的方式 就是log系统 其实就和C语言中的printf函数的使用类似 但是 它是将调试信息存入了缓冲区内 而安卓有四个缓冲区 他的设计模式是模仿了linux内核中的缓冲区模式 将所有的调试信息放入缓
  • Redis的IO多路复用原理

    什么是阻塞 非阻塞 异步同步 select poll epoll 今天我们用一遍文章解开这多年的迷惑 首先我们想要通过网络接收消息 是这样的一个步骤 用户空间向内核空间请求网络数据 内核空间把网卡数据读取到内核缓冲区 将内核缓冲区的数据复制
  • RC正弦波震荡电路

    就开始边写边整理自己的思路吧 毕竟今天刚刚学完 振荡电路是没有输入却有输出的电路 而且是正弦波 就是从白噪声放大 选频得来的 So 可想而知 这个电路需要放大部分 用来放大我们所需的部分 其实是在放大所有频率的 没办法 选频网络 就是两个滤
  • educoder算法设计与分析 实验三 动态规划实验拓展

    实验三 动态规划实验拓展 第1关 聪明的寻宝人 第2关 基因检测 第3关 药剂稀释 第4关 找相似串 第1关 聪明的寻宝人 题目描述 本关任务 计算寻宝人所能带走的宝物的最大价值 一个寻宝人在沙漠中发现一处神秘的宝藏 宝藏中共有n个宝物 n
  • activiti7执行流程详解

    什么是工作流 官方定义 工作流是将一组任务组织起来以完成某个经营过程 定义了任务的触发顺序和触发条件 每个任务可以由一个或多个软件系统完成 也可以由一个或一组人完成 还可以由一个或多个人与软件系统协作完 我的理解 工作流就是针对程序的业务流