别再手动拖拽了!用Java代码生成Activiti流程图XML的保姆级教程
用Java代码生成Activiti流程图XML的实战指南
在传统的Activiti流程开发中,我们通常依赖Eclipse插件或在线设计器通过拖拽方式创建流程图。这种方式对于简单流程尚可接受,但当面对批量流程生成、动态流程配置或系统集成场景时,手动操作就显得力不从心。本文将彻底改变这一局面,带你掌握通过纯Java代码生成标准Activiti流程图XML的核心技术。
1. 环境准备与基础概念
在开始编码之前,我们需要明确几个关键概念。Activiti的流程图生成本质上是通过构建BPMN模型对象,再将其序列化为符合BPMN 2.0规范的XML文件。整个过程涉及两个核心模块:
- activiti-bpmn-model:提供BPMN模型的对象表示
- activiti-bpmn-converter:负责模型与XML的相互转换
创建Maven项目时,需添加以下依赖:
<dependency> <groupId>org.activiti</groupId> <artifactId>activiti-bpmn-model</artifactId> <version>6.0.0</version> </dependency> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-bpmn-converter</artifactId> <version>6.0.0</version> </dependency>提示:建议使用最新稳定版本,本文示例基于6.0.0版本,不同版本API可能略有差异。
2. 构建基础BPMN模型
让我们从创建一个最简单的流程开始——仅包含开始事件和结束事件。这是理解模型构建原理的最佳起点。
// 创建BPMN模型容器 BpmnModel bpmnModel = new BpmnModel(); // 创建流程定义 Process process = new Process(); process.setId("demoProcess"); bpmnModel.addProcess(process); // 添加开始事件 StartEvent startEvent = new StartEvent(); startEvent.setId("startEvent"); process.addFlowElement(startEvent); // 添加结束事件 EndEvent endEvent = new EndEvent(); endEvent.setId("endEvent"); process.addFlowElement(endEvent); // 添加顺序流连接 SequenceFlow flow = new SequenceFlow("startEvent", "endEvent"); flow.setId("flow1"); process.addFlowElement(flow);此时我们已经构建了完整的逻辑模型,但还缺少可视化的图形信息。接下来需要为每个元素添加GraphicInfo:
// 设置开始事件图形属性 GraphicInfo startGi = new GraphicInfo(); startGi.setX(100); startGi.setY(100); startGi.setWidth(30); startGi.setHeight(30); bpmnModel.addGraphicInfo("startEvent", startGi); // 设置结束事件图形属性 GraphicInfo endGi = new GraphicInfo(); endGi.setX(300); endGi.setY(100); endGi.setWidth(30); endGi.setHeight(30); bpmnModel.addGraphicInfo("endEvent", endGi); // 设置顺序流路径 List<GraphicInfo> flowPath = new ArrayList<>(); GraphicInfo point1 = new GraphicInfo(); point1.setX(130); point1.setY(115); flowPath.add(point1); GraphicInfo point2 = new GraphicInfo(); point2.setX(300); point2.setY(115); flowPath.add(point2); bpmnModel.addFlowGraphicInfoList("flow1", flowPath);3. 复杂流程元素的代码化实现
真实业务场景中的流程往往包含多种元素,下面我们构建一个包含用户任务、排他网关的完整审批流程。
3.1 用户任务与网关配置
// 创建用户任务 UserTask applyTask = new UserTask(); applyTask.setId("applyTask"); applyTask.setName("提交申请"); process.addFlowElement(applyTask); // 创建审批网关 ExclusiveGateway decisionGateway = new ExclusiveGateway(); decisionGateway.setId("decisionGateway"); process.addFlowElement(decisionGateway); // 创建审批任务 UserTask approveTask = new UserTask(); approveTask.setId("approveTask"); approveTask.setName("主管审批"); process.addFlowElement(approveTask); // 创建拒绝任务 UserTask rejectTask = new UserTask(); rejectTask.setId("rejectTask"); rejectTask.setName("申请驳回"); process.addFlowElement(rejectTask);3.2 条件顺序流配置
网关的分支需要配置条件表达式:
// 申请提交到网关的连线 SequenceFlow toGateway = new SequenceFlow("applyTask", "decisionGateway"); toGateway.setId("flowToGateway"); process.addFlowElement(toGateway); // 审批通过的连线 SequenceFlow approveFlow = new SequenceFlow("decisionGateway", "approveTask"); approveFlow.setId("flowApprove"); approveFlow.setConditionExpression("${approved == true}"); process.addFlowElement(approveFlow); // 审批拒绝的连线 SequenceFlow rejectFlow = new SequenceFlow("decisionGateway", "rejectTask"); rejectFlow.setId("flowReject"); rejectFlow.setConditionExpression("${approved == false}"); process.addFlowElement(rejectFlow);3.3 图形布局策略
对于复杂流程,合理的图形布局至关重要。以下是推荐的位置计算方式:
| 元素类型 | 初始X坐标 | Y坐标 | 宽度 | 高度 |
|---|---|---|---|---|
| 开始事件 | 100 | 150 | 30 | 30 |
| 用户任务 | 200 | 125 | 100 | 80 |
| 网关 | 350 | 140 | 40 | 40 |
| 结束事件 | 500 | 150 | 30 | 30 |
实现代码示例:
// 设置申请任务位置 GraphicInfo applyGi = new GraphicInfo(); applyGi.setX(200); applyGi.setY(125); applyGi.setWidth(100); applyGi.setHeight(80); bpmnModel.addGraphicInfo("applyTask", applyGi); // 设置网关位置 GraphicInfo gatewayGi = new GraphicInfo(); gatewayGi.setX(350); gatewayGi.setY(140); gatewayGi.setWidth(40); gatewayGi.setHeight(40); bpmnModel.addGraphicInfo("decisionGateway", gatewayGi);4. 高级技巧与最佳实践
4.1 动态生成复杂流程
对于需要根据业务数据动态生成流程的场景,可以采用模板方法:
public BpmnModel generateDynamicProcess(List<TaskDefinition> tasks) { BpmnModel model = new BpmnModel(); Process process = new Process(); process.setId("dynamicProcess"); model.addProcess(process); // 添加开始事件 StartEvent startEvent = addStartEvent(process); // 动态添加任务节点 FlowElement previous = startEvent; for (int i = 0; i < tasks.size(); i++) { UserTask task = new UserTask(); task.setId(tasks.get(i).getId()); task.setName(tasks.get(i).getName()); process.addFlowElement(task); // 添加连线 SequenceFlow flow = new SequenceFlow(previous.getId(), task.getId()); process.addFlowElement(flow); // 设置图形位置 GraphicInfo gi = new GraphicInfo(); gi.setX(200 + i * 150); gi.setY(100); gi.setWidth(100); gi.setHeight(80); model.addGraphicInfo(task.getId(), gi); previous = task; } // 添加结束事件和最后连线 EndEvent endEvent = addEndEvent(process); SequenceFlow lastFlow = new SequenceFlow(previous.getId(), endEvent.getId()); process.addFlowElement(lastFlow); return model; }4.2 流程元素的复用
对于常用元素如开始/结束事件,可以创建构建器类:
public class BpmnBuilder { private final BpmnModel model; private final Process process; public BpmnBuilder(String processId) { this.model = new BpmnModel(); this.process = new Process(); this.process.setId(processId); this.model.addProcess(process); } public StartEvent addStartEvent() { StartEvent event = new StartEvent(); event.setId("startEvent"); process.addFlowElement(event); GraphicInfo gi = new GraphicInfo(); gi.setX(100); gi.setY(100); gi.setWidth(30); gi.setHeight(30); model.addGraphicInfo(event.getId(), gi); return event; } // 其他构建方法... }4.3 XML生成与验证
最终生成XML并验证其正确性:
BpmnXMLConverter converter = new BpmnXMLConverter(); byte[] xmlBytes = converter.convertToXML(model); // 验证XML是否符合规范 try { InputStream xmlStream = new ByteArrayInputStream(xmlBytes); BpmnModel parsedModel = converter.convertToBpmnModel(xmlStream, true, true); System.out.println("验证成功,生成的XML有效"); } catch (Exception e) { System.err.println("XML验证失败: " + e.getMessage()); } // 保存到文件 Files.write(Paths.get("process.bpmn20.xml"), xmlBytes);在实际项目中,我们通常会将这些代码封装成流程服务,结合业务规则动态生成各种审批流程。我曾在一个电商平台项目中用这种方式实现了售后流程的自动配置,根据商品类别、价格区间等参数生成不同的审批路径,大大提升了流程配置的灵活性。
