我今天在工作中遇到了同样的问题,当我们必须在定义为从银行 Web 服务公开的 WSDL 中的数据结构的字段文本上注入 CDATA 部分时。
要求是引入 CDATA 部分以将 Unicode 字符“+”转义到电话号码字段中。 WSDL 不可能因各种动机而改变。
我们有相同的环境:
org.springframework.oxm.jaxb.Jaxb2Marshaller
webServiceTemplate.marshalSendAndReceive(payloadRequest, SoapActionCallback)
同样的失败结果
<![CDATA[<tag>+<\tag>
而不是
<[[CDATA[+]]>
经过多次测试以及在 Stackoverflow 和其他网站上咨询了许多字体后,我们了解到 JAXB 引擎本身不支持该解决方案,因此有必要将 SOAP 消息处理为处理请求的准时步骤。
其他解决方案表明使用第三方插件和库,例如 MOXy,以实现对 CDATA 部分和 JAXB 的强大支持。但是这种解决方案不可能尽快以形式在大型企业应用程序上快速集成。
我在此回复中发布的此解决方案允许使用经典 DOMSource 对象的规范方法从 messagecontext 转换消息 SOAP 来注入 CDATASection。
在您的回答中,您公开了解决方案的一部分,这是 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 服务肥皂的所有环境中。关键方面是使用规范方法将 SoapMessage 转换为更友好的 DOMSource 来探索节点。也可以使用 XPath 引擎来导航这个 DOMSource。
祝你好运!
上午