You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot WS应用中如何从MessageContext获取SOAP Header

问题:Spring Boot WS中如何获取SOAP Header的子节点键值对

在将旧Web Service应用迁移至Spring Boot WS应用时,需要获取SOAP Header中的键值对,编写了如下EndpointInterceptor代码,但无法获取SOAP请求中CustomHeaderElement节点及其子节点的键值:

现有Interceptor代码

import javax.wsdl.Message;
import javax.xml.namespace.QName;
import javax.xml.transform.Result;
import javax.xml.transform.Source;

import org.apache.cxf.jaxws.context.WrappedMessageContext;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.soap.SoapBody;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapHeaderElement;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.xml.namespace.QNameUtils;

public class LogHttpHeaderEndpointInterceptor implements EndpointInterceptor {

    @Override
    public boolean handleRequest(MessageContext messageContext, Object arg1) throws Exception {
        SoapHeader soapHeader = ((SoapMessage) messageContext.getRequest()).getSoapHeader();

        Iterator<SoapHeaderElement> soapHeaderElementIterator = soapHeader.examineAllHeaderElements();
        while (soapHeaderElementIterator.hasNext()) {
            SoapHeaderElement soapHeaderElement = soapHeaderElementIterator.next();
            Iterator<QName> allAttributes3 = soapHeaderElement.getAllAttributes();

            while (allAttributes3.hasNext()) {
                QName qName = (QName) allAttributes3.next();
                System.out.println();
                System.out.println("    LocalPart: " + qName.getLocalPart());
                System.out.println("    NamespaceURI: " + qName.getNamespaceURI());
                System.out.println("    Prefix: " + qName.getPrefix());
                System.out.println("    ToString(): " + qName.toString());
                System.out.println();
            }
            System.out.println("Header Name: " + soapHeaderElement.getName());
            System.out.println("Text: " + soapHeaderElement.getText());
            String attributeValue = soapHeaderElement.getAttributeValue(soapHeaderElement.getName());
            System.out.println("Header Value: " + attributeValue);
            Iterator<QName> allAttributes = soapHeaderElement.getAllAttributes();
            while (allAttributes.hasNext()) {
                QName qName = (QName) allAttributes.next();
                System.out.println();
                System.out.println("    LocalPart: " + qName.getLocalPart());
                System.out.println("    NamespaceURI: " + qName.getNamespaceURI());
                System.out.println("    Prefix: " + qName.getPrefix());
                System.out.println("    ToString(): " + qName.toString());
                System.out.println();
            }
        }

        return true;
    }
}

目标SOAP请求示例

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:gen="http://www.baeldung.com/springsoap/gen">
   <soapenv:Header>
      <CustomHeaderElement>
         <clientID>xyz</clientID>
         <wsdlVersion>1.0</wsdlVersion>
         <serviceType>ExampleService_v1</serviceType>
      </CustomHeaderElement>
   </soapenv:Header>
   <soapenv:Body>
   </soapenv:Body>
</soapenv:Envelope>

解决方案

现有代码仅处理了SoapHeaderElement的属性,但CustomHeaderElement中的clientID、wsdlVersion是其子节点而非属性,因此需要解析Header元素的子节点内容。

修改后的Interceptor代码如下,核心是将SoapHeaderElement转换为DOM节点,遍历其子节点获取键值对:

import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapHeaderElement;
import org.springframework.ws.soap.SoapMessage;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import java.util.Iterator;

public class LogHttpHeaderEndpointInterceptor implements EndpointInterceptor {

    @Override
    public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
        SoapHeader soapHeader = ((SoapMessage) messageContext.getRequest()).getSoapHeader();
        Iterator<SoapHeaderElement> headerElements = soapHeader.examineAllHeaderElements();

        while (headerElements.hasNext()) {
            SoapHeaderElement headerElement = headerElements.next();
            System.out.println("Header Element Name: " + headerElement.getName());

            // 将SoapHeaderElement转换为DOM节点,以便遍历子节点
            DOMResult domResult = new DOMResult();
            TransformerFactory.newInstance().newTransformer().transform(headerElement.getSource(), domResult);
            Node headerNode = domResult.getNode();
            NodeList childNodes = headerNode.getChildNodes();

            // 遍历子节点,提取键值对
            for (int i = 0; i < childNodes.getLength(); i++) {
                Node child = childNodes.item(i);
                // 跳过文本节点(空白节点)
                if (child.getNodeType() == Node.ELEMENT_NODE) {
                    String key = child.getLocalName();
                    String value = child.getTextContent().trim();
                    System.out.println("    " + key + ": " + value);
                }
            }
        }
        return true;
    }
}

关键说明

  1. DOM转换:通过Transformer将SoapHeaderElement的Source转换为DOMResult,获取DOM节点后可直接操作子元素。
  2. 子节点遍历:遍历DOM节点的子节点,过滤掉空白文本节点,仅处理元素节点,提取标签名作为键,文本内容作为值。
  3. 兼容性:该方式适用于Spring WS框架,无需依赖额外库,能处理任意层级的Header子节点结构。

内容的提问来源于stack exchange,提问作者Kishore_2021

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 17:27:26