bpmn-js显示Flowable的BpmnModel转换为xml文档的流程图排他网关丢失中间“X”

1 问题引入

这应该是一篇十分小众的文章,能找见这篇文章的同学,应该对审批流框架Flowablebpmn-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/bpmn-js@11.5.0/dist/assets/bpmn-js.css">

    <!-- viewer distro (with pan and zoom) -->
    <script src="https://unpkg.com/bpmn-js@11.5.0/dist/bpmn-navigated-viewer.development.js"></script>

    <!-- needed for this example only -->
    <script src="https://unpkg.com/jquery@3.3.1/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&gt;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&gt;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问问作者这个问题,看看到底是代码的疏漏还是别的什么原因。

看到这篇文章的伙伴,有更好的解决方法,也欢迎一起讨论,不足之处,还请多多指教。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值