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; } }
关键说明
- DOM转换:通过
Transformer将SoapHeaderElement的Source转换为DOMResult,获取DOM节点后可直接操作子元素。 - 子节点遍历:遍历DOM节点的子节点,过滤掉空白文本节点,仅处理元素节点,提取标签名作为键,文本内容作为值。
- 兼容性:该方式适用于Spring WS框架,无需依赖额外库,能处理任意层级的Header子节点结构。
内容的提问来源于stack exchange,提问作者Kishore_2021
相关产品推荐
相关产品推荐

