Activiti6---流程加签征询实现

1. 加签

加签是指当前节点审批完后需要额外再加一个审批人进行审批,额外加的审批用户审批完后流程流转到下一节点。比如正常审批流程为A->B->C,如果B执行了加签动作,那么流程就变为A->B-->D-->C,节点D就是加进来的。

医学上有个万能药叫做安慰剂,没有任何药物作用,可能就是一颗糖果,但患者并不知道,但因患者对医生信任、患者叫自我暗示以及对某种药物疗效的期望等而起到镇痛、镇蘸或缓解症状的作用。为什么提到这个呢,因为加签的方案就是一个安慰剂方案,用户感知到加签是从审批历史里感知的,在做加签操作时,审批历史里面记录了加签的动作,但是后台执行了重新分配(reassign)的操作将当前流程重新分配给另外一个人,达到加签的效果,所以加签就一行代码:

taskService.setAssignee(task.getTaskId(), user);  

这样可能会有以下问题:

流程图无法体现加签,因为并没有新的节点产生

如果你的系统做好了对activiti进行改造的准备,那么标准的activiti流程图是远远满足不了你的需求的,你需要额外的方案记录审批历史绘制流程图。

2. 征询

征询是指,你对当前的流程不是很清楚,你需要将流程转发给另外一个人需要另外一个人给你指导,另外一个人审批完后流程回到你这里,你根据他的审批意见进行审批。简单说,如果正常的审批流程为A->B->C,如果B执行了征询操作,那么流程就变为了A->B-->D-->B->C,征询和加签的区别就在于,征询会回到发起征询的节点,加签不会。

征询就是两次的重新分配:

  1. B重新分配给D
  2. D重新分配给B

两次的reassign操作就可以实现征询,要解决的问题就是怎么协调好这两次重新分配。

  1. B执行征询操作时,通过变量标记征询动作,并将征询人B的信息(主要是账号)保存在变量中

  2. D执行回复操作时(流程变为征询后,被征询人只有回复的权限),从变量中取出B的账号,重新将流程分配给B

  3. B执行正常的审批操作,流程正常流转。

3. 测试

设计流程图
在这里插入图片描述
Bpmn文件:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1597390628483" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
  <process id="consultation" isClosed="false" isExecutable="true" processType="None">
    <startEvent id="_2" name="开始"/>
    <userTask activiti:assignee="A" activiti:exclusive="true" id="_3" name="A"/>
    <userTask activiti:assignee="B" activiti:exclusive="true" id="_4" name="B"/>
    <userTask activiti:assignee="C" activiti:exclusive="true" id="_5" name="C"/>
    <endEvent id="_6" name="结束"/>
    <sequenceFlow id="_7" sourceRef="_2" targetRef="_3"/>
    <sequenceFlow id="_8" sourceRef="_3" targetRef="_4"/>
    <sequenceFlow id="_9" sourceRef="_4" targetRef="_5"/>
    <sequenceFlow id="_10" sourceRef="_5" targetRef="_6"/>

  </process>
  <bpmndi:BPMNDiagram documentation="background=#000000;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
    <bpmndi:BPMNPlane bpmnElement="consultation">
      <bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
        <omgdc:Bounds height="32.0" width="32.0" x="20.0" y="315.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
        <omgdc:Bounds height="55.0" width="85.0" x="140.0" y="305.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
        <omgdc:Bounds height="55.0" width="85.0" x="315.0" y="305.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
        <omgdc:Bounds height="55.0" width="85.0" x="500.0" y="305.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_6" id="Shape-_6">
        <omgdc:Bounds height="32.0" width="32.0" x="645.0" y="315.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_11" id="Shape-_11">
        <omgdc:Bounds height="55.0" width="85.0" x="315.0" y="140.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="_7" id="BPMNEdge__7" sourceElement="_2" targetElement="_3">
        <omgdi:waypoint x="52.0" y="331.0"/>
        <omgdi:waypoint x="140.0" y="332.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_8" id="BPMNEdge__8" sourceElement="_3" targetElement="_4">
        <omgdi:waypoint x="225.0" y="332.5"/>
        <omgdi:waypoint x="315.0" y="332.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_9" id="BPMNEdge__9" sourceElement="_4" targetElement="_5">
        <omgdi:waypoint x="400.0" y="332.5"/>
        <omgdi:waypoint x="500.0" y="332.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10" sourceElement="_5" targetElement="_6">
        <omgdi:waypoint x="585.0" y="332.5"/>
        <omgdi:waypoint x="645.0" y="331.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

测试类:

package com.yb;

import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * @author liangjie@itcast.cn
 * @version 1.0
 * @date 2020/8/5
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class ActivitiJpaTest09 {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;

    @Resource
    private HttpServletRequest request;

    /**
     * 部署流程,测试征询
     */
    @Test
    public void repositoryDeploy(){
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("processes/activiti_Consultation.bpmn")
                .addClasspathResource("processes/activiti_Consultation.png")
                .name("测试征询-2")
                .deploy();
        System.out.println("部署ID:"+deploy.getId());
        System.out.println("部署名称"+deploy.getName());
    }

    /**
     * 发布流程
     */
    @Test
    public void runtimeRelease(){

        ProcessInstance pi = runtimeService.startProcessInstanceByKey("consultation");
        System.out.println("流程实例ID:"+pi.getId());
        System.out.println("流程定义ID:"+pi.getProcessDefinitionId());
    }

    /**
     * 查询及完成任务
     */
    @Test
    public void taskQueryComplete(){
        List<Task> list = taskService.createTaskQuery()
                .taskAssignee("A")
                .list();
        for (Task task : list) {
            System.out.println("--------------------------------------------");
            System.out.println("任务ID:" + task.getId());
            System.out.println("任务名称:" + task.getName());
            System.out.println("任务创建时间:" + task.getCreateTime());
            System.out.println("任务委派人:" + task.getAssignee());
            System.out.println("流程实例ID:" + task.getProcessInstanceId());
            System.out.println("--------------------------------------------");
            taskService.complete(task.getId());
        }
    }





    /**
     *征询
     */
    @Test
    public void taskQueryComplete2(){

        Task task = taskService.createTaskQuery()
                .taskAssignee("B")
                .singleResult();
        taskService.setAssignee(task.getId(),"D");

        //对被征询者做出记录
        taskService.setVariableLocal(task.getId(),"status","D");
        //对发出征询者做出记录
        taskService.setVariableLocal(task.getId(),"originUser","B");


    }

    /**
     * D执行回复操作
     */
    @Test
    public void reply(){

        String originUser = (String)
                taskService.getVariableLocal("5002", "originUser");
        System.out.println(originUser);

        taskService.setAssignee("5002",originUser);
        taskService.removeVariable("5002", "status");
        taskService.removeVariable("5002", "originUser");
    }
}

数据库:
基本发出征询和回复的简单流程:
在这里插入图片描述
在数据库中保存发出征询的和回复的审批人的信息:
在这里插入图片描述
说明:
测试完毕,为了在后期在案例4中添加功能,当前审批人不知如何审批时可以征询他人,他人做出回复,当前审批人根据回复的内容进行接下来的审批。也就是征询加签功能。后续更新案例4.

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现并签功能需要使用到Activiti中的多实例任务和JavaDelegate,具体步骤如下: 1. 在BPMN流程图中添加一个多实例任务节点,设置节点的参与者为“并签人”,设置实例完成条件为“所有实例完成”。 2. 在节点的扩展属性中添加“collection”和“elementVariable”属性,分别指定并签任务的参与者列表和每个实例的变量名。 3. 在节点的扩展属性中添加“completionCondition”属性,设置并签任务的完成条件为“nrOfCompletedInstances == nrOfInstances”。 4. 在JavaDelegate中实现并签任务的处理逻辑,在处理过程中可以通过流程变量获取并签任务的实例列表和每个实例的处理结果。 5. 在节点的扩展属性中添加“delegateExpression”属性,指定JavaDelegate的实现类。 6. 将JavaDelegate的实现类注册到Activiti的Spring容器中,使其能够被流程引擎调用。 7. 启动流程实例,流程引擎会自动创建并签任务的实例,并将其分配给指定的参与者,等待处理。 8. 参与者处理任务时,可以通过流程表单提交处理结果,流程引擎会将结果存储到流程变量中。 9. 当所有实例都完成时,JavaDelegate会被调用,处理并签任务的结果,并将结果存储到流程变量中,后续流程节点可以根据该结果进行处理。 需要注意的是,并签任务的参与者数量建议不要过多,否则会影响流程性能。同时,在JavaDelegate中处理并签任务的逻辑需要考虑到并发处理的情况,建议使用线程安全的方式处理任务结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值