我要求XmlData
中的CDATA
发送给肥皂请求,该请求会返回附件。
使用org.springframework.oxm.jaxb.Jaxb2Marshaller
作为marshaller和unmarshaller。
<![CDATA[<tag>Test</tag>]]>
这是我想要在soap请求中发送的内容,远程服务期望它以相同的方式显示。
我创建了数据但是当我使用webServiceTemplate.marshalSendAndReceive(payloadRequest, SoapActionCallback)
以某种方式,有效负载请求xmltags被编码并显示为
<![CDATA[<tag>Test<\tag>
由于此编码,远程服务无法处理请求并发送
org.springframework.ws.soap.client.SoapFaultClientException: Object reference not set to an instance of an object.
我该如何解决这个问题?任何建议!
更新:是否将spring mvc的defaultHtmlEscape作为web.xml中的context-param负责此行为?
答案 0 :(得分:3)
我在工作的这一天遇到了同样的问题,我们必须在定义到从银行Web服务公开的WSDL中的数据结构的字段文本上注入CDATA部分。
要求是引入CDATA部分以逃避Unicode字符&#34; +&#34;进入一个电话领域。 WSDL不可能因各种动机而改变。
我们有相同的环境:
org.springframework.oxm.jaxb.Jaxb2Marshaller
webServiceTemplate.marshalSendAndReceive(payloadRequest, SoapActionCallback)
和相同的失败结果
<![CDATA[<tag>+<\tag>
而不是
<[[CDATA[+]]>
经过多次测试以及在Stackoverflow和其他站点上查询了很多字体之后,我们已经了解到JAXB引擎本身不支持该解决方案,并且必须将SOAP消息操作到一个简单的步骤处理请求。
其他解决方案表示使用第三方插件和库,例如MOXy,以完成对CDATA部分的强大支持,也是JAXB。但是,这种解决方案不可能尽快在大型企业应用程序中快速集成。
我在此回复中发布的此解决方案允许使用经典DOMSource对象的规范方法注入CDATASection,该对象从messagecontext转换消息SOAP。
在你的回答中,你公开了解决方案的一部分,这是marshalSendAndReceive的回调。
如果您定义marshalSendAndReceive
方法支持的临时回调,并且在此回调中操作注入CDATASection的DOMSource,您可以解决问题。
这是代码:
WebServiceMessageCallback callbackCDATANumTelefono = new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message) {
//Recover the DOMSource dal message soap
DOMSource domSource = (DOMSource)message.getPayloadSource();
//recover set of child nodes of domsource
NodeList nodeList = domSource.getNode().getChildNodes();
//definisco il nome del tag da cercare
String nameNumTel = "ns2:sNumTel"; //in this example, but you can define another QName string to recover the target node (or nodes)
Node nodeNumTel = null;
for (int i = 0; i < nodeList.getLength(); i++) {
//search of text node of this tag name
if (nodeList.item(i).getNodeName().compareTo(nameNumTel) == 0) {
nodeNumTel = nodeList.item(i);
break;
}
}
//recover the string value (in this case of telephone number)
String valueNumTelefono = nodeNumTel.getTextContent();
//clean of value of target text node
nodeNumTel.setTextContent("");
//define and inject of CDATA section, in this case encapsulate "+" character
CDATASection cdata = nodeNumTel.getOwnerDocument().createCDATASection("+");
//create of new text node
Text tnode = nodeNumTel.getOwnerDocument().createTextNode(valueNumTelefono);
//append of CDATASection (in this point is possible to inject many CDATA section on various parts of string (very usefull)
nodeNumTel.appendChild(cdata);
nodeNumTel.appendChild(tnode);
//done!
}
};
此回调将从marshalSendAndReceive
调用PayloadSoapResponse output = (PayloadSoapResponse ) getWebServiceTemplate()
.marshalSendAndReceive(input, callbackCDATANumTelefono);
结果是正确发送请求,CDATA部分有效且未以ascii字符转换。
此解决方案的目标是使用JAXB技术在Spring基础架构上操作CDATA部分,而不是使用第三部分库。 一般来说,回调方法的指令集非常可靠,并且可以在Web服务soap的所有环境中进行注入。关键的方面是使用规范方法将SoapMessage转换为更友好的DOMSource以探索节点。它也可以使用XPath引擎来导航这个DOMSource。
祝你好运!上午
答案 1 :(得分:2)
使用spring-ws生成SOAP Web服务时遇到了这个问题。 CDATA部分将始终如上所述进行转义。
在我的情况下,解决方案(非常类似于Alessandro)是创建一个EndpointInterceptor,我将所需的节点转换为handleResponse中的org.w3c.dom.CDATASection。 然后,您需要将此拦截器添加到实现中的拦截器列表中。
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.w3c.dom.CDATASection;
import javax.xml.soap.Node;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import java.util.Iterator;
public class MyCdataInterceptor implements EndpointInterceptor {
@Override
public boolean handleRequest(MessageContext messageContext, Object o) throws Exception {
return true;
}
@Override
public boolean handleResponse(MessageContext messageContext, Object o) throws Exception {
WebServiceMessage response = messageContext.getResponse();
SaajSoapMessage saajSoapMessage = (SaajSoapMessage) response;
SOAPMessage soapMessage = saajSoapMessage.getSaajMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPBody body = envelope.getBody();
Iterator it = body.getChildElements();
...
/* find node of interest */
Node interestingNode = (Node) blah.getNextSibling();
CDATASection cdat = soapPart.createCDATASection(interestingNode.getFirstChild().getNodeValue());
interestingNode.removeChild(interestingNode.getFirstChild());
interestingNode.appendChild(cdat);
return true;
}
@Override
public boolean handleFault(MessageContext messageContext, Object o) throws Exception {
return true;
}
@Override
public void afterCompletion(MessageContext messageContext, Object o, Exception e) throws Exception {
}
}