03.flowable 流程模板部署

该博客主要介绍了如何进行模型的部署操作,包括根据modelId获取模型信息,转换为XML对象,修正过程ID,并针对不同租户进行部署。此外,还涉及了流程分类设置和异常处理。整个过程涉及到BPMN模型的转换、流程引擎的使用以及数据库操作。

1.演示

在这里插入图片描述
2.代码

@Override
    @Transactional
    public Object modelDeploy(ReqModel reqModel) throws IllegalAccessException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, ClassNotFoundException {
        /**
         * 1.根据modelId获取模型信息
         * 2.转换为xml对象
         * 3.部署对象以模型对象的名称命名
         * 4.部署转换出来的xml对象
         * */
        RetBean retbean = new RetBean();
        FlowModel model = this.queryFlowModelById(reqModel.getModelId());
        if (model == null) {
            return retbean.backError("No model found with the given id: " + reqModel.getModelId());
        }
        BpmnModel bpmnModel = getBpmnModel(model);
        for (Process process : bpmnModel.getProcesses()) {
            if (StringUtils.isNotEmpty(process.getId())) {
                char firstCharacter = process.getId().charAt(0);
                if (Character.isDigit(firstCharacter)) {
                    process.setId("a" + process.getId());
                }
            }
        }
        byte[] bytes = BPMN_XML_CONVERTER.convertToXML(bpmnModel);
        String processName = model.getName();
        if (!StringUtil.endsWithIgnoreCase(processName, FlowEngineConstant.SUFFIX)) {
            processName += FlowEngineConstant.SUFFIX;
        }
        String finalProcessName = processName;
        String[] ids = null;
        if (!StringUtil.isEmpty(reqModel.getTenantIds())) {
            ids = reqModel.getTenantIds().split(",");
        }
        if (!StringUtil.isEmpty(ids)) {
            for (String tenantId : ids) {
                Deployment deployment = repositoryService.createDeployment().addBytes(finalProcessName, bytes).name(model.getName()).key(model.getModel_key()).tenantId(tenantId).deploy();
                deploy(deployment, reqModel.getCategory());
            }
        } else {
            Deployment deployment = repositoryService.createDeployment().addBytes(finalProcessName, bytes).name(model.getName()).key(model.getModel_key()).deploy();
            deploy(deployment, reqModel.getCategory());
        }
        return retbean;
    }

	private BpmnModel getBpmnModel(FlowModel model) throws IllegalAccessException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, ClassNotFoundException {
        BpmnModel bpmnModel;
        try {
            Map<String, FlowModel> formMap = new HashMap<>(16);
            Map<String, FlowModel> decisionTableMap = new HashMap<>(16);
            List<FlowModel> referencedModels = this.findByParentModelId(model.getId());
            for (FlowModel childModel : referencedModels) {
                if (FlowModel.MODEL_TYPE_FORM == childModel.getModel_type()) {
                    formMap.put(childModel.getId(), childModel);
                } else if (FlowModel.MODEL_TYPE_DECISION_TABLE == childModel.getModel_type()) {
                    decisionTableMap.put(childModel.getId(), childModel);
                }
            }
            bpmnModel = getBpmnModel(model, formMap, decisionTableMap);
        } catch (Exception e) {
            throw new ServiceException("Could not generate BPMN 2.0 model");
        }
        return bpmnModel;
    }


    private BpmnModel getBpmnModel(FlowModel model, Map<String, FlowModel> formMap, Map<String, FlowModel> decisionTableMap) throws JsonProcessingException {
        ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(model.getModel_editor_json());
        Map<String, String> formKeyMap = new HashMap<>(16);
        for (FlowModel formModel : formMap.values()) {
            formKeyMap.put(formModel.getId(), formModel.getModel_key());
        }
        Map<String, String> decisionTableKeyMap = new HashMap<>(16);
        for (FlowModel decisionTableModel : decisionTableMap.values()) {
            decisionTableKeyMap.put(decisionTableModel.getId(), decisionTableModel.getModel_key());
        }
        return BPMN_JSON_CONVERTER.convertToBpmnModel(editorJsonNode, formKeyMap, decisionTableKeyMap);
    }

 private boolean deploy(Deployment deployment, String category) {
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list();
        // 设置流程分类
        for (ProcessDefinition processDefinition : list) {
            if (StringUtil.isNotBlank(category)) {
                repositoryService.setProcessDefinitionCategory(processDefinition.getId(), category);
            }

        }
        if (list.size() == 0) {
            throw new ServiceException("部署失败,未找到流程");
        } else {
            return true;
        }
    }
<think>我们正在详细讨论Flowable流程从定义到结束的完整生命周期。以下将分步骤详细说明: 1. **流程定义(流程模板)**: - 使用BPMN 2.0标准定义流程,通常以XML文件(如`leave.bpmn20.xml`)存储。 - 流程定义包含节点(任务、网关等)、顺序流、变量定义等。 - 通过`RepositoryService`部署流程定义,将其存入数据库(如`ACT_RE_PROCDEF`表)。 2. **启动流程实例**: - 使用`RuntimeService`根据流程定义的key或id启动一个流程实例。 - 启动时可设置初始流程变量(全局变量)。 - 流程实例启动后,会在运行时表(如`ACT_RU_EXECUTION`)中创建一条记录。 3. **节点任务处理**: - 流程启动后,第一个节点(通常为用户任务)会被激活。 - 任务信息存储在`ACT_RU_TASK`表中。 - 使用`TaskService`查询任务(如根据处理人),处理任务(如完成、设置变量)。 4. **节点流转**: - 任务完成后,引擎根据顺序流(Sequence Flow)和网关(Gateway)条件决定下一节点。 - 条件表达式可使用流程变量(如`${approved == true}`)。 - 流程实例状态在运行时表(`ACT_RU_*`)中实时更新。 5. **流程结束**: - 当流程到达结束事件(End Event)时,流程实例终止。 - 运行时数据(`ACT_RU_*`)被清除,历史数据写入历史表(`ACT_HI_*`)。 - 可通过`HistoryService`查询历史流程实例。 下面是一个简化的代码示例,展示从部署流程结束的关键步骤: ```java // 1. 部署流程定义 RepositoryService repositoryService = processEngine.getRepositoryService(); Deployment deployment = repositoryService.createDeployment() .addClasspathResource("processes/leave.bpmn20.xml") .deploy(); // 2. 启动流程实例 RuntimeService runtimeService = processEngine.getRuntimeService(); Map<String, Object> variables = new HashMap<>(); variables.put("applicant", "张三"); ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leaveProcess", variables); // 3. 查询并完成任务 TaskService taskService = processEngine.getTaskService(); Task task = taskService.createTaskQuery() .processInstanceId(processInstance.getId()) .singleResult(); // 设置任务变量(局部变量)并完成 taskService.setVariable(task.getId(), "approved", true); taskService.complete(task.getId()); // 4. 流程结束:自动清理运行时数据,写入历史表 ``` **关键表说明**: - **流程定义**:`ACT_RE_PROCDEF`(存储部署流程定义)。 - **运行时**:`ACT_RU_EXECUTION`(流程实例执行信息),`ACT_RU_TASK`(任务信息),`ACT_RU_VARIABLE`(运行时变量)。 - **历史**:`ACT_HI_PROCINST`(流程实例历史),`ACT_HI_TASKINST`(任务历史),`ACT_HI_VARINST`(历史变量)。 **相关问题**: 1. Flowable中如何查询历史流程实例的结束时间? 2. 如何在流程实例运行时修改流程变量? 3. Flowable的网关(如排他网关、并行网关)如何影响流程流转? </think>以下详细说明 Flowable 工作流从流程模板到实例结束的完整生命周期过程,结合关键代码和存储结构: --- ### **一、生命周期全流程详解** #### 1. **流程定义(模板部署)** - **本质**:将 BPMN 2.0 XML 文件解析为可执行模型 - **存储表**:`ACT_RE_PROCDEF`(流程定义元数据) - **部署代码**: ```java RepositoryService repoService = processEngine.getRepositoryService(); Deployment deployment = repoService.createDeployment() .addClasspathResource("leave-process.bpmn20.xml") // BPMN文件 .name("请假流程") .deploy(); // 部署后生成流程定义ID ``` #### 2. **启动流程实例** - **触发条件**:通过 API 或事件触发 - **运行时存储**: - `ACT_RU_EXECUTION`(执行流) - `ACT_RU_VARIABLE`(初始流程变量) - **启动代码**: ```java RuntimeService runtimeService = processEngine.getRuntimeService(); Map<String, Object> vars = new HashMap<>(); vars.put("applicant", "张三"); vars.put("days", 3); // 根据流程定义KEY启动 ProcessInstance instance = runtimeService.startProcessInstanceByKey( "leaveProcess", // 流程定义KEY vars // 全局变量 ); ``` #### 3. **节点任务激活** - **运行时行为**: 1. 引擎定位当前节点(如用户任务) 2. 创建任务记录:`ACT_RU_TASK` 3. 分配任务处理人(Assignee) - **任务查询**: ```java TaskService taskService = processEngine.getTaskService(); List<Task> tasks = taskService.createTaskQuery() .processInstanceId(instance.getId()) // 按实例ID过滤 .taskAssignee("李四") // 按处理人过滤 .list(); ``` #### 4. **节点流转** - **驱动机制**: - **完成任务**:触发离开当前节点 ```java taskService.complete(task.getId()); // 无变量更新 ``` - **条件网关**:基于变量值分支 ```xml <!-- BPMN 示例:排他网关 --> <sequenceFlow id="flow1" sourceRef="approveTask" targetRef="hrTask"> <conditionExpression xsi:type="tFormalExpression"> ${approved == true} <!-- 变量驱动条件 --> </conditionExpression> </sequenceFlow> ``` #### 5. **流程结束** - **终止条件**:到达结束事件(End Event) - **数据迁移**: - 运行时表(`ACT_RU_*`)数据删除 - 历史表(`ACT_HI_*`)持久化记录: - `ACT_HI_PROCINST`(流程实例历史) - `ACT_HI_TASKINST`(任务历史) - **状态验证**: ```java if (instance.isEnded()) { HistoricProcessInstance histInstance = historyService .createHistoricProcessInstanceQuery() .processInstanceId(instance.getId()) .singleResult(); // 查询历史记录 } ``` --- ### **二、核心存储表说明** | **阶段** | **关键表** | **存储内容** | |------------------|----------------------|--------------------------------| | **定义阶段** | `ACT_RE_PROCDEF` | 流程定义ID、版本、KEY | | **运行时** | `ACT_RU_EXECUTION` | 当前执行路径 | | | `ACT_RU_TASK` | 待处理任务详情 | | | `ACT_RU_VARIABLE` | 流程实例全局变量 [^1] | | **历史记录** | `ACT_HI_PROCINST` | 已结束的流程实例 | | | `ACT_HI_TASKINST` | 已完成的任务记录 | | | `ACT_HI_VARINST` | 历史变量快照 [^2] | --- ### **三、典型流程示例(请假审批)** ```mermaid graph LR A[启动] --> B(提交申请) B --> C{经理审批} C -- 批准 --> D[HR备案] C -- 拒绝 --> E[修改申请] D --> F[结束] E --> B ``` 1. **启动实例**:设置 `applicant="张三", days=3` 2. **经理审批**:任务存入 `ACT_RU_TASK`,Assignee="李四" 3. **决策分支**: - `approved=true` → 流向 HR 节点 - `approved=false` → 返回申请节点 4. **流程结束**:数据从 `ACT_RU_*` 迁移至 `ACT_HI_*` --- ### **四、相关问题** 1. Flowable 如何保证流程实例的状态一致性? 2. 如何在流程运行过程中动态修改流程变量? 3. 网关(Gateway)有哪些类型?各自的使用场景是什么? 4. 历史表 `ACT_HI_VARINST` 存储变量的具体机制是什么?[^2] 5. 流程实例暂停和恢复的操作如何实现? [^1]: 运行时变量存储在 `ACT_RU_VARIABLE` 表 [^2]: 历史变量快照机制参考 `ACT_HI_VARINST` 表结构
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值