flowable动态创建多级流程

  1. 引入Maven依赖

    <dependency>    <groupId>org.flowable</groupId>    <artifactId>flowable-spring-boot-starter</artifactId>    <version>6.6.0</version></dependency>
  2. 动态创建流程节点工具类

    /** * 动态创建流程节点 */@Slf4j@Component@RequiredArgsConstructorpublic class FlowableBpmnHandler {    /**     * 创立开始节点信息     *     * @return     */    public static FlowElement createStartFlowElement(String id, String name) {        StartEvent startEvent = new StartEvent();        startEvent.setId(id);        startEvent.setName(name);        return startEvent;    }    /**     * 创立完结节点信息     *     * @param id     * @param name     * @return     */    public static FlowElement createEndFlowElement(String id, String name) {        EndEvent endEvent = new EndEvent();        endEvent.setId(id);        endEvent.setName(name);        return endEvent;    }    /**     * 循环创立一般工作节点信息     *     * @param processEntity 流程实体     * @return     */    public static List<UserTask> createCommonUserTask(ProcessEntity processEntity) {        List<ProcessNode> processNodes = processEntity.getProcessNodeList();        List<UserTask> userTaskList = Lists.newLinkedList();        for (int i = 0; i < processNodes.size(); i++) {            ProcessNode node = processNodes.get(i);            node.setNodeId(UUIDHelper.randomUUID());            node.setNodeLevel(i + 1);            UserTask userTask = new UserTask();            userTask.setId(TypeEnum.getProcessKey(processEntity.getType()) + "_task_" + node.getNodeId());            userTask.setCategory(String.valueOf(i + 1));            userTask.setDocumentation(i == processNodes.size() - 1 ? "true" : "false");            userTask.setName(node.getNodeName());            userTaskList.add(userTask);        }        return userTaskList;    }    /**     * 创立排它网关节点     *     * @return     */    public static ExclusiveGateway createExclusiveGateway(Integer i) {        ExclusiveGateway gateway = new ExclusiveGateway();        gateway.setName("getaway_name_" + i);        gateway.setId("getaway_id_" + i);        return gateway;    }}
  3. 动态创建流程模板工具类

    /** * 动态创建流程模板 * * @author ll * @date 2023/04/19 14:28 **/@Slf4j@Componentpublic class DynamicProcessDefinition {    @Resource    private RepositoryService repositoryService;    public String createProcessDefinition(ProcessEntity processEntity) {        //数据校验:传入的数据节点字段:流程配置id、节点id、节点程序、节点形容        List<ProcessNode> nodeList = processEntity.getProcessNodeList();        if (CollUtil.isEmpty(nodeList)) {            throw new RuntimeException("流程节点不能少于一个,请配置发起人节点和至多一个审批节点");        }        BpmnModel bpmnModel = new BpmnModel();        Process process = new Process();        bpmnModel.addProcess(process);        // 流程标识        process.setId(TypeEnum.getProcessKey(processEntity.getType()));        process.setName(TypeEnum.getProcessKey(processEntity.getType()));        //开始事件        FlowElement startEvent = FlowableBpmnHandler.createStartFlowElement("start", "开始");        process.addFlowElement(startEvent);        //完结事件--工作失常实现        FlowElement endEvent = FlowableBpmnHandler.createEndFlowElement("end", "完结");        process.addFlowElement(endEvent);        //创立用户节点工作        List<UserTask> userTaskList = FlowableBpmnHandler.createCommonUserTask(processEntity);        //构建流程模板        buildProcessTemplate(process, startEvent, endEvent, userTaskList);        //该流程的流程xml字符串        //BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();        //byte[] convertToXML = bpmnXMLConverter.convertToXML(bpmnModel);        //String bytes = new String(convertToXML);        //log.info("该流程的流程xml为:{}", bytes);        // 创立一个新的部署        Deployment deploy = repositoryService.createDeployment().key(TypeEnum.getProcessKey(processEntity.getType()))                .name(TypeEnum.getProcessKey(processEntity.getType()))                .addBpmnModel(TypeEnum.getProcessKey(processEntity.getType()) + ".bpmn", bpmnModel)                .deploy();        log.info("部署id:{}", deploy.getId());        return deploy.getId();    }    /**     * 构建流程模板     *     * @param process     * @param startEvent     * @param endEvent     * @param userTaskList     * @return void     * @author ll     * @date 2023/04/24 08:53     */    private void buildProcessTemplate(Process process, FlowElement startEvent, FlowElement endEvent, List<UserTask> userTaskList) {        for (int i = 0; i < userTaskList.size(); i++) {            //用户工作            UserTask userTask = userTaskList.get(i);            process.addFlowElement(userTask);            //创立排它网关节点            ExclusiveGateway exclusiveGateway = FlowableBpmnHandler.createExclusiveGateway(i);            process.addFlowElement(exclusiveGateway);            //开始事件到第一个节点            if (i == 0) {                // 开始节点到第一级节点                SequenceFlow startSequenceFlow = new SequenceFlow(startEvent.getId(), userTask.getId());                process.addFlowElement(startSequenceFlow);            }            //用户工作到网关节点            SequenceFlow sequenceFlow = new SequenceFlow(userTask.getId(), exclusiveGateway.getId());            sequenceFlow.setName(userTask.getName() + "_开始审批");            process.addFlowElement(sequenceFlow);            //批准:取下一步用户工作的节点id,可能为完结节点或者用户工作节点            String nextUserTaskId = endEvent.getId();            if (userTaskList.size() - i > 1) {                nextUserTaskId = userTaskList.get(i + 1).getId();            }            SequenceFlow sequenceFlowAgree = new SequenceFlow(exclusiveGateway.getId(), nextUserTaskId);            sequenceFlowAgree.setConditionExpression("${auditResult}");            sequenceFlowAgree.setName("批准");            process.addFlowElement(sequenceFlowAgree);            //不批准:回退到上一步,取上一步的节点id            String preUserTaskId = userTaskList.get(0).getId();            if (i != 0) {                preUserTaskId = userTaskList.get(i - 1).getId();            }            SequenceFlow sequenceFlowRefuse = new SequenceFlow(exclusiveGateway.getId(), preUserTaskId);            sequenceFlowRefuse.setConditionExpression("${!auditResult}");            sequenceFlowRefuse.setName("回绝");            process.addFlowElement(sequenceFlowRefuse);        }    }}
  4. 保留流程配置模板的接口

    @Resourceprivate DynamicProcessDefinition dynamicProcessDefinition;@RequestMapping("/save")public Result<String> save(@RequestBody ProcessEntity processEntity) {    return dynamicProcessDefinition.createProcessDefinition(processEntity);;}
  5. 开启流程接口

        @RequestMapping("/start")    public String start(@RequestBody AuditData auditData) {                //业务本人定义key        String businessKey = auditData.getBusinessKey();        //流程定义key        String processKey = auditData.getType();        // 判断是否启动流程        boolean isStartProcess = null != runtimeService.createProcessInstanceQuery()                .processDefinitionKey(processKey)                .processInstanceBusinessKey(businessKey)                .singleResult();        if (!isStartProcess) {            //记录开启流程的用户            HashMap<String, Object> variable = Maps.newHashMap();            //启动流程            ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey, businessKey, variable);            log.info("启动流程实例胜利:processInstanceId={}", processInstance.getId());        }        return !isStartProcess ? "流程启动胜利" : "流程启动失败";    }