养成习惯,先赞后看!!!
如果没有看前一篇文章的小伙伴,可以先去看一下之前的一篇文章:还在自己手写请假流程吗?Activiti7帮你快速请假!!!,再来看这篇文章.
目录
Activiti7流程框架基本功能学习
1.整合Activiti7与springboot:
官网给出的pom依赖我们是无法导入的,就算是通过阿里云的镜像也是无法识别的.
但是阿里云的Maven仓库里面是有的,只是名字不同而已,所以我们需要去重新导入这些依赖.并且M5的版本存在一个bug就是每次项目之后都会在 act_re_deployment表里面插入一条数据SpringAutoDeployment ,所以建议大家使用M4的版本
接着我们进入阿里云的Maven仓库,去重新搜索一下这些文件的pom依赖:
activiti-spring-boot-starter的pom依赖:
activiti-dependencies的pom依赖:
之后我们重新引入pom依赖之后可以发现,已经能够正常导入了.
之后我们运行项目可以发现已经自动帮我们创建了一部分的表:
但是呢,这部分的表其实是不全
的,我们还需要通过下面的配置创建我们关于历史信息的表:
但是到这里我们还是不够,我们还需要通过下面的SQL脚本创建我们的用户表以及Formdata表:
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- 创建用户表
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(32) DEFAULT NULL COMMENT '姓名',
`address` varchar(64) DEFAULT NULL COMMENT '联系地址',
`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '账号',
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密码',
`roles` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '角色',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- 填充用户表
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'admincn', 'beijing', 'admin', '$2a$10$gw46pmsOVYO.smHYQ2jH.OoXoe.lGP8OStDkHNs/E74GqZDL5K7ki', 'ROLE_ACTIVITI_ADMIN');
INSERT INTO `user` VALUES ('2', 'bajiecn', 'shanghang', 'bajie', '$2a$10$gw46pmsOVYO.smHYQ2jH.OoXoe.lGP8OStDkHNs/E74GqZDL5K7ki', 'ROLE_ACTIVITI_USER,GROUP_activitiTeam,g_bajiewukong');
INSERT INTO `user` VALUES ('3', 'wukongcn', 'beijing', 'wukong', '$2a$10$gw46pmsOVYO.smHYQ2jH.OoXoe.lGP8OStDkHNs/E74GqZDL5K7ki', 'ROLE_ACTIVITI_USER,GROUP_activitiTeam');
INSERT INTO `user` VALUES ('4', 'salaboycn', 'beijing', 'salaboy', '$2a$10$gw46pmsOVYO.smHYQ2jH.OoXoe.lGP8OStDkHNs/E74GqZDL5K7ki', 'ROLE_ACTIVITI_USER,GROUP_activitiTeam');
-- ----------------------------
-- 修复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;
-- ----------------------------
-- 动态表单数据存储
-- ----------------------------
DROP TABLE IF EXISTS `formdata`;
CREATE TABLE `formdata` (
`PROC_DEF_ID_` varchar(64) DEFAULT NULL,
`PROC_INST_ID_` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`FORM_KEY_` varchar(255) DEFAULT NULL,
`Control_ID_` varchar(100) DEFAULT NULL,
`Control_VALUE_` varchar(2000) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
运行完我们的脚本文件之后我们就获得了我们所需要的所有的表:
2.Deployment-部署操作:
Deployment主要三个表操作有关,分别是act_re_deployment,act_ge_bytearray和act_re_procdef这三个表,我们再来说说这三个表分别代表以及存储的都是些什么信息
act_re_deployment
该表主要是记录了我们已经部署了那些流程,主要记录部署流程的时间,版本号,名称等等
act_ge_bytearray
该表主要就是记录我们部署流程过程中我们已经上传过的流程文件的数据,并且以二进制的形式保存这些文件
act_re_procdef
该表主要就是记录我们已经部署过的流程的详细信息,主要包括流程的版本号,名称等等
尤其要区别act_re_deployment
与act_re_procdef
这两个表. act_re_deployment主要是记录 部署流程的过程 的信息,act_re_procdef则是记录 部署的该流程的信息
2.1-Deployment单个文件部署:
测试Activiti7关于bpmn流程文件的部署,编写一个测试类进行测试
@SpringBootTest
public class Part1_Deployment {
@Autowired
private RepositoryService repositoryService;
@Test
public void initDeploymentBPMN(){
//bpmn文件所在的文件路径
String filename="BPMN/Part1_Deployment.bpmn";
//部署bpmn文件
Deployment deployment=repositoryService.createDeployment()
.addClasspathResource(filename)
.name("流程部署测试BPMN")
.deploy();
System.out.println(deployment.getName());
}
}
这样我们的测试代码就已经编写好了,我们执行完成之后我们去查看数据库的这两个表各多了一条数据
一个就是act_re_deployment,代表部署表,表示该文件已经部署在了数据库里面
另一个就是act_ge_bytearray,代表文件表,这个表主要就是存储部署的bpmn文件的实际数据,这里我们是可以通过保存数据的方式查看该bpmn文件的xml数据
这是目前部署bpmn流程文件的方式,但是在此之前的版本中因为 可能不能够直接打开bpmn文件
,所以一般部署的时候还会 带上一张bpmn文件的图片即流程图
,这样就能够方便用户查看流程,所以我们再来看看之前版本部署流程文件时候,是怎么做的.
@SpringBootTest
public class Part1_Deployment {
@Autowired
private RepositoryService repositoryService;
@Test
public void initDeploymentBPMN(){
String filename="BPMN/Part1_Deployment.bpmn";
String imagename="BPMN/Part1_Deployment.png";
Deployment deployment=repositoryService.createDeployment()
.addClasspathResource(filename)
.addClasspathResource(imagename)
.name("流程部署测试BPMN")
.deploy();
System.out.println(deployment.getName());
}
}
这时候我们运行完,重新去看看数据库的数据变成什么样了
先是act_re_deployment,我们可以看到又重新部署了一次
再来看看act_ge_bytearray,可以看到多了两条数据,一个就是bpmn流程文件,一个就是我们刚刚定义的png图像文件
这就是之前我们部署bpmn流程文件的方式,但是现在我们就只需要部署bpmn文件即可,之后可以直接通过 将bpmn文件转换成相应的HTML文件展示给用户看.
2.2-Deployment压缩文件部署:
这里我们将上面的文件重命名之后打包成压缩包的形式,看看以压缩文件的形式进行部署是怎么样的.
@Test
public void initDeploymentZIP(){
InputStream inputStream=this.getClass().getClassLoader().getResourceAsStream("BPMN/BPMN.zip");
ZipInputStream zipInputStream=new ZipInputStream(inputStream);
Deployment deployment=repositoryService.createDeployment()
.addZipInputStream(zipInputStream)
.name("流程部署测试ZIP")
.deploy();
System.out.println(deployment.getName());
}
这里我们还是再去看看数据库里面手机怎么添加数据的
先是act_re_deployment,我们可以看到又重新部署了一次
再来看看act_ge_bytearray,可以发现他并不是将整个压缩包保存起来的,而时间压缩包里的文件单个保存的:
2.3-Deployment文件读取:
@Test
public void getDeployment(){
List<Deployment> deployments=repositoryService.createDeploymentQuery().list();
for(Deployment deployment:deployments){
System.out.println("ID:"+deployment.getId());
System.out.println("Name:"+deployment.getName());
System.out.println("Time:"+deployment.getDeploymentTime());
System.out.println("Key:"+deployment.getKey());
}
}
3.ProcessDefinition-流程定义操作:
流程定义操作主要针对的就是我们提前画好的BPMN文件的详细信息
这里我们先来看看我们的BPMN文件是什么样的
可以看到我们的流程定义的信息是这样的,那么接下来我们在看看我们的流程定义的读取操作读出来的信息是不是和我们定义的一样呢?
3.1-ProcessDefinition文件读取:
可以看到读取到的信息也的确是一样的,并且因为我们的流程Key没有发生改变,所以我们的版本是不一样的,并且采用+1操作的方式
3.2-ProcessDefinition文件删除:
//删除流程定义
@Test
public void delDefinition(){
String pdID="fadb560c-3b76-11eb-a72f-3c58c24c1a1b";
repositoryService.deleteDeployment(pdID,true);
System.out.println( );
}
这里我们想要删除我们定义的流程,就需要获得我们的Deployment的ID号,就是我们在上面查询Deployment获得的ID号.并且他会有一个选项即boolen的选项
true代表删除该流程的一切历史信息包括该流程的相关信息以及部署该流程的过程的详细信息,以及该流程文件的详细信息,反正就是所有的信息
false代表只删除该流程的信息,其他的信息是不会删除的.即只删除act_re_procdef表中的记录.
这里我们测试完成之后,可以发现已经测试成功了
那么接下来我们再去看看数据库里的信息发生率什么样的变化.
首先是act_re_procdef表,可以看到只剩下了一条数据了
我们再来看看act_re_deploymemt关于该流程的记录因为已经是删除了
最后我们再来看看act_ge_bytearray,发现该流程部署的两条文件数据也已近删除了,只剩下两条数据了.
这下我们便能更好的理解true和false的区别了
4.ProcessInstance-流程实例操作:
在学习下面的操作之前我们首先需要明白ProcessDefinition和Processinstance的区别.
ProcessDefinition指的是我们定义的流程,这个流程只是一个一般化的流程,就比方说请假,我们只是定义了请假的一般化流程,比如说各个层级请假需要经过哪些层级的审核等等
但是Processinstance指的则是我们已经创建好的一个流程实例,比方说今天小赵想要请假,那么就会根据上面的定义流程创建一个流程是只适用于小赵的请假流程,然后今天小余也像请假,呢么就肯定要在根据上面定义的实例再创建一个实例是只适用于小余的,那么我们就能了解这两者的区别以及联系了
简单来说就可以用下面的图来表示:
一对多的关系.流程只是一个一般化的过程,流程实例是需要与特定的业务数据进行绑定的
了解完两者的区别之后,我们就能继续下面的操作了.
4.1-ProcessInstance-流程实例定义操作:
@Autowired
private RuntimeService runtimeService;
//初始化流程实例
@Test
public void initProcessInstance(){
//获取页面表单填报的内容,比如说请假时间,请假事由等等数据
//将填好的数据写入我们的业务表里,返回业务表的主键ID=====>BussinessKey
//之后就需要将我们的业务数据绑定到流程上,这样创建出来的流程实例既能表现流程,同时又能够体现出我们系统的业务数据
ProcessInstance processInstance=runtimeService.startProcessInstanceByKey("myProcess_Part1","bKey0001");
System.out.println("ID:"+processInstance.getId());
System.out.println("ProcessInstanceId:"+processInstance.getProcessInstanceId());
System.out.println("ProcessDefinitionId:"+processInstance.getProcessDefinitionId());
}
这里我们定义流程实例是通过Key以及businessKey来进行定义的
这里我们需要重点理解的businessKey,其实这个key就是我们上面讲到的业务数据,一般我们定义流程实例之前都需要将我们本次流程实例需要绑定的业务数据的信息定义出来,定义出来时候,该业务数据本身就会有他自己的ID,那么我们创建流程实例的时候就只需要将该流程实例与该业务数据的ID绑定之后,那么完整的流程实例就已经创建好了,确切的创建流程实例的过程应该是这样的
理解上面的概念之后,我们来执行以下代码,可以发现已经执行成功了.
那么我们再来看看数据库中的信息会发生怎么样的变化.
首先我们先看到的就是act_ru_execution表里面增加了两条信息,为什么增加的是两条信息,大家可能要问了,这主要是因为我们的BPMN文件里面都是定义了一个起始结点以及一个结束结点的,所以会增加两条记录.
接着我们再看,就是能够发现我们的数据已经和我们定义的业务数据绑定了,这样后续我们查找该流程实例的业务数据后悔方便很多,直接关联我们的业务数据表进行关联查询即可.
还有一个表的数据是发生了变化的,就是act_ru_identitylink,这张表主要就是记录我们流程过程中参与流程的人员身份,这其中的人员身份只包括我们在BPMN文件里面定义的用户信息,并且这个信息应该只是代表一种身份,并不具体到确切的个人,只是我们这里定义的时候为了方便大家理解,选择使用bajie来替换,确切的人员信息应该是在业务数据里面定义的
这样我们的流式实例定义操作就已经结束了.
4.2-ProcessInstance-流程实例查询操作:
//获取流程实例列表
@Test
public void getProcessInstances(){
List<ProcessInstance>processInstances=runtimeService.createNativeProcessInstanceQuery().list();
for(ProcessInstance processInstance:processInstances){
//流程实例ID
System.out.println("ProcessInstanceId:"+processInstance.getProcessInstanceId());
//流程定义ID
System.out.println("ProcessDefinitionId:"+processInstance.getProcessDefinitionId());
//流程实例是否已经执行结束
System.out.println("isEnded:"+processInstance.isEnded());
//流程实例是否已经挂起
System.out.println("isSuspended:"+processInstance.isSuspended());
}
}
执行完代码之后我们就能够发现是的确已经执行成功了
4.3-ProcessInstance-流程实例挂起激活操作:
//暂停与激活流程实例
@Test
public void activitieProcessInstances(){
runtimeService.suspendProcessInstanceById("bcad5409-3db6-11eb-87c1-3c58c24c1a1b");
System.out.println("流程实例挂起成功");
// runtimeService.activateProcessInstanceById("bcad5409-3db6-11eb-87c1-3c58c24c1a1b");
// System.out.println("流程实例激活成功");
}
我们首先先测试流程实例的挂起操作
嘴上说挂起成功没用,这时候我们重新去查询一下所有的流程实例,并且看看他们的状态
可以看到该流程实例奇缺已经挂起了
这时候我们重新将该流程实例重新激活
我们在重新去查看一下所有的流程实例
可以看到该流程实例的确已经激活了
4.4-ProcessInstance-流程实例删除操作:
//删除流程实例
@Test
public void delProcessInstances(){
runtimeService.deleteProcessInstance("bcad5409-3db6-11eb-87c1-3c58c24c1a1b","拜拜了您嘞");
System.out.println("流程实例删除成功");
}
这里我们选择删除我们上面定义的流程实例,我们主要看第二个属性
可以看到Activiti7要求删除流程实例的时候必须要提供一个删除的原因,这个主要就是为了迎合我们的业务数据,我们停掉某个流程,很明显都是有原因的,那么我们就肯定是要记录这个原因的,所以Activiti7要求我们记录该原因.
接着我们测试一下删除流程实例的代码
可以看到该流程实例已经被成功删除掉了,我们这时候再去查看流程实例
可以看到已经没有流程实例,说明我们已经成功将该流程实例删除掉了.
5.Task-任务处理操作:
在继续任务处理的相关操作之前,我们先来简单认识一下BPMN文件的相关属性信息
首先我们先看整体的BPMN文件,红色框框选中的就是整个流程的ID,但是在数据库中显示的话会是以Key的形式展示
接着我们再来看看任务处理节点
主要有两个是我们需要注意的,一个就是Name就是直接定义任务节点处理的业务,另外一个就是Assignee就是直接定义任务节点的处理人.
了解完这些最基本的BPMN文件的概念之后,我们再来了解一下Task在数据库中主要操作的两个表分别是act_ru_task和act_ru_identitylink这两张表.
act_ru_task主要是存放我们的任务节点的信息
act_ru_identitylink主要就是存放我们关于任务节点中执行人的相关信息
了解完上面这些概念之后,我们就能继续我们关于Task的操作了.
任务节点其实是和流程实例相关的!!!
想想我们创建完流程实例之后,流程实例最开始的那个任务节点是不是就按理就已经创建完毕了,相应的如果我们将某个流程实例中的所有任务节点都已经执行完毕的话,那么这个流程实例是不是就相应的执行完毕了呢?
这些问题我们在下面的操作过程中都会以实例来验证!!!
那么我们先来验证第一点,创建完相应的流程实例之后,相应的最开始的任务节点是否会自动产生呢?
首先先看一下我们本次使用的BPMN文件
5.1-Task-任务节点查询操作:
我们可以看到我们创建完流程实例时候,流程实例中最开始的任务节点就已经生成了,那么显然我们关于第一点的证明就已经完毕了.
此时我们已经有任务节点了,那么这时候我们在去数据库里面看看我们之前将的那两张表的数据发生看什么样的变化吧
我们先来看看act_ru_task表:
我们可以看到该任务节点的相关信息都已经记录到该表了
我们再来看看act_ru_identitylink表:
可以看执行者的信息也已经添加进来了.
接下来我们在仔细讲一下任务节点的查询操作
5.1.1-查询所有任务节点的信息 :
我们上面的查询操作是查询的所有任务节点的状态
@Autowired
private TaskService taskService;
@Test
public void getTasks(){
List<Task>tasks=taskService.createTaskQuery().list();
for(Task task:tasks){
System.out.println("ID:"+task.getId());
System.out.println("Assignee:"+task.getAssignee());
}
}
显然这种操作只能是管理员才能拥有的操作,所以我们应该为一般的人员设置只能查询自己当前任务节点的方法,那么 就到下面的方法了
5.1.2-查询该用户下的任务节点:
@Test
public void getTaskByAssignee(){
List<Task>tasks=taskService.createTaskQuery().taskAssignee("wukong").list();
for(Task task:tasks){
System.out.println("ID:"+task.getId());
System.out.println("Assignee:"+task.getAssignee());
}
}
这样我们就能查找特定执行下的任务了
那么我们分别查询一下bajie和wukong两者的下的任务节点:
可以看到bajie的任务节点已经存在了
当我们去在查询一下wukong的任务节点的时候,其实大家也能够猜到了,很明显wukong的任务节点是还没有生成的:
可以看到wukong下面的确什么任务节点都没有,其实我们想一下,wukong所属的任务节点是在bajie的任务节点之下的,那么显然是不是bajie的任务节点执行完毕之后,wukong的任务节点就能够看到了呢?说干就干.那么我们接下来就来看看执行任务节点
5.2-Task-任务节点完成操作:
//执行任务
@Test
public void completeTask(){
taskService.complete("13909b7d-3e72-11eb-beee-3c58c24c1a1b");
System.out.println("该任务节点已经处理完毕");
}
这里我们 是通过TaskId来执行任务的
我们运行一下代码
可以看到已经成功运行了,这时候我们再来重新看一下两张数据表里面的是数据发生了什么样的变化吧
act_ru_task:
可以看到任务已经流转到下面一个流程了,并且之前一个bajie的任务节点已经消失了,只剩下了wukong的审批请假的任务节点了
那么显然我们现在再去查找bajie和wuykong所属的任务节点的时候,大家应该也能够有猜到相应的结果了:
act_ru_identitylink:
可以看到执行人这张表里面则不是像act_ru_task表一样直接删除之前的在执行人信息,还是不断添加整个流程里面的执行人信息的
看完上面两个表的数据之后,我们尝试将整个流程的任务节点都执行完,看看最后任务节点以及流程实例最后会是什么样的?
可以看到当我们将所有的任务节点全部执行完毕之后,相应的流程实例也会自动的消失掉,这样的确是符合正常的流程的,完成之后自动消失.
接着我们再来看看我们两张表中的数据发生了怎么样的变化:
act_ru_task:
act_ru_identitylink:
可以看到这两张表中关于该流程实例的所有任务节点以及执行人的信息全部都已经删除了.
虽然这两张表里面的数据都已经删除了,但是Activiti7为我们提供了另外一张表来帮我们存储我们的历史数据,这张表我们之后也会提到,这里先不讲.这样假如我们有溯源的功能的话,我们也是可以实现的,这样看来,这种流程执行完毕就把相应的任务节点删除掉,只保留当前存在且待执行的任务节点的确是合理的,毕竟任务节点到后面只会越来越多,如果不进行这种类似的操作的话,那么后续查询的速度就会越来越满,严重影响用户体验.
5.3-Task-任务节点拾取,退还,交办操作:
上面我们的任务都是单线的,意思就是一条线走到底的,但是我们有时候的任务可能是这样的:
那么显然我们的任务节点就会出现我在标题中写的那三种操作方式,拾取,退还,交办操作.
我们还是先来看看我们这次定义的BPMN文件是什么样的:
还是老样子,先部署流程–>创建流程实例–>执行候选任务的各项操作
我们创建完了,接下来我们分别查询一下wukong,bajie,shaseng下面是否有任务节点:
可以看到我们分别查询了wukong,bajie,shaseng下面的任务节点,发现都是没有相应的任务的.显然这也刚好符合候选任务的定义的,的确是需要我们主动分配.
那么接下来我们就开始候选任务中的第一项操作
5.3.1-拾取任务操作:
//拾取任务
@Test
public void claimTask(){
// Task task=taskService.createTaskQuery().taskId("").singleResult();
taskService.claim("","bajie");
}
我们可以看到在我们给候选任务分配了执行人之后,任务节点就已经产生.并且查询其他没有被分配的执行人时可以看到都是没有的.
5.3.2-退还任务操作:
//退还任务
@Test
public void setTaskAssignee(){
taskService.setAssignee("",null);//退任务
}
可以看到我们是接着上一步操作的,我们直接将任务退回之后,接着分别取我们分配的三个执行人下面查找,发现三个人都是没有改任务节点的,并且直接查找任务节点列表也是显示为空,这就表示我们的任务的确已经退回成功.
5.3.3-交办任务操作:
//交办任务
@Test
public void setTaskAssignee(){
taskService.setAssignee("","wukong");//交办任务
}
可以看到我们还是接着上一步,我们先是给我们已经退回的任务重新先分配了一个执行人bajie,然后再重新把任务交办给执行人wukong的,之后我们先是查找bajie下面的任务节点,发现是没有的,之后我们再去查找wukong下面的任务节点,发现是有的,这样我们的任务就已经交办成功了.
并且其实大家看完上述三个操作之后可以发现,其实这三者操作的代码是类似的,只不过是修改执行人的名称即可,所以其实这三部的代码是完全可以放在一个方法里面执行的,只要稍微注意一下情况的区分即可,比如说如果没有任务节点那么显然就是拾取操作,剩下的操作就是退还与交办了.
6.HistoricTaskInstance-历史任务:
关于历史任务,主要就是操作下面这几张表
act_hi_actinst:历史节点表,存放流程实例运转的各个节点信息(包含开始、结束等非任务节点);
act_hi_attachment:历史附件表,存放历史节点上传的附件信息(不常用);
act_hi_comment:历史意见表,可改造用于保存节点审批意见、备注;
act_hi_detail:历史详情表,存储节点运转的一些信息(不常用);
act_hi_identitylink:历史流程人员表,存储流程各节点候选、办理人员信息,常用于查询某人或部门的已办任务;
act_hi_procinst:历史流程实例表,存储流程实例历史数据(包含正在运行的流程实例);
act_hi_taskinst:历史流程任务表,存储历史任务节点;
act_hi_varinst:流程历史变量表,存储流程历史节点的变量信息;
6.1-HistoricTaskInstance根据执行人查询历史信息操作:
@Autowired
private HistoryService historyService;
//根据执行人查询历史任务信息
@Test
public void HistoricTaskInstanceByAssignee(){
List<HistoricTaskInstance> historicTaskInstances=historyService.createHistoricTaskInstanceQuery()
.orderByHistoricTaskInstanceEndTime().asc()
.taskAssignee("bajie")
.list();
for(HistoricTaskInstance historicTaskInstance:historicTaskInstances){
System.out.println("Id:"+historicTaskInstance.getId());
System.out.println("Assignee:"+historicTaskInstance.getAssignee());
System.out.println("ProcessInstanceId:"+historicTaskInstance.getProcessInstanceId());
System.out.println("EndTime:"+historicTaskInstance.getEndTime());
System.out.println("Name:"+historicTaskInstance.getName());
}
}
运行完成之后我们可以看到bajie所执行的所有历史历史任务了
6.2-HistoricTaskInstance根据流程实例ID查询历史信息操作:
//根据流程实例ID查询历史任务信息
@Test
public void HistoricTaskInstanceByProcessInstanceId(){
List<HistoricTaskInstance> historicTaskInstances=historyService.createHistoricTaskInstanceQuery()
.processInstanceId("")
.list();
for(HistoricTaskInstance historicTaskInstance:historicTaskInstances){
System.out.println("Id:"+historicTaskInstance.getId());
System.out.println("Assignee:"+historicTaskInstance.getAssignee());
System.out.println("ProcessInstanceId:"+historicTaskInstance.getProcessInstanceId());
System.out.println("EndTime:"+historicTaskInstance.getEndTime());
System.out.println("Name:"+historicTaskInstance.getName());
}
}
7.UEL表达式:
7.1-UEL-传递执行人:
${变量名}
我们重新创建一个BPMN文件:
我们重新创建了一个BPMN文件,并且这次我们并没有给他直接分配执行人,而是通过通过UEL表达式进行动态的分配的.
//启动流程实例带参数--执行人
@Test
public void initProcessInstanceWithArgs(){
//流程实例变量
Map<String,Object> map=new HashMap<>();
map.put("Staff","wukong");
// map.put("Staff1","");
// map.put("Staff2","");
ProcessInstance processInstance=runtimeService.startProcessInstanceByKey("myProcess_UEL_V1","test001",map);
System.out.println("ID:"+processInstance.getId());
System.out.println("Name:"+processInstance.getName());
System.out.println("ProcessDefinitionId:"+processInstance.getProcessDefinitionId());
}
这里我们首先显示部署我们刚才生成的BPMN文件,之后我们便去实例化我们的流程实例,并且在这个过程中我们同事赋予该流程实例的执行人是wukong,之后我们便去查询wukong下的所有任务节点可以发现wukong下面的确多出来一个任务节点.说明我们赋予执行人的操作已经成功执行了.
7.2-UEL-传递流程变量:
我们在创建一个BPMN文件:
我们这里定义了一个条件转移过程,如果报销费用小于等于100的话就由悟空审核,超过100的话就由唐僧审核,这个费用的变量值就是在八戒的任务节点产生,并且直接判断之后转移到下一个任务节点.
@Test
public void CompletetaskWithArgs(){
Map<String,Object> map=new HashMap<>();
map.put("pay","120");
taskService.complete("a61d9134-3f49-11eb-97e4-3c58c24c1a1b",map);
System.out.println("该任务节点已经处理完毕");
}
我们可以看我们首先先将我们刚才定义的BPMN文件部署号,之后我们再去创建该流程定义的流程实例,之后我们先去查询一下tangseng下面时候有任务节点,应该是没有的,因为我们之前就没有给他分配过任务.
之后我们再去获取该流程实例生成的关于bajie的任务节点的ID号,这样我们才能去执行我们的任务节点,执行完任务节点之后,按道理这时候任务节点就已经转接到tangseng的任务节点了.这时候我们再去查询tangseng的任务节点我们就能发现的确是已经将任务节点流转到tangseng这里了,这就说明我们关于传递流程变量的操作已经成功执行了.
7.3-UEL-传递实体类的流程变量以及候选任务的执行人:
还是先来看看我们的BPMN文件:
这次可以看到我们的任务节点中的变量不再是我们直接定义的变量名了,而是换成了我们定义的实体类的一个属性,注意这里要注意,实体类的属性只能使用小写字母,不能使用大写字母,否则会出错.
接着就是我们的候选任务了,其实这里的变量定义和我们之前的定义是一样不一样的是我们之后为这个变量赋值的时候需要注意一下.
接着就是我们的代码了:
我们先看变量是实体类:
//启动流程实例带参数--实体类
@Test
public void initProcessInstanceWithClassArgs(){
UELDao uelDao=new UELDao();
uelDao.setStaff("wukong");
//流程实例变量
Map<String,Object> map=new HashMap<>();
map.put("uel",uelDao);
// map.put("Staff1","");
// map.put("Staff2","");
ProcessInstance processInstance=runtimeService.startProcessInstanceByKey("myProcess_UEL_V3","test001",map);
System.out.println("ID:"+processInstance.getId());
System.out.println("Name:"+processInstance.getName());
System.out.println("ProcessDefinitionId:"+processInstance.getProcessDefinitionId());
}
这其中我们定义的实体类必须要实现序列化,否则也是不会生效的.
为了节省时间我们就不重复录制部署的过程了,直接开始我们赋予实体类流程变量的过程,之后就是查看该角色下的任务节点时候有一个叫做 “实体类任务” 的任务节点,可以发现的确有这样一个任务节点,说明我们通过实体类赋值的操作已经执行成功了.
接下来就是赋予候选人执行人:
//任务执行完成后赋予候选任务节点多个候选人
@Test
public void initTaskWithCandiDateArgs(){
Map<String,Object>map=new HashMap<>();
map.put("staffs","bajie,shaseng,tangseng");
taskService.complete("",map);
System.out.println("任务节点已完成,候选任务执行人变量已赋予,带拾取");
}
这里面我们主要需要注意一点就是多位候选人中间需要通过英文状态下的,隔开,否则不会生效的.
这里我们将我们的实体类任务执行完成的同时将候选任务的执行人变量赋予,之后我们再去查找所有的任务节点会发现有一个任务节点的执行人为null.为null就和我们上面的候选任务一样,只有在我们已经对该任务进行拾取操作之后才会显示执行人,否则是会显示为null的,很明显我在设置的时候使用的是中文状态的标点符号,所以他把整体都算成是一个执行人了.这里大家一定要注意.
8.流程网关:
我们先稍微区分一下这三个流程网关分别长什么样:
之后我们再来分别讲解一下三者:
8.1-流程网关-并行:
并行网关指的是某个任务执行完毕之后需要有多个任务全部执行完毕
之后才能算是结束.
通过下面的BPMN文件,大家就应该能够更好的理解了:
bajie的报销申请提交之后,需要wukong以及tangseng两者都审核完毕之后才能算是执行完毕.
还是老样子,我们还是先部署该流程定义,之后先去查找bajie任务节点下关于八戒报销申请的任务ID号,之后将该任务执行完成后,看看wukong和tangseng两者任务节点中按理应该各有一个并行悟空审核和并行唐僧审核的任务
8.2-流程网关-排他:
排他网关其实我们已经尝试过了,就是上面 7.2-UEL-传递流程变量
里面已经讲过了,这里就不过多讲解了.
8.3-流程网关-包容:
我们还是先来看看我们的BPMN文件:
之后我们还是老样子,先部署该流程定义,然后去创建一个该流程定义的流程实例,之后我们再去查看bajie下的关于该任务节点的ID号.
之后我们完成该任务的时候传递一个pay为2的变量,这个条件是同时满足wukong
以及shaseng
两者的任务路线的,并且这时候我们会发现这个任务也的确流转到wukong以及sheseng两者下面.
并且只有当我们他们两者的任务节点全部执行完毕
,该流程实例才会真的结束掉.
到这里我们关于Activiti7的一基本功能就已经全部介绍完毕,之后还会出一篇博客是关于Activiti7的实战,不想错过的朋友记得关注我的公众号哦,新人up需要你的支持!!!
原创不易,码字不易.点个赞支持一下吧!
不点在看,你也好看!
点点在看,你更好看!