flowable 特殊多实例并行例子解决方案

场景描述:

由于公司需要在流程图中明确的显示不同部门的流程情况,而这些部门是并行的,最后要有系统自动判断这些节点的审核结果给出一个最终的结果,来确定流程的走向,如果是单个审核节点的话可以使用多实例(设置多实例结束条件即可),但是通常业务中包含着不止一个节点,这种情况我们可以使用子流程解决,也可以使用下边我要介绍的方案,这个方案我只画了每个并行节点的一个审核,但是实际通常会有多个,我只做例子讲解,就不画多个了。

注意:如果大家有更好的解决,请大家在下方留言,谢谢。(还有一种简单的解决方案是设置任务过期时间)

  • 流程图如下

    flowable 特殊多实例并行例子解决方案_第1张图片
  • 流程图xml
    
    
      
        测试流程
        
        
        
        
        
          
            
          
        
        
          
            
          
        
        
        
          
            
            
          
        
        
        
          
            
          
        
        
        
        
        
        
        
        
        
        
        
          
        
        
        
        
          
        
        
          
        
        
          
        
        
        
          
        
        
          
        
      
      
        
          
            
          
          
            
          
          
            
          
          
            
          
          
            
          
          
            
          
          
            
          
          
            
          
          
            
          
          
            
          
          
            
          
          
            
          
          
            
          
          
            
            
            
          
          
            
            
          
          
            
            
            
          
          
            
            
          
          
            
            
          
          
            
            
          
          
            
            
            
          
          
            
            
            
          
          
            
            
          
          
            
            
            
          
          
            
            
          
          
            
            
          
          
            
            
          
          
            
            
          
          
            
            
          
        
      
    

    此时我们可以看到主编1和主编2 是并行审核的,当他们审核完的时候要有有一个系统判断来判断最终的审核结果,决定流程的走向。

解决方案:

在系统判断这个节点的时候我们就要是使用任务监听器:TaskListener

/**
 * @ProjectName: spark-platform
 * @Package: com.spark.platform.flowable.biz.listener
 * @ClassName: TaskListener
 * @Author: wangdingfeng
 * @Description: 任务监听器
 * @Date: 2020/4/8 14:22
 * @Version: 1.0
 */
@Slf4j
@Component
public class MyTaskListener implements TaskListener {

    @Override
    public void notify(DelegateTask delegateTask) {
        String eventName = delegateTask.getEventName();
        switch (eventName) {
            case BaseTaskListener.EVENTNAME_CREATE:
                log.info("当前监听创建事件:create");
                //开启消息发送线程
                Thread thread = new Thread(
                        new MessageRunnableTask(delegateTask));
                thread.start();
                break;
            case BaseTaskListener.EVENTNAME_ASSIGNMENT:
                log.info("当前监听指派事件:assignment");
                break;
            case BaseTaskListener.EVENTNAME_COMPLETE:
                log.info("当前监听完成事件:complete");
                break;
            case BaseTaskListener.EVENTNAME_DELETE:
                log.info("当前监听销毁事件:delete");
                break;
            default:
                break;
        }
    }
}

TaskListener 虽然是可以做监听,但是由于此时任务数据还没有在数据库中落地,所以无法获取到当前节点的taskID,不能自动推动流程的走向,所以我加了一个线程用来刷此个节点的taskId,代码如下

/**
 * @ProjectName: spark-platform
 * @Package: com.spark.platform.flowable.biz.listener
 * @ClassName: RunnableTask
 * @Author: wangdingfeng
 * @Description: 线程
 * @Date: 2020/4/14 11:07
 * @Version: 1.0
 */
@Slf4j
public class MessageRunnableTask implements Runnable {

    private DelegateTask delegateTask;

    MessageRunnableTask(DelegateTask delegateTask) {
        this.delegateTask = delegateTask;
    }


    @Override
    public void run() {
        Task task = getTask(delegateTask);
        StringRedisTemplate redisTemplate = SpringContextHolder.getBean(StringRedisTemplate.class);
        TaskVO taskVO = new TaskVO();
        BeanUtil.copyProperties(task, taskVO, "variables");
        taskVO.setVariables(task.getProcessVariables());
        redisTemplate.convertAndSend(RedisTopicName.topicName, JSONObject.toJSONString(taskVO));

    }

    /**
     * 递归查询 直到查询到task任务已经落地为止,然后发布消息
     *
     * @param delegateTask
     * @return
     */
    private Task getTask(DelegateTask delegateTask) {
        ActTaskQueryService actTaskQueryService = SpringContextHolder.getBean(ActTaskQueryService.class);
        Task task = null;
        while (null == task){
            log.info("开是休眠40S");
            ThreadUtil.sleep(1000 * 40);
            task = actTaskQueryService.createTaskQuery().processInstanceId(delegateTask.getProcessInstanceId()).taskAssignee(delegateTask.getAssignee()).includeProcessVariables().singleResult();
        }
        log.info("代办任务数据库已经落地----");
        return task;
    }
}

由于通常我们的业务代码不会在工作流这个服务中判断,通常由业务发起服务器判断,所以我使用了消息订阅。此示例代码用的是redis消息发布订阅,实际开发中不要使用redis,由于redis的消息队列一旦消费者不存在,就会出现消息丢失的情况,请使用rabbitmq这些消息队列。

Redis 订阅处理消息

@Component
@Slf4j
public class RedisChannelListener implements MessageListener {

    @Override
    public void onMessage(Message message, byte[] pattern) {
        //接受消息
        byte[] channel = message.getChannel();
        byte[] body = message.getBody();
        try {
            String content = new String(body, "UTF-8");
            String address = new String(channel, "UTF-8");
            log.info("接收到频道{}发来的消息:{}", address, address);
            switch (address) {
                case RedisTopicName.topicName:
                    articleMessage(content);
                    break;
                default:
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 文章消息处理
     *
     * @param content
     */
    public void articleMessage(String content) {
        log.info("开始处理文章信息");
        TaskVO taskVO = JSONObject.parseObject(content,TaskVO.class);
        //推进任务
        boolean flag = true;
        Iterator> it = taskVO.getVariables().entrySet().iterator();
        //判断两个主编的最终审核结果 只有当两个主编都审核通过才通过
        while (it.hasNext()) {
            Map.Entry entry = it.next();
            if (entry.getKey().startsWith("multiInstance_result")) {
                if (!(boolean) entry.getValue()) {
                    flag = false;
                    break;
                }
            }
        }
        ActTaskService actTaskService = SpringContextHolder.getBean(ActTaskService.class);
        Map map = ImmutableMap.of("SYSTEM_JUDGE_SUBMIT_VALUE", "SUBMIT_APPROVAL");
        if (flag) {
            map = ImmutableMap.of("SYSTEM_JUDGE_SUBMIT_VALUE", "PASS");
        }
        actTaskService.complete(taskVO.getId(), map);
    }

}

具体的例子,请参考我的开源项目:

spark: https://gitee.com/dreamfeng/spark-platform

 

你可能感兴趣的:(java)