Activiti6.0获取下一节点任务的心路历程

获取下一节点任务,这个看起来非常的简单,但在开发过程中遇到了许多的坑,在这里进行记录,如果你想要快速知道结果,请看代码版本(3)

  1. 首先,就是获取下一节点的任务信息,这里说简单也简单,说难也难,初期,我查阅了大量的资料,那些资料中都是在代码层面获取下一节点任务信息,我尝试了一下,非常的复杂,后来,我仔细研究了activiti流程变化与数据库变化之间的联系,发现act_ru_task表的执行特性,它会在当前节点任务完成后自动加载下一节点任务,根据这一点,我们就能能够获取到下一节点的相关信息。
/**
     * @author : ADun
     * 获取当前节点的下一节点所有节点信息
     * 解释:当当前节点任务完成后,ac_ru_task表会删除当前任务保存下一待办任务,因此可以获得下一节点任务相关信息
     * @param task
     * @return
     */
    public List<Task> nextAllNodeTaskList(Task task) {
        List<Task> taskList = null;
        taskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
        return taskList;
    }
  1. 接着就是判断流程是怎样执行的了,何时给下一节点发信息,何时不发,在这里我由于对项目流程图不够熟悉,出现了各种的逻辑漏洞
    (1)代码的第一个版本
/**
     * 发送待办提醒的通用入口
     * @param task 当前节点的任务信息
     */
    @Override
    public void sendTaskNotice(Task task){
        //1、获取下一节点所有任务信息,实际是查询act_ru_task表中的信息
        List<Task> nextNodeUserTask = taskQueryService.nextAllNodeTaskList(task);
        if(nextNodeUserTask == null || nextNodeUserTask.size() <= 0){//下一节点任务为空,即当前节点为最后一个节点
            return;
        }

      for (Task nextNodeTask : nextNodeUserTask) {
            List<Execution> executionList = runtimeService.createExecutionQuery().processInstanceId(nextNodeTask.getProcessInstanceId()).list();//查询出所有的执行实例
            for (int i = 0; i < executionList.size(); i++) {
                //如果当前任务的执行实例id是下一节点任务执行实例的父id,则进行下一步
                if(task.getExecutionId() == executionList.get(i).getParentId()){
                    String assignee = nextNodeTask.getAssignee();//下一节点任务的参与者uid
                    if (assignee == null || "".equals(assignee)){
                        log.error("下一节点任务参与者为空");
                        return;
                    }
                    SysUser assigneeUser = sysUserService.selectUserByUserName(assignee);//下一节点任务参与者用户信息
                    //2、获取流程实例的任务属性
                    GatherTaskProperty gatherTaskProperty = gatherTaskPropertyMapper.selectGatherTaskPropertyByProcessInstanceId(task.getProcessInstanceId());
                    SysUser initialUser = sysUserService.selectUserByUserName(gatherTaskProperty.getCreateBy());//发起人用户信息

                    //3、发送邮件、短信提醒
                    sendTaskSMNotice(nextNodeTask, assigneeUser, initialUser);
                    sendTaskMailNotice(nextNodeTask, assigneeUser, initialUser);
                }
            }
        }
    }

在这一个版本的代码逻辑中,我的的逻辑是这样的,这里使用到了activiti流程引擎在执行过程中的一个特性,如果流程是单线流程,那么在执行过程中只会在act_ru_exection执行实例表【这个表中会保存流程实例与执行实例,它们有细微的区别,不明白的可以去了解一下】中保存一条流程实例信息,如果是并行流程,那么在act_ru_exection表中会同时保存流程实例与执行实例,并且执行实例属于流程实例,在表中可以发现,这里包含三条信息,第一条就是流程实例的信息,下面两条是执行实例的信息
在这里插入图片描述
由此我们也能够得出此时是一个下图这种类型的流程图
在这里插入图片描述
当初是这样想的,现在看起来非常的智障::当1号节点任务完成时,act_ru_task表会自动加载2与4任务节点的信息【并行网关的特性】,此时的2与3属于一个执行实例,4与5属于一个执行实例,当任务2完成时,act_ru_task表会自动删除2号节点,加载3号任务,此时3号执行实例的parentid我认为是2号节点的执行id,但后来发现,act_ru_exection表中一直会保存三条数据,变化的只是act_id,第一版本宣布失败
(2)代码的第二个版本

/**
     * 发送待办提醒的通用入口
     * @param task 当前节点的任务信息
     */
    @Override
    public void sendTaskNotice(Task task){
        //1、获取下一节点所有任务信息,实际是查询act_ru_task表中的信息
        List<Task> nextNodeUserTask = taskQueryService.nextAllNodeTaskList(task);
        if(nextNodeUserTask == null || nextNodeUserTask.size() <= 0){//下一节点任务为空,即当前节点为最后一个节点
            return;
        }


        //2、如果下一节点只有一个任务,act_ru_task中只有一条数据
        if (nextNodeUserTask.size() == 1) {
            String assignee =null;
            //判断是单线流程还是并行流程,根据当前任务的执行流程实例id查询act_ru_exection,只有一条数据说明是单线流程,否则时多线
            List<Execution> executionList = runtimeService.createExecutionQuery().processInstanceId(nextNodeUserTask.get(0).getProcessInstanceId()).list();
            if(executionList.size()==1){
                //单线流程,直接向下一节点任务负责人发送信息
                assignee = nextNodeUserTask.get(0).getAssignee();//下一节点任务的参与者uid
                if (assignee == null || "".equals(assignee)){
                    log.error("下一节点任务参与者为空");
                    return;
                }
                SysUser assigneeUser = sysUserService.selectUserByUserName(assignee);//下一节点任务参与者用户信息
                //2、获取流程实例的任务属性
                GatherTaskProperty gatherTaskProperty = gatherTaskPropertyMapper.selectGatherTaskPropertyByProcessInstanceId(task.getProcessInstanceId());
                SysUser initialUser = sysUserService.selectUserByUserName(gatherTaskProperty.getCreateBy());//发起人用户信息

                //3、发送邮件、短信提醒
                sendTaskSMNotice(nextNodeUserTask.get(0), assigneeUser, initialUser);
                sendTaskMailNotice(nextNodeUserTask.get(0), assigneeUser, initialUser);
                sendTask(task,nextNodeUserTask.get(0));
            }else{
                //多线流程,只有一条执行实例完成时有可能出现一个任务节点,此时跳过
                return;
            }

        }


        //3、如果下一节点任务不只一个任务,act_ru_task中有多条数据
        Set<Task> taskArraySet = new HashSet<>();//去重
        if (nextNodeUserTask.size() > 1) {
            for (int i = 0; i < nextNodeUserTask.size() - 1; i++) {
                Date timeOne = nextNodeUserTask.get(i).getCreateTime();
                Date timeTwo = nextNodeUserTask.get(i + 1).getCreateTime();
                if (timeOne.compareTo(timeTwo) == 0) {
                    //如果当前任务的创建时间相同,都发送
                    taskArraySet.add(nextNodeUserTask.get(i));
                    taskArraySet.add(nextNodeUserTask.get(i + 1));
                } else if (timeOne.compareTo(timeTwo) > 0) {
                    //如果当前任务的创建时间不同,timeOne在timeTwo时间之后
                    taskArraySet.add(nextNodeUserTask.get(i));//只发送最近时间创建的任务
                } else {
                    //如果当前任务的创建时间不同,timeOne在timeTwo时间之前
                    taskArraySet.add(nextNodeUserTask.get(i + 1));//只发送最近时间创建的任务
                }
            }



        }
        for (Task nextNodeTask : taskArraySet) {
            sendTask(task, nextNodeTask) ;
        }
    }

在这一个版本的代码,我加入了大量的判断,在后期发现这里的逻辑只能适用于两条并行的流程,三条并行会有重复发送的情况,而且在单线流程与并行流程的判断处有逻辑错误,不适合下图流程
在这里插入图片描述
在2、3、4任务完成后不会向5发送信息,这是严重的逻辑性错误

(3)代码的最终版本

/**
     * @param task 当前节点的任务信息
     * @author : ADun
     * 发送待办提醒的通用入口
     */
    public void sendTaskNotice(Task task) {
        //1、获取下一节点所有任务信息,实际是查询act_ru_task表中的信息
        List<Task> nextNodeUserTask = taskQueryService.nextAllNodeTaskList(task);
        //下一节点任务为空,即当前节点为最后一个节点
        if (nextNodeUserTask == null || nextNodeUserTask.size() <= 0) {
            return;
        }

        for (Task nextNodeTask : nextNodeUserTask) {
            String assignee = nextNodeTask.getAssignee();
            if(assignee == null || "".equals(assignee)){
                log.error("taskId为" + nextNodeTask.getId() + "的任务参与者不存在!");
                continue;
            }
            //获取当前任务的结束时间
            HistoricTaskInstance hisTask = historyService.createHistoricTaskInstanceQuery().taskId(task.getId()).singleResult();
            Date hisTaskEndTime = hisTask.getEndTime();
            //获取下一任务开始时间
            Date nextNodeTaskCreateTime = nextNodeTask.getCreateTime();
            //只有下一任务节点创建时间与当前任务完成时间相等时,向下一节点发送信息
            if (nextNodeTaskCreateTime.compareTo(hisTaskEndTime) == 0) {
                sendTask(task, nextNodeTask);
            }
        }

    }

在这一版本中我还是沿用上一版本代码的思想,在时间中做文章,这个思想适用于网络延时非常小,几乎不计,最后我是通过判断当前任务的完成时间是否下一任务的开始时间相同,相同就向下一任务审批人发送信息,我认为这里还是存在漏洞,可能时间会存在秒级的不准确。

最新思路:
通过bpmn文件内容来获取下一节点
进而使用taskService的api进行查询

 List<Task> list = taskService.createTaskQuery().processInstanceId(processInstanceId).taskDefinitionKey(nodeId).list();

这里通过bpmn目前只支持简单流程,条件分支、子流程暂不支持

大家有什么好的想法可以在评论区留言。

### 回答1: Activiti 是一款流程引擎,它可以通过 Java API 或者 REST API 连接到我们的应用程序中,并提供了丰富的流程管理功能。如果想要获取一个节点,需要通过 ActivitiJava API 进行以下操作: 1. 获得当前任务所在的流程实例,可以使用 ProcessEngine#getRuntimeService() 方法来获取 RuntimeService 对象,并使用该对象下的 createProcessInstanceQuery() 方法查询流程实例。 2. 获得当前任务,可以使用 TaskService# createTaskQuery() 方法查询任务。 3. 通过下一个任务的名称、审批人、代理人等来查询下一个要执行的任务。 4. 获得下一个任务节点 ID,可以使用查询到的任务对象下的 Task#getExecution() 方法获取当前任务所在的 Execution 对象,再通过 Execution#getActivityId() 方法获取当前任务所在的节点 ID。 5. 获得下一个任务的定义信息,可以使用 ProcessEngine#getRepositoryService() 方法获取 RepositoryService 对象,使用该对象下的 createProcessDefinitionQuery() 方法查询流程定义信息。 通过以上步骤就能够获取一个节点的 ID 和定义信息。在实际开发中,我们可以将获取一个节点的操作封装成工具类或者插件,简化我们的代码实现并提高代码可维护性。 ### 回答2: Activiti一个流程引擎框架,它可以实现工作流管理和业务流程管理。获取一个节点Activiti中比较常见的一个任务,可以通过以下几种方式来实现: 1. 使用Java API获取一个节点:可以通过Activiti提供的Java API来获取流程定义中的下一个节点。使用该API需要连接到Activiti的流程引擎,然后在运行时使用该API调用流程实例以获取一个节点的信息。 2. 使用表达式获取一个节点Activiti支持使用表达式来获取一个节点,可以通过设置用户任务的连线名称来设置一个表达式。该表达式会在流程运行时被解析,并返回下一个节点的名称。 3. 使用EL表达式获取一个节点Activiti还支持使用EL表达式来获取一个节点。可以在用户任务的连线名称上设置一个表达式,使用EL表达式语言隐藏要执行的目标节点。 4. 使用Activiti内置的下一个节点获取功能:Activiti提供了一些内置功能来获取一个节点。其中之一是使用默认顺序获取一个节点。可以在流程模型的流程定义中定义任务顺序,并使用内置函数来获取一个节点。 总之,Activiti获取一个节点有多种方式。可以根据自己的实际需求来选择适合的方法。无论使用哪种方法,都需要在谨慎考虑与实践中仔细测试。 ### 回答3: Activiti是一款流程引擎,用于管理和自动化业务流程。在进行业务流程设计时,需要定义各种流程节点,并在流程执行中动态获取一个节点。本篇文章将介绍如何使用Activiti获取一个节点。 1. Activiti中的节点类型 Activiti中有多种节点类型,如开始事件、结束事件、用户任务、服务任务等。其中最常用的节点是用户任务,它代表了需要人来处理的任务。在用户任务的执行过程中,需要获取一个节点以便继续流程的执行。 2. 获取一个节点的方法 Activiti提供了多种方式来获取一个节点,包括: (1)通过代码获取一个节点 我们可以使用Java代码来获取一个节点Activiti中已经封装了相关API,我们只需要按照API的要求来编写代码即可。以下是获取一个节点的示例代码: //获取当前任务节点ID String currentTaskID = "xxxxx"; //当前任务对应的节点ID Task currentTask = taskService.createTaskQuery().taskId(currentTaskID).singleResult(); //获取当前任务对应的流程定义ID String processDefinitionID = currentTask.getProcessDefinitionId(); //获取当前任务对应的流程定义 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionID).singleResult(); //获取当前任务后面的所有节点 List<Activity> list = ProcessDiagramGenerator.getAllActivities(processDefinition); //获取一个节点 Activity nextActivity = list.get(0); (2)使用流程变量获取一个节点 Activiti中的流程变量可以在任务的执行过程中传递数据。我们可以将下一个节点的ID存储在流程变量中,然后在任务完成后获取这个变量来获取一个节点。 以下是设置流程变量的示例代码: //设置下一个处理节点的ID String nextNodeId = "xxxxx"; //下一个节点的ID taskService.setVariable(taskId, "nextNodeId", nextNodeId); 获取流程变量的示例代码如下: //获取流程变量中存储的下一个节点的ID String nextNodeId = (String)taskService.getVariable(taskId, "nextNodeId"); 以上是两种常用的获取一个节点的方法。可以根据具体情况选择合适的方法。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值