1 问题引入
这应该是一篇十分小众的文章,能找见这篇文章的同学,应该对审批流框架Flowable和bpmn-js都有所了解,所以对一些基础知识就不做过多介绍,直接说问题。
在利用ruoyi-vue-pro项目做审批流,通过流程定义id获取流程的xml文档,前端bpmn-js通过拿到的xml文档,显示对应的流程图,在显示流程图时,排他网关菱形中间的'X'丢失。其中flowable的版本是6.8.1,bpmn-js的版本是11.5.0。
1.1 引用flowable的Maven
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-process</artifactId>
<version>6.8.1</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-actuator</artifactId>
<version>6.8.1</version>
</dependency>
1.2 后端生成xml核心代码
public String getProcessDefinitionBpmnXML(String id) {
BpmnModel bpmnModel = repositoryService.getBpmnModel(id);
if (bpmnModel == null) {
return null;
}
BpmnXMLConverter converter = new BpmnXMLConverter();
return StrUtil.utf8Str(converter.convertToXML(bpmnModel));
}
1.3 后端获取model的xml代码
public BpmModelRespVO getModel(String id) {
Model model = repositoryService.getModel(id);
if (model == null) {
return null;
}
BpmModelRespVO modelRespVO = BpmModelConvert.INSTANCE.convert(model);
// 拼接 bpmn XML
byte[] bpmnBytes = repositoryService.getModelEditorSource(id);
modelRespVO.setBpmnXml(StrUtil.utf8Str(bpmnBytes));
return modelRespVO;
}
1.4 bpmn-js显示流程图的example
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/assets/bpmn-js.css">
<!-- viewer distro (with pan and zoom) -->
<script src="https://unpkg.com/[email protected]/dist/bpmn-navigated-viewer.development.js"></script>
<!-- needed for this example only -->
<script src="https://unpkg.com/[email protected]/dist/jquery.js"></script>
<!-- example styles -->
<style>
html, body, #canvas {
height: 100%;
padding: 0;
margin: 0;
}
.diagram-note {
background-color: rgba(66, 180, 21, 0.7);
color: White;
border-radius: 5px;
font-family: Arial;
font-size: 12px;
padding: 5px;
min-height: 16px;
width: 50px;
text-align: center;
}
.needs-discussion:not(.djs-connection) .djs-visual > :nth-child(1) {
stroke: rgba(66, 180, 21, 0.7) !important; /* color elements as red */
}
</style>
</head>
<body>
<div id="canvas"></div>
<script>
//var diagramUrl = 'http://localhost:8088/honor/oa/api/v1/bpm/process-definition/get-bpmn-xml?id=zgr-test1:2:90dc0bc9-ca14-11ed-a5a9-12a5bcdcfbee';
//var diagramUrl = 'https://cdn.staticaly.com/gh/bpmn-io/bpmn-js-examples/dfceecba/starter/diagram.bpmn';
var diagramUrl = 'http://localhost:8888/honor/oa/api/v1/bpm/model/get?id=7f939a50-c980-11ed-af1d-c6eeaec5e8bb';
// viewer instance
var bpmnViewer = new BpmnJS({
container: '#canvas'
});
// console.log(xml);
async function openDiagram(bpmnXML) {
console.log(bpmnXML.data);
// import diagram
try {
await bpmnViewer.importXML(bpmnXML.data);
// access viewer components
var canvas = bpmnViewer.get('canvas');
var overlays = bpmnViewer.get('overlays');
// zoom to fit full viewport
canvas.zoom('fit-viewport');
} catch (err) {
console.error('could not import BPMN 2.0 diagram', err);
}
}
// load external diagram file via AJAX and open it
$.get(diagramUrl, openDiagram, 'json');
</script>
</body>
</html>
1.5 正常的流程图
1.5.1 通过1.3接口获取的是流程最新的模型图
1.5.2 对应的xml文档
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_0001" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:process id="zgr-test1" name="测试条件走向" isExecutable="true">
<bpmn:startEvent id="Event_0a6bsya">
<bpmn:outgoing>Flow_0454chc</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:userTask id="Activity_0pfz1cb" name="第一">
<bpmn:incoming>Flow_0454chc</bpmn:incoming>
<bpmn:outgoing>Flow_02g6tt4</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_0454chc" sourceRef="Event_0a6bsya" targetRef="Activity_0pfz1cb" />
<bpmn:exclusiveGateway id="Gateway_1q7504o" default="Flow_1wu0khg">
<bpmn:incoming>Flow_02g6tt4</bpmn:incoming>
<bpmn:outgoing>Flow_1wu0khg</bpmn:outgoing>
<bpmn:outgoing>Flow_0rdv9v5</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_02g6tt4" sourceRef="Activity_0pfz1cb" targetRef="Gateway_1q7504o" />
<bpmn:userTask id="Activity_19w1ng8" name="第二">
<bpmn:incoming>Flow_1wu0khg</bpmn:incoming>
<bpmn:outgoing>Flow_1d0b1lk</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_1wu0khg" sourceRef="Gateway_1q7504o" targetRef="Activity_19w1ng8" />
<bpmn:endEvent id="Event_14e42yk">
<bpmn:incoming>Flow_1d0b1lk</bpmn:incoming>
<bpmn:incoming>Flow_0rdv9v5</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1d0b1lk" sourceRef="Activity_19w1ng8" targetRef="Event_14e42yk" />
<bpmn:sequenceFlow id="Flow_0rdv9v5" sourceRef="Gateway_1q7504o" targetRef="Event_14e42yk">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=${day>3}</bpmn:conditionExpression>
</bpmn:sequenceFlow>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="zgr-test1">
<bpmndi:BPMNShape id="Event_0a6bsya_di" bpmnElement="Event_0a6bsya">
<dc:Bounds x="222" y="202" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0pfz1cb_di" bpmnElement="Activity_0pfz1cb">
<dc:Bounds x="358" y="170" width="100" height="100" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_1q7504o_di" bpmnElement="Gateway_1q7504o" isMarkerVisible="true">
<dc:Bounds x="558" y="195" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_19w1ng8_di" bpmnElement="Activity_19w1ng8">
<dc:Bounds x="708" y="170" width="100" height="100" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_14e42yk_di" bpmnElement="Event_14e42yk">
<dc:Bounds x="908" y="202" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0454chc_di" bpmnElement="Flow_0454chc">
<di:waypoint x="258" y="220" />
<di:waypoint x="358" y="220" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_02g6tt4_di" bpmnElement="Flow_02g6tt4">
<di:waypoint x="458" y="220" />
<di:waypoint x="558" y="220" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1wu0khg_di" bpmnElement="Flow_1wu0khg">
<di:waypoint x="608" y="220" />
<di:waypoint x="708" y="220" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1d0b1lk_di" bpmnElement="Flow_1d0b1lk">
<di:waypoint x="808" y="220" />
<di:waypoint x="908" y="220" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0rdv9v5_di" bpmnElement="Flow_0rdv9v5">
<di:waypoint x="583" y="245" />
<di:waypoint x="583" y="420" />
<di:waypoint x="926" y="420" />
<di:waypoint x="926" y="238" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
1.5.3 正常的流程图
1.6 丢失“X”的流程图
1.6.1 后端接口
1.6.2 对应xml文档
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://bpmn.io/schema/bpmn" id="Definitions_0001">
<process id="zgr-test1" name="测试条件走向" isExecutable="true">
<startEvent id="Event_0a6bsya"></startEvent>
<userTask id="Activity_0pfz1cb" name="第一"></userTask>
<sequenceFlow id="Flow_0454chc" sourceRef="Event_0a6bsya" targetRef="Activity_0pfz1cb"></sequenceFlow>
<exclusiveGateway id="Gateway_1q7504o" default="Flow_1wu0khg"></exclusiveGateway>
<sequenceFlow id="Flow_02g6tt4" sourceRef="Activity_0pfz1cb" targetRef="Gateway_1q7504o"></sequenceFlow>
<userTask id="Activity_19w1ng8" name="第二"></userTask>
<sequenceFlow id="Flow_1wu0khg" sourceRef="Gateway_1q7504o" targetRef="Activity_19w1ng8"></sequenceFlow>
<endEvent id="Event_14e42yk"></endEvent>
<sequenceFlow id="Flow_1d0b1lk" sourceRef="Activity_19w1ng8" targetRef="Event_14e42yk"></sequenceFlow>
<sequenceFlow id="Flow_0rdv9v5" sourceRef="Gateway_1q7504o" targetRef="Event_14e42yk">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[=${day>3}]]></conditionExpression>
</sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_zgr-test1">
<bpmndi:BPMNPlane bpmnElement="zgr-test1" id="BPMNPlane_zgr-test1">
<bpmndi:BPMNShape bpmnElement="Event_0a6bsya" id="BPMNShape_Event_0a6bsya">
<omgdc:Bounds height="36.0" width="36.0" x="222.0" y="202.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="Activity_0pfz1cb" id="BPMNShape_Activity_0pfz1cb">
<omgdc:Bounds height="100.0" width="100.0" x="358.0" y="170.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="Gateway_1q7504o" id="BPMNShape_Gateway_1q7504o">
<omgdc:Bounds height="50.0" width="50.0" x="558.0" y="195.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="Activity_19w1ng8" id="BPMNShape_Activity_19w1ng8">
<omgdc:Bounds height="100.0" width="100.0" x="708.0" y="170.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="Event_14e42yk" id="BPMNShape_Event_14e42yk">
<omgdc:Bounds height="36.0" width="36.0" x="908.0" y="202.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="Flow_0454chc" id="BPMNEdge_Flow_0454chc">
<omgdi:waypoint x="258.0" y="220.0"></omgdi:waypoint>
<omgdi:waypoint x="358.0" y="220.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="Flow_02g6tt4" id="BPMNEdge_Flow_02g6tt4">
<omgdi:waypoint x="458.0" y="220.0"></omgdi:waypoint>
<omgdi:waypoint x="558.0" y="220.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="Flow_1wu0khg" id="BPMNEdge_Flow_1wu0khg">
<omgdi:waypoint x="608.0" y="220.0"></omgdi:waypoint>
<omgdi:waypoint x="708.0" y="220.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="Flow_1d0b1lk" id="BPMNEdge_Flow_1d0b1lk">
<omgdi:waypoint x="808.0" y="220.0"></omgdi:waypoint>
<omgdi:waypoint x="908.0" y="220.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="Flow_0rdv9v5" id="BPMNEdge_Flow_0rdv9v5">
<omgdi:waypoint x="583.0" y="245.0"></omgdi:waypoint>
<omgdi:waypoint x="583.0" y="420.0"></omgdi:waypoint>
<omgdi:waypoint x="926.0" y="420.0"></omgdi:waypoint>
<omgdi:waypoint x="926.0" y="238.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
1.6.3 显示的问题流程图
从图中可以看到,排他网关中间的“X”丢失了!!!
2 查找问题
查看问题,每天只能利用零碎的时间,前后两周,在这里首先介绍一个工具,bpmn流程设计器camunda-modeler,一款流程设计器,还是借用引言的话,能看到这篇文章的同学,基础知识应该都了解,我就不做过多的解释了。
前面失败的摸索过程就不多做赘述,直接说最后成功发现问题的过程。debug1.2节的代码,拿到xml,粘贴复制保存为xml文件,文件内容为1.6.2所示,利用1.4节的example,把最后的jQuery的get请求的URL替换为本地xml文件路径,浏览器直接打开1.4节的html文件,此时显示的流程图是有问题的流程图。
同样的xml文件,利用camunda-modeler显示,发现排他网关显示无任何问题
我利用camunda-modeler调整了排他网关直接到结束连线的位置,然后保存此xml文件,然后刷新1.4节的html页面,发现排他网关能正常显示了。
保存后的xml文档
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" id="Definitions_0001" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.9.0">
<bpmn:process id="zgr-test1" name="测试条件走向" isExecutable="true">
<bpmn:startEvent id="Event_0a6bsya" />
<bpmn:userTask id="Activity_0pfz1cb" name="第一" />
<bpmn:sequenceFlow id="Flow_0454chc" sourceRef="Event_0a6bsya" targetRef="Activity_0pfz1cb" />
<bpmn:exclusiveGateway id="Gateway_1q7504o" default="Flow_1wu0khg" />
<bpmn:sequenceFlow id="Flow_02g6tt4" sourceRef="Activity_0pfz1cb" targetRef="Gateway_1q7504o" />
<bpmn:userTask id="Activity_19w1ng8" name="第二" />
<bpmn:sequenceFlow id="Flow_1wu0khg" sourceRef="Gateway_1q7504o" targetRef="Activity_19w1ng8" />
<bpmn:endEvent id="Event_14e42yk" />
<bpmn:sequenceFlow id="Flow_1d0b1lk" sourceRef="Activity_19w1ng8" targetRef="Event_14e42yk" />
<bpmn:sequenceFlow id="Flow_0rdv9v5" sourceRef="Gateway_1q7504o" targetRef="Event_14e42yk">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=${day>3}</bpmn:conditionExpression>
</bpmn:sequenceFlow>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_zgr-test1">
<bpmndi:BPMNPlane id="BPMNPlane_zgr-test1" bpmnElement="zgr-test1">
<bpmndi:BPMNEdge id="BPMNEdge_Flow_0rdv9v5" bpmnElement="Flow_0rdv9v5">
<di:waypoint x="513" y="155" />
<di:waypoint x="513" y="230" />
<di:waypoint x="856" y="230" />
<di:waypoint x="856" y="148" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_Flow_1d0b1lk" bpmnElement="Flow_1d0b1lk">
<di:waypoint x="738" y="130" />
<di:waypoint x="838" y="130" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_Flow_1wu0khg" bpmnElement="Flow_1wu0khg">
<di:waypoint x="538" y="130" />
<di:waypoint x="638" y="130" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_Flow_02g6tt4" bpmnElement="Flow_02g6tt4">
<di:waypoint x="388" y="130" />
<di:waypoint x="488" y="130" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge_Flow_0454chc" bpmnElement="Flow_0454chc">
<di:waypoint x="188" y="130" />
<di:waypoint x="288" y="130" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="BPMNShape_Event_0a6bsya" bpmnElement="Event_0a6bsya">
<dc:Bounds x="152" y="112" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_Activity_0pfz1cb" bpmnElement="Activity_0pfz1cb">
<dc:Bounds x="288" y="80" width="100" height="100" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_Gateway_1q7504o" bpmnElement="Gateway_1q7504o" isMarkerVisible="true">
<dc:Bounds x="488" y="105" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_Activity_19w1ng8" bpmnElement="Activity_19w1ng8">
<dc:Bounds x="638" y="80" width="100" height="100" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_Event_14e42yk" bpmnElement="Event_14e42yk">
<dc:Bounds x="838" y="112" width="36" height="36" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
都是xml文档,为什么一个排他网关能正常显示,一个排他网关不能正常显示了?此时要做的就是对比两个xml文档,找出关键差异所在,对比了很久,最后定位一个非常关键的地方,xml的BPMNDiagram元素中,对于排他网关的描述,排他网关非正常显示的xml少了“isMarkerVisible="true" ”这个关键的属性,对于原来有问题的xml,我直接在相应位置加上该属性,保存xml,html网页正常显示。
至此,排他网关菱形中间的"X"丢失问题应该算是找到了病根,接下来就是如何解决问题。
3 解决问题
第一个想法是,通过模型id查找,利用repositoryService.getModelEditorSource(id)接口获取xml流程图不就可以了吗?但是一个流程模型会有多个流程定义,每个流程定义版本可能流程图是不相同的,如果要查看每个流程版本的流程图,此方法是只能获取最新流程定义的版本图,后面使用时行不通的,所以必须通过流程定义id获取对应的BpmnModel,再利用BpmnXMLConverter进行转换。
byte[] bpmnBytes = repositoryService.getModelEditorSource(id);
3.1 跟踪BpmnXMLConverter的convertToXML方法源码
跟踪convertToXML方法,找出生成BPMNDiagram的关键代码
跟进此方法,进入 org.flowable.bpmn.converter.export包下的writeBPMNDI方法。
writeBPMNDI调用了同一个类下面的 createBpmnShape方法,这个方法最关键,此方法生成的xml就包含了对于排他网关是否会添加isMarkerVisible="true"属性。
protected static void createBpmnShape(BpmnModel model, String elementId, XMLStreamWriter xtw) throws Exception {
xtw.writeStartElement(BPMNDI_PREFIX, ELEMENT_DI_SHAPE, BPMNDI_NAMESPACE);
xtw.writeAttribute(ATTRIBUTE_DI_BPMNELEMENT, elementId);
xtw.writeAttribute(ATTRIBUTE_ID, "BPMNShape_" + elementId);
GraphicInfo graphicInfo = model.getGraphicInfo(elementId);
FlowElement flowElement = model.getFlowElement(elementId);
if (flowElement instanceof SubProcess && graphicInfo.getExpanded() != null) {
xtw.writeAttribute(ATTRIBUTE_DI_IS_EXPANDED, String.valueOf(graphicInfo.getExpanded()));
}
xtw.writeStartElement(OMGDC_PREFIX, ELEMENT_DI_BOUNDS, OMGDC_NAMESPACE);
xtw.writeAttribute(ATTRIBUTE_DI_HEIGHT, String.valueOf(graphicInfo.getHeight()));
xtw.writeAttribute(ATTRIBUTE_DI_WIDTH, String.valueOf(graphicInfo.getWidth()));
xtw.writeAttribute(ATTRIBUTE_DI_X, String.valueOf(graphicInfo.getX()));
xtw.writeAttribute(ATTRIBUTE_DI_Y, String.valueOf(graphicInfo.getY()));
xtw.writeEndElement();
xtw.writeEndElement();
}
通过以上代码可以看出,对于子流程做了特殊判断,添加了新的属性ATTRIBUTE_DI_IS_EXPANDED = "isExpanded",对于排他网关,并没有任何特殊之处。
3.2 最后的解决之道
第一个想法就是继承类BPMNDIExport,重写方法createBpmnShape,但此方法是静态的,并不能重写,如果完全重写BpmnXMLConverter工作量太大了,放弃。
改造xml了?对于convertToXML的结果,进行解析,在相应位置添加上属性isMarkerVisible="true"是不是就可以了。说干就干!!!
说一说思路,首先解析xml,获取process下面的排他网关的id,此id是唯一的,接着解析xml,获取BPMNDiagram下面属性,拿到属性“bpmnElement”值为排他网关id的element,添加属性isMarkerVisible="true",返回前端显示。
思路有了,实现工具使用dom4j,Dom4j是一个易用的、开源的库,用于XML,XPath和XSLT。它应用于Java平台,采用了Java集合框架并完全支持DOM,SAX和JAXP。
Maven依赖如下
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.4</version>
</dependency>
1.2节的通过流程定义获取xml的方法改造为
public String getProcessDefinitionBpmnXML(String id) {
try {
BpmnModel bpmnModel = repositoryService.getBpmnModel(id);
if (bpmnModel == null) {
return null;
}
BpmnXMLConverter converter = new BpmnXMLConverter();
//返回给前端的xml,排他网关的显示会丢失中间的X,经过探索是xml少了attribute isMarkerVisible="true",手动需要添加此属性
return addAttributeWithXmlDocument(StrUtil.utf8Str(converter.convertToXML(bpmnModel)));
}catch (Exception e){
throw exception(PROCESS_DEFINITION_IS_CHANGE_ERROR);
}
}
/**
* 给xml添加属性
* @param xmlStr 字符串格式的xml
* @return 添加属性后的xml
*/
private String addAttributeWithXmlDocument(String xmlStr) throws DocumentException {
// 加载文档
Document document = DocumentHelper.parseText(xmlStr);
//获取根节点
Element root = document.getRootElement();
//查找排他网关的id
Element process = root.elements("process").get(0);
Element exclusiveGateway = process.elements("exclusiveGateway").get(0);
String exclusiveGatewayId = exclusiveGateway.attribute("id").getValue();
//向下搜索
Element diagram = root.elements("BPMNDiagram").get(0);
Element BPMNPlane = diagram.elements("BPMNPlane").get(0);
for (Iterator i = BPMNPlane.elementIterator(); i.hasNext(); ) {
Element el = (Element) i.next();
if (el.attribute("bpmnElement").getValue().equals(exclusiveGatewayId)) {
//添加属性
el.addAttribute("isMarkerVisible", Boolean.toString(true));
}
}
return document.asXML();
}
至此算解决了此问题!
4 总结
从遇到此问题,到找到问题的根源,花了很长的时间,毕竟也是第一次尝试,前端自己也是新手。找出问题到解决问题,其实花的时间并不多。到目前为止,问题算是解决了,但感觉解决这个问题的方式不够优雅,后续可能会在GitHub上提个issue问问作者这个问题,看看到底是代码的疏漏还是别的什么原因。
看到这篇文章的伙伴,有更好的解决方法,也欢迎一起讨论,不足之处,还请多多指教。