springboot使用flowable(9)

22 篇文章 3 订阅

接下来,我们对出差申请,做下改造,加入多实例会签

,就是多个人同时审批一个任务的意思

打开我们的流程设计器flowable-ui,在原理的基础上加入总经理并行会签

注意,如果你的会签里面加了回退,那么会签任务必须要和结束节点挨着,

不能有其他的会签任务,如果你的会签没有回退,那么可以设置多个

如果你的会签设置多个,并且有回退,那么他会自动给你添加一个下一个任务的数据

多实例类型:  我们这里选择并行

集合(多实例): 输入userIds 用于传用户的集合名称

在代码里面对应这一部分

基数(多实例): 输入3,就是你要几个人审批,我这里输入3个人审批

元素变量(多实例) :输入userId 这里不要加s啊

分配用户:输入表达式 ${userId} 和要和 元素变量(多实例)的字段一样

 然后保存流程图,部署,重新走出差流程

我们在提交出差单,和审批出差单这块坐下改造

package com.dmg.service.impl;

@Service
public class TravelServiceImpl implements TravelService {

    @Autowired
    private TravelMapper travelMapper;

    @Autowired
    private FlowService flowService;


    /**
     * 提交出差单
     * @param req
     */
    @Transactional
    @Override
    public boolean submitApplication(Req req) {
        //从数据库查询当前信息
        Travel travel=travelMapper.selectById(req.getId());
        if(travel==null){
            throw new RuntimeException("出差单不存在");
        }
        if("3".equals(travel.getApprovalStatus())){
            throw new RuntimeException("已审批通过,不能提交");
        }
        //业务key 用于待办已办 扩展字段 展示使用
        //我这里以 流程定义key + 主键 + 申请单名称 的方式命名
        String businessKey="cc."+travel.getId()+"."+travel.getName();

        //因为我们增加了会签的审批 所以要提前吧会签人传入
        Map<String,Object>map=new HashMap<>();
        //多个用户,你这里可以从前端传过来 让用户选择会签人
        // 人数就是你在流程图设置的 基数(多实例)
        List<String> userIds=new ArrayList<>();
        userIds.add("zhangsan");
        userIds.add("lisi");
        userIds.add("wangwu");
        //userIds就是 集合(多实例) 那个位置填写的数据
        map.put("userIds",userIds);


        //如果流程实例为空 启动一个新的流程实例
        String instanceId = flowService.startProcessInstance(businessKey, map,travel.getInstanceId());
        //保存instanceId到数据库
        travel.setInstanceId(instanceId);
        //审批状态改为 2:审批中
        travel.setApprovalStatus("2");
        travelMapper.updateById(travel);
        return true;
    }

    /**
     * 审批出差单
     * @param req
     */
    @Transactional
    @Override
    public boolean approval(Req req) {
        //从数据库查询当前信息
        Travel travel=travelMapper.selectById(req.getId());
        if(travel==null){
            throw new RuntimeException("出差单不存在");
        }
        //2:审批中
        if(!"2".equals(travel.getApprovalStatus())){
            throw new RuntimeException("状态不是审批中,不能审批");
        }
        //审批条件 用于会签使用
        Map<String,Object>map=new HashMap<>();
        map.put("flag",req.getFlag());

        String res = flowService.complete(travel.getInstanceId(), map, travel.getId(), req.getApprovalComments(), req.getApprover());
        if("end".equals(res)){
            //如果流程已经走完了 那么吧审批状态修改为 3:审批通过
            travel.setApprovalStatus("3");
            travelMapper.updateById(travel);
        }
        return true;
    }

}

提交出差单主要增加这部分代码

 审批出差单,主要加了这部分代码

 完成条件(多实例):输入 ${compCondition.getComCondition(execution)}

就是对应箭头的位置,接下来我们在写下条件类

package com.dmg.condition;

/**
 * 条件类 ${compCondition.getComCondition(execution)}
 */
@Slf4j
@Component("compCondition")
public class ZongJingLiCondition implements Serializable {
    
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;

    public boolean getComCondition(DelegateExecution execution){
        //实例总数
        Object nrOfInstances = execution.getVariable("nrOfInstances");
        //未完成的实例
        Object nrOfActiveInstances = execution.getVariable("nrOfActiveInstances");
        //已完成实例
        Object nrOfCompletedInstances = execution.getVariable("nrOfCompletedInstances");
        //map里面传过来的流程变量 审批通过 还是驳回
        String flag = execution.getVariable("flag").toString();

        log.info("总实例数量:{}",nrOfInstances.toString());
        log.info("未完成的实例:{}",nrOfActiveInstances.toString());
        log.info("已完成实例:{}",nrOfCompletedInstances.toString());

        if("false".equals(flag)) {
            //如果是拒绝 那么回退到上一个节点
            //获取当前节点的id
            String currentActivityId = execution.getCurrentActivityId();
            //根据流程定义id 查询bpmn模型
            BpmnModel bpmnModel = repositoryService.getBpmnModel(execution.getProcessDefinitionId());
            //查询当前流节点
            FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(currentActivityId);
            //获取前面的连线
            SequenceFlow sequenceFlow = flowNode.getIncomingFlows().get(0);
            //获取上一个节点的id
            String firstId = sequenceFlow.getSourceRef();
            //判断上一个节点是不是并行网关
            FlowNode firstNode = (FlowNode) bpmnModel.getFlowElement(firstId);

            //如果是并行网关,那么回退到并行网关 所有的分支
            if (firstNode instanceof ParallelGateway) {
                //并行网关上一个节点id集合
                List<String> activityIds = new ArrayList<>();
                List<SequenceFlow> incomingFlows = firstNode.getIncomingFlows();
                for (SequenceFlow x : incomingFlows) {
                    //并行网关上一个节点的id
                    String sourceRef = x.getSourceRef();
                    activityIds.add(sourceRef);
                }

                if (CollectionUtils.isNotEmpty(activityIds)) {
                    //如果集合不为空 回退到上一个节点 多个任务
                    runtimeService.createChangeActivityStateBuilder()
                            .processInstanceId(execution.getProcessInstanceId())
                            .moveSingleActivityIdToActivityIds(currentActivityId, activityIds)
                            .changeState();
                }
            }else {
                //如果是串行,直接回退上一个节点
                runtimeService.createChangeActivityStateBuilder()
                        .processInstanceId(execution.getProcessInstanceId())
                        .moveActivityIdTo(currentActivityId,firstId)
                        .changeState();
            }
            //结束当前所有任务
            return true;
        }

        //我们也可以设置百分比 有多少人审批通过 就能结束当前任务 业务场景 由你来控制
        //已审批的数量  / 总的数量 > 一半 那么就可以往下走
        if (Float.parseFloat(nrOfCompletedInstances.toString())/Float.parseFloat(nrOfInstances.toString()) > 0.5){
            //如果完成的比例高于50%就返回ture,代表会签结束,没有完成的任务就自动结束了
            return true;
        }else {
            //如果完成的比例不高于50%就返回false,还需要继续会签
            return false;
        }
    }
}

nrOfInstances
nrOfActiveInstances
nrOfCompletedInstances

上面三个字段是flowable自带的,不要改动

我们这里设置的会签,2个人成功才能往下走,1个人审批不通过,就退回到上一个节点

我们来看下效果

http://localhost:8080/travel/approval

{

    "id":"003",

    "approvalComments":"我不同意",

    "flag":"false",

    "approver":"zhangsan"

}

我们可以看到,在总经理审批不通过,就回退到并行网关里面的任务了

然后再审批通过,回到了我们的总经理审批这里

 有2个人审批通过,那么我们的流程就结束了

那么接下来,我们还可以做前加签,后加签的操作

前加签:在张三审批之前,选择李四先去审批,李四审批完了,张三在审批

后加签:张三审批完了,选择李四在审批一次

我们对请假申请代码改造一下

package com.dmg.vo.req;

import lombok.Data;


@Data
public class Req {


    /**
     * 主键
     */
    private String id;


    /**
     * 审批意见
     */
    private String approvalComments;


    /**
     * 通过:true  驳回false
     */
    private String flag;


    /**
     * 审批人
     */
    private String approver;

    /**
     * 加签人
     */
    private String signatory;

    /**
     * 加签类型 1:前加签  2:后加签  如果为空 正常审批流程
     */
    private String signatureType;


}
package com.dmg.service.impl;

@Service
public class QjServiceImpl implements QjService {


    @Autowired
    private QjMapper qjMapper;

    @Autowired
    private FlowService flowService;



    /**
     * 审批请假单
     * @param req
     */
    @Transactional
    @Override
    public boolean approval(Req req) {
        //从数据库查询当前信息
        Qj qj=qjMapper.selectById(req.getId());
        if(qj==null){
            throw new RuntimeException("请假单不存在");
        }
        //2:审批中
        if(!"2".equals(qj.getApprovalStatus())){
            throw new RuntimeException("状态不是审批中,不能审批");
        }
        //返回结果
        String res ="";
        //参数 分支条件
        Map<String, Object> map=new HashMap<>();
        //通过:true  驳回false
        map.put("flag",req.getFlag());

        if("1".equals(req.getSignatureType())){
            //如果是前加签 我们可以给张三 审批之前 先设置一个其他的审批人 ,让他审批完了 张三才审批
            res = flowService.frontEndorsement(qj.getInstanceId(),req);
        }else if("2".equals(req.getSignatureType())){
            //如果是后加签 那就是张三审批完成之后, 还需要一个人来审批
            res =flowService.postEndorsement(qj.getInstanceId(),req);
        }else {
            //正常审批
            res = flowService.complete(qj.getInstanceId(), map, qj.getId(), req.getApprovalComments(), req.getApprover());
        }

        if("end".equals(res)){
            //如果流程已经走完了 那么吧审批状态修改为 3:审批通过
            qj.setApprovalStatus("3");
            qjMapper.updateById(qj);
        }
        if("false".equals(req.getFlag())){
            //如果是驳回 那么修改状态为 未提交
            qj.setApprovalStatus("1");
            qjMapper.updateById(qj);
        }
        return true;
    }

  


}
package com.dmg.service;


public interface FlowService {


    public String frontEndorsement(String processInstanceId, Req req);

    public String postEndorsement(String processInstanceId, Req req);
}
package com.dmg.service.impl;

/**
 * 流程定义服务实现类
 */
@Service
public class FlowServiceImpl extends FlowServiceFactory implements FlowService {

    @Autowired
    private HisApprovalMapper hisApprovalMapper;
    @Autowired
    private QjMapper qjMapper;


    /**
     * 审批
     * @param businessId 业务表主键
     * @param map 分支条件
     * @param approvalComments 审批意见
     * @param instanceId 流程实例id
     * @param assignee 审批人
     */
    @Override
    public String complete(String instanceId,Map<String,Object>map,
                         String businessId,String approvalComments,
                         String assignee){
        //根据流程实例id 获取任务
        Task task = taskService.createTaskQuery()
                .processInstanceId(instanceId)
                .taskAssignee(assignee)
                .singleResult();
        if(task==null){
            throw new RuntimeException("任务不存在,或者不是当前任务的审批人");
        }
        //判断当前任务 是否被委托过
        if(StringUtils.isNotEmpty(task.getOwner())
           && !task.getOwner().equals(task.getAssignee())){
            //如果不是空 并且和签收人 不一样  那么解决前加签的任务
            taskService.resolveTask(task.getId(),map);
        }else {
            //完成任务
            taskService.complete(task.getId(),map);
        }
        //审批完成后 再次查询任务是否还有数据
        long count = taskService.createTaskQuery()
                .processInstanceId(instanceId)
                .count();
        //添加历史审批
        insertHisApproval(approvalComments, assignee, businessId, task.getName());
        if(count==0){
            //返回结束 修改表单的状态
            return "end";
        }
        return "ok";
    }

  



    /**
     * 前加签
     * @param processInstanceId
     * @param req
     * @return
     */
    @Override
    public String frontEndorsement(String processInstanceId, Req req) {
        //根据流程实例id 获取任务
        Task task = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .taskAssignee(req.getApprover())
                .singleResult();
        if(task==null){
            throw new RuntimeException("任务不存在,或者不是当前任务的审批人");
        }
        //把张三的任务 委托给 另一个人审批 当另一个人审批完了,自动回到张三手里
        taskService.delegateTask(task.getId(),req.getSignatory());
        //添加历史审批
        insertHisApproval( "前加签", req.getApprover(), req.getId(), task.getName());
        return "ok";
    }

    /**
     * 后加签
     * @param processInstanceId
     * @param req
     * @return
     */
    @Override
    public String postEndorsement(String processInstanceId, Req req) {
        //根据流程实例id 获取任务
        Task task = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .taskAssignee(req.getApprover())
                .singleResult();
        if(task==null){
            throw new RuntimeException("任务不存在,或者不是当前任务的审批人");
        }
        //把张三的任务 设置为 李四审批
        taskService.setAssignee(task.getId(),req.getSignatory());
        //添加历史审批
        insertHisApproval( "后加签", req.getApprover(), req.getId(), task.getName());
        return "ok";
    }

}

我们操作下审批 来看下结果,先设置下前加签

http://localhost:8080/qj/approval

{

    "id":"001",

    "approvalComments":"我同意",

    "flag":"true",

    "approver":"zhangsan",

    "signatory":"xiaoming",

    "signatureType":"1"

}

 前加签主要是在这里通过委托 把OWNER_设置数据

 可以看到OWNER_变成了张三,ASSIGNEE_变成了xiaoming

接下来我们用xiaoming审批一下

 http://localhost:8080/qj/approval

{

    "id":"001",

    "approvalComments":"我同意",

    "flag":"true",

    "approver":"xiaoming"

}

在任务审批之前,通过前加签委托

 然后再审批这里 这样审批

 

 可以看到任务又回到张三手里了

我们这次来看下 后加签 的结果

http://localhost:8080/qj/approval

{

 "id":"001",

 "approvalComments":"我同意",

 "flag":"true",

 "approver":"lisi",

 "signatory":"xiaobai",

 "signatureType":"2"

}

主要就是在这里,吧当前审批人 转办给加签人

 在数据库中 签收人已经变成了xiaobai,这就是我们的后加签

springboot使用flowable(10)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果你想在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 ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值