广东适合种植牵牛花吗?

小说:广东适合种植牵牛花吗?作者:王石更新时间:2019-05-27字数:51473

那一份放佛天地规则一般的睥睨天下的自信,让雅典娜眼中闪过了一丝异彩,雅典娜号称战争和智慧的女神,对于战争,战斗,智慧方面的事情当然极为擅长了,而刘皓的表现让她这个战争和智慧的女神都找不到任何一点不足和错误的地方,这让雅典娜一直对刘皓多次另眼相看。

黄刺玫球批发价格多少钱?

无论哪一点都让刘皓十分的欣赏和佩服当然还有喜欢了,也正是因为如此,刘皓越是想得到夏日星,因此才帮夏日星完成那么多事情。
鬼子驱逐舰甲板上顿时传来一阵阵吆喝声,船头一侧的主炮开始昂起来黑洞洞的炮口,随即一阵巨响声响起来,硕大的炮弹夹杂着火焰和白烟从炮口中喷射而出,扑向对面江面上的海子他们乘坐的小舢板。

「唉!『江阴三少』的头,现在正被你们『白霭门』给立在山下城门示众!」田开疆还真是语不惊人死不休,讲的事一件比一件惊天动地。

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

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

PS:

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

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

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

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

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

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

1.启动报销流程

  1. 启动后查询流程轨迹

2.启动后查询流程轨迹

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

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

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

4.驳回任务到指定节点

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

5.驳回后查询

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

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

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

7启动一个新的流程实例

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

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

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

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

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

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

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

研究过程中的错误

好了下面上代码~~~~

代码:

每一个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这些类,还需要再研究研究~~

编辑:卓帝乙侯

发布:2019-05-27 00:54:09

当前文章:http://cnsdbtzg.com/play/l282qnlh2b.html

【视频】高度60公分70公分红叶小檗价格优惠_苗圃现场 精品现货,海量批发1~8公分正宗红色木槿 美国红枫最常见品种有哪些? 哪买东北耐寒月季花苗? 扶芳藤价格表哪家最接近市场行情? 南方紫藤冬天落叶吗? 紫藤和凌霄花哪个好养? 胸径20公分银杏树

97474 69510 76643 31986 51737 70791 31831 82079 58167 37044 74223 39358 93238 97348 55547 92476 40433 10486 50701 52027

我要说两句: (0人参与)

发布