Activiti7流程操作详解

编程入门 行业动态 更新时间:2024-10-19 16:29:05

Activiti7流程操作<a href=https://www.elefans.com/category/jswz/34/1770044.html style=详解"/>

Activiti7流程操作详解

一、Activiti流程操作步骤

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

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

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

  • 操作流程当中的各个任务

通过以上三步、就可以创建一个Activiti工作流、并且启动该流程。

二、常见流程符号

2.1 BPMN 2.0

BPMNBusiness Process Model AndNotation)- 业务流程模型和符号 是由BPMIBusinessProcess Management Initiative)开发的一套标准的业务流程建模符号,使用BPMN提供的符号可以创建业务流程。

BPMN 是目前被各 BPM 厂商广泛接受的 BPM 标准。

Activiti 就是使用 BPMN 2.0 进行流程建模、流程执行管理等。

BPMN的五类元素:

类别对象
流对象 (Flow Objects )事件( Events)、活动 (Activities )、网关 ( Gateways )
数据 (Data)数据对象 ( Data Objects )、数据输入 ( Data Inputs )、数据输出( Data Outputs )、数据存储 ( Data Stores )
连接对象 (Connecting Objects )顺序流 ( Sequence Flows )、消息流 ( Message Flows )、关联 ( Associations )、数据关联( Data Associations )
泳道(Swimlanes)池子( Pools)、泳道 ( Lanes)
工件 ( Artifacts )组 (Group )、文字注释

2.2 常用流程符号

1)事件 Event
  • 开始事件

  • 中间事件


  • 结束事件

2)活动 Activity

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

3)网关 GateWay

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

  • 排他网关 (x)

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

    如果多条线路计算结果都是 true,则会执行第一个值为 true 的线路。

    如果所有网关计算结果没有true,则引擎会抛出异常。

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

  • 并行网关 (+)

    所有路径会被同时选择

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

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

  • 包容网关 (+)

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

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

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

  • 事件网关 (+)

    专门为中间捕获事件设置的,允许设置多个输出流指向多个不同的中间捕获事件。

    当流程执行到事件网关后,流程处于等待状态,需要等待抛出事件才能将等待状态转换为活动状态。

4)流向 Flow

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

三、安装Activiti BPMN visualizer插件

这个在idea2020版本开始,老的插件actiBPM已经在插件市场中搜索不到了。

虽然依旧可以在插件官网下载actiBPM到本地进行安装,但是没必要,新的插件更好使用一些。

四、流程设计器使用

4.1 新建BPMN 2.0文件


新建以后会得到一个XML文件,并没有出现画BPMN流程图的界面。

4.2 调出流程设计页面


4.3 绘制出差流程

1)绘制开始事件

右击流程设计页面,选择Start events

选择后注意下面三个区域即可:

2)绘制用户任务流程
  • 创建申请单

绘制出用户任务之后,可以指定流程名称为创建出差申请,并且指定分配到任务的人为小王。

  • 部门经理审批

  • 总经理审批

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XblAWfMu-1683250543424)(assets\流程-部门经理审批.png)]

  • 财务审批
3)绘制结束事件


4)绘制流向
1.选中流程节点

2.鼠标左键按住右上角箭头进行拖动

拖向需要指向的节点即可。

3.最终流程图效果

五、流程操作

5.1 流程定义

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

使用idea下的designer设计器绘制流程,需要成两个文件:.bpmn.png

1)bpmn文件

已经按第三步的操作定义完成,在就是first.bpmn.xml文件。

2)png文件

直接在流程设计器中,右击后再菜单栏点击Save to PNG,然后选择文件位置,放到.bpmn文件的相同目录下即可。

5.2 流程部署

1)单文件部署方式

将上面在设计器中定义的流程部署到activiti数据库中,就是流程定义部署。

直观的说就是把bpmn文件定义的流程和png文件存储到数据库当中。

这里使用一个单元测试来进行演示:

/*** 部署流程定义测试*/
@Test
public void DeployTest() {// 1. 创建ProcessEngine流程引擎对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 2、得到RepositoryService实例RepositoryService repositoryService = processEngine.getRepositoryService();// 3、使用RepositoryService进行部署,定义一个流程名字,把bpmn和png部署到数据库中Deployment deployment = repositoryService.createDeployment()    // 创建一个部署流程.name("出差申请流程")                                 	// 给部署流程命名.addClasspathResource("a-bpmn/first.bpmn20.xml")    	// 添加类路径下的资源文件.addClasspathResource("a-bpmn/first.png").deploy();												// 执行流程部署// 4、输出部署信息System.out.println("流程部署id:" + deployment.getId());System.out.println("流程部署名称:" + deployment.getName());
}

运行之后,activiti主要操作了4张表:

  • act_re_deployment :流程部署表,每部署一个流程就会多一条数据

  • act_re_procdef:流程定义表

    这里面比较重要的字段:

    • KTY_:也就是之前流程定义时的ID属性
    • RESOURCE_NAME_bpmn文件的资源路径
    • DGRM_RESOURCE_NAME_png文件的资源路径
  • act_ge_bytearray :通用的流程资源表

    • 查看图像的方法:用Navicat的话选择开始事务旁边的下拉框为图像,再选中想看的png文件,下方就能显示了

    • 查看bpmn文件的方法

    其实这就是一个xml文件即可。

  • act_ge_property:系统相关属性

完成上述操作后Activiti会将上边代码中指定的bpmn文件和图片文件保存在Activiti数据库中的相关表中。

小结:

act_re_deploymentact_re_procdef一对多关系.

一次部署在流程部署表生成一条记录,但一次部署可以部署多个流程定义,每个流程定义在流程定义表生成一条记录。

每一个流程定义在act_ge_bytearray会存在两个资源记录,bpmnpng

建议:

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

2)压缩包部署方式

这种方式需要把bpmn文件和png文件打成一个.zip的压缩包。

/*** 部署流程--压缩包部署方式*/
@Test
public void deployByZipTest() {// 1. 创建ProcessEngine流程引擎对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 2.定义字节输入流InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("bpmn/evection.zip");ZipInputStream zipInputStream = new ZipInputStream(inputStream);// 3.获取repositoryServiceRepositoryService repositoryService = processEngine.getRepositoryService();// 4.流程部署Deployment deployment = repositoryService.createDeployment().addZipInputStream(zipInputStream).deploy();// 5、输出部署信息System.out.println("流程部署id:" + deployment.getId());System.out.println("流程部署名称:" + deployment.getName());
}

当有很多流程的时候,很多时候都是使用这种压缩包的形式来进行流程的部署

前端直接把这个压缩包上传上来,后端拿到后,进行流程部署即可。

5.3 启动流程实例

/*** 启动流程实例*/
@Test
public void startProcessTest(){// 1、创建ProcessEngineProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 2、获取RunTimeServiceRuntimeService runtimeService = processEngine.getRuntimeService();// 3、根据流程定义Id启动流程,并获取流程实例ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myEvection");// 输出内容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 :任务信息

5.4 流程任务查询

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

/*** 查询当前个人待执行的任务*/
@Test
public void findTaskListTest() {// 1.创建流程引擎ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 2.获取TaskServiceTaskService taskService = processEngine.getTaskService();// 3.根据流程key 和 任务负责人 查询任务String assignee = "小王";List<Task> list = taskService.createTaskQuery().processDefinitionKey("myEvection")     	//流程Key.taskAssignee(assignee)                 	//只查询当前任务负责人的任务.list();list.forEach(task -> {System.out.printf("-----------------------------------------");System.out.println("流程实例id:" + task.getProcessInstanceId());System.out.println("任务id:" + task.getId());System.out.println("任务负责人:" + task.getAssignee());System.out.println("任务名称:" + task.getName());});
}

执行上述代码后,就可以查询出来小王的所有待办任务了:

5.5 流程任务处理

任务负责人查询属于自己的待办任务,选择相应的任务进行处理,并且去完成自己的代办任务。

/*** 完成个人代办任务*/
@Test
public void completTaskTest(){// 1.创建流程引擎ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 2. 获取TaskService实例TaskService taskService = processEngine.getTaskService();// 3.根据流程key 和 任务的负责人 查询任务String assignee = "小王";Task task = taskService.createTaskQuery().processDefinitionKey("myEvection")     //流程Key.taskAssignee(assignee)                 //只查询当前任务负责人的任务.singleResult();// 4.完成待办任务,参数:任务idtaskServiceplete(task.getId());
}

执行上述代码之前,act_ru_task表中的内容还是第一步创建出差申请单:

执行上述代码之前,act_ru_task表中的内容已经替换为了当前流程:

而之前的流程就放到了act_hi_taskinst历史的任务实例当中去了:

5.6 流程定义信息查询

查询流程相关信息也是经常要用到的操作,通常包含对流程定义,流程部署,流程定义版本的查询。

/*** 查询流程定义*/
@Test
public void findProcessDefinitionTest(){// 1.创建流程引擎ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 2.获取repositoryService资源管理实例RepositoryService repositoryService = processEngine.getRepositoryService();// 3.通过repositoryService获取ProcessDefinitionQuery对象ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();// 4.查询出当前所有的流程定义List<ProcessDefinition> definitionList = processDefinitionQuery.processDefinitionKey("myEvection")  // 根据流程key(id)进行查询.orderByProcessDefinitionVersion()                 // 按照版本排序.desc()                                            // 倒序.list();// 5.输出流程定义信息definitionList.forEach(processDefinition -> {System.out.printf("----------------------------------------");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());});
}

5.7 流程删除

如果某个流程不想要了,可以选择删除该流程。

/*** 流程删除(它影响的表和流程定义时的表)*/
@Test
public void deleteDeploymentTest() {// 1.创建流程引擎ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 2.通过流程引擎获取repositoryServiceRepositoryService repositoryService = processEngine.getRepositoryService();// 3.删除流程定义,如果该流程定义已有流程实例启动,那么删除时就会报错String deploymentId = "1";       // 流程部署idrepositoryService.deleteDeployment(deploymentId);// 4.设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除//   设置为false非级别删除方式,如果该流程定义已有流程实例启动,那么删除时就会报错//repositoryService.deleteDeployment(deploymentId, true);
}

注意:

  • 使用repositoryService删除流程定义,历史表信息不会被删除

  • 如果该流程定义下没有正在运行的流程,则可以用普通删除

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

5.8 流程资源下载

虽然jdbc也可以把blob类型的数据读取出来,但是这里主要还是用Activiti提供的API来进行操作。

1)引入commons-io的Maven依赖
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version>
</dependency>
2)代码示例
/*** 下载资源文件 * @throws IOException*/
@Test
public void  findBpmnFileTest() 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信息//  5.1 获取png图片的流InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());//  5.2 获取bpmn文件的流InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getResourceName());//  6、构造OutputStream流File file_png = new File("d:/first.png");File file_bpmn = new File("d:/first.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();
}

这只是在本地是这么操作的,是比较原生的写法,更有利于理解。

如果是在web项目中,就直接按文件下载的方式传输数据就可以了。

5.9 流程历史信息的查看

/*** 查看历史信息*/
@Test
public void findHistoryInfoTest(){// 1.创建流程引擎ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 2.获取HistoryServiceHistoryService historyService = processEngine.getHistoryService();// 3.获取 actinst表的查询对象HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();// 查询 actinst表,条件:根据 InstanceId 查询(等价于: instanceQuery.processInstanceId("2501");  根据 InstanceId 查询)instanceQuery.processDefinitionId("myEvection:1:4");// 增加排序操作,orderByHistoricActivityInstanceStartTime 根据开始时间排序 asc 升序instanceQuery.orderByHistoricActivityInstanceStartTime().asc();// 查询所有内容List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();// 输出查询结果activityInstanceList.forEach(hi -> {System.out.println("<==========================>");System.out.println(hi.getActivityId());System.out.println(hi.getActivityName());System.out.println(hi.getProcessDefinitionId());System.out.println(hi.getProcessInstanceId());});
}

5.10 流程实例的挂起

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

比如每月的最后一天不处理出差申请呀,财务审批流程改变需要暂停已经发起的审批等等。

流程实例的挂起也有下面两种方式:

1)将单个流程实例的挂起和激活
/*** 挂起、激活单个流程实例*/
@Test
public void suspendSingleProcessInstance(){// 1. 创建ProcessEngine流程引擎对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 2、获取RuntimeServiceRuntimeService runtimeService = processEngine.getRuntimeService();// 3、通过RuntimeService获取流程实例对象ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId("27501").singleResult();// 4、得到当前流程实例的暂停状态,true-已暂停  false -激活boolean suspended = instance.isSuspended();// 5、获取流程实例idString instanceId = instance.getId();// 6、判断是否已经暂停,如果已经暂停,就执行激活操作if(suspended){// 如果已经暂停,就执行激活runtimeService.activateProcessInstanceById(instanceId);System.out.println("流程实例id:"+instanceId+"已经激活");}else {// 7、如果是激活状态,就执行暂停操作runtimeService.suspendProcessInstanceById(instanceId);System.out.println("流程实例id:"+instanceId+"已经暂停");}
}
2)将全部流程实例的挂起和激活
/*** 全部流程实例的挂起和激活* suspend 暂停*/
@Test
public void suspendAllProcessInstance(){// 1. 创建ProcessEngine流程引擎对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 2、获取RepositoryserviceRepositoryService repositoryService = processEngine.getRepositoryService();// 3、根据流程定义Key查询流程定义,获取流程定义的查询对象ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey("myEvection").singleResult();// 4、获取当前流程定义的实例是否都是挂起状态boolean suspended = processDefinition.isSuspended();// 5、获取流程定义的idString definitionId = processDefinition.getId();// 6、如果是挂起状态,改为激活状态if(suspended){// 如果是挂起,可以执行激活的操作,参数1:流程定义id 参数2:是否激活,参数3:激活时间repositoryService.activateProcessDefinitionById(definitionId, true, null);System.out.println("流程定义id:"+definitionId+",已经被激活");}else {// 7、如果是激活状态,改为挂起状态,参数1:流程定义id 参数2:是否暂停 参数3 :暂停的时间repositoryService.suspendProcessDefinitionById(definitionId, true, null);System.out.println("流程定义id:"+definitionId+",已经被挂起");}
}

这两者的区别也就是一个是查询实例,拎一个查询的是流程定义罢了

六、小结

上面已经演示了常见的BPMN操作和流程操作,更偏向于新手理解相关API

但是在绘制流程图的时候,暂时都是把责任人等信息写死了。这显然在实际的业务中是难以适应业务的变化的。

并且流程审批的时候,下一个审批人根本不知道审批的具体内容是啥。

比如上面的出差申请,具体要出差去哪,出差几天,都是不知道的。

因为这些数据在业务系统当中,而不是在Activiti中。

只有两者联动起来才能完成实际的业务开发需求,这个是需要注意的。

下一篇博客会讲诉Activiti的中流程实例、用户任务、流程变量以及网关的使用,更加贴合实际开发。

更多推荐

Activiti7流程操作详解

本文发布于:2024-02-07 02:23:39,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1752310.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:详解   流程   操作

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!