会签 or 或签
- nrOfCompletedInstances:审批完成人员
- nrOfInstances :全部人员
- ${nrOfCompletedInstances/nrOfInstances == 1 }:表示会签人员全部审批完成
- ${nrOfCompletedInstances/nrOfInstances > 0} :表示或签,只要有一个人审批过了就通过
//1.部署流程
@Test
public void testdeploy()
{
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.name("请假流程定义")
.addClasspathResource("bpmn/test01.bpmn20.xml")
.deploy();
System.out.println("流程部署id = " + deploy.getId());
System.out.println("流程部署名称 = " + deploy.getName());
}
//2.启动流程实例
@Test
public void testStartProcess()
{
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map<String,Object> map = new HashMap<>();
map.put("assignee0","经理a");
map.put("assignee00","财务a");
map.put("assignee000","老板a");
//会签/或签人员
List<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
map.put("assignList",list);
ProcessInstance instance = runtimeService
.startProcessInstanceByKey("process","bussiness2",map); // xml > id, 业务id , 人员映射
System.out.println("部署id:"+instance.getDeploymentId());
System.out.println("进程id:"+instance.getProcessDefinitionId());
System.out.println("当前活动的id:"+instance.getId());
System.out.println("**(唯一和业务ID关联的)流程实例id:"+instance.getProcessInstanceId());
}
//3 根据业务key + 人:完成当前人节点审批
@Test
public void completeProcess(){
String user = "王五";
/**
*
*完成任务
*/
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task taskSingle = taskService.createTaskQuery()
.processInstanceBusinessKey("bussiness2")
.taskAssignee(user)
.singleResult();
if(Objects.isNull(taskSingle)){
System.out.println("此人当前节点没有审批任务");
return;
}
taskService.complete(taskSingle.getId());
System.out.println("任务: bussiness1 ==> "+user+"审批完成");
}
驳回操作
/**
* 驳回操作:
* 驳回上一步
*/
@Test
public void testFindPersonalTaskList8() throws Exception {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().processInstanceBusinessKey("bussiness2").singleResult();
Retru.backProcess(task);
}
/**
* 驳回操作:
* 驳回初始步骤
*/
@Test
public void testFindPersonalTaskList9() throws Exception {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().processInstanceBusinessKey("bussiness2").singleResult();
System.out.println(1);
// .processInstanceId("207501").singleResult();
Retru.jumpToStart(task);
}
/**
* 驳回操作:
* 驳回到指定人员那一步(单人节点驳回|会签节点驳回)
*/
@Test
public void testFindPersonalTaskList10() throws Exception {
//----------------------------------第1种方式----------------------------------------------
// ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// TaskService taskService = processEngine.getTaskService();
// // 根据 instance_id 精准查询当前流程
// List<Task> taskList = taskService.createTaskQuery().processInstanceBusinessKey("bussiness2").list();
// if(CollectionUtils.isEmpty(taskList)){
// System.out.println("未查询到历史活动节点,无法驳回!");
// return;
// }
// Task task = taskList.get(0);
// Retru.backProcessByUserName(task,"财务a"); // 单人审批节点驳回
//----------------------------------第2种方式----------------------------------------------
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
List<Task> taskList = taskService.createTaskQuery().processInstanceBusinessKey("bussiness2").list();
if(CollectionUtils.isEmpty(taskList)){
System.out.println("未查询到历史活动节点,无法驳回!");
return;
}
Retru.huiBackProcessByUserName(taskList,"财务a","财务");// 会签节点驳回
}
/**
* Created with IntelliJ IDEA
* Date: 2022/10/26
* Time: 10:46
*
* 1取得当前节点的信息
* 2取得当前节点的上一个节点的信息
* 3保存当前节点的流向
* 4新建流向,由当前节点指向上一个节点
* 5将当前节点的流向设置为上面新建的流向
* 6当前节点完成任务
* 7将当前节点的流向还原
* 8取得之前上个节点的执行人
* 9设置上个节点的assignee为之前的执行人
*/
public class Retru {
/**
* 跳到最开始的任务节点(直接打回),
* 也是可以当做拒绝任务,即无论走到哪一步,拒绝了直接打回到起点!!!!
* @param task 当前任务
*/
public static void jumpToStart(Task task) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
HistoryService historyService = processEngine.getHistoryService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();
String processInstanceId = task.getProcessInstanceId();
// 获取所有历史任务(按创建时间升序)
List<HistoricTaskInstance> hisTaskList = historyService.createHistoricTaskInstanceQuery()
.processInstanceId(processInstanceId)
.orderByTaskCreateTime()
.asc()
.list();
if (CollectionUtils.isEmpty(hisTaskList) || hisTaskList.size() < 2) {
return;
}
// 第一个任务
HistoricTaskInstance startTask = hisTaskList.get(0);
// 当前任务
HistoricTaskInstance currentTask = hisTaskList.get(hisTaskList.size() - 1);
BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
// 获取第一个活动节点
FlowNode startFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(startTask.getTaskDefinitionKey());
// 获取当前活动节点
FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentTask.getTaskDefinitionKey());
// 临时保存当前活动的原始方向 (当前审批节点------> 下一审批节点)
List<SequenceFlow> originalSequenceFlowList = new ArrayList<>();
originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
// 清理活动方向
currentFlowNode.getOutgoingFlows().clear();
// 建立新方向
SequenceFlow newSequenceFlow = new SequenceFlow();
newSequenceFlow.setId("newSequenceFlowId");
newSequenceFlow.setSourceFlowElement(currentFlowNode);
newSequenceFlow.setTargetFlowElement(startFlowNode);
List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
newSequenceFlowList.add(newSequenceFlow);
// 当前节点指向新的方向
currentFlowNode.setOutgoingFlows(newSequenceFlowList);
// 完成当前任务
taskService.complete(task.getId());
// 重新查询当前任务
Task nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
if (null != nextTask) {
taskService.setAssignee(nextTask.getId(), startTask.getAssignee());
}
// 恢复原始方向
currentFlowNode.setOutgoingFlows(originalSequenceFlowList);
}
/**
* 驳回 / 回退
* 按照这种方法,可以回退至任意节点(默认上一步)
* @param task
* @throws Exception
*/
public static void backProcess(Task task) throws Exception {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
HistoryService historyService = processEngine.getHistoryService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();
String processInstanceId = task.getProcessInstanceId();
// 获取所有历史任务(按创建时间降序)
List<HistoricTaskInstance> hisTaskList = historyService.createHistoricTaskInstanceQuery()
.processInstanceId(processInstanceId)
.orderByTaskCreateTime()
.desc()
.list();
// 获取所有历史活动
List<HistoricActivityInstance> hisActivityList = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId).list();
if (CollectionUtils.isEmpty(hisTaskList) || hisTaskList.size() < 2) {
return;
}
// 当前任务
HistoricTaskInstance currentTask = hisTaskList.get(0);
// 前一个任务
HistoricTaskInstance lastTask = hisTaskList.get(1);
// 当前活动
HistoricActivityInstance currentActivity = hisActivityList.stream().filter(e -> currentTask.getId().equals(e.getTaskId())).collect(Collectors.toList()).get(0);
// 前一个活动
HistoricActivityInstance lastActivity = hisActivityList.stream().filter(e -> lastTask.getId().equals(e.getTaskId())).collect(Collectors.toList()).get(0);
BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
// 获取前一个活动节点
FlowNode lastFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(lastActivity.getActivityId());
// 获取当前活动节点
FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivity.getActivityId());
// 临时保存当前活动的原始方向
List<SequenceFlow> originalSequenceFlowList = new ArrayList<>();
originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
// 清理活动方向(删除指向下一个节点的箭头)
currentFlowNode.getOutgoingFlows().clear();
// 建立新方向
SequenceFlow newSequenceFlow = new SequenceFlow();
newSequenceFlow.setId("newSequenceFlowId");
newSequenceFlow.setSourceFlowElement(currentFlowNode);
newSequenceFlow.setTargetFlowElement(lastFlowNode);
List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
newSequenceFlowList.add(newSequenceFlow);
// 当前节点指向新的方向
currentFlowNode.setOutgoingFlows(newSequenceFlowList);
// 完成当前任务
taskService.complete(task.getId());
// 重新查询当前任务
Task nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
if (null != nextTask) {
taskService.setAssignee(nextTask.getId(), lastTask.getAssignee());
}
// 恢复原始方向(前面已经指向了上一个节点,还得恢复上一个节点指向的下一个节点)
currentFlowNode.setOutgoingFlows(originalSequenceFlowList);
}
/**
* 驳回 / 回退
* 按照这种方法,可以回退至输入的指定用户(当前节点只能有1人审批)
*/
public static void backProcessByUserName(Task task,String userName) throws Exception {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
HistoryService historyService = processEngine.getHistoryService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();
String processInstanceId = task.getProcessInstanceId();
// 获取所有历史任务(按创建时间降序)
List<HistoricTaskInstance> hisTaskList = historyService.createHistoricTaskInstanceQuery()
.processInstanceId(processInstanceId)
.orderByTaskCreateTime()
.desc()
.list();
// 获取所有历史活动
List<HistoricActivityInstance> hisActivityList = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId).list();
if (CollectionUtils.isEmpty(hisTaskList) || hisTaskList.size() < 2) {
return;
}
// 当前任务
HistoricTaskInstance currentTask = hisTaskList.get(0);
// 前一个任务
HistoricTaskInstance lastTask = hisTaskList.stream().filter(e->e.getAssignee().equals(userName)).findFirst().orElse(null);
if(ObjectUtils.isEmpty(lastTask)){
System.out.println("历史任务指定人员 "+userName+" 不存在!");
return;
}
// 当前活动
HistoricActivityInstance currentActivity = hisActivityList.stream().filter(e -> currentTask.getId().equals(e.getTaskId())).collect(Collectors.toList()).get(0);
// 前一个活动
HistoricActivityInstance lastActivity = hisActivityList.stream().filter(e -> lastTask.getId().equals(e.getTaskId())).collect(Collectors.toList()).get(0);
BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
// 获取前一个活动节点
FlowNode lastFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(lastActivity.getActivityId());
// 获取当前活动节点
FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivity.getActivityId());
// 临时保存当前活动的原始方向
List<SequenceFlow> originalSequenceFlowList = new ArrayList<>();
originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
// 清理活动方向(删除指向下一个节点的箭头)
currentFlowNode.getOutgoingFlows().clear();
// 建立新方向
SequenceFlow newSequenceFlow = new SequenceFlow();
newSequenceFlow.setId("newSequenceFlowId");
newSequenceFlow.setSourceFlowElement(currentFlowNode);
newSequenceFlow.setTargetFlowElement(lastFlowNode);
List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
newSequenceFlowList.add(newSequenceFlow);
// 当前节点指向新的方向
currentFlowNode.setOutgoingFlows(newSequenceFlowList);
// 完成当前任务
taskService.complete(task.getId());
// 重新查询当前任务
Task nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).list().get(0);
if (null != nextTask) {
taskService.setAssignee(nextTask.getId(), lastTask.getAssignee());
}
// 恢复原始方向(前面已经指向了上一个节点,还得恢复上一个节点指向的下一个节点)
currentFlowNode.setOutgoingFlows(originalSequenceFlowList);
}
/**
* 会签 多人审批情况下驳回(有1人驳回就算未通过and会签中其他人无需操作,驳回给指定用户)
* userName:驳回给指定人员(这里就有个大问题就是,一个审批流程每个节点不能存在相同人员)
* taskName(非必传): 此节点起的名,防止多个节点都是1个人审批,根据人员筛选不太准确,人员+节点 筛选就准了
*/
public static void huiBackProcessByUserName(List<Task> tasks,String userName,String taskName) throws Exception {
Task task = tasks.get(0);
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
HistoryService historyService = processEngine.getHistoryService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();
String processInstanceId = task.getProcessInstanceId();
// 获取所有历史任务(按创建时间降序)
List<HistoricTaskInstance> hisTaskList = historyService.createHistoricTaskInstanceQuery()
.processInstanceId(processInstanceId)
.orderByTaskCreateTime()
.desc()
.list();
// 获取所有历史活动
List<HistoricActivityInstance> hisActivityList = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId).list();
if (CollectionUtils.isEmpty(hisTaskList) || hisTaskList.size() < 2) {
return;
}
// 当前任务
HistoricTaskInstance currentTask = hisTaskList.get(0);
// 前一个任务
HistoricTaskInstance lastTask = hisTaskList.stream().filter(e->e.getAssignee().equals(userName) && StringUtils.isEmpty(taskName)?true:e.getName().equals(taskName)).findFirst().orElse(null);
if(ObjectUtils.isEmpty(lastTask)){
System.out.println("历史任务指定人员 "+userName+" 不存在!");
return;
}
// 当前活动
HistoricActivityInstance currentActivity = hisActivityList.stream().filter(e -> currentTask.getId().equals(e.getTaskId())).collect(Collectors.toList()).get(0);
// 前一个活动
HistoricActivityInstance lastActivity = hisActivityList.stream().filter(e -> lastTask.getId().equals(e.getTaskId())).collect(Collectors.toList()).get(0);
BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
// 获取前一个活动节点
FlowNode lastFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(lastActivity.getActivityId());
// 获取当前活动节点
FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivity.getActivityId());
// 临时保存当前活动的原始方向
List<SequenceFlow> originalSequenceFlowList = new ArrayList<>();
originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
// 清理活动方向(删除指向下一个节点的箭头)
currentFlowNode.getOutgoingFlows().clear();
// 建立新方向
SequenceFlow newSequenceFlow = new SequenceFlow();
newSequenceFlow.setId("newSequenceFlowId");
newSequenceFlow.setSourceFlowElement(currentFlowNode);
newSequenceFlow.setTargetFlowElement(lastFlowNode);
List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
newSequenceFlowList.add(newSequenceFlow);
// 当前节点指向新的方向
currentFlowNode.setOutgoingFlows(newSequenceFlowList);
// 完成当前任务
tasks.forEach(e->{
taskService.complete(e.getId());
});
// 重新查询当前任务
// Task nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).list().get(0);
// if (null != nextTask) {
// taskService.setAssignee(nextTask.getId(), lastTask.getAssignee());
// }
// 恢复原始方向(前面已经指向了上一个节点,还得恢复上一个节点指向的下一个节点)
currentFlowNode.setOutgoingFlows(originalSequenceFlowList);
}
/**
* 结束任务 (和驳回一样直接从当前任务指向结束)
* @param task 当前任务
* 可用作被拒绝到发起人时,发起人可以选择结束任务(代替重新提交),然后再重新发起一个新的任务
*/
public static void endTask(Task task) {
// 当前任务
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
RepositoryService repositoryService = processEngine.getRepositoryService();
BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
List endEventList = bpmnModel.getMainProcess().findFlowElementsOfType(EndEvent.class);
FlowNode endFlowNode = (FlowNode)endEventList.get(0);
FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(task.getTaskDefinitionKey());
// 临时保存当前活动的原始方向
List originalSequenceFlowList = new ArrayList<>();
originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
// 清理活动方向
currentFlowNode.getOutgoingFlows().clear();
// 建立新方向
SequenceFlow newSequenceFlow = new SequenceFlow();
newSequenceFlow.setId("newSequenceFlowId");
newSequenceFlow.setSourceFlowElement(currentFlowNode);
newSequenceFlow.setTargetFlowElement(endFlowNode);
List newSequenceFlowList = new ArrayList<>();
newSequenceFlowList.add(newSequenceFlow);
// 当前节点指向新的方向
currentFlowNode.setOutgoingFlows(newSequenceFlowList);
// 完成当前任务
taskService.complete(task.getId());
// 可以不用恢复原始方向,不影响其它的流程
currentFlowNode.setOutgoingFlows(originalSequenceFlowList);
}
}
删除流程
/**
* 删除流程信息
* 流程开发只有超级管理员有权限 删除流程
*/
@Test
public void testFindPersonalTaskList7(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
final RepositoryService repositoryService = processEngine.getRepositoryService();
// 如果流程实例已经启动则删除报错
repositoryService.deleteDeployment("17501");
// 如果流程实例已经启动照样删除
repositoryService.deleteDeployment("17501",true);
}
结束任务:无论在哪个节点,直接跳到结束节点(同样是驳回思想)
/**
* 结束任务操作:无论在哪个节点,直接跳到结束节点
*/
@Test
public void testFindPersonalTaskList101() throws Exception {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().processInstanceBusinessKey("bussiness2").singleResult();
System.out.println(1);
Retru.endTask(task);
}
流程挂起 / 激活
/**
* 全部实例:挂起 或 激活流程 暂停
* 挂起的作用就是:我启动了一批请假流程,但是中途发现有问题,就挂起暂停住不用他的,重新开启新的请假流程
*/
@Test
public void ALLstopOrActive(){
final ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
final RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
final ProcessDefinition evection = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("evection") // 实例名称
.singleResult();
final boolean suspended = evection.isSuspended();
final String id = evection.getId();
//流程是挂起的
if(suspended){
// 如果是挂起的,就激活
repositoryService.activateProcessDefinitionById(
id // 流程定义id
,
true // 激活
,null); // 时间
System.out.println("流程定义 :"+id+" ,已激活");
}else{
repositoryService.suspendProcessDefinitionById(
id // 流程定义id
,
true // 暂停
,null
);
System.out.println("流程定义 :"+id+" ,已挂起");
}
}
/**
* 单个流程实例的挂起与激活
*/
@org.junit.Test
public void ONEstopOrActive(){
final ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
final RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
final ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId("12501").singleResult();// 通过实例id
// .processInstanceBusinessKey("").singleResult() // 通过业务id
final boolean suspended = processInstance.isSuspended();
final String id = processInstance.getId();
//流程是挂起的
if(suspended){
// 如果是挂起的,就激活
runtimeService.activateProcessInstanceById(id);
System.out.println("流程实例id :"+id+" ,已激活");
}else{
runtimeService.suspendProcessInstanceById(id);
System.out.println("流程实例id :"+id+" ,已挂起");
}
}
网关
// 排他网关:只能走一条线,可以设置默认走哪条,知道排他网关就够了
// 并行网关:就是同时进行的两个节点都审批过了才能进入下一节点,可以用会签代替!
// 包容网关:排他和并行的合体
// 事件网关:用不着
只是在线上加控制选择那个分支
@Test
public void testStartProcess()
{
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map<String,Object> map = new HashMap<>();
map.put("assignee0","姜1");
map.put("assignee1","姜2");
map.put("assignee2","领导a");
map.put("assignee3","领导b");
map.put("days",2);
ProcessInstance instance = runtimeService.
startProcessInstanceByKey("testActiviti","bussiness2",map); // xml 的process id,业务id,流程节点对应人员
System.out.println("流程定义id:"+instance.getProcessDefinitionId());
System.out.println("流程定义id:"+instance.getProcessDefinitionId());
System.out.println("当前活动的id:"+instance.getActivityId());
}
部署涉及表:
act_re_deployment 流程定义部署表,每部署一次增加一条记录
act_re_procdef 流程定义表,部署每个新的流程定义都会在这张表中增加一条记录
act_ge_bytearray 流程资源表,存xml二进制文件
启动流程涉及表:
act_hi_actinst 流程实例执行历史记录 (详细记录) *
act_hi_identitylink 流程的参与用户历史信息
act_hi_procinst 流程实例历史信息(主要是记录开始时间,结束时间,流程实例Id)
act_hi_taskinst 流程任务历史信息
act_ru_execution 流程执行信息
act_ru_identitylink 流程的参与用户信息
act_ru_task 待审批用户 *