Activiti工作流基本概念

一、核心思想

理解:

	Activiti核心思想,实际上就是提供一系列的API,对他规定的23张数据库表进行操作。所有的数据流转,都是在这23张表里面完成,其中RE表存储流程
部署相关信息,RU表存储运行时信息,HI表存储历史信息。通过表里面的业务键,与具体的业务信息关联起来。

	通过流程设计插件,画BPMN流程图,实际上就是xml文件,规定了一个流程里面的每个节点的信息,每个节点可以通过设置变量的方式,填充一些信息,
比如审批人/审批组等信息。在运行的时候,通过API里面提供的参数和方法,将具体的值填充到这些变量。

	一个流程部署信息,就相当于模板,可以根据这个模板启动多个流程实例。

二、核心API

(1)、ProcessEngineConfiguration和ProcessEngine

ProcessEngineConfiguration实际上就是一个配置类,用于加载配置文件里面的信息,配置文件
activiti.cfg.xml里面配置了数据源信息、生成表的策略、事务管控等。
通过这个流程配置对象,可以生成ProcessEngine流程引擎,其它的所有对象都是基于流程引擎生成的,可以说这是一个门面对象。

灵活的读取配置对象的方式:
ProcessEngineConfiguration.createProcessEngineConfigurationFromResource(String resource, String beanName);

如果将 activiti.cfg.xml ⽂件名及路径固定,且 activiti.cfg.xml ⽂件中有 processEngineConfiguration 的配置,也可以使用简单方式:

使⽤classpath下的activiti.cfg.xml中的配置创建processEngine ProcessEngine processEngine =ProcessEngines.getDefaultProcessEngine();

(2)、RepositoryService

资源服务类,用于管理和部署流程,发布流程定义,查看流程定义信息
(包括发布包里面的流程图和文件),暂停和激活流程,总而言之就是管理流程定义部署的资源。

(3)、RuntimeService

流程运行管理类,管理和查看流程实例,启动流程、暂停/激活流程、设置流程变量等待,
总而言之就是管理流程实例。

(4)、 TaskService

任务管理类,管理和查看任务,执行任务\拾起任务\归还任务、设置任务执行人,总而言之,就是
对一个流程实例里面的任务节点进行管理和查询。

(5)、HistoryService

历史信息管理类,管理查询历史操作信息,流程实例在每个节点的操作,都会记录在历史表里面,
⽐如流程实例启动时间,任务的参与者, 完成任务的时间,每个流程实例的执⾏路径等等。

三、基本流程

(1)、流程定义:

 Activiti-Designer流程图
 流程元素:
 Connection—连接 
 Event—事件 
 Task—任务 
 Gateway—⽹关 
 Container—容器 
 Boundary event—边界事件 
 Intermediate event- -中间事件
 流程定义完成之后,保存bpmn文件。
 
 1、在流程图的properties上指定流程定义的 key,后面启动流程实例要通过这个key来启动,
 才能生成对应的实例。
 2、在每个任务节点上指定负责人(或者候选人/候选人组),可以通过写死的方式或者uel表达式的方式
 3、对于有分支的情况,可以在连接上指定判断条件
 4、有分支的情况,可以通过网关来解决,网关分为排他网关(一个流程实例只能通过条件选择一个方向,串行执行),和并行网关(可以分发到不同的节点)。

(2)、流程部署

将上面绘制的流程定义图(实际上就是一个xml),部署到Activiti上(实际上就是把这些
数据插入到RE资源表),这些操作通过Activiti提供的api来完成
// 获取
repositoryService RepositoryService repositoryService = processEngine.getRepositoryService(); 
//部署对象 
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("diagram/myholiday.bpmn")// bpmn⽂件 
.addClasspathResource("diagram/myholiday.png")// 图 ⽚ ⽂件
.name("请假申请流程").deploy();

(3)、流程实例启动

根据流程部署的key,启动一个实例,一个流程就按照流程定义图开始了,实际上就是往ru和hi表插入了一条实例数据。


//定义流程变量 
Map<String, Object> variables = new HashMap<String, Object>(); 
//设置流程变量assignee 
variables.put("assignee", "张三"); 
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, variables);

(4)、任务查询

流程流转到不同的节点,对应节点上的负责人查询⾃⼰当前需要处理的任务,查询出来的任务都是该⽤户的待办任务。
// 任务负责⼈ 
String assignee = "zhangsan"; 
// 创建TaskService 
TaskService taskService = processEngine.getTaskService(); 
List<Task> list = taskService.createTaskQuery().processDefinitionKey("myholiday01")
.taskAssignee(assignee).list(); 

(5)、任务处理

任务负责⼈查询待办任务,选择任务进⾏处理,完成任务。实际上这里就是更新re表和插入数据到hi表。
//任务id 
String taskId = "8305"; 
// 创建TaskService 
TaskService taskService = processEngine.getTaskService(); 
//完成任务 
taskService.complete(taskId);

(6)、其它细节

<1>、流程定义部署的其它方式:

通过zip的方式进行部署
// 定义zip输⼊流 
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(" diagram/holiday.zip"); ZipInputStream zipInputStream = new ZipInputStream(inputStream); 
// 获取repositoryService 
RepositoryService repositoryService = processEngine.getRepositoryService(); 
// 流程部署 
Deployment deployment = repositoryService.createDeployment().addZipInputStream(zipInputStream).deploy();

<2>、查询器

一般查询都是通过查询器对象进行查询,例如流程定义信息的查询
// 流程定义key 
String processDefinitionKey = "holiday"; 
// 获取repositoryService 
RepositoryService repositoryService = processEngine.getRepositoryService(); 
// 查询流程定义 
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery(); 
//遍历查询结果 
List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey(processDefinitionKey).orderByProcessDefinitionVersion().desc().list();

<3>、流程定义删除

删除已经部署成功的流程定义。一般用级联删除,删除流程定义的同时,也会把流程实例也删除掉。
// 流程部署id 
String deploymentId = "8801"; 
// 通过流程引擎获取
repositoryService RepositoryService repositoryService = processEngine.getRepositoryService(); 
//删除流程定义, 如果该流程定义已有流程实例启动则删除时出错 repositoryService.deleteDeployment(deploymentId); 
repositoryService.deleteDeployment(deploymentId, true);

<4>、业务标识

启动流程的时候,可以将业务key存入到Activiti的表中,这样就可以关联上业务信息,
或者也可以将流程实例id存入到业务表
// 根据流程定义的key和业务key启动⼀个流程实例 
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey);
//获取业务key
String businessKey = processInstance.getBusinessKey();

<5>、挂起、激活流程实例

挂起流程定义,则属于该流程定义的流程实例全部暂停,并且不能启动新的流程实例。
// 获得流程定义 
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionId(processDefinitionId).singleResult();

//是否暂停 boolean suspend = processDefinition.isSuspended(); 
if(suspend){ 
//如果暂停则激活,这⾥将流程定义下的所有流程实例全部激活 repositoryService.activateProcessDefinitionById(processDefinitionId,true, null); 
System.out.println("流程定义: "+processDefinitionId+"激活"); }
else{ 
//如果激活则挂起,这⾥将流程定义下的所有流程实例全部挂起 repositoryService.suspendProcessDefinitionById(processDefinitionId,true, null); 
System.out.println("流程定义: "+processDefinitionId+"挂起"); 
}
也可以单独暂停和激活一个流程实例,不会影响其它实例
//根据流程实例id查询流程实例 
ProcessInstance processInstance =
runtimeService.createProcessInstanceQuery()
.processInstanceId(processInstanceId).singleResult(); 

boolean suspend = processInstance.isSuspended(); 
if(suspend){ 
//如果暂停则激活 
runtimeService.activateProcessInstanceById(processInstanceId); System.out.println("流程实例: "+processInstanceId+"激活"); 
}else{ 
//如果激活则挂起 
runtimeService.suspendProcessInstanceById(processInstanceId); System.out.println("流程实例: "+processInstanceId+"挂起"); 
}

<6>、监听器

针对任务,可以设置监听器,在不同的时候触发,必须实现 org.activiti.engine.delegate.TaskListener 接⼝
Create:任务创建后触发 
Assignment:任务分配后触发 
Delete:任务完成后触发 
All:所有事件发⽣都触发
public class MyTaskListener implements TaskListener { 
@Override 
public void notify(DelegateTask delegateTask) { 
//这⾥指定任务负责⼈ delegateTask.setAssignee("张三"); 
}
}

<7>、变量流程

流程变量作用域分为全局(流程实例内都有效)和局部(任务节点或者执行实例内有效),
类型可以是pojo对象(须实现序列化接⼝ serializable)
流程变量可以在启动时设置/任务办理时设置/通过当前流程实例设置
// 启动流程时设置流程变量 
@Test 
public void startProcessInstance() { 
 
Holiday holiday = new Holiday(); 
holiday.setNum(3); 
// 定义流程变量 
Map<String, Object> variables = new HashMap<String, Object>(); 
//变量名是num,变量值是holiday.getNum(),变量名也可以是⼀个对象
variables.put("num", holiday.getNum());
RuntimeService runtimeService = processEngine.getRuntimeService(); 
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, variables); 

//任务办理时设置
taskService.complete(taskId, variables);
//通过流程实例id设置
runtimeService.setVariable(executionId, "holiday", holiday);
//通过任务设置流程变量 
taskService.setVariable(taskId, "holiday", holiday);
//⼀次设置多个值 
taskService.setVariables(taskId, variables)

// 设置local变量,作⽤域为该任务 
taskService.setVariablesLocal(tasked, variables);

<8>、Candidate-users 候选⼈(组任务)

在流程图中任务节点的配置中设置 candidate-users(候选⼈)
根据候选⼈查询组任务,然后拾起任务,其它的候选人就不能再拾起,当前用户变成负责人。
并且还可以转发给其它人和退回(本质上就是设置负责人这个流程变量,
设置为null就是退回组
//拾取任务 即使该⽤户不是候选⼈也能拾取(建议拾取时校验是否有资格) 
//校验该⽤户有没有拾取任务的资格 
Task task = taskService.createTaskQuery()
.taskId(taskId) 
.taskCandidateUser(userId)
.singleResult(); 
if(task!=null){ 
	taskService.claim(taskId, userId); 
 }
// 如果设置为null,归还组任务,该 任务没有负责⼈ 
taskService.setAssignee(taskId, null);
//交接给其它人
taskService.setAssignee(taskId, candidateuser);

(7)、网关

<1>、 排他⽹关

经过网关,判断分支连线上设置的条件为true,就会走对应的分支,属于串行,
经过排他⽹关必须要有⼀条且只有⼀条分⽀⾛。
如果都不满足,就会抛出异常,这也是用排它网关和用连线直接设置条件的区别,不会造成异常流程结束而没有感应的情况发生。

<2>、 并⾏⽹关

有两个作用,一个是fork分支,一个是join汇聚分支,
经过并行网关出去后,所有的分支都会创建一个并发流程,
输入到并行网关后,所有分支都会汇聚在一起,在并行网关可以设置达到什么条件(到达并行网关的分支比例/数量等),再进入到下个流程。
基于并行网关的这种特性,可以用来做会签功能。
与其他⽹关的主要区别是,并⾏⽹关不会解析条件。 即使顺序流中定义了条件,也会被忽略

<3>、包含⽹关

可以看做是排他⽹关和并⾏⽹关的结合体,又可以设置条件(只有条件为true的分支才会创建),
又可以分发流程和汇聚流程分支(只等待条件为true的分支到达)。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值