在运行过程中,我们不想使用这个流程了,可以终止掉
package com.dmg.service;
public interface FlowService {
public void termination(String processInstanceId);
}
package com.dmg.controller;
/**
* 流程定义控制层
*/
@RestController
public class ProcessDefinitionController {
@Autowired
private FlowService flowService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private TaskService taskService;
/**
* 终止流程
* @return
*/
@PostMapping(value = "termination")
public Result termination(@RequestBody FlowReq req){
flowService.termination(req.getProcessInstanceId());
return Result.success();
}
}
package com.dmg.service.impl;
/**
* 流程定义服务实现类
*/
@Service
public class FlowServiceImpl extends FlowServiceFactory implements FlowService {
@Autowired
private HisApprovalMapper hisApprovalMapper;
@Autowired
private QjMapper qjMapper;
/**
* 终止流程-- 当前申请单都废掉了,请重新申请
* @param processInstanceId
*/
@Override
public void termination(String processInstanceId) {
//查询流程实例
ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
if(instance==null){
throw new RuntimeException("流程实例不能为空");
}
//获取bpmn模型 就是对应流程图xml中 这个标签里面的内容
Process mainProcess = repositoryService.getBpmnModel(instance.getProcessDefinitionId()).getMainProcess();
//获取流程元素
Collection list = mainProcess.getFlowElements();
//结束节点的id
String activityId="";
for (FlowElement x : list) {
if(x instanceof EndEvent){
//如果是结束 节点 那么说明找到了
//就是对应 流程图xml 这个标签
activityId=x.getId();
break;
}
}
if(StringUtils.isEmpty(activityId)){
throw new RuntimeException("结束节点不存在,流程图绘制有问题");
}
//获取运行时执行实例表
List executions = runtimeService.createExecutionQuery().parentId(processInstanceId).list();
ListexecutionIds=new ArrayList<>();
for (Execution x : executions) {
executionIds.add(x.getId());
}
//创建更改活动状态生成器
runtimeService.createChangeActivityStateBuilder()
//将执行移动到单个活动 ID 将当前的执行实例 全部移动到结束节点
.moveExecutionsToSingleActivityId(executionIds,activityId)
//改变状态
.changeState();
}
}
这的x instanceof EndEvent就是下面这个图片展示的位置,他是EndEvent结束节点的信息,
所以我们这里这样操作,才能拿到id
我们来看下结果
http://localhost:8080/termination
{
"processInstanceId":"47bb34eb-6e30-11ed-be7d-005056c00008"
}
可以看到任务表 和执行实例表的数据都清空了
在领导审批的时候,我们没有设置驳回的地方,那么领导也可以手动选择一些之前审批的节点,进行退回操作;
注意:并行网关要退回多个分支,我们以出差申请为例子
在总经理审批这里,退回选择节点的时候 必须选一个经理审批和组长审批,
不能经理审批和主管审批,因为经理审批了 才能流转到主管审批,顺序不能错误,
否则流程就走不下去了。
我们先来查询当前的活动节点
package com.dmg.controller;
/**
* 任务控制层
*/
@RestController
public class TaskController {
@Autowired
private QjService qjService;
@Autowired
private FlowService flowService;
/**
* 查询可以退回的任务节点
*/
@PostMapping("getNodeList")
public Result getNodeList(@RequestBody FlowReq req){
List list = flowService.getNodeList(req.getTaskId());
return Result.success(list);
}
}
package com.dmg.vo;
import lombok.Data;
@Data
public class TaskNodeVo {
/**
* 任务节点的id userTask 的id
*/
private String activityId;
/**
* 任务节点的名称
*/
private String name;
}
package com.dmg.service;
public interface FlowService {
public List getNodeList(String taskId);
}
package com.dmg.service.impl;
/**
* 流程定义服务实现类
*/
@Service
public class FlowServiceImpl extends FlowServiceFactory implements FlowService {
@Autowired
private HisApprovalMapper hisApprovalMapper;
@Autowired
private QjMapper qjMapper;
/**
* 查询可以退回的任务节点
* @param taskId
* @return
*/
@Override
public List getNodeList(String taskId){
List result = new ArrayList<>();
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null){
return result;
}
//获取当前任务的节点id userTask的id
//
String taskDefinitionKey=task.getTaskDefinitionKey();
//查询历史节点实例 并且是完成审批的
List list = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(task.getProcessInstanceId())
.finished()
.orderByHistoricActivityInstanceEndTime().asc()
.list();
List activityIdList=new ArrayList<>();
//遍历出 只有userTask的节点
for (HistoricActivityInstance x : list) {
if("userTask".equals(x.getActivityType()) && !taskDefinitionKey.equals(x.getActivityId())){
//是任务节点 并且不是当前节点
activityIdList.add(x.getActivityId());
}
}
//获取bpmn模型
BpmnModel bpmnModel=repositoryService.getBpmnModel(task.getProcessDefinitionId());
//获取主流程
Process process=bpmnModel.getMainProcess();
//查询当前流节点
FlowNode currentFlowNode=(FlowNode) process.getFlowElement(taskDefinitionKey,true);
for (String activityId : activityIdList) {
// activityId 对应的节点
FlowNode x = (FlowNode) process.getFlowElement(activityId, true);
// 判断 是否能从这个节点 到目标节点 因为可能存在历史的节点 所以我们这里要判断一下 防止越界
Set set = new HashSet<>();
if (x != null && ExecutionGraphUtil.isReachable(process,x,currentFlowNode, set)) {
TaskNodeVo nodeVo=new TaskNodeVo();
nodeVo.setActivityId(x.getId());
nodeVo.setName(x.getName());
result.add(nodeVo);
}
}
return result;
}
}
我们来看下结果
http://localhost:8080/getNodeList
{
"taskId":"da20c629-6e60-11ed-885a-005056c00008"
}
用户就可以在列表选择一个串行退回,多个并行退回,
在并行网关内,要同时审批完才能走到总经理审批,一定要注意
总经理退回到提交,可以选择一个,因为他前面没有并行网关
package com.dmg.service.impl;
/**
* 流程定义服务实现类
*/
@Service
public class FlowServiceImpl extends FlowServiceFactory implements FlowService {
@Autowired
private HisApprovalMapper hisApprovalMapper;
@Autowired
private QjMapper qjMapper;
/**
* 退回 并行网关退回多个节点,串行网关退回一个节点
* @param activityIds 节点id 集合
* @param taskId 任务id
*/
@Override
public void goBack(ListactivityIds,String taskId) {
if(CollectionUtils.isEmpty(activityIds)){
throw new RuntimeException("节点不能为空");
}
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null){
throw new RuntimeException("任务不存在");
}
//获取bpmn模型
BpmnModel bpmnModel=repositoryService.getBpmnModel(task.getProcessDefinitionId());
//获取主流程
Process process=bpmnModel.getMainProcess();
//判断当前流程图是否存在并行网关
int parallel=Integer.MAX_VALUE;
//获取当前节点之前有没有并行网关
int index=0;
for (FlowElement flowElement : process.getFlowElements()) {
if(flowElement instanceof ParallelGateway){
parallel=index;
break;
}
index++;
}
//节点id 对应的索引
Mapmap=new HashMap<>();
int index1=0;
for (FlowElement flowElement : process.getFlowElements()) {
map.put(flowElement.getId(),index1);
index1++;
}
FlowNode currentFlowNode = (FlowNode) process.getFlowElement(task.getTaskDefinitionKey(), true);
for (String activityId : activityIds) {
int x=map.get(activityId);
if(x1){
throw new RuntimeException("串行请选择一个节点");
}
}else {
//如果当前索引比网关的索引大
if(activityIds.size()==1){
throw new RuntimeException("并行网关请选择多个节点");
}
}
//判断activityId 能否回到当前节点
// activityId 对应的节点
FlowNode node = (FlowNode) process.getFlowElement(activityId, true);
if(node==null){
throw new RuntimeException("节点不存在");
}
// 判断 是否能从这个节点 到目标节点
Set set = new HashSet<>();
if (!ExecutionGraphUtil.isReachable(process,node,currentFlowNode, set)) {
throw new RuntimeException("回退节点不正确,请重新选择");
}
}
if(activityIds.size()>1){
//说明走的是并行网关 那么校验他们之间是否是挨着的
for (int i = 0; i
package com.dmg.service;
public interface FlowService {
public void goBack(ListactivityIds,String taskId);
}
package com.dmg.controller;
/**
* 任务控制层
*/
@RestController
public class TaskController {
@Autowired
private QjService qjService;
@Autowired
private FlowService flowService;
/**
* 退回
*/
@PostMapping("goBack")
public Result goBack(@RequestBody FlowReq req){
flowService.goBack(req.getActivityIds(),req.getTaskId());
return Result.success();
}
}
package com.dmg.vo.req;
import lombok.Data;
import java.util.List;
@Data
public class FlowReq extends PageReq{
/**
* 流程定义名称
*/
private String processDefinitionName;
/**
* 流程定义key
*/
private String processDefinitionKey;
/**
* 任务id
*/
private String taskId;
/**
* 当前人账号
*/
private String account;
/**
* 流程定义id
*/
private String processDefinitionId;
/**
* 流程实例id
*/
private String processInstanceId;
/**
* 部署id
*/
private String deploymentId;
/**
* 如果为true 已经启动的流程关联的数据也一并删除 历史流程也会删除
* 如果为false 只删除运行 并且没有任务的流程信息
*/
private Boolean cascade;
/**
* 任务节点id集合
*/
List activityIds;
}
我们来看下结果
http://localhost:8080/goBack
{
"taskId":"da20c629-6e60-11ed-885a-005056c00008",
"activityIds":[
"sid-F176B67F-64F3-4239-B8EC-2A3BC2E0EFFE"
]
}
我们选择回退到提交单,可以在表中act_ru_task看到回退到提交单了
springboot使用flowable(8)_我是一只代码狗的博客-CSDN博客