使用flowable生成动态流程图

  • Post author:
  • Post category:其他


项目中用到使用flowable生成动态流程图的地方,所以用笔记记下来

/**
 * 动态创建流程图
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class FlowableBpmnHandler {

    private RepositoryService repositoryService;
    //最少流程节点数量
    private static final Integer MIN_NODE_SIZE = 2;


    /**
     * 根据流程信息和节点配置创建流程图
     * 传入map
     *
     * @return
     */
    public void createFlowableBpmn(Map<String,String> map) {
        //流程名称、流程id,流程类型、
        if (null == map.get("procinstId")|| StringUtils.isBlank(map.get("procinstName")) || StringUtils.isBlank(map.get("procinstTypeName")) || StringUtils.isBlank(map.get("procinstType"))) {
            throw new RuntimeException("procinstId、procinstName、procinstTypeName、ProcinstType不允许为空");
        }
        //数据校验:传入的数据节点字段:流程配置id、节点id、节点顺序、节点描述
        List<MgProcinstNode> nodeList = map.get("procinstNode");
        if (ListUtil.isEmpty(nodeList) || nodeList.size() < MIN_NODE_SIZE) {
            throw new RuntimeException("流程节点不能少于两个,请配置发起人节点和至少一个审批节点");
        }
        //流程配置节点主键id过滤
        List<Long> ids = nodeList.stream().map(MgProcinstNode::getProcinstNodeId).distinct().filter(Objects::nonNull).collect(Collectors.toList());
        if (ListUtil.isEmpty(ids) || ids.size() < nodeList.size()){
            throw new RuntimeException("请检查node节点的主键id是否为空");
        }
        /*
         * 整合节点和连线成为一个 process
         */
        Process process = new Process();
        // 流程标识
        process.setId("pro_" + map.get("procinstId"));
        process.setName(map.get("procinstName"));


        //开始事件
        FlowElement startEvent = createStartFlowElement("start","开始");
        process.addFlowElement(startEvent);
        //结束事件--任务正常完成
        FlowElement completeEvent = createEndFlowElement("complete","结束");

        List<UserTask> userTaskList = createCommonUserTask(nodeList);
        //发起人节点
        UserTask startUserTask = userTaskList.get(0);
        for (int i = 0; i < userTaskList.size(); i++) {
            UserTask userTask = userTaskList.get(i);
            process.addFlowElement(userTask);
            //发起人到第一个节点不需要网关
            if(i == 0) {
                // 开始节点到发起人节点
                SequenceFlow startSequenceFlow = new SequenceFlow(startEvent.getId(), userTask.getId());
                process.addFlowElement(startSequenceFlow);

               // 发起人节点到审批节点

                UserTask nextUserTask = userTaskList.get(i + 1);
                SequenceFlow sequenceFlow = new SequenceFlow(userTask.getId(), nextUserTask.getId());
                process.addFlowElement(sequenceFlow);
            } else {
                //从发起人后的第一个节点开始增加网关节点
                ExclusiveGateway exclusiveGateway = createGateway(i,userTask.getName());
                process.addFlowElement(exclusiveGateway);
                //审批节点到网关节点
                SequenceFlow sequenceFlow = new SequenceFlow(userTask.getId(), exclusiveGateway.getId());
                sequenceFlow.setName(userTask.getName()+ "开始审批");
                process.addFlowElement(sequenceFlow);
                // 取下一步的节点id,可能为结束节点或者审批节点
                String nextUserTaskId = completeEvent.getId();
                if (userTaskList.size() - i > 1 ){
                    nextUserTaskId = userTaskList.get(i + 1).getId();
                }
                //网关节点审批通过继续下一步
                SequenceFlow sequenceFlowAgree = new SequenceFlow(exclusiveGateway.getId(), nextUserTaskId);
                sequenceFlowAgree.setConditionExpression("${agree == 1}");
                sequenceFlowAgree.setName("同意");
                process.addFlowElement(sequenceFlowAgree);
                //网关节点审批拒绝返回到发起人,认领直接终止流程
                SequenceFlow sequenceFlowRefuse = new SequenceFlow(exclusiveGateway.getId(),startUserTask.getId());
                sequenceFlowRefuse.setConditionExpression("${agree == 0}");
                sequenceFlowRefuse.setName("拒绝");
                process.addFlowElement(sequenceFlowRefuse);
            }
        }

        process.addFlowElement(completeEvent);


        BpmnModel bpmnModel = new BpmnModel();
        bpmnModel.addProcess(process);
        // 自动生成布局 布局节点位置
        new BpmnAutoLayout(bpmnModel).execute();

        BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
        byte[] convertToXML = bpmnXMLConverter.convertToXML(bpmnModel);
        String bytes = new String(convertToXML);
        log.info("该流程的流程xml为:{}", bytes);

        ProcessValidatorFactory processValidatorFactory = new ProcessValidatorFactory();
        ProcessValidator defaultProcessValidator = processValidatorFactory.createDefaultProcessValidator();
        // 验证失败信息的封装ValidationError
        List<ValidationError> validate = defaultProcessValidator.validate(bpmnModel);
        log.error("获取到的验证信息为:{}", validate);
//        if (ListUtil.isNotEmpty(validate) ){
//            throw new RuntimeException("流程有误,请检查后重试");
//        }

        //  流程部署
        Deployment deploy = repositoryService.createDeployment()
                .tenantId("1099")
                .addString(map.get("procinstName")+".bpmn", bytes)
                .category(map.get("procinstTypeName")).deploy();
        log.info("部署id:" + deploy.getId());
    }
    /**
     * 创建开始节点信息
     * @return
     */
    public FlowElement createStartFlowElement(String id,String name){
        StartEvent startEvent = new StartEvent();
        startEvent.setId(id);
        startEvent.setName(name);
        startEvent.setInitiator("initiator");
        return startEvent;
    }

    /**
     * 创建结束节点信息
     * @param id
     * @param name
     * @return
     */
    public FlowElement createEndFlowElement(String id,String name){
        EndEvent endEvent=new EndEvent();
        endEvent.setId(id);
        endEvent.setName(name);
        return endEvent;
    }
    /**
     * 创建普通任务节点信息
     * @param mgProcinstNodes 节点信息
     * @return
     */
    public List<UserTask> createCommonUserTask(List<MgProcinstNode> mgProcinstNodes){
        List<MgProcinstNode> nodeList = mgProcinstNodes.stream().sorted((u1, u2) -> u1.getNodeSort().compareTo(u2.getNodeSort())).collect(Collectors.toList());
        List<UserTask> userTaskList = new ArrayList<>();
        for (int i = 0; i < nodeList.size(); i++) {
            MgProcinstNode node = nodeList.get(i);
            UserTask userTask = new UserTask();
            userTask.setId("task_" + node.getProcinstNodeId());
            userTask.setName(node.getRoleName());
            if (i > 0) {
                userTask.setName(userTask.getName());
            }else {
                userTask.setAssignee("${initiator}");
            }
            userTaskList.add(userTask);
        }
        return userTaskList;
    }

    /**
     * 创建监听类
     * @return
     */
    public List<FlowableListener> CreateTaskListeners(){
        List<FlowableListener> taskListeners = new ArrayList<>();
        FlowableListener listener = new FlowableListener();
        listener.setEvent("all");
        listener.setImplementationType("delegateExpression");
        listener.setImplementation("${permissinTaskListener}");
        //listener.setId("CATEGORYID_FILE_AUDIT_listener");
        taskListeners.add(listener);
        return taskListeners;
    }

    /**
     * 创建拍他网关节点
     * @return
     */
    private ExclusiveGateway createGateway(Integer i,String name){
        StringBuilder gateWayId = new StringBuilder(FlowableCommonConstant.GATEWAY_PREFIX);
        ExclusiveGateway gateway = new ExclusiveGateway();
        gateway.setName(name + "审批");
        gateway.setId(gateWayId.append(i).toString());
        return gateway;
    }
}

生成的流程图的样式,可以在控制中打印的xml中查看,也可以修改生成方式,直接下载



版权声明:本文为enhengguodong原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。