Activiti7工作流入门和基本使用-Activiti入门和流程操作

2023-10-24 03:50

本文主要是介绍Activiti7工作流入门和基本使用-Activiti入门和流程操作,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

五、Activiti入门

在本章内容中,我们来创建一个 Activiti 工作流,并启动这个流程。
创建 Activiti 工作流主要包含以下几步:
1 、定义流程,按照 BPMN 的规范,使用流程定义工具,用 流程符号 把整个流程描述出来
2 、部署流程,把画好的流程定义文件,加载到数据库中,生成表的数据
3 、启动流程,使用 java 代码来操作数据库表中的内容

5.1 流程符号

BPMN 2.0 是业务流程建模符号 2.0 的缩写。
它由 Business Process Management Initiative 这个非营利协会创建并不断发展。作为一种标识, BPMN 2.0 是使用一些 来明确业务流程设计流程图的一整套符号规范,它能增进业务建模时的沟通效率。
目前 BPMN2.0 是最新的版本,它用于在 BPM 上下文中进行布局和可视化的沟通。
接下来我们先来了解在流程设计中常见的符号。
BPMN2.0 基本符合 主要包含:
事件 Event
活动 Activity
活动是工作或任务的一个通用术语。一个活动可以是一个任务,还可以是一个当前流程的子处理流程; 其次,你还可以为活动指定不同的类型。常见活动如下:

 

网关 GateWay
网关用来处理决策,有几种常用网关需要了解:
排他网关 (x)
—— 只有一条路径会被选择。流程执行到该网关时,按照输出流的顺序逐个计算,当条件的计算结果为 true 时,继续执行当前网关的输出流;
如果多条线路计算结果都是 true ,则会执行第一个值为 true 的线路。如果所有网关计算结果没有 true ,则引擎会抛出异常。
排他网关需要和条件顺序流结合使用, default 属性指定默认顺序流,当所有的条件不满足时会执行默认顺序流。
并行网关 (+)
—— 所有路径会被同时选择
拆分 —— 并行执行所有输出顺序流,为每一条顺序流创建一个并行执行线路。
合并 —— 所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行。
包容网关 (+)
—— 可以同时执行多条线路,也可以在网关上设置条件
拆分 —— 计算每条线路上的表达式,当表达式计算结果为 true 时,创建一个并行线路并继续执行
合并 —— 所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行。
事件网关 (+) —— 专门为中间捕获事件设置的,允许设置多个输出流指向多个不同的中间捕获事件。当流程执行到事件网关后,流程处于等待状态,需要等待抛出事件才能将等待状态转换为活动状态。
流向 Flow
流是连接两个流程节点的连线。常见的流向包含以下几种:

 

5.2 流程设计器使用

Activiti-Designer 使用
Palette (画板)
idea 中安装插件即可使用,画板中包括以下结点:
Connection— 连接
Event--- 事件
Task--- 任务
Gateway--- 网关
Container— 容器
Boundary event— 边界事件
Intermediate event- - 中间事件
流程图设计完毕保存生成 .bpmn 文件
新建流程 (IDEA 工具 )
首先选中存放图形的目录 ( 选择 resources 下的 bpmn 目录 ) ,点击菜单: New -> BpmnFile ,如图:

弹出如下图所示框,输入 evection 表示 出差审批流程:

起完名字 evection 后(默认扩展名为 bpmn ),就可以看到流程设计页面,如图所示:

左侧区域是绘图区,右侧区域是 palette 画板区域
鼠标先点击画板的元素即可在左侧绘图
绘制流程
使用滑板来绘制流程,通过从右侧把图标拖拽到左侧的画板,最终效果如下:

 

指定流程定义Key(如果左侧properties 视图出不来可以更换一下主题intellij light,然后重新打开文件
流程定义 key 即流程定义的标识,通过 properties 视图查看流程的 key
经理审批负责人为 jerry
总经理审批负责人为 jack
财务审批负责人为 rose

六、流程操作

6.1 流程定义

概述

流程定义是线下按照 bpmn2.0 标准去描述 业务流程,通常使用 idea 中的插件对业务流程进行建模。
使用 idea 下的 designer 设计器绘制流程,并会生成两个文件: .bpmn .png

.bpmn文件

使用 activiti-desinger 设计业务流程,会生成 .bpmn 文件,上面我们已经创建好了 bpmn 文件
BPMN 2.0 根节点是 definitions 节点。 这个元素中,可以定义多个流程定义(不过我们建议每个文件只包含一个流程定义, 可以简化开发过程中的维护难度)。 注意,definitions 元素 最少也要包含 xmlns targetNamespace 的声明。
targetNamespace 可以是任意值,它用来对流程实例进行分类。 流程定义部分:定义了流程每个结点的描述及结点之间的流程流转。
流程布局定义:定义流程每个结点在流程图上的位置坐标等信息。

生成.png图片文件

IDEA 工具中的操作方式
1 、修改文件后缀为 xml
首先将 evection.bpmn 文件改名为 evection.xml ,如下图:

 

2 、使用 designer 设计器打开 .xml 文件
evection.xml 文件上面,点右键并选择 Diagrams 菜单,再选择 Show BPMN2.0 Designer…

 

3 、查看打开的文件
打开后,如图:

 

4 、解决中文乱码
如果出现中文乱码问题,可参考以下操作解决
工作流学习之 IDEA 使用activiti插件 出现乱码
idea解决activiti(*.bpmn)文件乱码问题
一定到重新打开文件
最后重新在 evection.xml 文件上面,点右键并选择 Diagrams 菜单,再选择 Show BPMN2.0 Designer…
5 、导出为图片文件
点击 Export To File 的小图标,打开如下窗口,注意填写文件名及扩展名,选择好保存图片的位置:

然后,我们把png文件拷贝到resources下的bpmn目录,并且把evection.xml改名为evection.bpmn

6.2 流程定义部署

概述

将上面在设计器中定义的流程部署到 activiti 数据库中,就是流程定义部署。
通过调用 activiti api 将流程定义的 bpmn png 两个文件一个一个添加部署到 activiti 中,也可以将两个文件打成 zip 包进行部署。

单个文件部署方式

分别将 bpmn 文件和 png 图片文件部署。

 

package com.activiti.test;import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.junit.Test;public class ActivitiDemo {/*** 测试流程部署*/@Testpublic void testDeployment(){//1.创建ProcessEngineProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//2.获取RepositorySerrviceRepositoryService repositoryService = processEngine.getRepositoryService();//3.使用service进行流程的部署,定义一个流程的名字,把bpmn和png文件部署到数据库中Deployment deploy = repositoryService.createDeployment().name("出差申请").addClasspathResource("bpmn/evection.bpmn").addClasspathResource("bpmn/evection.png").deploy();//4.输出部署信息System.out.println("流程部署id="+deploy.getId());System.out.println("流程部署名字="+deploy.getName());}
}
执行此操作后 activiti 会将上边代码中指定的 bpm 文件和图片文件保存在 activiti 数据库。
压缩包部署方式
evection.bpmn evection.png 压缩成 zip 包。
可以同时部署多个流程
/*** 使用zip包进行批量的部署*/@Testpublic void deployProcessByZip() {//1.获取流程引擎ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//2.获取repositoryServiceRepositoryService repositoryService = processEngine.getRepositoryService();//3.流程部署//读取资源包文件,构造成inputStreamInputStream stream = this.getClass().getClassLoader().getResourceAsStream("bpmn/evection.zip");//用inputstream 构造成zioinputstreamZipInputStream zipInputStream = new ZipInputStream(stream);//使用压缩包的流进行流程构建Deployment deploy = repositoryService.createDeployment().addZipInputStream(zipInputStream).deploy();System.out.println("流程部署id=" + deploy.getId());System.out.println("流程部署名字=" + deploy.getName());}

操作数据表
流程定义部署后操作 activiti 3 张表如下:
act_re_deployment 流程定义部署表,每部署一次增加一条记录
act_re_procdef 流程定义表,部署每个新的流程定义都会在这张表中增加一条记录
act_ge_bytearray 流程资源表
接下来我们来看看,写入了什么数据:
SELECT * FROM act_re_deployment; #流程定义部署表,记录流程部署信息

SELECT * FROM act_re_procdef; #流程定义表,记录流程定义信息
结果:
注意, KEY 这个字段是用来唯一识别不同流程的关键字

 

SELECT * FROM act_ge_bytearray; #资源表

 

注意:
act_re_deployment act_re_procdef 一对多关系,一次部署在流程部署表生成一条记录,但一次部署可以部署多个流程定义,每个流程定义在流程定义表生成一条记录。每一个流程定义在act_ge_bytearray 会存在两个资源记录, bpmn 和png
建议:一次部署一个流程,这样部署表和流程定义表是一对一有关系,方便读取流程部署及流程定义信息。
流程定义部署
    1、使用流程设计器,使用流程符号,画出流程图
       bpmn文件、png文件
       都是流程资源文件,用来描述流程,流程中需要的节点,节点的负责人
    
    2、把流程资源文件进行部署
       上传到数据库中,使用java代码来进行部署
       一次部署操作:act_re_deployment 会生成一条记录
                     act_re_procdef 生成流程定义信息
    3、deployment和procdef表 一对多关系
       在procdef表中可以有多条记录,每条记录对应一个流程的定义信息
       
       同样是出差申请  张三和李四 的流程可以不同

6.3 启动流程实例

流程定义部署在 activiti 后就可以通过工作流管理业务流程了,也就是说上边部署的出差申请流程可以使用了。
针对该流程,启动一个流程表示发起一个新的出差申请单,这就相当于 java 类与 java 对象的关系,类定义好后需要new创建一个对象使用,当然可以 new 多个对象。对于请出差申请流程,张三发起一个出差申请单需要启动一个流程实例,出差申请单发起一个出差单也需要启动一个流程实例。
代码如下:
/*** 启动流程实例*/@Testpublic void testStartProcess(){//1.创建ProcessEngineProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//2.获取RunTimeServiceRuntimeService runtimeService = processEngine.getRuntimeService();//3.根据流程定义的id启动流程ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection");//4.输出内容System.out.println("流程定义id="+instance.getProcessDefinitionId());System.out.println("流程实例id="+instance.getId());System.out.println("当前活动的id="+instance.getActivityId());}
输出内容如下:

 

操作数据表
act_hi_actinst 流程实例执行历史
act_hi_identitylink 流程的参与用户历史信息
act_hi_procinst 流程实例历史信息
act_hi_taskinst 流程任务历史信息
act_ru_execution 流程执行信息
act_ru_identitylink 流程的参与用户信息
act_ru_task 流程当前 任务信息

6.4 任务查询

流程启动后,任务的负责人就可以查询自己当前需要处理的任务,查询出来的任务都是该用户的待办任务。
@Testpublic void testFindPersonalTaskList(){//1.创建ProcessEngineProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//2.获取taskServiceTaskService taskService = processEngine.getTaskService();//3.根据流程key和任务的负责人查询任务List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("myEvection") //流程key.taskAssignee("zhangsan") //要查询的负责人.list();//4.输出for (Task task : taskList) {System.out.println("流程实例id="+task.getProcessInstanceId());System.out.println("任务id="+task.getId());System.out.println("任务负责人="+task.getAssignee());System.out.println("任务名称="+task.getName());}}

输出结果如下:

 

select distinct RES.* 
from ACT_RU_TASK RES inner join ACT_RE_PROCDEF D on RES.PROC_DEF_ID_ = D.ID_ 
WHERE RES.ASSIGNEE_ = 'zhangsan' and D.KEY_ = 'myEvection' 
order by RES.ID_ asc 
LIMIT 2147483647 OFFSET 0 

6.5 流程任务处理

任务负责人查询待办任务,选择任务进行处理,完成任务。
/*** 完成个人任务*/@Testpublic void completTask() {//1.获取流程引擎ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//2.获取taskServiceTaskService taskService = processEngine.getTaskService();// 根据流程key 和 任务的负责人 查询任务// 返回一个任务对象Task task = taskService.createTaskQuery().processDefinitionKey("myEvection") //流程Key.taskAssignee("zhangsan") //要查询的负责人.singleResult();// 完成任务,参数:任务idtaskService.complete(task.getId());}

操作数据库表:

ACT_HI_TASKINST --insert 下一步任务
ACT_HI_ACTINST --insert 下一步任务
ACT_HI_IDENTITYLINK  --insert 下一步任务负责人
ACT_RU_TASK   --insert 下一步任务
ACT_RU_IDENTITYLINK --insert 下一步任务负责人
ACT_HI_ACTINST  --update 完成当前操作
ACT_HI_TASKINST  --update 完成当前操作
ACT_RU_EXECUTION  --update 完成当前操作
ACT_RU_TASK  --删除当前操作

6.6 流程定义信息查询

查询流程相关信息,包含流程定义,流程部署,流程定义版本
/*** 查询流程定义*/@Testpublic void queryProcessDefinition() {// 获取引擎ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// repositoryServiceRepositoryService repositoryService = processEngine.getRepositoryService();// 得到ProcessDefinitionQuery 对象ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();// 查询出当前所有的流程定义// 条件:processDefinitionKey =evection// orderByProcessDefinitionVersion 按照版本排序// desc倒叙// list 返回集合List<ProcessDefinition> definitionList = processDefinitionQuery.processDefinitionKey("myEvection").orderByProcessDefinitionVersion().desc().list();// 输出流程定义信息for (ProcessDefinition processDefinition : definitionList) {System.out.println("流程定义 id=" + processDefinition.getId());System.out.println("流程定义 name=" + processDefinition.getName());System.out.println("流程定义 key=" + processDefinition.getKey());System.out.println("流程定义 Version=" + processDefinition.getVersion());System.out.println("流程部署ID =" + processDefinition.getDeploymentId());}}

6.7 流程删除

/*** 流程删除*/@Testpublic void deleteDeployment() {// 流程部署idString deploymentId = "1";ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 通过流程引擎获取repositoryServiceRepositoryService repositoryService = processEngine.getRepositoryService();// 删除流程定义,如果该流程定义已有流程实例启动则删除时出错repositoryService.deleteDeployment(deploymentId);// 设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除,设置为false非级别删除方式,如果流 程// repositoryService.deleteDeployment(deploymentId, true);}
说明:
1) 使用 repositoryService 删除流程定义,历史表信息不会被删除
2) 如果该流程定义下没有正在运行的流程,则可以用普通删除。
如果该流程定义下存在已经运行的流程,使用普通删除报错,可用级联删除方法将流程及相关记录全部删除。
先删除没有完成流程节点,最后就可以完全删除流程定义信息
项目开发中级联删除操作一般只开放给超级管理员使用 .

6.8 流程资源下载

现在我们的流程资源文件已经上传到数据库了,如果其他用户想要查看这些资源文件,可以从数据库中把资源文件下载到本地。
解决方案有:
1 jdbc blob 类型, clob 类型数据读取出来,保存到文件目录
2 、使用 activiti api 来实现
使用 commons-io.jar 解决 IO 的操作
引入 commons-io 依赖包
        <dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency>
通过流程定义对象获取流程定义资源,获取 bpmn png
@Testpublic void queryBpmnFile() throws IOException {// 1、得到引擎ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 2、获取repositoryServiceRepositoryService repositoryService = processEngine.getRepositoryService();// 3、得到查询器:ProcessDefinitionQuery,设置查询条件,得到想要的流程定义ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey("myEvection").singleResult();// 4、通过流程定义信息,得到部署IDString deploymentId = processDefinition.getDeploymentId();// 5、通过repositoryService的方法,实现读取图片信息和bpmn信息// png图片的流InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());// bpmn文件的流InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getResourceName());// 6、构造OutputStream流File file_png = new File("E:\\activiti\\code\\activiti01\\evectionflow01.png");File file_bpmn = new File("E:\\activiti\\code\\activiti01\\evectionflow01.bpmn");FileOutputStream bpmnOut = new FileOutputStream(file_bpmn);FileOutputStream pngOut = new FileOutputStream(file_png);// 7、输入流,输出流的转换IOUtils.copy(pngInput, pngOut);IOUtils.copy(bpmnInput, bpmnOut);// 8、关闭流pngOut.close();bpmnOut.close();pngInput.close();bpmnInput.close();}
说明:
1) deploymentId 为流程部署 ID
2) resource_name act_ge_bytearray 表中 NAME_ 列的值
3) 使用 repositoryService getDeploymentResourceNames 方法可以获取指定部署下得所有文件的名称
4) 使用 repositoryService getResourceAsStream 方法传入部署 ID 和资源图片名称可以获取部署下指定名称文件的输入流
最后的将输入流中的图片资源进行输出。

6.9 流程历史信息的查看

即使流程定义已经删除了,流程执行的历史信息通过前面的分析,依然保存在 activiti act_hi_* 相关的表中。所以我 们还是可以查询流程执行的历史信息,可以通过HistoryService 来查看相关的历史记录。
    /*** 查看历史信息*/@Testpublic void findHistoryInfo() {// 获取引擎ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 获取HistoryServiceHistoryService historyService = processEngine.getHistoryService();// 获取 actinst表的查询对象HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();// 查询 actinst表,条件:根据 InstanceId 查询// instanceQuery.processInstanceId("2501");// 查询 actinst表,条件:根据 DefinitionId 查询instanceQuery.processDefinitionId("myEvection:1:4");// 增加排序操作,orderByHistoricActivityInstanceStartTime 根据开始时间排序 asc 升序instanceQuery.orderByHistoricActivityInstanceStartTime().asc();// 查询所有内容List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();// 输出for (HistoricActivityInstance hi : activityInstanceList) {System.out.println(hi.getActivityId());System.out.println(hi.getActivityName());System.out.println(hi.getProcessDefinitionId());System.out.println(hi.getProcessInstanceId());System.out.println("<==========================>");}}

这篇关于Activiti7工作流入门和基本使用-Activiti入门和流程操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/272512

相关文章

如何使用celery进行异步处理和定时任务(django)

《如何使用celery进行异步处理和定时任务(django)》文章介绍了Celery的基本概念、安装方法、如何使用Celery进行异步任务处理以及如何设置定时任务,通过Celery,可以在Web应用中... 目录一、celery的作用二、安装celery三、使用celery 异步执行任务四、使用celery

使用Python绘制蛇年春节祝福艺术图

《使用Python绘制蛇年春节祝福艺术图》:本文主要介绍如何使用Python的Matplotlib库绘制一幅富有创意的“蛇年有福”艺术图,这幅图结合了数字,蛇形,花朵等装饰,需要的可以参考下... 目录1. 绘图的基本概念2. 准备工作3. 实现代码解析3.1 设置绘图画布3.2 绘制数字“2025”3.3

Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单

《Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单》:本文主要介绍Springboot的ThreadPoolTaskScheduler线... 目录ThreadPoolTaskScheduler线程池实现15分钟不操作自动取消订单概要1,创建订单后

Jsoncpp的安装与使用方式

《Jsoncpp的安装与使用方式》JsonCpp是一个用于解析和生成JSON数据的C++库,它支持解析JSON文件或字符串到C++对象,以及将C++对象序列化回JSON格式,安装JsonCpp可以通过... 目录安装jsoncppJsoncpp的使用Value类构造函数检测保存的数据类型提取数据对json数

python使用watchdog实现文件资源监控

《python使用watchdog实现文件资源监控》watchdog支持跨平台文件资源监控,可以检测指定文件夹下文件及文件夹变动,下面我们来看看Python如何使用watchdog实现文件资源监控吧... python文件监控库watchdogs简介随着Python在各种应用领域中的广泛使用,其生态环境也

Python中构建终端应用界面利器Blessed模块的使用

《Python中构建终端应用界面利器Blessed模块的使用》Blessed库作为一个轻量级且功能强大的解决方案,开始在开发者中赢得口碑,今天,我们就一起来探索一下它是如何让终端UI开发变得轻松而高... 目录一、安装与配置:简单、快速、无障碍二、基本功能:从彩色文本到动态交互1. 显示基本内容2. 创建链

SpringBoot操作spark处理hdfs文件的操作方法

《SpringBoot操作spark处理hdfs文件的操作方法》本文介绍了如何使用SpringBoot操作Spark处理HDFS文件,包括导入依赖、配置Spark信息、编写Controller和Ser... 目录SpringBoot操作spark处理hdfs文件1、导入依赖2、配置spark信息3、cont

springboot整合 xxl-job及使用步骤

《springboot整合xxl-job及使用步骤》XXL-JOB是一个分布式任务调度平台,用于解决分布式系统中的任务调度和管理问题,文章详细介绍了XXL-JOB的架构,包括调度中心、执行器和Web... 目录一、xxl-job是什么二、使用步骤1. 下载并运行管理端代码2. 访问管理页面,确认是否启动成功

使用Nginx来共享文件的详细教程

《使用Nginx来共享文件的详细教程》有时我们想共享电脑上的某些文件,一个比较方便的做法是,开一个HTTP服务,指向文件所在的目录,这次我们用nginx来实现这个需求,本文将通过代码示例一步步教你使用... 在本教程中,我们将向您展示如何使用开源 Web 服务器 Nginx 设置文件共享服务器步骤 0 —

Java中switch-case结构的使用方法举例详解

《Java中switch-case结构的使用方法举例详解》:本文主要介绍Java中switch-case结构使用的相关资料,switch-case结构是Java中处理多个分支条件的一种有效方式,它... 目录前言一、switch-case结构的基本语法二、使用示例三、注意事项四、总结前言对于Java初学者