蓝凌EKP产品:从 XML 到 JSON ——表单存储的性能优化实践

1. 背景介绍

蓝凌 EKP 的表单引擎,是整个低代码平台的核心能力之一。它不仅仅是"存储表单",更是 企业级应用快速构建的基础设施

  • 它支持各种复杂表单配置(字段、布局、校验、权限、联动、子表单)。

  • 它能灵活绑定流程,实现 表单 + 流程 + 权限 的一体化管控。

  • 它为低代码应用提供了统一入口,业务人员通过拖拽和配置就能搭建应用,而无需写代码。

正是这种 强大、灵活、稳定 的能力,让我们的表单引擎能支撑上千种应用场景,从人事、财务、行政到项目、客户管理,真正成为企业数字化的核心引擎。


业务强大带来的新挑战

然而,随着业务场景越来越复杂,表单配置越来越灵活,表单数据存储的性能瓶颈也逐渐显现。

  • 我们早期选择 XML 存储表单值,非常合理:它层次清晰、可扩展、可校验,能快速支撑表单配置和跨系统兼容。

  • 但在今天,表单数量激增、字段量级庞大,XML 的 解析性能和存储冗余 成为用户体验的隐形负担。

为了让表单引擎在保持业务强大的同时,也能在性能上持续突破,我们开始探索 将存储方式从 XML 演进到 JSON


为什么要转向 JSON?

  • 更快:JSON 解析效率普遍高于 XML,能明显提升表单的加载速度。

  • 更轻:JSON 格式更紧凑,占用存储空间更小。

  • 更兼容:JSON 已经成为前后端交互的事实标准,更符合微服务和低代码平台的技术生态。

  • 更灵活:数据库(如 MySQL、Postgres、OceanBase)原生支持 JSON 类型,后续还能直接做查询和索引。

这一转变,不是推翻 XML,而是顺应业务发展、技术迭代的 优化升级

表单引擎已经足够强大,但强大也意味着要面对更高的性能挑战。选择从 XML 向 JSON 迁移,是我们在持续优化用户体验、提升系统性能道路上的又一次重要演进。

2. 问题分析

  • 性能瓶颈:XML 解析开销大,DOM 需要完整装载,SAX 流式复杂。

  • 存储冗余:XML 标签过长,大字段占用存储空间明显。

  • 兼容性差:前后端交互大多倾向于 JSON,XML 转换额外耗时。

  • 举例:某个大表单打

  • 开耗时 2s+,主要在 XML 解析环节。

3. 技术对比:XML vs JSON

表格形式更直观:

维度 XML JSON
数据格式 标签结构 键值对结构
存储大小 冗余多,占用大 紧凑,节省空间
解析速度 慢(需逐层解析) 快(轻量解析库)
可读性 层次清晰 更简洁
Schema 约束 有 (XSD) 弱(需额外方案)
生态兼容 传统系统友好 前端 & 微服务友好

4. 优化方案设计

  • 保留表单定义的层次化结构,但存储层改为 JSON。

  • 数据库层:如果 DB 支持 JSON 类型,可以直接用 JSON 字段;否则用 TEXT 存 JSON 字符串。

  • 应用层:使用 Jackson/Fastjson/Gson 替代 XML 解析器。

  • 兼容方案:老表单继续用 XML,新增表单优先用 JSON。


5. 实践过程

  • 贴代码示例:

XML 解析示例(原有实现)

将Map 表单集合转换为XML

java 复制代码
    public static String objectXmlEncoder(Object obj)
            throws FileNotFoundException, IOException, Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        XMLEncoder encoder = new XMLEncoder(baos);
        encoder.setPersistenceDelegate(BigDecimal.class,
                bigDecimalPersistenceDelegate);
        encoder.writeObject(obj);
        encoder.flush();
        encoder.close();
        String rtnVal = new String(baos.toByteArray(), "UTF-8");
        baos.close();
        return rtnVal;
    }

将XML 转换为Map 表单集合

java 复制代码
  String safeIns = ins.replaceAll("[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]", "");
   ByteArrayInputStream byteArrayInputStream = null;
     try{
         byteArrayInputStream = new ByteArrayInputStream(safeIns.getBytes("UTF-8"));
          //通过流读取转换成表单集合数据。
         return objectXmlDecoder(byteArrayInputStream);
     }finally{
         if(byteArrayInputStream!=null){
            byteArrayInputStream.close();
         }
     }

JSON 解析示例(优化后)

复制代码

将Map 表单集合转换为XML

java 复制代码
import com.fasterxml.jackson.databind.ObjectMapper

 private  static ObjectMapper mapper = null;
static {
    mapper = new ObjectMapper();
    mapper.activateDefaultTyping(
        mapper.getPolymorphicTypeValidator(),
        ObjectMapper.DefaultTyping.NON_FINAL_AT_LEVEL,
        JsonTypeInfo.As.PROPERTY
    );
}
      
    //传入参数Map 集合 obj ,直接转换为xml
    public static String objectJsonEncoder(Object obj) throws Exception{
        String string = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        return string;
    }

将XML 转换为Map 表单集合

java 复制代码
    //读取xml 转换为表单Map集合
public static Map objectJsonDecoder(String obj) throws Exception{
        Map datas = mapper.readValue(obj, HashMap.class);
        return datas;
    }
  • 对比两段代码的简洁度。

为了考虑兼容性和提供给用户选择,提供了开关让用户选择xml 和json。


6. 性能对比实验

  • 描述测试环境:JDK 版本、表单大小(如 500 字段)、数据库类型。

  • 给出测试数据(例如:解析 1000 次表单的耗时对比)。

  • 示例表格:

测试场景 XML 解析耗时 JSON 解析耗时 提升比例
小表单(50 字段) 120ms 40ms 3x
大表单(500 字段) 2100ms 600ms 3.5x

7. 收益与思考

  • 收益:表单打开速度更快,存储空间减少,系统响应更快。

  • 不足:JSON 缺乏严格约束,需要额外校验。

  • 未来:考虑进一步利用数据库 JSON 索引、缓存机制,提升查询效率。


8. 总结

  • XML 在早期合适,但随着系统演进,JSON 更适合高性能和前后端一体化。

  • 从 XML 到 JSON 的迁移,带来了 性能优化 + 存储优化 + 技术栈统一 的价值。

  • 希望本文的经验能为有类似困扰的开发者提供参考。