深入探究Camunda加签问题

开源项目介绍:点击直达

前言

这里我们先抛出两个大问题,整篇文章针对这两个大问题再详细解析。

首先我们在设计流程定义时,流程节点可能是或签也可能是会签

会签:指同一个审批节点设置多个人,如ABC三人,三人会同时收到审批,需全部同意之后,审批才可到下一审批节点。
或签:指同一个审批节点设置多个人,如ABC三人,三人会同时收到审批,只要其中任意一人审批即可到下一审批节点。

当前会签也可以是比例签,比如节点上的审批人同意的超过60%就算通过。此时我们需要考虑的问题如下:

问题一:被加签人如何加到节点上

问题二:加签后是否会影响节点的通过【不同通过规则的节点】

如何加签

这里还需要区分设置审批人的方式:

  1. 在发起流程实例时,一次性将所有节点的审批人全部设置完成
  2. 通过监听器来设置审批人

在设计流程定义时,节点上主要设置这几个参数

1是分配到待办任务的人,变量名和3保持一致;2是我们要传入的参数名,3是用来遍历2中集合的变量名,4是节点通过的条件。

关于怎么发布流程定义可以查看我之前的文章,不赘述了。

一次性设置审批人

    @GetMapping("/startProcessInstance")
    public String startProcessInstance(@RequestParam("processDefineKey")String processDefineKey,
                                     @RequestParam("businessKey")String businessKey) {
        Map<String, Object> map = new HashMap<>();
        List<String> userOneList = new ArrayList<>();
        userOneList.add("zhangsan");
        userOneList.add("lisi");
        List<String> userTwoList = new ArrayList<>();
        userTwoList.add("wangwu");
        userTwoList.add("maliu");
        map.put("initiator","lonewalker");
        map.put("userOneList", userOneList);
        map.put("userTwoList", userTwoList);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefineKey, businessKey, map);
        //默认把发起人节点审批通过
        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).singleResult();
        String taskId = task.getId();
        taskService.complete(taskId);
        return processInstance.getProcessInstanceId();
    }

请求接口

来看一下流程图,生成两个用户任务

我们开始加签,这里流程跑到第二个节点时会创建和userOneList.size 的Task,想在这个节点加签,就得想办法让这个事件再触发一次。

    @GetMapping("/addSign")
    public void addSign(@RequestParam("processInstanceId")String processInstanceId,
                        @RequestParam("nodeId")String nodeId,
                        @RequestParam("userId")String userId){
        runtimeService.createProcessInstanceModification(processInstanceId)
                .startBeforeActivity(nodeId)
                .setVariable("userOne",userId)
                .setAnnotation("加签")
                .execute();
    }

请求接口后查看已经成功加签

按节点设置审批人

此时我们需要通过执行监听器来完成审批人的设置,两种监听器的区别可查看此篇

修改流程定义,在或签节点之前的连线上设置执行监听器。

自定义一个执行监听器

@Component
public class CustomExecutionListener implements ExecutionListener {
    @Override
    public void notify(DelegateExecution execution) throws Exception {
        System.out.println("触发了执行监听器");
        List<String> userOneList = new ArrayList<>();
        userOneList.add("zhangsan");
        userOneList.add("lisi");
        execution.setVariable("userOneList",userOneList);
    }
}

发起流程实例的接口中把或签节点审批人去掉

然后部署,发起流程实例

此时我们加签的逻辑和之前一样,但是实现不一样了:

    @GetMapping("/addSign")
    public void addSign(@RequestParam("processInstanceId")String processInstanceId,
                        @RequestParam("nodeId")String nodeId){
        //获取实例的流程定义 这里主要是为了拿到节点前的那条线的Id
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        BpmnModelInstance bpmnModel = repositoryService.getBpmnModelInstance(processInstance.getProcessDefinitionId());
        ModelElementInstance modelElement = bpmnModel.getModelElementById(nodeId);
        UserTask userTask = (UserTask) modelElement;
        Collection<SequenceFlow> incoming = userTask.getIncoming();
        String transitionId = "";
        if (incoming.stream().findFirst().isPresent()) {
            transitionId = incoming.stream().findFirst().get().getId();
        } else {
            throw new ProcessException(ErrorCodeEnum.PROC_TASK_REJECT_FAILURE);
        }
        runtimeService.createProcessInstanceModification(processInstanceId)
                .setAnnotation("加签")
                .startTransition(transitionId)
                .execute();
    }

重新触发或签节点前连线上的执行监听器,然后加了一个sunjiu

调用加签接口后:

问题:

此时我模拟sunjiu审批,因为是或签节点按正常情况,流程会到会签节点,或签节点结束。

刚刚加签的那个人确实审批通过了,也到会签节点了,但是原先的两个人还停留在或签,看一下原因

因为重新解析了userOneList,导致加签的任务和原来的任务它们的父环节实例不一致

这是不是意味着,这两个人的其中一人审批都会再次触发会签节点前连线上的执行监听器。这明显不是我们想要的。改一下审批接口

    @GetMapping("/agreeTask")
    public  void agreeTask(@RequestParam("taskId")String taskId){
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        String processInstanceId = task.getProcessInstanceId();
        //完成任务
        taskService.complete(taskId);
        List<Task> activeTaskList = taskService.createTaskQuery().processInstanceId(processInstanceId).active().list();
        if (CollUtil.isNotEmpty(activeTaskList)){
            //如果nodeIdSet大于1 就说明下一节点开启待办任务了,而当前节点还有待办任务  说明刚刚处理的这个任务是或签操作
            Set<String> nodeIdSet = activeTaskList.stream().map(Task::getTaskDefinitionKey).collect(Collectors.toSet());
            if (nodeIdSet.size() > 1){
                //查询当前节点未完成的实例
                List<HistoricActivityInstance> unfinishedInstanceList = historyService.createHistoricActivityInstanceQuery().
                        processInstanceId(processInstanceId).activityId(task.getTaskDefinitionKey()).unfinished().list();

                if (CollUtil.isNotEmpty(unfinishedInstanceList)){
                    //说明或签节点有加签
                    for (HistoricActivityInstance instance : unfinishedInstanceList) {
                        runtimeService.createProcessInstanceModification(processInstanceId).cancelActivityInstance(instance.getId()).execute();
                    }
                }
            }
        }
    }

重新发起一条流程实例,将上述操作再走一遍:

注意:这种情况下可以一次性加多个人,但是会签就不行了,因为这种方式加签会产生多个multiInstanceBody 。 比如会签节点现在有两个审批人a、b,那它们俩的multiInstanceBody 是同一个,但是如果我用上述加签方式加签 c 后会又产生一个multiInstanceBody,当c审批通过时会触发下一节点连线上的执行监听器,a、b审批通过后又会触发一次

此时就要利用好这个Assignee变量

    @GetMapping("/addSign")
    public void addSign(@RequestParam("processInstanceId")String processInstanceId,
                        @RequestParam("nodeId")String nodeId,
                        @RequestParam("userId")String userId){
          runtimeService.createProcessInstanceModification(processInstanceId)
                  .startBeforeActivity(nodeId)
                  .setVariable("userTwo",userId)
                  .execute();
    }

 个人觉得最好的方式还是这种,而上述的也是为了提供给大家更好的思路,毕竟需求都是不一样的

 扩展

有朋友会疑问为什么不用这个参数,这个相当于事先知道这个节点上有几个审批人,比如我设置5,那到这个节点就会创建5个待办任务,那如果是角色呢?所以才用上述的监听器去查询角色对应的人数,从而实现动态设置审批人

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 18
    评论
宜信SDL(Security Development Lifecycle,安全开发生命周期)是宜信集团在软件开发过程中引入的一种安全开发方法论。它以安全为核心,包括不同阶段的安全活动,以确保开发出高质量、安全可靠的软件产品。 宜信SDL的深入探究与实践是指对SDL开展详细研究和实际应用的过程。宜信集团对SDL进行了深入的研究,探索如何在软件开发过程中嵌入安全性,并不断优化和完善SDL的各个阶段和相关的最佳实践。 在实践方面,宜信集团在多个软件项目中实施了SDL,并取得了显著的成果。它将SDL整合到软件开发生命周期的各个阶段,包括需求分析、设计、编码、测试和部署等。宜信集团还制定了一套完整的安全控制措施,以确保在每个阶段都能够有效地进行安全性验证和评估。 通过实践宜信SDL,宜信集团取得了一些明显的效益。首先,它帮助宜信集团及早发现和解决软件开发过程中的安全漏洞和风险。其次,宜信SDL还有助于降低软件开发过程中的安全成本,减少因安全漏洞而引发的修复和维护成本。最重要的是,宜信SDL使宜信集团的软件产品能够提供更高的安全性和可靠性,增强了宜信集团在市场上的竞争力。 总之,宜信SDL的深入探究与实践对于宜信集团的软件开发过程和产品安全性具有重要意义。通过持续的研究和实践,宜信集团能够进一步完善和优化SDL,提高软件开发过程中的安全性,为客户提供更加安全可靠的软件产品。
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LoneWalker、

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值