【工作流Activiti7】3、Activiti7 回退与会签

这篇具有很好参考价值的文章主要介绍了【工作流Activiti7】3、Activiti7 回退与会签。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.  回退(驳回)

回退的思路就是动态更改节点的流向。先遇水搭桥,最后再过河拆桥。

具体操作如下:

  1. 取得当前节点的信息
  2. 取得当前节点的上一个节点的信息
  3. 保存当前节点的流向
  4. 新建流向,由当前节点指向上一个节点
  5. 将当前节点的流向设置为上面新建的流向
  6. 当前节点完成任务
  7. 将当前节点的流向还原
  8. 取得之前上个节点的执行人
  9. 设置上个节点的assignee为之前的执行人

代码实现起来可能是这样的: 

@Test
public void huitui() throws Exception {
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    TaskService taskService = processEngine.getTaskService();
    Task task = taskService.createTaskQuery().processInstanceId("55001").singleResult();
    backProcess(task);
}

/**
 * 驳回 / 回退
 * 按照这种方法,可以回退至任意节点
 * @param task
 * @throws Exception
 */
public void backProcess(Task task) throws Exception {
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    HistoryService historyService = processEngine.getHistoryService();
    RepositoryService repositoryService = processEngine.getRepositoryService();
    TaskService taskService = processEngine.getTaskService();

    String processInstanceId = task.getProcessInstanceId();

    //  获取所有历史任务(按创建时间降序)
    List<HistoricTaskInstance> hisTaskList = historyService.createHistoricTaskInstanceQuery()
            .processInstanceId(processInstanceId)
            .orderByTaskCreateTime()
            .desc()
            .list();

    List<HistoricActivityInstance> hisActivityList = historyService.createHistoricActivityInstanceQuery()
            .processInstanceId(processInstanceId).list();

    if (CollectionUtils.isEmpty(hisTaskList) || hisTaskList.size() < 2) {
        return;
    }

    //  当前任务
    HistoricTaskInstance currentTask = hisTaskList.get(0);
    //  前一个任务
    HistoricTaskInstance lastTask = hisTaskList.get(1);
    //  当前活动
    HistoricActivityInstance currentActivity = hisActivityList.stream().filter(e -> currentTask.getId().equals(e.getTaskId())).collect(Collectors.toList()).get(0);
    //  前一个活动
    HistoricActivityInstance lastActivity = hisActivityList.stream().filter(e -> lastTask.getId().equals(e.getTaskId())).collect(Collectors.toList()).get(0);

    BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());

    //  获取前一个活动节点
    FlowNode lastFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(lastActivity.getActivityId());
    //  获取当前活动节点
    FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivity.getActivityId());

    //  临时保存当前活动的原始方向
    List<SequenceFlow> originalSequenceFlowList = new ArrayList<>();
    originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
    //  清理活动方向
    currentFlowNode.getOutgoingFlows().clear();

    //  建立新方向
    SequenceFlow newSequenceFlow = new SequenceFlow();
    newSequenceFlow.setId("newSequenceFlowId");
    newSequenceFlow.setSourceFlowElement(currentFlowNode);
    newSequenceFlow.setTargetFlowElement(lastFlowNode);
    List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
    newSequenceFlowList.add(newSequenceFlow);
    //  当前节点指向新的方向
    currentFlowNode.setOutgoingFlows(newSequenceFlowList);

    //  完成当前任务
    taskService.complete(task.getId());

    //  重新查询当前任务
    Task nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
    if (null != nextTask) {
        taskService.setAssignee(nextTask.getId(), lastTask.getAssignee());
    }

    //  恢复原始方向
    currentFlowNode.setOutgoingFlows(originalSequenceFlowList);
}

以请假为例

【工作流Activiti7】3、Activiti7 回退与会签

<process id="holiday" name="holiday" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <userTask id="usertask1" name="填写请假单" activiti:assignee="${assignee1}"></userTask>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <userTask id="usertask2" name="部门经理审批" activiti:assignee="${assignee2}"></userTask>
    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
    <userTask id="usertask3" name="人事审批" activiti:candidateUsers="tom,jerry"></userTask>
    <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow4" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>
</process>

假设现在已经到“人事审批”这个节点了,当前活动是usertask3

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

接下来,我们运行上面的代码,回退到上一个节点“部门经理审批”,于是

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

流程重新从“部门经理审批”节点开始往下走,当流程走完以后

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

证明,思路正确,写法没啥问题。但是,上面的代码可以简化一下,如下:

/**
 * 跳到最开始的任务节点(直接打回)
 * @param task 当前任务
 */
public void jumpToStart(Task task) {
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    HistoryService historyService = processEngine.getHistoryService();
    RepositoryService repositoryService = processEngine.getRepositoryService();
    TaskService taskService = processEngine.getTaskService();

    String processInstanceId = task.getProcessInstanceId();

    //  获取所有历史任务(按创建时间升序)
    List<HistoricTaskInstance> hisTaskList = historyService.createHistoricTaskInstanceQuery()
            .processInstanceId(processInstanceId)
            .orderByTaskCreateTime()
            .asc()
            .list();

    if (CollectionUtils.isEmpty(hisTaskList) || hisTaskList.size() < 2) {
        return;
    }

    //  第一个任务
    HistoricTaskInstance startTask = hisTaskList.get(0);
    //  当前任务
    HistoricTaskInstance currentTask = hisTaskList.get(hisTaskList.size() - 1);

    BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());

    //  获取第一个活动节点
    FlowNode startFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(startTask.getTaskDefinitionKey());
    //  获取当前活动节点
    FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentTask.getTaskDefinitionKey());

    //  临时保存当前活动的原始方向
    List<SequenceFlow> originalSequenceFlowList = new ArrayList<>();
    originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
    //  清理活动方向
    currentFlowNode.getOutgoingFlows().clear();

    //  建立新方向
    SequenceFlow newSequenceFlow = new SequenceFlow();
    newSequenceFlow.setId("newSequenceFlowId");
    newSequenceFlow.setSourceFlowElement(currentFlowNode);
    newSequenceFlow.setTargetFlowElement(startFlowNode);
    List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
    newSequenceFlowList.add(newSequenceFlow);
    //  当前节点指向新的方向
    currentFlowNode.setOutgoingFlows(newSequenceFlowList);

    //  完成当前任务
    taskService.complete(task.getId());

    //  重新查询当前任务
    Task nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
    if (null != nextTask) {
        taskService.setAssignee(nextTask.getId(), startTask.getAssignee());
    }

    //  恢复原始方向
    currentFlowNode.setOutgoingFlows(originalSequenceFlowList);
}

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

2.  会签

多个人同时处理一个任务,这种任务我们称之为会签任务 。Activiti实现会签是基于多实例任务,将节点设置成多实例,主要通过在UserTask节点的属性上配置。

【工作流Activiti7】3、Activiti7 回退与会签

会签的种类:

  • 按数量通过: 达到一定数量的通过表决后,会签通过。
  • 按比例通过: 达到一定比例的通过表决后,会签通过。
  • 一票否决: 只要有一个表决时否定的,会签通过。
  • 一票通过: 只要有一个表决通过的,会签通过。

每个实例有以下变量:

  • nrOfInstances: 实例总数
  • nrOfActiveInstances: 当前激活的(未完成的)实例总数。 如果串行执行,则改值永远是1

  • nrOfCompletedInstances: 已完成的实例总数

条件${nrOfInstances == nrOfCompletedInstances}表示所有人员审批完成后会签结束。

条件${ nrOfCompletedInstances == 1}表示一个人完成审批,该会签就结束。

其他条件依次类推,同时这里也可以写自己添加的流程变量。

相关文档如下:

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

下面举个例子:

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

<process id="countersign" name="countersign" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <userTask id="usertask1" name="申请" activiti:assignee="zhangsan"></userTask>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <userTask id="usertask2" name="会签审批" activiti:assignee="${approver}">
        <multiInstanceLoopCharacteristics isSequential="false" 
            activiti:collection="${approverList}" activiti:elementVariable="approver">
            <completionCondition>${nrOfCompletedInstances == nrOfInstances}</completionCondition>
        </multiInstanceLoopCharacteristics>
    </userTask>
    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
    <userTask id="usertask3" name="备案" activiti:assignee="tianqi"></userTask>
    <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow4" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>
</process>

编写代码:

//  部署流程定义
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("diagram/countersign.bpmn")
                .name("会签示例")
                .key("countersign")
                .deploy();

//  启动流程实例
RuntimeService runtimeService = processEngine.getRuntimeService();
Map<String, Object> variables = new HashMap<>();
variables.put("approverList", Arrays.asList("lisi","wangwu","zhaoliu"));
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("countersign", variables);

//  完成任务
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().processInstanceId("107501").taskAssignee("zhaoliu").singleResult();
if (null != task) {
    taskService.complete(task.getId());
}

流程启动后,首先是zhangsan审批

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

当zhangsan完成自己的任务后,进入会签环节,于是我们看到当前有3个激活的任务

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

当lisi完成任务以后,当前任务剩下2个

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

当wangwu和zhaoliu都完成任务了以后,会签任务完成,进入下一个环节

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

刚才的例子中没有考虑到审批不通过的情况,接下来我们完善一下,考虑下面的流程

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

<process id="countersign" name="countersign" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <userTask id="usertask1" name="申请" activiti:assignee="zhangsan"></userTask>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <userTask id="usertask2" name="会签审批" activiti:assignee="${approver}">
        <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="${approverList}" activiti:elementVariable="approver">
            <completionCondition>${nrOfCompletedInstances / nrOfInstances == 1 || pass == false}</completionCondition>
        </multiInstanceLoopCharacteristics>
    </userTask>
    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
    <userTask id="usertask3" name="备案" activiti:assignee="tianqi"></userTask>
    <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway>
    <sequenceFlow id="flow5" sourceRef="usertask2" targetRef="exclusivegateway1"></sequenceFlow>
    <sequenceFlow id="flow6" name="通过" sourceRef="exclusivegateway1" targetRef="usertask3">
        <conditionExpression xsi:type="tFormalExpression"><![CDATA[${pass == true}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow7" name="拒绝" sourceRef="exclusivegateway1" targetRef="usertask1">
        <conditionExpression xsi:type="tFormalExpression"><![CDATA[${pass == false}]]></conditionExpression>
    </sequenceFlow>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow8" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>
</process>

在会签审批完成任务时就要加上流程变量pass了

RuntimeService runtimeService = processEngine.getRuntimeService();
TaskService taskService = processEngine.getTaskService();

Task task = taskService.createTaskQuery().processInstanceId("152501").taskAssignee("lisi").singleResult();
if (null != task) {
    Map<String, Object> variables = new HashMap<>();
    variables.put("pass", true);
//            variables.put("pass", false);
    taskService.complete(task.getId(), variables);

    runtimeService.getVariable(task.getExecutionId(), "nrOfCompletedInstances");
}

zhaoliu审批的时候pass传的false,于是流程又走到zhangsan那里,流程重新又走了一遍才全部完成

【工作流Activiti7】3、Activiti7 回退与会签

【工作流Activiti7】3、Activiti7 回退与会签

回退和会签就先讲到这里 文章来源地址https://www.toymoban.com/news/detail-419631.html

到了这里,关于【工作流Activiti7】3、Activiti7 回退与会签的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Activiti7工作流引擎:在线流程编辑器Activiti Modoler5.x

    有的时候我们的流程图需要业务人员自己绘制,然后使用自己绘制的流程图,此时就需要一个在线流程图编辑器需要集成到我们的web系统中。Activiti Modoler是Activiti官方推出的在线流程编辑器。 https://github.com/Activiti/Activiti/tree/5.x 将整个项目下载下来。不同版本的目录结构区别

    2024年02月09日
    浏览(40)
  • 【业务功能篇38】上篇:Springboot+activiti7 工作流引擎 增加网关组件、Assignment分配权限

    在前面的一篇文章中,简单举例了一个 工单电子流,【业务功能篇36】Springboot+activiti7 工作流引擎_studyday1的博客-CSDN博客仅有一个子任务,这种一般是针对比较简单的一个遗留问题记录场景,今天再介绍一个,相对比较复杂的流程,多个处理,审批节点任务,通过排他网关组

    2024年02月13日
    浏览(25)
  • Activiti 工作流简介

    1、什么是工作流         工作流(Workflow),就是通过计算机对业务流程自动化执行管理。它主要解决的是“使在多个参与者之间按照某种预定义的规则自动进行传递文档、信息或任务的过程,从而实现某个预期的业务目标,或者促使此目标的实现”。 1.2、工作流系统   

    2024年02月04日
    浏览(40)
  • 【activiti】工作流入门基础概念

    为什么使用activiti 状态--------------------------------------------------引擎engin(业务变动不影响程序的进行) 每个人只能看到个人负责的,流程变更困难 bpmn建模语言 activiti流程步骤 步骤: 1、部署流程 2、定义流程 3、部署流程定义:使用activiti中的API把流程定义存储,在Acitivti执行过

    2024年02月16日
    浏览(29)
  • springboot项目集成activiti工作流引擎

    一、一种较为简单,只需要使用idea的插件来画流程图。(我所使用的的插件是Activiti BPMN visualizer) 二、另一种就是可以使用(在线流程设计器)或者(页面设计器部署到自己项目中)来画流程图。 本文是将流程设计页面部署到了项目中 一、使用idea的插件来画流程图。  二

    2024年02月10日
    浏览(31)
  • Spring Boot + Activiti 结合,实现工作流

    Activiti是一个工作流引擎,Activiti可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言BPMN2.0进行定义,业务流程按照预先定义的流程进行执行,实现了系统的流程由Activiti进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,Activiti流程就是数据库表

    2023年04月13日
    浏览(69)
  • 若依框架SpringBoot+Activiti工作流的使用

    使用简介:本技术点主要是针对类审批的业务流程的建模,可以有:任务发布(即流程开始)到一级一级的审批到最终结束(即流程结束)一整套完备的模型 1、idea下载activiti插件 ider以前版本下载actiBPM,但是新版ider这个插件已经被淘汰,已经被下面这个替代     2、单独起

    2024年02月11日
    浏览(30)
  • SpringBoot整合Activiti实现工作流的低代码系统(附源码+文档)

    activiti工作流引擎项目,企业erp、oa、hr、crm等企事业办公系统轻松落地,一套完整并且实际运用在多套项目中的案例,满足日常业务流程审批需求。 springboot+vue+activiti集成了activiti在线编辑器,流行的前后端分离部署开发模式,快速开发平台,可插拔工作流服务。工作流表单

    2024年04月09日
    浏览(34)
  • 后端面试话术集锦第 九 篇:Activiti工作流面试话术

    这是后端面试集锦第九篇博文—— Activiti 工作流面试话术❗❗❗ 工作流这块儿,实际在工作中使用的时候, Activiti 用的居多,当然还有一些其他的工作流引擎。 在网上看了也大概看了一下,其他的像 JBPM 以及 workflow 等用的情况来讲不是很多。 所以说 Activiti 目前来讲用的比

    2024年02月10日
    浏览(32)
  • SpringBoot整合Activiti实现工作流的低代码系统(附源码和配套文档)

    activiti工作流引擎项目,企业erp、oa、hr、crm等企事业办公系统轻松落地,一套完整并且实际运用在多套项目中的案例,满足日常业务流程审批需求。 springboot+vue+activiti集成了activiti在线编辑器,流行的前后端分离部署开发模式,快速开发平台,可插拔工作流服务。工作流表单

    2024年03月15日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包