如果单纯使用activiti进行流程的自动控制,是可以实现的。但是通常我们都需要结合自定义的表,便于在流程执行中更加清晰的看到每一个流程实例节点的具体信息。关联自定义表与activiti表才能完成真正的业务
BusinessKey关联
// 定义businessKey
@Test
public void addBusinessKey(){
// 获取流程引擎
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 获取启动流程service
RuntimeService runtimeService = engine.getRuntimeService();
// 启动流程 并添加businessKey
// param1:流程ID param2:businessKey
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("forLeave", "1001");
System.out.println("businessKey=="+processInstance.getBusinessKey());
}
当我们启动流程的时候,activiti将businessKey添加到了act_ru_execution表中。该表就是我们将自定义表和activiti表关联的重点
流程定义的挂起与激活
// 全部流程挂起与激活
@Test
public void suspendAllprocessInstance(){
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
// 获取流程定义查询对象
ProcessDefinition forLeave = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("forLeave")
.singleResult();
// 查询当前流程任务是否为挂起状态 true挂起状态 false
boolean suspended = forLeave.isSuspended();
// 流程定义id
String id = forLeave.getId();
if (suspended){
// 挂起就激活
// param1:流程任务id param2:是否挂起 param3:激活时间
repositoryService.activateProcessDefinitionById(id,true,null);
System.out.println("流程定义id=="+id+"已激活");
// 激活状态为:1
}else {
// 激活就挂起
// param1:流程定义id param2:是否暂停 param3:暂停时间
repositoryService.suspendProcessDefinitionById(id,true,null);
System.out.println("流程定义id=="+id+"已挂起");
// 挂起状态为:2
}
可以通过查看运行时执行表act_ru_execution的SUBPENSION_STATE查看,状态为1表示该任务已激活,状态为2表示已挂起
单个流程实例挂起与激活
@Test
public void suspendSingleProcess(){
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = engine.getRuntimeService();
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId("27501")
.singleResult();
// true 已挂起 false 已激活
boolean suspended = processInstance.isSuspended();
// 获取流程实例id
String id = processInstance.getId();
// 挂起和激活转换
if (suspended){
runtimeService.activateProcessInstanceById(id);
System.out.println("流程实例id"+id+"已激活");
}else {
runtimeService.suspendProcessInstanceById(id);
System.out.println("流程实例id"+id+"已挂起");
}
}
可以对比流程定义和流程实例的挂起激活:
流程定义是指某一种任务类型,该类型的全部待处理任务会全部挂起或者执行。比如请假,那么不会单独针对张三或者李四的请假操作,而是针对所有的请假流程进行操作。流程定义的挂起与激活通过的是RepositoryService
流程实例是指某一流程定义下的某一个流程,比如张三的请假审批流程就是一个流程实例。那么就可以通过单个操作来对张三进行激活和挂起操作。流程实例是通过RunTimeService进行操作。
两者的激活都是通过activatePrecess***ById进行转换,挂起都是通过suspendProcess ***ById
任务负责人分配–uel表达式
首先在绘制bpmn时使用${key}
表达式,再自定义填充key。
填充完毕之后,进行流程部署然后在启动流程时利用map集合进行传参。map集合的key对应上述的uel表达式中的key,activiti会自动帮我们完成该表达式的值替换:
// 测试uel表达式分配负责人
@Test
public void test02(){
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = engine.getRuntimeService();
// 启动时传入负责人
// map用于替换bpmn的uel表达式
Map<String, Object> map = new HashMap<>();
map.put("assignee0","六六");
map.put("assignee1","七七");
ProcessInstance vacationIns = runtimeService.startProcessInstanceByKey("vacation", map);
}
如上述程序所示,最终可以通过查看act_ru_task表会发现对应的assignee字段是我们预先定义好的key,而后面的text字段就是替换后的值value:
流程变量
流程变量:在流程的审批执行过程中,经常会需要一些变量来作为判决跳转下一流程节点的依据,这个变量就称之为流程变量。
举例:员工想要预支薪水,如果预支金额小于月薪那么直接经部门经理审批后上报财务即可,反之如果预支金额大于月薪那么需要上报总经理,通过后再上报财务即可。此时的预支金额就是流程变量
globa变量是流程变量的默认作用域,也就是流程实例,globa变量不允许重复,如果两次或多次使用了统一globa变量名那么后续的值会覆盖前面的值
local变量:针对一个任务task和一个执行实例范围,没有globa范围大。local变量由于存在于不同的任务或者不同的实例中,所以相互间没有影响,变量名可以一致,也可以与globa变量名一致
排他网关ExclusiveGateway
网关用于控制流程分支的走向。
排他网关是当流程执行至此网关时,所有分支都会判断条件是否为true,如果为true则执行该分支。排他网关只会选择一个为true的分支执行,如果有多个分支为true,那么就会选择id值较小的一个执行
springBoot整合activiti
首先导入依赖资源
<!-- activiti整合springboot -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.1.0.M1</version>
</dependency>
配置application.yaml文件
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/activiti?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
activiti:
#1.flase:默认值。activiti在启动时,对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常
#2.true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建
#3.create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)
#4.drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
database-schema-update: true
# 检测历史信息表 activiti7默认不生成信息表 此处开启
db-history-used: true
# 历史记录存储等级
history-level: full
check-process-definitions: true
在主程序处排除掉springSecurity框架
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
SecurityAutoConfiguration.class,
SecurityAutoConfiguration.class,
ManagementWebSecurityAutoConfiguration.class
})
最后我们需要保证已经编绘好的bpmn文件位于resources文件夹下的processes目录下,否则activiti会找不到文件无法创建表
如下图所示:
如果是第一次使用activi的话就直接启动主程序,activiti将会自动的在对应数据库中建表,并且如果在你的processes包下扫描到了对应的bpmn文件那么activiti也会自动的进行流程部署
测试启动流程:
@Controller
public class TestController {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@RequestMapping(value = "/hello/{id}")
@ResponseBody
public String testHello(@PathVariable("id") String id){
// 测试完成任务
Task task = taskService.createTaskQuery()
.processInstanceId(id)
.singleResult();
taskService.complete(task.getId());
return "完成任务人=="+task.getAssignee()+
"获取到的id=="+id+
"get到的id=="+task.getId();
}
@RequestMapping(value = "/create")
@ResponseBody
public String testCreate(){
// 定义负责人名称
Map<String, Object> maps = new HashMap<>();
maps.put("a1","五一");
maps.put("a2","六一");
ProcessInstance holidy = runtimeService.startProcessInstanceByKey("holiday", maps);
return "流程实例ID=="+holidy.getId()+
"流程实例ID=="+holidy.getProcessInstanceId()+
"流程定义Id=="+holidy.getProcessDefinitionId()+
"流程定义Name=="+holidy.getProcessDefinitionName();
}
}