springboot使用flowable(7)

22 篇文章 2 订阅

在运行过程中,我们不想使用这个流程了,可以终止掉

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 id="cc" name="出差流程" isExecutable="true"> 这个标签里面的内容
        Process mainProcess = repositoryService.getBpmnModel(instance.getProcessDefinitionId()).getMainProcess();
        //获取流程元素
        Collection<FlowElement> list = mainProcess.getFlowElements();
        //结束节点的id
        String activityId="";
        for (FlowElement x : list) {
            if(x instanceof EndEvent){
                //如果是结束 节点 那么说明找到了
                //就是对应 流程图xml 这个标签 <endEvent id="sid-C3367FFF-B656-4B98-898D-62B311177004" name="结束"/>
                activityId=x.getId();
                break;
            }
        }
        if(StringUtils.isEmpty(activityId)){
            throw new RuntimeException("结束节点不存在,流程图绘制有问题");
        }
        //获取运行时执行实例表
        List<Execution> executions = runtimeService.createExecutionQuery().parentId(processInstanceId).list();
        List<String>executionIds=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<TaskNodeVo> 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<TaskNodeVo> 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<TaskNodeVo> getNodeList(String taskId){
        List<TaskNodeVo> result = new ArrayList<>();
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null){
            return result;
        }
        //获取当前任务的节点id userTask的id
        //<userTask id="sid-D0065118-3FDD-4981-8C28-28736B4C8210" name="总经理审批" flowable:assignee="zongjingli" flowable:formFieldValidation="true">
        String taskDefinitionKey=task.getTaskDefinitionKey();

        //查询历史节点实例 并且是完成审批的
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(task.getProcessInstanceId())
                .finished()
                .orderByHistoricActivityInstanceEndTime().asc()
                .list();

        List<String> 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 id="cc" name="出差流程" isExecutable="true">
        Process process=bpmnModel.getMainProcess();
        //查询当前流节点
        FlowNode currentFlowNode=(FlowNode) process.getFlowElement(taskDefinitionKey,true);

        for (String activityId : activityIdList) {
            // activityId 对应的节点
            FlowNode x = (FlowNode) process.getFlowElement(activityId, true);
            // 判断 是否能从这个节点 到目标节点 因为可能存在历史的节点 所以我们这里要判断一下 防止越界
            Set<String> 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(List<String>activityIds,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 id="cc" name="出差流程" isExecutable="true">
        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 对应的索引
        Map<String,Integer>map=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(x<parallel){
                //当前节点之前 不存在网关
                if(activityIds.size()>1){
                    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<String> set = new HashSet<>();
            if (!ExecutionGraphUtil.isReachable(process,node,currentFlowNode, set)) {
                throw new RuntimeException("回退节点不正确,请重新选择");
            }

        }

        if(activityIds.size()>1){
            //说明走的是并行网关 那么校验他们之间是否是挨着的
            for (int i = 0; i <activityIds.size()-1 ; i++) {
                //从流程中 获取当前节点
                 FlowNode aNode=(FlowNode) process.getFlowElement(activityIds.get(i),true);
                 FlowNode bNode=(FlowNode) process.getFlowElement(activityIds.get(i+1),true);

                for (SequenceFlow x : aNode.getIncomingFlows()) {
                    if(x.getSourceRef().equals(bNode.getId())
                        || x.getTargetRef().equals(bNode.getId())){
                        throw new RuntimeException("并行网关节点不能挨着,请选择其他分支");
                    }
                }
                for (SequenceFlow x : aNode.getOutgoingFlows()) {
                    if(x.getSourceRef().equals(bNode.getId())
                            || x.getTargetRef().equals(bNode.getId())){
                        throw new RuntimeException("并行网关节点不能挨着,请选择其他分支");
                    }
                }
            }
        }


        //执行退回
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(task.getProcessInstanceId())
                .moveSingleActivityIdToActivityIds(task.getTaskDefinitionKey(),activityIds)
                .changeState();


    }

}
package com.dmg.service;


public interface FlowService {

  
    public void goBack(List<String>activityIds,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<String> 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博客

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
如果你想在Spring Boot项目中使用Flowable,你可以通过引入相应的依赖来实现。根据引用的内容,你可以添加以下依赖到你的项目中: ```xml <dependency> <groupId>org.flowable</groupId> <artifactId>flowable-spring-boot-starter</artifactId> <version>6.7.2</version> </dependency> <dependency> <groupId>org.flowable</groupId> <artifactId>flowable-spring-boot-starter-actuator</artifactId> <version>6.7.2</version> </dependency> ``` 你也可以从引用和引用中提供的链接中下载Flowable的zip文件。这些文件包含了Flowable引擎的各个组件和执行器。下载并解压缩zip文件后,你可以将Flowable引擎部署到Tomcat服务器上,从而在Spring Boot项目中使用Flowable。 希望以上信息能帮助到你。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Spring Boot + Flowable 工作流引擎](https://blog.csdn.net/qq_39035773/article/details/125414301)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [SpringBoot + Flowable使用](https://blog.csdn.net/fajing_feiyue/article/details/116209534)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [SpringBoot + Flowable的基础使用](https://blog.csdn.net/S0001100/article/details/120042604)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值