Activity7动态创建工作流
package org.example.core; import org.activiti.bpmn.converter.BpmnXMLConverter; import org.activiti.bpmn.model.Process; import org.activiti.engine.RepositoryService; import org.activiti.engine.RuntimeService; import org.activiti.engine.delegate.ExecutionListener; import org.activiti.engine.delegate.TaskListener; import org.activiti.engine.repository.Deployment; import org.activiti.bpmn.model.*; import org.apache.commons.io.FileUtils; import org.example.listener.FlowEndListener; import org.example.listener.TaskCompleteListener; import org.example.listener.TaskCreateListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.File; import java.io.IOException; import java.util.*; /** * 动态Bpmn服务 */ @Service public class DynamicWorkflowService { @Autowired private RepositoryService repositoryService;/** * 动态创建和部署工作流 */ public void createWorkflowAndDeploy() { // 创建一个新的BPMN模型 BpmnModel bpmnModel = new BpmnModel(); Process process = new Process(); bpmnModel.addProcess(process); process.setId("flowDefId"); process.setName("流程名称"); // 添加开始事件 StartEvent startEvent = new StartEvent(); startEvent.setId("START"); startEvent.setName("开始"); process.addFlowElement(startEvent); // 添加用户任务 UserTask userTask1 = createUserTask("userTask1", "User Task 1", "user1"); process.addFlowElement(userTask1); UserTask userTask2 = createUserTask("userTask2", "User Task 2", "user2"); process.addFlowElement(userTask2); UserTask userTask3 = createUserTask("userTask3", "User Task 3", "user3"); process.addFlowElement(userTask3); // 添加结束事件 EndEvent endEvent = createEndEvent("END", "结束"); process.addFlowElement(endEvent); // 添加顺序流转 SequenceFlow sequenceFlow1 = new SequenceFlow("START", "userTask1"); sequenceFlow1.setId("flow1"); SequenceFlow sequenceFlow2 = new SequenceFlow("userTask1", "userTask2"); sequenceFlow2.setId("flow2"); sequenceFlow2.setName("通过"); SequenceFlow sequenceFlow3 = new SequenceFlow("userTask2", "userTask3"); sequenceFlow3.setId("flow3"); sequenceFlow3.setName("通过"); SequenceFlow sequenceFlow4 = new SequenceFlow("userTask3", "END"); sequenceFlow4.setId("flow4"); sequenceFlow4.setName("通过"); SequenceFlow rejectFlow1 = new SequenceFlow("userTask2", "userTask1"); rejectFlow1.setName("驳回"); rejectFlow1.setId("rejectFlow1"); SequenceFlow rejectFlow2 = new SequenceFlow("userTask3", "END"); rejectFlow2.setName("驳回"); rejectFlow2.setId("rejectFlow2"); process.addFlowElement(sequenceFlow1); process.addFlowElement(sequenceFlow2); process.addFlowElement(sequenceFlow3); process.addFlowElement(sequenceFlow4); process.addFlowElement(rejectFlow1); process.addFlowElement(rejectFlow2); List<String> taskNodeIds = Arrays.asList(userTask1.getId(), userTask2.getId(), userTask3.getId()); List<String> flowIds = Arrays.asList(sequenceFlow1.getId(), sequenceFlow2.getId(), sequenceFlow3.getId(), sequenceFlow4.getId()); List<SequenceFlow> rejectFlows = Arrays.asList(rejectFlow1, rejectFlow2); addBpmnDiInfo(bpmnModel, taskNodeIds, flowIds, rejectFlows); // 将BPMN模型转换为XML格式 BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter(); byte[] bpmnBytes = bpmnXMLConverter.convertToXML(bpmnModel); // 将BPMN XML保存到文件系统 try { FileUtils.writeByteArrayToFile(new File("dynamic-process.bpmn20.xml"), bpmnBytes); } catch (IOException ex) { ex.printStackTrace(); } // 部署BPMN模型 Deployment deployment = repositoryService.createDeployment() .addBytes("dynamic-process.bpmn20.xml", bpmnBytes) .name("Dynamic Process Deployment") .deploy(); } private UserTask createUserTask(String id, String name, String assignee) { UserTask userTask = new UserTask(); userTask.setId(id); userTask.setName(name); userTask.setAssignee(assignee); // 添加任务创建事件监听器 ActivitiListener createListener = new ActivitiListener(); createListener.setEvent(TaskListener.EVENTNAME_CREATE); createListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_CLASS); createListener.setImplementation(TaskCreateListener.class.getName()); userTask.getTaskListeners().add(createListener); // 添加任务完成事件监听器 ActivitiListener completeListener = new ActivitiListener(); completeListener.setEvent(TaskListener.EVENTNAME_COMPLETE); completeListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_CLASS); completeListener.setImplementation(TaskCompleteListener.class.getName()); userTask.getTaskListeners().add(completeListener); return userTask; } private EndEvent createEndEvent(String id, String name) { EndEvent endEvent = new EndEvent(); endEvent.setId(id); endEvent.setName(name); // 添加执行结束事件监听器 ActivitiListener endListener = new ActivitiListener(); endListener.setEvent(ExecutionListener.EVENTNAME_END); endListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_CLASS); endListener.setImplementation(FlowEndListener.class.getName()); endEvent.getExecutionListeners().add(endListener); return endEvent; } private static void addBpmnDiInfo(BpmnModel model, List<String> taskNodeIds, List<String> flowIds, List<SequenceFlow> rejectFlows) { double x = 100; double y = 100; double startEndWidth = 30; double startEndHeight = 30; double taskWidth = 100; double taskHeight = 60; double gap = 100; double startX = x; double startEndY = y + (taskHeight - startEndHeight) / 2.0; //画节点 model.addGraphicInfo("START", createGraphicInfo(startX, startEndY, startEndWidth, startEndHeight)); x = x + startEndWidth + gap; for (String taskNodeId : taskNodeIds) { model.addGraphicInfo(taskNodeId, createGraphicInfo(x, y, taskWidth, taskHeight)); x = x + taskWidth + gap; } model.addGraphicInfo("END", createGraphicInfo(x, startEndY, startEndWidth, startEndHeight)); //画前进线 double point1X = startX + startEndWidth; double pointY = y + taskHeight / 2.0; double point2X = point1X + gap; for (String flowId : flowIds) { model.addFlowGraphicInfoList(flowId, createFlowGraphicInfo(point1X, pointY, point2X, pointY)); point1X = (point2X + taskWidth); point2X = (point1X + gap); } //画后退线 int rejectHeightGap = 30; int i = 0; for (SequenceFlow rejectFlow : rejectFlows) { String fromTaskNodeId = rejectFlow.getSourceRef(); String toTaskNodeId = rejectFlow.getTargetRef(); int formIndex = taskNodeIds.indexOf(fromTaskNodeId); int toIndex = taskNodeIds.indexOf(toTaskNodeId); double x1 = getRejectStartX(startEndWidth, taskWidth, gap, startX, formIndex); double y1 = y + taskHeight; double x2 = x1; double y2 = y1 + 30 + i * rejectHeightGap; double x4 = getRejectEndX(startEndWidth, taskWidth, gap, startX, toIndex, taskNodeIds.size()); double y4 = y1; double x3 = x4; double y3 = y2; model.addFlowGraphicInfoList(rejectFlow.getId(), createFlowGraphicInfo(x1, y1, x2, y2, x3, y3, x4, y4)); i++; } } private static double getRejectStartX(double startEndWidth, double taskWidth, double gap, double startX, int taskIndex) { return startX + startEndWidth + (taskIndex + 1) * gap + taskIndex * taskWidth + taskWidth / 2.0; } private static double getRejectEndX(double startEndWidth, double taskWidth, double gap, double startX, int taskIndex, int taskSize) { if (taskIndex != -1) { //打回到指定任务 return getRejectStartX(startEndWidth, taskWidth, gap, startX, taskIndex); } else { //打回到结束 return startX + startEndWidth + (taskSize + 1) * gap + taskSize * taskWidth + startEndWidth / 2.0; } } private static GraphicInfo createGraphicInfo(double x, double y, double width, double height) { GraphicInfo graphicInfo = new GraphicInfo(); graphicInfo.setX(x); graphicInfo.setY(y); graphicInfo.setWidth(width); graphicInfo.setHeight(height); return graphicInfo; } private static List<GraphicInfo> createFlowGraphicInfo(double... waypoints) { List<GraphicInfo> flowGraphicInfoList = new ArrayList<>(); for (int i = 0; i < waypoints.length; i += 2) { GraphicInfo graphicInfo = new GraphicInfo(); graphicInfo.setX(waypoints[i]); graphicInfo.setY(waypoints[i + 1]); flowGraphicInfoList.add(graphicInfo); } return flowGraphicInfoList; } }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [翻译] 为什么 Tracebit 用 C# 开发
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· 刚刚!百度搜索“换脑”引爆AI圈,正式接入DeepSeek R1满血版