1. 引言

本教程探讨如何在Java中将原始SOAP XML字符串转换为可用的SOAPMessage对象。**SOAPMessage是Java API for XML-based messaging (SAAJ)的核心组件,它封装了完整的SOAP请求或响应,包含信封(Envelope)、头部(Header)和主体(Body)。**

2. 使用SAAJ MessageFactory

第一种方法采用javax.xml.soap包提供的标准MessageFactory。该工厂直接从输入流创建SOAPMessage,其核心流程是:

  1. 将原始字符串转换为字节流
  2. 通过工厂解析生成结构化SOAP消息

以下是工具方法usingSAAJMessageFactory()的实现:

static SOAPMessage usingSAAJMessageFactory(String soapXml) throws Exception {
    ByteArrayInputStream input = new ByteArrayInputStream(soapXml.getBytes(StandardCharsets.UTF_8));
    MessageFactory factory = MessageFactory.newInstance();
    return factory.createMessage(null, input);
}

关键点解析:

  • ✅ 使用StandardCharsets.UTF_8确保编码转换无丢失
  • MessageFactory.newInstance()获取默认实现
  • createMessage()方法直接解析输入流

准备测试用的SOAP字符串(股票价格查询示例):

String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
  "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
  "<soapenv:Header/>" +
  "<soapenv:Body>" +
  "<m:GetStockPrice xmlns:m=\"http://example.com/stock\">" +
  "<m:StockName>GOOG</m:StockName>" +
  "</m:GetStockPrice>" +
  "</soapenv:Body>" +
  "</soapenv:Envelope>";

SOAPMessage message = SoapParser.usingSAAJMessageFactory(xml);

验证结果正确性:

SOAPBody body = message.getSOAPBody();
assertNotNull(message, "SOAPMessage should not be null");
assertNotNull(body, "SOAP Body should not be null");
assertTrue(body.getTextContent().contains("GOOG"), "Expected 'GOOG' not found in the SOAP body");

适用场景: 需要完整访问SOAP消息组件(信封/头部/主体)时

3. 使用DOM解析

替代方案:先通过DOM API将XML解析为Document对象,再用DOM结构填充SOAPPart。实现方法usingDOMParsing()如下:

static SOAPMessage usingDOMParsing(String soapXml) throws Exception {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware(true); // 关键:启用命名空间感知
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.parse(new ByteArrayInputStream(soapXml.getBytes(StandardCharsets.UTF_8)));

    MessageFactory factory = MessageFactory.newInstance();
    SOAPMessage message = factory.createMessage();
    SOAPPart part = message.getSOAPPart();
    part.setContent(new DOMSource(doc.getDocumentElement())); // 用DOM源替换内容
    message.saveChanges(); // 确保结构更新
    return message;
}

核心步骤:

  1. 创建命名空间感知的DocumentBuilderFactory(SOAP依赖XML命名空间)
  2. 解析字符串为Document对象
  3. 初始化空SOAPMessage
  4. DOMSource包装文档根元素并设置到SOAPPart
  5. 调用saveChanges()完成构建

测试代码与方案1相同:

SOAPMessage message = SoapParser.usingDOMParsing(xml);

验证逻辑保持一致:

SOAPBody body = message.getSOAPBody();
assertNotNull(message, "SOAPMessage should not be null");
assertNotNull(body, "SOAP Body should not be null");
assertTrue(body.getTextContent().contains("GOOG"), "Expected 'GOOG' not found in the SOAP body");

优势场景:

  • ✅ 需在构建前修改XML结构时
  • ✅ 系统已使用Document处理XML时

4. 结论

两种方案对比:

方案 特点 适用场景
MessageFactory 简单直接 基础转换需求
DOM解析 灵活可控 需预处理XML或与现有DOM系统集成

踩坑提示:

  • ⚠️ 务必启用命名空间感知(setNamespaceAware(true)),否则解析SOAP会失败
  • ✅ 字符编码统一用UTF-8避免乱码
  • ❌ 忘记调用saveChanges()可能导致消息结构不完整

源码参考:GitHub示例代码


原始标题:Converting a String to a SOAPMessage | Baeldung