一、画流程图
我们以请假流程为例,画一个简单的流程图
新建文件
右键新建BPMN
文件,命名为Myprocess
,打开文件出现如下界面:
点击空白处,然后在右边可看到ID
选项,为流程图设置一个唯一的ID,如果ID重复,部署的时候就会认为是一个流程的新版本。
加入元素
需要用到如下几个组件:
完成后的结果:
二、流程部署
把我们画好的流程信息保存到数据库中
:::tip 提示
bpmn文件存放到processes文件夹下,会自动部署.
:::
部署指定的文件
Deployment deploy =
repositoryService.createDeployment().addClasspathResource("MyProcess.bpmn").deploy();
部署后表数据分析
1.act_ge_bytearray表
二进制数据表,存储了流程定义图形的XML文件和图片信息
保存流程定义的xml信息
保存流程定义的图片
2.act_re_deployment
部署信息表,存储了部署的相关信息(部署时间)
3.act_re_procdef
流程定义数据表,存储了当前流程图形的相关信息(id,name,版本号)
解决乱码问题
import org.activiti.spring.SpringProcessEngineConfiguration;
import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ActivitiConfig implements ProcessEngineConfigurationConfigurer{
@Override
public void configure(SpringProcessEngineConfiguration processEngineConfiguration) {
processEngineConfiguration.setActivityFontName("宋体");
processEngineConfiguration.setLabelFontName("宋体");
}
}
三、查询流程定义数据
对应表:act_re_procdef
ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
//查询流程
List<ProcessDefinition> list = query.list();
for (ProcessDefinition pd : list) {
System.out.println("name:"+pd.getName()+"\nid:"+pd.getId());
}
//查询流程定义数量
System.out.println("流程定义数量:"+query.count());
//最后一次部署的流程定义对象
ProcessDefinition singleResult = query.latestVersion().singleResult();
System.out.println("最后一次部署的流程定义对象"+singleResult);
//根据版本号进行倒序排序
ProcessDefinitionQuery processDefinitionQuery = query.orderByProcessDefinitionVersion().desc();
List<ProcessDefinition> list2 = processDefinitionQuery.list();
for (ProcessDefinition pd : list2) {
System.out.println("name:"+pd.getName()+"\nid:"+pd.getId());
}
四、运行流程实例
//查询流程实例
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myProcess_1")
.latestVersion()
.singleResult();
//System.out.println(myProcess);
//运行流程实例
ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId());
System.out.println(processInstance);
发生变化的表
act_hi_procinst
: 历史流程实例表 保存了流程实例的信息act_hi_taskinst
: 历史任务实例表 保存了流程任务的相关信息act_hi_actinst
:历史节点表 保存了流程执行的节点顺序act_ru_execution
: 运行时流程执行实例表 保存了当前流程执行的节点数据,流程开始会自动完成,直接执行第一个任务
act_ru_task
: 运行时任务节点表 保存当前流程执行的任务数据
完成请假流程
画流程图 并添加委托人,委托人的作用就是来完成这个任务。
部署新的工作流程,启动流程实例,观察表数据
查看act_ru_identitylink
表:增加了委托人的信息
查询任务:
TaskQuery taskQuery = taskService.createTaskQuery();
//获取zhangsan的任务列表
List<Task> taskList = taskQuery.taskAssignee("zhangsan").list();
for (Task task : taskList) {
System.out.println(task.getId()+":"+task.getName());
}
完成任务:
TaskQuery taskQuery = taskService.createTaskQuery();
//获取zhangsan的任务列表
List<Task> taskList = taskQuery.taskAssignee("zhangsan").list();
for (Task task : taskList) {
System.out.println(task.getId()+":"+task.getName());
taskService.complete(task.getId());
}
TaskQuery taskQuery = taskService.createTaskQuery();
//获取zhangsan的任务列表
List<Task> taskList = taskQuery.taskAssignee("lisi").list();
for (Task task : taskList) {
System.out.println(task.getId()+":"+task.getName());
taskService.complete(task.getId());
}
查看act_hi_actinst
可查看历史结点:
五、查询历史流程
找到act_hi_procinst
,历史流程实例表,可以看到里面有完成的也有为完成的任流程。
先查询流程定义,找到我们要查询的那个流程,然后在查询历史流程实例:
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myProcess_1")
.latestVersion()
.singleResult();
HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();
HistoricProcessInstance historicProcessInstance = query.processInstanceId("15001").finished().singleResult();
System.out.println("historicProcessInstance:"+historicProcessInstance);
输出:historicProcessInstance:HistoricProcessInstanceEntity[superProcessInstanceId=null]
输出结果不为空,表示流程已经完成。
六、领取任务
重新画一个流程图,并指定委派人为一个组
运行流程实例
//查找对应的流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myProcess_2")
.latestVersion()
.singleResult();
//运行
ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId());
运行后可以查询根据委托人分组查询到对应的流程实例:
Task cpes = taskService.createTaskQuery().taskCandidateGroup("cpes").singleResult();
System.out.println(cpes);
输出如下:Task[id=25004, name=组长审批]
任务领取
Task task1 = taskService.createTaskQuery().taskCandidateGroup("cpes").singleResult();
taskService.claim(task1.getId(),"zhangsan");
List<Task> tasks = taskService.createTaskQuery().taskAssignee("zhangsan").list();
for (Task task : tasks) {
System.out.println(task);
}
完成任务:
taskService.complete(task.getId());
七、流程变量
重新定义流程,委托人采用流程变量获取委托人
部署运行流程
因为指定了流程变量,需要给流程变量赋值,所以直接运行流程实例会报错。
//从act_re_procdef找到流程定义key
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myProcess_4")
.latestVersion().singleResult();
ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId());
startProcessInstanceById
方法还有一个map
参数,就是用来给流程变量赋值的。
//从act_re_procdef找到流程定义key
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myProcess_4")
.latestVersion().singleResult();
Map<String,Object> var = new HashMap<>();
var.put("tl","zhangsan");
ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId(),var);
这时候就可以查找zhangsan
的流程列表,完成任务了。看我们的流程图,下一步是经理审批,因为经理审批处的流程变量还没有赋值,所以也要在这里给我们设置的${pm}设置值。
TaskQuery taskQuery = taskService.createTaskQuery();
//获取zhangsan的任务列表
List<Task> taskList = taskQuery.taskAssignee("zhangsan").list();
for (Task task : taskList) {
Map<String,Object> var = new HashMap<>();
var.put("pm","lisi");
System.out.println(task.getId()+":"+task.getName());
taskService.complete(task.getId(),var);
}
这时候运行经理审批这个节点了,我们设置了这个节点的委托人为lisi
,我们就查找lisi
的任务列表,然后完成。
TaskQuery taskQuery = taskService.createTaskQuery();
//获取zhangsan的任务列表
List<Task> taskList = taskQuery.taskAssignee("lisi").list();
for (Task task : taskList) {
System.out.println(task.getId()+":"+task.getName());
taskService.complete(task.getId());
}
到这里任务就完成了。
可以查看下act_hi_actinst
表如下:
八、网关
排他网关:有多个分支的情况下,只走其中一个分支。(决策网关)。
并行网关:多个分支同时走。(会签网关)。
包含网关:以上两种网关结合在一起使用。(至少满足一个分支或者同时满足两个分支才会走这个流程)
排他网关
同样以请假流程为例,请假天数大于三天需要经理审批,小于等于三天不需要经理审批,设置组长委托人为zhangsan,设置经理委托人为lisi,并设置排他网关的条件。
同样设置另一条线条件为${days>3}
//查询流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myProcess_6")
.latestVersion()
.singleResult();
//准备流程变量
Map<String,Object> var = new HashMap<>();
var.put("days",3);
//启动流程,传递流程变量
ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId(), var);
//完成任务
List<Task> taskList = taskService.createTaskQuery().taskAssignee("zhangsan").list();
for (Task task : taskList) {
System.out.println(task);
taskService.complete(task.getId());
}
//查看流程是否完成 完成则!= null
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
.processInstanceId(processInstance.getId())
.finished()
.singleResult();
System.out.println(historicProcessInstance);
输出结果如下,则流程完成
Task[id=125005, name=组长审核]
HistoricProcessInstanceEntity[superProcessInstanceId=null]
::: tip 注意
特殊情况,条件判断分支中不包含3,但恰恰给了3的值,导致两个分支都没有执行。
:::
并行网关
出差,出差天数项目经理要审批,申请出差费用财务部门要需要审批
项目经理审批:zhangsan
财务经理审批:lisi
//部署流程
System.out.println(processEngine);
//查询流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myProcess_6")
.latestVersion()
.singleResult();
System.out.println(processDefinition);
//部署流程
ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId());
System.out.println(processInstance);
//查看zhangsan,lisi的任务
Task task = taskService.createTaskQuery()
.processDefinitionKey("myProcess_6")
.taskAssignee("lisi")
.singleResult();
System.out.println(task);
//完成任务
taskService.complete(task.getId());
包含网关
项目经理审批:zhangsan
条件:${days>3}
财务经理审批:lisi
条件:${cost>5000}
System.out.println(processEngine);
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myProcess_9")
.latestVersion()
.singleResult();
Map<String,Object> var = new HashMap<>();
var.put("days",2);
var.put("cost",10000);
ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId(),var);
Task task = taskService.createTaskQuery().processDefinitionKey("myProcess_9").taskAssignee("lisi").singleResult();
System.out.println(task);
taskService.complete(task.getId());
九、流程监听器
审核通过:${flag==true}
审核拒绝:${flag==false}
创建监听类,实现ExcutorListener
接口
package cn.ishangit.helloactivity5.act.listener;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
/**
* @description:
* @author: Chen
* @create: 2019-06-29 21:23
**/
public class NoListener implements ExecutionListener {
@Override
public void notify(DelegateExecution delegateExecution) throws Exception {
System.out.println("流程拒绝-------------------");
}
}
package cn.ishangit.helloactivity5.act.listener;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
/**
* @description:
* @author: Chen
* @create: 2019-06-29 21:23
**/
public class YesListener implements ExecutionListener {
@Override
public void notify(DelegateExecution delegateExecution) throws Exception {
System.out.println("流程同意-------------------");
}
}
绑定监听器
测试:
System.out.println(processEngine);
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myProcess_10")
.latestVersion()
.singleResult();
ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId());
Task task = taskService.createTaskQuery().processDefinitionKey("myProcess_10").taskAssignee("zhangsan").singleResult();
System.out.println(task);
Map<String,Object> var = new HashMap<>();
var.put("flag",true);
taskService.complete(task.getId(),var);
结果: