码迷,mamicode.com
首页 > 其他好文 > 详细

Activiti 5.22.0 之自由驳回任务实现(亲测)

时间:2018-01-20 18:50:50      阅读:4622      评论:0      收藏:0      [点我收藏+]

标签:author   comm   orderby   大于等于   ica   list   流程   down   管理器   

? 上篇博文,我们完成一个任务SKIP的实现,说好要给各位看官带来驳回实现的现在,就奉上具体实现和讲解。(其实我感觉我的注释写的已经非常清楚了,哈哈)

? 依旧是,先说我们的需求和思路。

PS:

? 从6.0.0降到5.22.0版本的原因因为项目中有一个版本冲突,导致的降级。后期还是以新版本为主。6.0版本的驳回有时间再来搞。

需求:
  1. 流程中的审批任务节点可以驳回到之前的任意任务节点
  2. 驳回到指定节点的任务之后的轨迹不需要显示

嗯,大致上就是这样的一个需求,根据这个需求,其实我走了很多弯路,但都离不开两点。

思路:
1. 将当前的任务节点的下一个任务节点指定为指定的驳回任务节点
2. 将指定任务(目标任务)节点之后的流程轨迹,清空。

根据这个思路,我追了源码,看了各种Service,Manager等等。因为别人的驳回流程我拿下来发现是有错的,所以就自己研究了起来。现在就直接上代码吧。呸。先上图,没图谁会信你成功了呢?

  1. 启动报销流程 返回的是下个任务编号

技术分享图片

  1. 启动后查询流程轨迹

技术分享图片

  1. 查询流程中历史任务节点信息

技术分享图片

  1. 驳回任务到指定任务节点

技术分享图片

  1. 驳回后查询流程轨迹图

技术分享图片

  1. 查询驳回的历史任务信息

技术分享图片

  1. 启动一个新的流程实例

技术分享图片

  1. 查询新的流程实例的轨迹

技术分享图片

  1. 完成新的流程实例任务,模拟审批通过

技术分享图片

  1. 查询新流程实例对应完成任务后的轨迹

技术分享图片

嗯 上面 就是一个测试过程,主要想表达一个意思:当前流程实例中的任务驳回之后,不影响别的流程实例。这里有一张之前研究时的错误图,可以给大家看看。不喷哈~~

技术分享图片

好了下面上代码~~~~

代码:

每一个region endregion是一个代码块。在IDEA中是可以折叠的。C#中的习惯吧算是 能让代码更好看些。。。。(个人认为)

/**
 * 驳回任务方封装
 *
 * @param destinationTaskID 驳回的任务ID 目标任务ID
 * @param messageContent    驳回的理由
 * @param currentTaskID     当前正要执行的任务ID
 * @return 驳回结果 携带下个任务编号
 */
public ResponseResult rejectTask(String destinationTaskID, String currentTaskID, String messageContent) {
        // region 目标任务实例 historicDestinationTaskInstance 带流程变量,任务变量
        HistoricTaskInstance historicDestinationTaskInstance =
                historyService
                        .createHistoricTaskInstanceQuery()
                        .taskId(destinationTaskID)
                        .includeProcessVariables()
                        .includeTaskLocalVariables()
                        .singleResult();
        // endregion
        // region 正在执行的任务实例 historicCurrentTaskInstance 带流程变量,任务变量
        HistoricTaskInstance historicCurrentTaskInstance =
                historyService
                        .createHistoricTaskInstanceQuery()
                        .taskId(currentTaskID)
                        .includeProcessVariables()
                        .includeTaskLocalVariables()
                        .singleResult();
        // endregion
        // 流程定义ID
        String processDefinitionId = historicCurrentTaskInstance.getProcessDefinitionId();
        // 流程实例ID
        String processInstanceId = historicCurrentTaskInstance.getProcessInstanceId();
        // 流程定义实体
        ProcessDefinitionEntity processDefinition =
                (ProcessDefinitionEntity) repositoryService.getProcessDefinition(processDefinitionId);
        // region 根据任务创建时间正序排序获取历史任务实例集合 historicTaskInstanceList 含流程变量,任务变量
        List<HistoricTaskInstance> historicTaskInstanceList = historyService
                .createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .includeProcessVariables()
                .includeTaskLocalVariables()
                .orderByTaskCreateTime()
                .asc()
                .list();
        // endregion
        // region 历史活动节点实例集合 historicActivityInstanceList
        List<HistoricActivityInstance> historicActivityInstanceList =
                historyService
                        .createHistoricActivityInstanceQuery()
                        .processInstanceId(processInstanceId)
                        .orderByHistoricActivityInstanceStartTime()
                        .asc()
                        .list();
        // endregion
        // 获取目标任务的节点信息
        ActivityImpl destinationActivity = processDefinition
                .findActivity(historicDestinationTaskInstance.getTaskDefinitionKey());
        // 定义一个历史任务集合,完成任务后任务删除此集合中的任务
        List<HistoricTaskInstance> deleteHistoricTaskInstanceList = new ArrayList<>();
        // 定义一个历史活动节点集合,完成任务后删除历史活动节点
        List<HistoricActivityInstanceEntity> deleteHistoricTaskActivityInstanceList = new ArrayList<>();
        // 目标任务ID类型转换
        Integer destinationTaskInstanceId = Integer.valueOf(destinationTaskID);
        // 有序 -- 此处的想法是遍历历史流程实例中的任务实例,排序之后与目标任务ID进行大小对比
        for (HistoricTaskInstance historicTaskInstance : historicTaskInstanceList) {
            Integer historicTaskInstanceId = Integer.valueOf(historicTaskInstance.getId());
            // 遍历中任务ID大于等于目标任务ID则将记录该任务信息
            if (destinationTaskInstanceId <= historicTaskInstanceId) {
                deleteHistoricTaskInstanceList.add(historicTaskInstance);
            }
        }
        // 有序
        for (int i = 0; i < historicActivityInstanceList.size() - 1; i++) {
            HistoricActivityInstance historicActivityInstance = historicActivityInstanceList.get(i);
            // 历史活动节点的任务编号
            Integer historicActivityInstanceTaskId;
            String taskId = historicActivityInstance.getTaskId();
            if (taskId != null) {
                historicActivityInstanceTaskId = Integer.valueOf(taskId);
                if (historicActivityInstanceTaskId <= destinationTaskInstanceId) {
                
// 遍历中的活动节点对应的任务ID小于等于目标任务ID则将记录该任务信息
                  deleteHistoricTaskActivityInstanceList.add((HistoricActivityInstanceEntity) historicActivityInstance);
                }
            } else {
              // ActivitiConstanct.START_EVENT = "startEvent" --> 定义的常量,表示是启动节点
                if (historicActivityInstance.getActivityType().equals(ActivitiConstanct.START_EVENT)) {
// 将启动节点保存起来
                  deleteHistoricTaskActivityInstanceList.add((HistoricActivityInstanceEntity) historicActivityInstance);
                }
            }
        }
        // 获取流程定义的节点信息
        List<ActivityImpl> processDefinitionActivities = processDefinition.getActivities();
        // 打印节点信息 -- > 自定义方法,用来在控制台上输出ActivityImpl的相关信息
        // printActiviti(processDefinitionActivities);
        // 定义一个实体用于保存正在执行的任务节点信息
        ActivityImpl currentActivity = null;
        // 定义一个转向用于保存原来的任务节点的出口信息
        PvmTransition pvmTransition = null;
        // 遍历保存正在执行的任务节点的原出口信息
        for (ActivityImpl activity : processDefinitionActivities) {
          // 在历史活动节点集合中获取正在运行的活动节点
            if (historicCurrentTaskInstance.getTaskDefinitionKey().equals(activity.getId())) {
                // 保存当前节点信息
                currentActivity = activity;
                // 备份流程转向信息
                pvmTransition = activity.getOutgoingTransitions().get(0);
                // 清空当前任务节点的出口信息
                activity.getOutgoingTransitions().clear();
            }
        }
        // 执行流程转向  -->  这里是一个类,下面奉上
        processEngine.getManagementService().executeCommand(
                new RejectTaskCMD(historicDestinationTaskInstance, historicCurrentTaskInstance, destinationActivity));
        // 当前流程的流程变量
        Map<String, Object> taskLocalVariables = historicCurrentTaskInstance.getTaskLocalVariables();
        // 目标任务中的任务变量
        Map<String, Object> processVariables = historicDestinationTaskInstance.getProcessVariables();
        // 修改任务不自动跳过,要求审批  ActivitiConstanct.SKIP_EXPRESSION = "_ACTIVITI_SKIP_EXPRESSION_ENABLED" --> 常量  详见上篇博文,如果没有设置可以不用
        processVariables.put(ActivitiConstanct.SKIP_EXPRESSION, false);
        taskLocalVariables.put(ActivitiConstanct.SKIP_EXPRESSION, false);
        // 设置驳回原因  ActivitiConstanct.REJECT_REASON = "reject_reason" --> 常量 
        taskLocalVariables.put(ActivitiConstanct.REJECT_REASON, messageContent);
        // 完成当前任务,使任务走向目标任务  --> 封装的一个方法,用于完成任务后返回下一个要处理的任务ID 可以自己实现下,参数为当前任务ID,流程变量,流程任务变量
        String nextTaskId = processService.completeTaskByTaskID(currentTaskID, processVariables, taskLocalVariables);
        // 清空临时转向信息
        currentActivity.getOutgoingTransitions().clear();
        // 恢复原来的走向
        currentActivity.getOutgoingTransitions().add(pvmTransition);
        // 删除历史任务  ---> 虽然不太地道,但是现在也只想到了这个方法。 historyService只提供了这个方法。
        for (HistoricTaskInstance historicTaskInstance : deleteHistoricTaskInstanceList) {
            historyService.deleteHistoricTaskInstance(historicTaskInstance.getId());
        }
        // 删除活动节点  --> lambda 表达式,不创建类了,虽然不太地道,但是在追源码的过程中,发现ACTIVITI只提供了deleteHistoricActivityInstancesByProcessInstanceId这个方法。所以才这样做了。后期优化吧。
        processEngine.getManagementService().executeCommand(
                (Command<List<HistoricActivityInstanceEntity>>) commandContext -> {
                    // 获取历史活动节点实例管理器
                    HistoricActivityInstanceEntityManager historicActivityInstanceEntityManager =
                            commandContext.getHistoricActivityInstanceEntityManager();
                    // 根据流程实例编号删除所有的历史活动节点
                    historicActivityInstanceEntityManager
                            .deleteHistoricActivityInstancesByProcessInstanceId(processInstanceId);
                    // 提交到数据库
                    commandContext.getDbSqlSession().flush();
                    // 添加历史活动节点到ACT_HI_ACTINST表
                    for (HistoricActivityInstanceEntity historicActivityInstance : deleteHistoricTaskActivityInstanceList) {
                        historicActivityInstanceEntityManager.insertHistoricActivityInstance(historicActivityInstance);
                    }
                    // 提交到数据库
                    commandContext.getDbSqlSession().flush();
                    return null;
                });
        // 返回下个任务的任务ID
        return ResponseResultUtil.success(nextTaskId);
    }

我自己都知道有不好的地方,但是别的方法我没有实现成功,所以先这样做吧。过年的时候再好好看看改改。

下面是RejectTaskCMD这个类的代码:

package com.edu.hart.web.manage.process;

import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;

/**
 * 任务驳回方法支持
 *
 * @author create by 叶云轩 at 2018/1/15 09:32
 */
public class RejectTaskCMD implements Command<Object>, Serializable {
    /**
     * RejectTaskCMD 日志控制器
     * Create by 叶云轩 at 2018/1/19 09:43
     * Concat at yCountJavaXuan@outlook.com
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(RejectTaskCMD.class);
    /**
     * 历史信息中的当前任务实例
     */
    private HistoricTaskInstance currentTaskInstance;
    /**
     * 历史信息中的目标任务实例
     */
    private HistoricTaskInstance destinationTaskInstance;
    /**
     * 目标任务节点
     */
    private ActivityImpl destinationActivity;

    /**
     * 构造方法
     *
     * @param currentTaskInstance     当前任务实例
     * @param destinationTaskInstance 目标任务实例
     * @param destinationActivity     目标节点
     */
    public RejectTaskCMD(HistoricTaskInstance currentTaskInstance
            , HistoricTaskInstance destinationTaskInstance
            , ActivityImpl destinationActivity) {
        this.currentTaskInstance = currentTaskInstance;
        this.destinationTaskInstance = destinationTaskInstance;
        this.destinationActivity = destinationActivity;
    }

    @Override
    public Object execute(CommandContext commandContext) {
        // 流程实例ID
        String processInstanceId = destinationTaskInstance.getProcessInstanceId();
        // 执行管理器
        ExecutionEntityManager executionEntityManager =
                commandContext.getExecutionEntityManager();
        // select * from ACT_RU_EXECUTION where ID_ = ?   查询当前流程实例中正在执行的唯一任务 --追源码时发现这个方法的作用,就记录了下来,省的自己遗忘掉
        ExecutionEntity executionEntity = executionEntityManager.findExecutionById(processInstanceId);
        // 当前活跃的节点信息
        ActivityImpl currentActivity = executionEntity.getActivity();
        // 创建一个出口转向
        TransitionImpl outgoingTransition = currentActivity.createOutgoingTransition();
        // 封装目标节点到转向实体
        outgoingTransition.setDestination(destinationActivity);
        // 流程转向
        executionEntity.setTransition(outgoingTransition);
        return null;
    }
}

嗯,就是这样来完成任意节点驳回的。当前先这样实现了,6.0版本没有了Pvm这些类,还需要再研究研究~~

Activiti 5.22.0 之自由驳回任务实现(亲测)

标签:author   comm   orderby   大于等于   ica   list   流程   down   管理器   

原文地址:https://www.cnblogs.com/tdg-yyx/p/8321399.html

(0)
(2)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!