Spring-WS如何正确处理SOAP请求Body中包含两个元素的问题
问题原因说明
Spring WS 中 @RequestPayload 注解默认仅会自动映射 SOAP Body 下的第一个顶级子元素,即便声明多个 @RequestPayload 参数也不会自动解析后续同级元素,所以你当前的写法只能拿到第一个 ProcessApplication 对象。
实现方案(可同时获取两个元素)
方案1:自定义复合请求包装类(推荐,适合JAXB绑定场景)
你可以定义一个包含两个目标元素的JAXB包装类,让Spring WS直接将整个Body内容绑定到该类上:
@XmlRootElement(name = "Body", namespace = "http://schemas.xmlsoap.org/soap/envelope/") @XmlAccessorType(XmlAccessType.FIELD) public class SoapBodyWrapper { @XmlElement(name = "ProcessApplication", namespace = B__NAMESPACE_URI) private ProcessApplication application; @XmlElement(name = "AdditionalInfo", namespace = A__NAMESPACE_URI) private AdditionalInfo addInfo; // 省略getter、setter }
修改端点方法的参数声明:
@PayloadRoots({ @PayloadRoot(localPart = "ProcessApplication", namespace = B__NAMESPACE_URI), @PayloadRoot(localPart = "AdditionalInfo", namespace = A__NAMESPACE_URI), }) @ResponsePayload public MyResponse processRequest(@RequestPayload SoapBodyWrapper wrapper) { ProcessApplication application = wrapper.getApplication(); AdditionalInfo addInfo = wrapper.getAddInfo(); // 业务逻辑 return response; }
方案2:手动解析SOAP消息(灵活度最高)
直接注入SOAP消息对象,自行解析Body下的所有子元素,同时可以直接获取Envelope、完整请求内容:
import org.springframework.ws.soap.SoapMessage; import javax.xml.bind.JAXBContext; import javax.xml.namespace.QName; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; @PayloadRoots({ @PayloadRoot(localPart = "ProcessApplication", namespace = B__NAMESPACE_URI), @PayloadRoot(localPart = "AdditionalInfo", namespace = A__NAMESPACE_URI), }) @ResponsePayload public MyResponse processRequest(SoapMessage soapMessage) throws Exception { // 获取Envelope、Body对象 SoapEnvelope envelope = soapMessage.getEnvelope(); SoapBody body = envelope.getBody(); // 分别解析两个子元素 JAXBContext jaxbContext = JAXBContext.newInstance(ProcessApplication.class, AdditionalInfo.class); ProcessApplication application = (ProcessApplication) jaxbContext.createUnmarshaller() .unmarshal(body.getChildElements(new QName(B__NAMESPACE_URI, "ProcessApplication")).next()); AdditionalInfo addInfo = (AdditionalInfo) jaxbContext.createUnmarshaller() .unmarshal(body.getChildElements(new QName(A__NAMESPACE_URI, "AdditionalInfo")).next()); // 获取完整请求原始内容 ByteArrayOutputStream baos = new ByteArrayOutputStream(); soapMessage.writeTo(baos); String fullRequestContent = baos.toString(StandardCharsets.UTF_8); // 业务逻辑 return response; }
注:JAXBContext可以提前配置为Spring Bean注入,避免重复创建影响性能。
完整请求、Envelope、Body的读取方式
除了上述方案2中直接注入SoapMessage读取的方式外,也可以通过注入MessageContext获取相关对象:
public MyResponse processRequest(MessageContext messageContext) { SoapMessage soapMessage = (SoapMessage) messageContext.getRequest(); // 后续操作和方案2一致 }
内容的提问来源于stack exchange,提问作者Serhiy Brytskyy
相关产品推荐
相关产品推荐

