美文网首页程序员
说说在 jBPM 工作流中如何实现【委派】功能

说说在 jBPM 工作流中如何实现【委派】功能

作者: deniro | 来源:发表于2018-06-16 15:39 被阅读30次

    委派,又称为代理,是一种很常见的任务再分配模式。

    委派的业务场景是这样的:任务已经分配给小李,但由于某种原因现在不方便办理,这时就需要委派给小王,代为办理。

    实现委派功能两种思路:

    1. 不创建新的任务,而是直接修改原始任务的分配人(assignee 属性)。这样做会彻底断绝任务与原始分配人之间的关联关系,所以我们需要调用 TaskService 的 addTaskParticipatingUser ()方法将任务的原始分配人作为一种特定的参与者与此任务建立关联;同时添加代理备注(TaskService 的 addTaskComment()),以供历史追溯。客户端需要实现 “我委派的任务” 列表,以供收回委派之用。这种方式可以方便地实现一个任务被委派多次的业务场景。
    2. 新创建委派任务,在原始任务的基础上创建委派子任务,以供代理人办理,这里我们需要注意同步原始任务及其子任务的业务数据,另外需要单独为办理委派任务,定义一个任务办理命令,在此命令中同时完成原始任务及其子任务,这种方式可以方便地实现一个任务被委派给多人办理的业务场景。

    在此,我们按照思路一实现委派功能。

    示例流程假设如下:

    这个任务在定义中被分配给 Deniro,然后在后面的单元测试中,我们把这个任务委派给另外一个用户 Jack。

    委派任务命令:

    public class TaskDelegateCmd implements Command<Void> {
    
        //任务 ID
        private String taskId;
    
        //受委托人 ID
        private String delegateUserId;
    
        public TaskDelegateCmd(String taskId, String delegateUserId) {
            this.taskId = taskId;
            this.delegateUserId = delegateUserId;
        }
    
        @Override
        public Void execute(Environment environment) throws Exception {
            //获取需要委派的任务
            TaskService taskService = environment.get(TaskService.class);
            Task task = taskService.getTask(taskId);
    
            //把任务的当前处理者设置为 REPLACED_ASSIGNEE,方便以后【撤销委派】
            taskService.addTaskParticipatingUser(taskId, task.getAssignee(), Participation.REPLACED_ASSIGNEE);
    
            //记录【委派】日志
            taskService.addTaskComment(taskId, task.getAssignee() + " 把任务委派给了 " + delegateUserId);
    
            //把任务委派给受委托人
            task.setAssignee(delegateUserId);
    
            //持久化
            taskService.saveTask(task);
    
            return null;
        }
    }
    

    单元测试:

    //发起流程实例
    ProcessInstance processInstance = executionService.startProcessInstanceByKey("Delegate");
    instanceId = processInstance.getId();//实例 ID
    
    //获取需要被委派的任务
    Task task = taskService.findPersonalTasks("Deniro").get(0);
    
    //委派给 Jack
    Configuration.getProcessEngine().execute(new TaskDelegateCmd(task.getId(), "Jack"));
    
    //获取 Jack 的任务
    Task delegateTask = taskService.findPersonalTasks("Jack").get(0);
    
    //断言该任务只有一个参与者(即委派人 Deniro)
    List<Participation> participations = taskService.getTaskParticipations(delegateTask
            .getId());
    assertEquals(1,participations.size());
    assertEquals(Participation.REPLACED_ASSIGNEE, participations.get(0).getType());
    
    //完成委派的任务
    taskService.completeTask(delegateTask.getId());
    
    //断言流程实例结束
    assertProcessInstanceEnded(instanceId);
    
    /**
     * 以下验证流程历史
     */
    //获取历史任务查询接口
    HistoryTaskQuery historyTaskQuery=historyService.createHistoryTaskQuery();
    
    //因为任务被委派给了 Jack 处理,所以历史中应该只有 Jack 的历史任务
    assertEquals(0,historyTaskQuery.assignee("Deniro").list().size());
    assertEquals(1,historyTaskQuery.assignee("Jack").list().size());
    
    //获取任务注释对象
    HistoryTask historyTask=historyTaskQuery.assignee("Jack").uniqueResult();
    final HistoryDetailQuery historyDetailQuery = historyService.createHistoryDetailQuery()
            .taskId(historyTask.getId());
    List<HistoryDetail> details=historyDetailQuery.list();
    HistoryComment comment=(HistoryComment) details.get(0);
    
    //断言任务注释
    assertEquals("Deniro 把任务委派给了 Jack",comment.getMessage());
    
    //获取任务参与者
    List<Participation> historyParticipations=taskService.getTaskParticipations
            (historyTask.getId());
    
    //断言任务提交后,对应的参与者信息被删除
    assertEquals(0,historyParticipations.size());
    

    关于第二种思路:即新创建委派任务,在原始任务的基础上创建委派子任务,以供代理人办理,我们可以自定义两条命令:

    1、 委派任务命令

    在此命令中根据原始任务,新创建一个子任务,把它委派给受委委托人:

    public class TaskDelegateCmd2 implements Command<TaskImpl> {
    
        //任务 ID
        private String taskId;
    
        //受委托人 ID
        private String delegateUserId;
    
        public TaskDelegateCmd2(String taskId, String delegateUserId) {
            this.taskId = taskId;
            this.delegateUserId = delegateUserId;
        }
    
        @Override
        public TaskImpl execute(Environment environment) throws Exception {
            //获取需要委派的任务
            TaskService taskService = environment.get(TaskService.class);
            Task task = taskService.getTask(taskId);
    
            //定义【委派】日志
            final String delegateMessage = task.getAssignee() + " 把任务委派给了 " + delegateUserId;
    
            //记录【委派】日志
            taskService.addTaskComment(taskId, delegateMessage);
    
            //创建委派子任务
            TaskImpl delegateTask = ((TaskImpl) task).createSubTask();
    
            //把任务委派给受委托人
            delegateTask.setAssignee(delegateUserId);
            delegateTask.setDescription(delegateMessage);
    
            //将原始任务的关键数据复制给委派任务
            delegateTask.setName(task.getName());//任务名称
            delegateTask.setFormResourceName(task.getFormResourceName());//任务表单
            //...
    
            //持久化原始任务与委派任务
            taskService.saveTask(task);
            taskService.saveTask(delegateTask);
    
            return delegateTask;
        }
    
    }
    
    

    2、提交委派任务命令

    在此,同时完成委派任务和原始任务:

    public class DelegateTaskCommitCmd implements Command<Void> {
    
    
        //委派任务 ID
        private String delegateTaskId;
    
        public DelegateTaskCommitCmd(String delegateTaskId) {
            this.delegateTaskId = delegateTaskId;
        }
    
        @Override
        public Void execute(Environment environment) throws Exception {
            TaskService taskService = environment.get(TaskService.class);
    
            //根据委派任务获取原始任务
            TaskImpl delegateTask = (TaskImpl) taskService.getTask(delegateTaskId);
            Task originalTask = delegateTask.getSuperTask();
    
            //完成委派任务与原始任务
            taskService.completeTask(delegateTask.getId());
            taskService.completeTask(originalTask.getId());
    
            return null;
        }
    
    }
    

    在实践中,【委派】还有一些业务场景需要考虑:

    • 如何收回委派任务(可用自定义命令实现)。
    • 如何支持给多个委托人(可能是多个人或者多个组)。

    其实只要真正了解了 jBPM 工作流的原理以及它的命令模式,我们就可以扩展出上述这些实际业务逻辑所需要的功能啦O(∩_∩)O哈哈~

    相关文章

      网友评论

        本文标题:说说在 jBPM 工作流中如何实现【委派】功能

        本文链接:https://www.haomeiwen.com/subject/xdofeftx.html