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;
}
}