一、Activiti入门

在本章内容中,我们来创建一个Activiti工作流,并启动这个流程。

创建Activiti工作流主要包含以下几步:

1、定义流程,按照BPMN的规范,使用流程定义工具,用流程符号把整个流程描述出来

2、部署流程,把画好的流程定义文件,加载到数据库中,生成表的数据

3、启动流程,使用java代码来操作数据库表中的内容

1 流程符号

BPMN 2.0是业务流程建模符号2.0的缩写。

它由Business Process Management Initiative这个非营利协会创建并不断发展。作为一种标识,BPMN 2.0是使用一些符号来明确业务流程设计流程图的一整套符号规范,它能增进业务建模时的沟通效率。

目前BPMN2.0是最新的版本,它用于在BPM上下文中进行布局和可视化的沟通。

接下来我们先来了解在流程设计中常见的 符号。

BPMN2.0的基本符合主要包含:

事件 Event

1.1 活动 Activity

活动是工作或任务的一个通用术语。一个活动可以是一个任务,还可以是一个当前流程的子处理流程; 其次,你还可以为活动指定不同的类型。常见活动如下:

1.2 网关 GateWay

网关用来处理决策,有几种常用网关需要了解:

1.2.1 排他网关 (x)

——只有一条路径会被选择。流程执行到该网关时,按照输出流的顺序逐个计算,当条件的计算结果为true时,继续执行当前网关的输出流;

​ 如果多条线路计算结果都是 true,则会执行第一个值为 true 的线路。如果所有网关计算结果没有true,则引擎会抛出异常。

​ 排他网关需要和条件顺序流结合使用,default 属性指定默认顺序流,当所有的条件不满足时会执行默认顺序流。

1.2.2 并行网关 (+)

——所有路径会被同时选择

​ 拆分 —— 并行执行所有输出顺序流,为每一条顺序流创建一个并行执行线路。

​ 合并 —— 所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行。

1.2.3 包容网关 (+)

—— 可以同时执行多条线路,也可以在网关上设置条件

​ 拆分 —— 计算每条线路上的表达式,当表达式计算结果为true时,创建一个并行线路并继续执行

​ 合并 —— 所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行。

1.2.4 事件网关 (+)

—— 专门为中间捕获事件设置的,允许设置多个输出流指向多个不同的中间捕获事件。当流程执行到事件网关后,流程处于等待状态,需要等待抛出事件才能将等待状态转换为活动状态。

1.3 流向 Flow

流是连接两个流程节点的连线。常见的流向包含以下几种:

2 流程设计器使用

2.1 Activiti-Designer使用

2.1.1 Palette(画板)

在idea中安装插件即可使用,画板中包括以下结点:

Connection—连接

Event—事件

Task—任务

Gateway—网关

Container—容器

Boundary event—边界事件

Intermediate event- -中间事件

流程图设计完毕保存生成.bpmn文件

2.1.2 新建流程(IDEA工具)

首先选中存放图形的目录(选择resources下的bpmn目录),点击菜单:New -> BpmnFile,如图:

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

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

左侧区域是绘图区,右侧区域是palette画板区域

鼠标先点击画板的元素即可在左侧绘图

2.2 绘制流程
使用滑板来绘制流程,通过从右侧把图标拖拽到左侧的画板,最终效果如下:


2.3 指定流程定义Key
流程定义key即流程定义的标识,通过properties视图查看流程的key

2.4 指定任务负责人
在properties视图指定每个任务结点的负责人,如:填写出差申请的负责人为 zhangsan

经理审批负责人为 jerry

总经理审批负责人为 jack

财务审批负责人为 rose

流程定义

概述

流程定义是线下按照bpmn2.0标准去描述 业务流程,通常使用idea中的插件对业务流程进行建模。

使用idea下的designer设计器绘制流程,并会生成两个文件;.bpmn和.png

.bpmn文件

使用activiti-designer设计业务流程,会生成.bpmn文件。上面我们已经创建好bpmn文件

BPMN2.0根节点是defintions节点。这个元素中,可以定义多个流程定义。注意,defintions元素最少也要包含xmlns和targetNamespace的声明。targetNamespace可以是任意值,它用来对流程实列进行分类。

流程定义部分:定义了流程每个结点的描述及结点之间的流程流转。

流程布局定义:定义流程每个结点在流程图上的位置坐标等信息。

生成.png图片文件

具体步骤如下,
一:利用bpmn文件生成png图片
1,更改bpmn文件扩展名为xml文件;

2,如图操作,holiday.xml-Diagrams-show BPMN 2.0 Designer,

出现如下界面,点击export to file,把生成的图片保存在某个位置;

3,找到生成的图片并查看;
注意:如果图片中出现了中文乱码,则按照后面介绍的方法进行解决!

4,把png图片复制到项目中;

解决中文乱码

二:生成的png图片,中文乱码的解决办法

打开setting,找到File Encodings把encoding的选项都选择UTF-8
1,找到idea的安装目录的bin中的两个文件(idea.exe.vmoptions及idea64.exe.vmoptions);

2,利用编辑工具分别打开两个文件,进行如下更改;
注意:可以使用Notepad++或Editplus等编辑工具打开编辑!

3,重新启动idea,并重新绘制bpmn图,再次按照步骤一进行操作,即可完成操作.

流程部署实现

单个文件部署方式

分别将bpmn20.xml文件和png图片文件部署。

创建并执行下面代码

创建一个类ActivitiDemo


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、得到RepositoryService实例RepositoryService repositoryService = processEngine.getRepositoryService();
//        3、使用RepositoryService进行部署Deployment deployment = repositoryService.createDeployment().addClasspathResource("bpmn/evection.bpmn20.xml") // 添加bpmn资源.addClasspathResource("bpmn/evection.png")  // 添加png资源.name("出差申请流程").deploy();
//        4、输出部署信息System.out.println("流程部署id:" + deployment.getId());System.out.println("流程部署名称:" + deployment.getName());}
}

执行此操作后activiti会将上边代码中指定的bpm文件和图片文件保存在activiti数据库。
执行如下图即成功

压缩包部署方式
将evection.bpmn和evection.png压缩成zip包。

  @Testpublic void deployProcessByZip() {//获取流程引擎ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 获取repositoryServiceRepositoryService repositoryService = processEngine.getRepositoryService();// 定义zip输入流InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("bpmn/evection.zip");//用inputStream构造ZipInputStreamZipInputStream zipInputStream = new ZipInputStream(inputStream);// 流程部署Deployment deployment = repositoryService.createDeployment().addZipInputStream(zipInputStream).deploy();System.out.println("流程部署id:" + deployment.getId());System.out.println("流程部署名称:" + deployment.getName());}

执行此操作后activiti会将上边代码中指定的bpm文件和图片文件保存在activiti数据库。

操作数据表
流程定义部署后操作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。

建议:一次部署一个流程,这样部署表和流程定义表是一对一有关系,方便读取流程部署及流程定义信息。

流程部署操作分析

ACT_RE_DEPLOYEMET 流程部署表:每部署一次会增加一条记录

ACT_RE_PRCOEF 流程定义表

ACT_GE_BYTEARRAY  流程资源表

流程部署知识点

流程定义部署

1.使用流程设计器、使用流程符号、画出原型图

bpmn文件、png文件

都是流程资源文件:用来描述流程、流程中需要的节点、节点的负责人

出差申请流程、请假申请流程、报销申请流程

2、把流程的资源文件、进行部署

上传到数据库中、使用java代码来进行流程部署

一次部署操作:ACT_RE_DEPLOYMENT会生成一条记录

ACT_RE_PROCDEF生成流程定义信息

3、deloyment和procdef表 一对多的关系

在procde表中可以有多条记录,每条记录对应一个流程的定义信息

张三 出差申请

李四 出差申请

启动流程实例

流程定义部署在activiti后就可以通过工作流管理业务流程了,也就是说上边部署的出差申请流程可以使用了。

针对该流程,启动一个流程表示发起一个新的出差申请单,这就相当于java类与java对象的关系,类定义好后需要new创建一个对象使用,当然可以new多个对象。对于请出差申请流程,张三发起一个出差申请单需要启动一个流程实例,出差申请单发起一个出差单也需要启动一个流程实例。

代码如下:

    /*** 启动流程实例*/@Testpublic void testStartProcess(){
//        1、创建ProcessEngineProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        2、获取RunTimeServiceRuntimeService runtimeService = processEngine.getRuntimeService();
//        3、根据流程定义Id启动流程ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("evection");
//        输出内容System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());System.out.println("流程实例id:" + processInstance.getId());System.out.println("当前活动Id:" + processInstance.getActivityId());}

输出内容如下:

操作数据表

act_hi_actinst 流程实例执行历史

act_hi_identitylink 流程的参与用户历史信息

act_hi_procinst 流程实例历史信息

act_hi_taskinst 流程任务历史信息

act_ru_execution 流程执行信息

act_ru_identitylink 流程的参与用户信息

act_ru_task 任务信息

(二)启动流程修改的表

1. ACT_HI_TASKINST(历史任务实例数据表)

2. ACT_HI_PROCINST(历史流程实例数据表,正在执行的任务也在其中)

3. ACT_HI_ACTINST(历史节点数据,图片上的节点信息)

4. ACT_HI_IDENTITYLINK(历史流程用户信息数据表)

5. ACT_RU_EXECUTION(运行时流程执行实例数据表,一条是开始事件的执行实例,这个一直存在,只到流程结束后才会自动删除,is_active字段表示是否正在执行实例)

6. ACT_RU_TASK(运行时任务信息数据信息表)

任务查询

流程启动后,任务的负责人就可以查询自己当前需要处理的任务,查询出来的任务都是该用户的待办任务。

  /*** 查询当前个人待执行的任务*/@Testpublic void testFindPersonalTaskList() {
//    任务负责人String assignee = "zhangsan";//1.获取流程引擎ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//    2.创建TaskServiceTaskService taskService = processEngine.getTaskService();
//   3. 根据流程key 和 任务负责人 查询任务List<Task> list = taskService.createTaskQuery().processDefinitionKey("evection") //流程Key.taskAssignee(assignee)//只查询该任务负责人的任务.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());}}

输出结果如下:

流程实例id:2501
任务id:2505
任务负责人:小付
任务名称:出差申请单

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

流程任务处理

任务负责人查询待办任务,选择任务进行处理,完成任务。

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

操作数据表

act_hi_taskinst 历史任务实例表

act_hi_actinst 历史节点表

act_ru_identitylink  历史流程人员表

act_ru_task 任务信息

act_ru_identitylink  历史流程人员表

act_hi_taskinst 历史任务实例表  update

act_ru_execution 运行时流程执行实例表  update

act_hi_actinst 历史节点表  update

act_ru_task 任务信息 delete

(三)完成个人任务修改的表、

ACT_HI_TASKINST(历史的任务实例表)

1、zhangsan完成任务(插入下一个jerry的任务实例,zhangsan任务实例end_time加入处理完结时间)

2、jerry完成任务(插入下一个jack的任务实例,jerry任务实例end_time加入处理完结时间)

3、jack完成任务(插入下一个rose的任务实例,jack任务实例end_time加入处理完结时间)

4、rose完成任务(插入结束的任务实例,任务实例end_time加入处理完结时间)

ACT_HI_ACTINST(历史节点数据)

1、zhangsan完成任务(插入下一个经理审批节点,节点中taskid为运行时任务信息表中的id,end_time加入处理完结时间)


2、jerry完成任务(插入下一个总经理节点,节点中taskid为运行时任务信息表中的id,end_time加入处理完结时间)

3、jack完成任务(插入下一个财务审批节点,节点中taskid为运行时任务信息表中的id,end_time加入处理完结时间)


4、rose完成任务(插入下一个结束节点,节点中taskid为运行时任务信息表中的id,end_time加入处理完结时间)

ACT_HI_IDENTITYLINK(历史流程用户信息数据表)

1、zhangsan完成任务(插入jerry负责人)

2、jerry完成任务(插入jack负责人)

3、jack完成任务(插入rose负责人)

ACT_RU_TASK(运行时任务信息数据信息表)

1、zhangsan完成任务(删除了10005zhangsan的创建出差申请任务,添加了经理审批任务记录)


2、jerry完成任务(删除了12502jerry的经理审批任务,添加了总经理审批任务记录)

3、jack完成任务(删除了15002jerry的总经理审批任务,添加了财务审批任务记录)

3、rose完成任务(删除了17502jack的财务审批任务)
ACT_RU_IDENTITYLINK(运行时用户信息数据)

1、zhangsan完成任务(插入jerry负责人)

2、jerry完成任务(插入jack负责人)

3、jack完成任务(插入rose负责人)

4、rose完成任务(删除所有记录)
ACT_RU_EXECUTION(运行时流程执行实例数据表)

  • 1、zhangsan完成任务(第二条记录改为_4id的节点(经理审批))

  • 2、jerry完成任务(第二条记录改为_5id的节点(总经理经理审批))

  • 3、jack完成任务(第二条记录改为_6id的节点(财务审批))

4、rose完成任务(第一、二条记录删除细节):
第一步先更改第二条记录REV为5、ACT_ID_为_7(结束节点)
第二步删除id为10002的记录。
第三步删除结束节点,id为10001的记录。

ACT_HI_PROCINST(历史流程实例数据表)

  • 4、rose完成任务:end_time更新为完成时间、end_act_id_更新为最后一个节点的id

流程定义信息查询

查询流程相关信息,包含流程定义,流程部署,流程定义版本

 /*** 查询流程定义*/@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("evection").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());}}

输出结果:

流程定义 id=evection:1:4
流程定义 name=evection
流程定义 key=evection
流程定义 Version=1
流程部署ID =1

流程删除

public void deleteDeployment() {// 流程部署idString deploymentId = "1";ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 通过流程引擎获取repositoryServiceRepositoryService repositoryService = processEngine.getRepositoryService();//删除流程定义,如果该流程定义已有流程实例启动则删除时出错repositoryService.deleteDeployment(deploymentId);//设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除,设置为false非级别删除方式,如果流程//repositoryService.deleteDeployment(deploymentId, true);}@Testpublic void deleteDeployment(){
//        获取引擎ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        获取repositoryServiceRepositoryService repositoryService = processEngine.getRepositoryService();
//        根据部署id 删除部署信息,如果想要级联删除,可以添加第二个参数,truerepositoryService.deleteDeployment("1");}

说明:

1.使用repositoryService删除流程定义,历史表信息不会被删除
  2.如果该流程定义下没有正在运行的流程,则可以用普通删除。

如果该流程定义下存在已经运行的流程,使用普通删除报错,可用级联删除方法将流程及相关记录全部删除。

先删除没有完成流程节点,最后就可以完全删除流程定义信息

项目开发中级联删除操作一般只开放给超级管理员使用.

流程资源下载

现在我们的流程资源文件已经上传到数据库了,如果其他用户想要查看这些资源文件,可以从数据库中把资源文件下载到本地。

解决方案有:

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

import org.apache.commons.io.IOUtils;@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("d:/evectionflow01.png");File file_bpmn = new File("d:/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();}

说明:

deploymentId为流程部署ID
  resource_name为act_ge_bytearray表中NAME_列的值
  使用repositoryService的getDeploymentResourceNames方法可以获取指定部署下得所有文件的名称
  使用repositoryService的getResourceAsStream方法传入部署ID和资源图片名称可以获取部署下指定名称文件的输入流

最后的将输入流中的图片资源进行输出。

流程历史信息的查看

即使流程定义已经删除了,流程执行的历史信息通过前面的分析,依然保存在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("<==========================>");}}

流程实例

什么是流程实例

流程实例(ProcessInstance)代表流程定义的执行实例。

一个流程实例包括了所有的运行节点。我们可以利用这个对象来了解当前流程实例的进度等信息。

例如:用户或程序按照流程定义内容发起一个流程,这就是一个流程实例。

流程定义和流程实例的图解:

实际工作中,需要把自己的业务表和Activiti的表进行关联,才能真正完成实际的业务

详细说明:

启动流程实例 并添加Businesskey(业务标识)

流程定义部署在activiti后,就可以在系统中通过activiti去管理该流程的执行,执行流程表示流程的一次执行。

比如部署系统出差流程后,如果某用户要申请出差这时就需要执行这个流程,如果另外一个用户也要申请出差则也需要执行该流程,每个执行互不影响,每个执行是单独的流程实例。

启动流程实例时,指定的businesskey,就会在act_ru_execution #流程实例的执行表中存储businesskey。

Businesskey:业务标识,通常为业务表的主键,业务标识和流程实例一一对应。业务标识来源于业务系统。存储业务标识就是根据业务标识来关联查询业务系统的数据。

比如:出差流程启动一个流程实例,就可以将出差单的id作为业务标识存储到activiti中,将来查询activiti的流程实例信息就可以获取出差单的id从而关联查询业务系统数据库得到出差单信息。

    /*** 启动流程实例,添加businessKey*/@Testpublic void addBusinessKey(){
//        1、得到ProcessEngineProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        2、得到RunTimeServiceRuntimeService runtimeService = processEngine.getRuntimeService();
//        3、启动流程实例,同时还要指定业务标识businessKey,也就是出差申请单id,这里是1001
// 第一个参数流程定义的key,第二个参数就是businessKey(这个key就是我们自身业务的key,后续更具需求变化,demo中我是写死了的)ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("evection","1001");
//        4、输出processInstance相关属性System.out.println("业务id=="+processInstance.getBusinessKey());}

Activiti的act_ru_execution中存储业务标识:

操作数据库

启动流程实例,操作如下数据库

SELECT * FROM   act_ru_execution #流程实列执行表,记录当前流程实列的执行情况

说明

流程实列执行,如果当前只有一个分支时,一个流程实列只有一条记录并且执行表的主键id和流程实列id相同,如果当前多个分支正在运行则该执行表中有多条记录,存在执行表的主键和流程实列id不相同的记录,不论当前有几个分支总会有一条记录执行表的主键和流程实列id相同

一个流程实列运行完成,此表与流程实列相关的记录删除。

SELECT * FROM act_ru_task#任务执行表,记录当前执行的任务

说明:启动流程实列,流程当前执行到第一个任务点,此表会插入一条记录表示当前任务的执行情况,如果任务完成则记录删除。

SELECT * FROM act_ru_identitylink # 任务参与者,记录当前参与任务的用户或者组

SELECT * FROM act_hi_procinst #流程实列历史表

流程实列启动,会在此表插入一条记录,流程实列运行完成记录也不会删除.

SELECT * FROM act_hi_taskinst #任务历史表,记录所有任务

开始一个任务,不仅在act_ru_task表插入记录,也会在历史任务表插入一条记录,任务历史表的主键就是任务id,任务完成此表记录不删除.

SELECT * FROM act_hi_actinst #活动历史表,记录所有活动

活动包括任务,所以表中1不仅记录了任务,还记录了流程执行过程的其他活动比如开始事件、结束事件

查询流程实例

流程在运行过程中可以查询流程实例的状态,当前运行结点等信息。

@Testpublic void queryProcessInstance() {// 流程定义keyString processDefinitionKey = "evection";ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 获取RunTimeServiceRuntimeService runtimeService = processEngine.getRuntimeService();List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().processDefinitionKey(processDefinitionKey)//.list();for (ProcessInstance processInstance : list) {System.out.println("----------------------------");System.out.println("流程实例id:"+ processInstance.getProcessInstanceId());System.out.println("所属流程定义id:"+ processInstance.getProcessDefinitionId());System.out.println("是否执行完成:" + processInstance.isEnded());System.out.println("是否暂停:" + processInstance.isSuspended());System.out.println("当前活动标识:" + processInstance.getActivityId());}}

关联BusinessKey
需求:

在activiti实际应用时,查询流程实例列表时可能要显示出业务系统的一些相关信息,比如:查询当前运行的出差流程列表需要将出差单名称、出差天数等信息显示出来,出差天数等信息在业务系统中存在,而并没有在activiti数据库中存在,所以是无法通过activiti的api查询到出差天数等信息。

实现:

在查询流程实例时,通过businessKey(业务标识 )关联查询业务系统的出差单表,查询出出差天数等信息。

通过下面的代码就可以获取activiti中所对应实例保存的业务Key。而这个业务Key一般都会保存相关联的业务操作表的主键,再通过主键ID去查询业务信息,比如通过出差单的ID,去查询更多的请假信息(出差人,出差时间,出差天数,出差目的地等)

String businessKey = processInstance.getBusinessKey();

在activiti的act_ru_execution表,字段BUSINESS_KEY就是存放业务KEY的。

挂起、激活流程实例

某些情况可能由于流程变更需要将当前运行的流程暂停而不是直接删除,流程暂停后将不会继续执行。

全部流程实例挂起

操作流程定义为挂起状态,该流程定义下边所有的流程实例全部暂停:

流程定义为挂起状态该流程定义将不允许启动新的流程实例,同时该流程定义下所有的流程实例将全部挂起暂停执行。

Activiti实现流程定义的全部挂起与激活

   /*** 全部流程实例的 挂起 和 激活*/@Testpublic void suspendAllProcessInstance(){
//        1、得到流程引擎ProcessEngineProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        2、得到serviceRepositoryService repositoryService = processEngine.getRepositoryService();
//        3、查询流程定义ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().processDefinitionKey("evection");ProcessDefinition processDefinition = processDefinitionQuery.singleResult();
//        4、获取当前流程定义的实例是否都是挂起的状态boolean suspended = processDefinition.isSuspended();//5.获取流程定义的idString id = processDefinition.getId();if (suspended){//如果是挂起状态,改为激活//参数1 流程定义id  参数2 是否要激活 参数3 激活时间repositoryService.activateProcessDefinitionById(id,true,null);System.out.println("流程定义:"+id+",已挂起");}else {//如果是正常状态,改为挂起状态//参数1 流程定义id  参数2 是否要挂起 参数3 挂起时间repositoryService.suspendProcessDefinitionById(id,true,null);System.out.println("流程定义:"+id+",已挂起");}}

单个流程实例挂起
Activiti实现流程定义的单个流程实例挂起与激活
操作流程实例对象,针对单个流程执行挂起操作,某个流程实例挂起则此流程不再继续执行,完成该流程实例的当前任务将报异常。

/*** 单个流程实例挂起与激活*/@Testpublic void SuspendSingleProcessInstance(){
//        获取processEngineProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        RuntimeServiceRuntimeService runtimeService = processEngine.getRuntimeService();
//        查询流程定义的对象ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId("15001").singleResult();
//        得到当前流程定义的实例是否都为暂停状态boolean suspended = processInstance.isSuspended();
//        流程定义idString processDefinitionId = processInstance.getId();
//        判断是否为暂停if(suspended){
//         如果是暂停,可以执行激活操作 ,参数:流程定义idruntimeService.activateProcessInstanceById(processDefinitionId);System.out.println("流程定义:"+processDefinitionId+",已激活");}else{
//          如果是激活状态,可以暂停,参数:流程定义idruntimeService.suspendProcessInstanceById( processDefinitionId);System.out.println("流程定义:"+processDefinitionId+",已挂起");}}

完成上面挂起了的单个流程实例会成功吗?
答案:不能,解释如下实例

   /*** 测试完成个人任务*/@Testpublic void completTask(){
//        获取引擎ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        获取操作任务的服务 TaskServiceTaskService taskService = processEngine.getTaskService();
//        完成任务,参数:流程实例id,完成小付的任务Task task = taskService.createTaskQuery().processInstanceId("15001").taskAssignee("小付").singleResult();System.out.println("流程实例id="+task.getProcessInstanceId());System.out.println("任务Id="+task.getId());System.out.println("任务负责人="+task.getAssignee());System.out.println("任务名称="+task.getName());taskService.complete(task.getId());}

任务完成失败
cannot complete a suspended task
不能完成一个挂起的任务

若想要完成,那么就将此单个任务激活后再来执行这个方法。

l

Activiti学习(二)之工作流的入门与流程实列相关推荐

  1. (转)MyBatis框架的学习(二)——MyBatis架构与入门

    http://blog.csdn.net/yerenyuan_pku/article/details/71699515 MyBatis框架的架构 MyBatis框架的架构如下图:  下面作简要概述: ...

  2. 《Activiti/Flowable  深入BPM工作流》-什么是流程变量?

               <Activiti/Flowable  深入BPM工作流>-什么是流程变量? 一. 问题:         1. 什么是流程变量?        2. 什么是glob ...

  3. Activiti学习(一)之工作流的介绍和使用

    什么是工作流 1. 工作流介绍 工作流(Workflow),就是通过计算机对业务流程自动化执行管理.它主要解决的是"使在多个参与者之间按照某种预定义的规则自动进行传递文档.信息或任务的过程, ...

  4. Activiti学习(4)简单的请假流程

    在前一篇文章的基础上,编写一个稍微复杂的请假流程,进一步熟悉Activiti的基本知识,并期望能够触类旁通,解决上一篇博文中没有解决的问题.实现过程中,参考了以下文章,在此向作者表示感谢. 1.act ...

  5. Kubernetes学习二:资源管理及入门实战

    此部分上接kubernetes学习一:https://blog.csdn.net/weixin_43155804/article/details/125831675?spm=1001.2014.300 ...

  6. V4L2学习 二 ----视频打开与保存简单流程

    open("/dev/video0") ->VIDIOC_S_INPUT             //set input ->VIDIOC_TRY_FMT        ...

  7. Activiti工作流从入门到入土:工作流简介

    文章源码托管:https://github.com/OUYANGSIHAI/Activiti-learninig 欢迎 star !!! 一.activiti介绍 Activiti5是由Alfresc ...

  8. 【青铜打铁篇】Activiti 工作流从入门到入土?

    点击上方"好好学java",选择"置顶"公众号 重磅资源.干货,第一时间送达 重磅推荐 ① 纯福利 | 公众号资源大汇总,一年才一次! ② 重磅!!2018年J ...

  9. Activiti工作流从入门到入土:完整Hello World大比拼(Activiti工作流 API结合实例讲解)

    文章源码托管:https://github.com/OUYANGSIHAI/Activiti-learninig 欢迎 star !!! 本来想着闲来无事,前面在项目中刚刚用到了工作流 Activit ...

  10. Activiti工作流从入门到入土:入门实例

    一.前言 在上一节中我们对activiti进行了基本的介绍activiti进行了基本的介绍,同时介绍了基本的概念. 这一节,我将用一个入门程序,介绍如何使用activiti. 二.环境准备 2.1.编 ...

最新文章

  1. 向Lucene增加中文分词功能
  2. NYOJ-523 亡命逃窜(三维立体的BFS)
  3. 问题生成的多样性会在多大程度上帮助下游QA任务?
  4. 对于如何删除redis中geo存入的坐标
  5. VTK:PolyData之SurfaceContourLineInterpolator
  6. Rundll32使用技巧
  7. vue/return-in-computed-property Enforce that a return statement is present in computed property
  8. 多态的概念、对象上下转型、多态的应用、异常(异常概念、异常分类、java异常处理机制、try...catch...finally、throw和throws、自定义异常)
  9. Java里面static, final, this, super, 代码块, 单例模式
  10. this.fields.get(c) is undefined
  11. 为什么机器学习在嵌入式系统中会失败?
  12. VB6.0动态加载ActiveX控件漫谈[转]
  13. grep常见操作整理(更新)
  14. “朝三暮四”与“BPO”
  15. python to datetime_Python中缺少datetime.timedelta.to_seconds()-float?
  16. 卡方检验检验水准矫正_医学统计学 第七章 卡方检验
  17. 微信小程序开发详细步骤是什么?
  18. java自行车s码适合身高_公路自行车尺寸与身高的选择
  19. 怎么做网站XML地图讲解
  20. R语言在逻辑回归中求R square R方

热门文章

  1. Flash 第二章 基本绘图工具-课堂笔记
  2. NLP任务增强:通过引入外部知识库来提供额外信息
  3. 纯HTML个人清新网站源码
  4. DNF2020年全新脚本展示第一部分
  5. docker-compose文件详解
  6. python--图像分割GraphCut
  7. android同步服务器时间同步,Android时间与服务器同步方案
  8. 中国大学生软件开发论坛 中国最大的大学生软件开发论坛
  9. vc2013控件第一个程序
  10. Bugku 社工——初步收集