目录
场景:需要对接客户服务,获取信息。客户采用webservice接口调用传输数据。我放需要开发webservice的服务端给客户调用。
经过一番折腾,采用CXFServlet结合springmvc 的web形式开发。
第一个问题,接收报错
org.apache.cxf.binding.soap.SoapFault: SOAP 1.2 message is not valid when sent to a SOAP 1.1 only endpoint.
原因是 协议不匹配,需要使用soap1.2协议才可以。
解决办法是:在接口或实现类上声明
@Component("receive")
@WebService(targetNamespace = "http://service.webservice.com")
@BindingType(value= SOAPBinding.SOAP12HTTP_BINDING)
public class XcfService {
}
第二个问题,响应不到
调好这个之后是能接收到客户的消息了。。
但是响应的消息那边没有办法获取到(或者解析不出来),对方研发给的回应是
异常回复的报文
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/soap+xml;charset=UTF-8
Content-Length: 441
Date: Mon, 18 Nov 2019 08:02:41 GMT
Connection: close
<soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<ns2:initSystemResponse
xmlns:ns2="http://service.webservice.com">
<return>
<?xml version='1.0' encoding='UTF-8'?>
<root>
<code>0</code>
<message>成功</message>
<sessionId>17448931860480646017448931860481</sessionId>
</root>
</return>
</ns2:initSystemResponse>
</soap:Body>
</soap:Envelope>
正常上级回复的报文
HTTP/1.1 200 OK
Server: gSOAP/2.8
Content-Type: application/soap+xml; charset=utf-8; action="urn:initSystem"
Content-Length: 922
Connection: close
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ns2="http://service.webservice.com/ServiceSoap11Binding"
xmlns:ns1="http://service.webservice.com"
xmlns:ns3="http://service.webservice.com/ServiceSoap12Binding">
<SOAP-ENV:Body>
<ns1:initSystemResponse>
<ns1:return>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<code>0</code>
<message>init system success.</message>
<sessionId>1007723808</sessionId>
</root>
</ns1:return>
</ns1:initSystemResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
看到之后第一想法就是消息头不一样,是不是要改。查阅一番,不好改。
后面就直接手动封装消息体,按照对方的格式封装,只是把自己的sessionId做动态设置,试了一下,果然可以。
才用的方法是
响应前重写消息
public class MyOutterceptor extends AbstractPhaseInterceptor<SoapMessage> {
private static final Logger log = LoggerFactory.getLogger(ThirdBayonetService.class);
private static String INIT_SYSTEM_RESPONSE = "initSystemResponse";
public MyOutterceptor() {
//流关闭之前 处理
super(Phase.PRE_STREAM);
}
public MyOutterceptor(String phase) {
super(phase);
}
public void handleMessage(SoapMessage message) {
try {
OutputStream os = message.getContent(OutputStream.class);
CachedStream cs = new CachedStream();
message.setContent(OutputStream.class, cs);
message.getInterceptorChain().doIntercept(message);
CachedOutputStream csnew = (CachedOutputStream) message.getContent(OutputStream.class);
InputStream in = csnew.getInputStream();
String xml = IOUtils.toString(in);
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://www.w3.org/2003/05/soap-envelope\"" +
" xmlns:SOAP-ENC=\"http://www.w3.org/2003/05/soap-encoding\"" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" +
" xmlns:ns2=\"http://service.webservice.com/ServiceSoap11Binding\"" +
" xmlns:ns1=\"http://service.webservice.com\"" +
" xmlns:ns3=\"http://service.webservice.com/ServiceSoap12Binding\">");
if (xml != null && xml.contains(INIT_SYSTEM_RESPONSE)) {
// 初始化
stringBuffer.append("<SOAP-ENV:Body><ns1:initSystemResponse><ns1:return>" +
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<root>" +
"<code>0</code>" +
"<message>init system success.</message>" +
"<sessionId>");
String sessionId = "随机生成";
stringBuffer.append(sessionId);
stringBuffer.append("</sessionId></root></ns1:return></ns1:initSystemResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>");
log.info("initSystem response sessionId:{}", sessionId);
} else{
stringBuffer = new StringBuffer(IOUtils.toString(in));
}
//这里对xml做处理,处理完后同理,写回流中
IOUtils.copy(new ByteArrayInputStream(stringBuffer.toString().getBytes()), os);
cs.close();
os.flush();
message.setContent(OutputStream.class, os);
} catch (Exception e) {
log.error("Error when split original inputStream. CausedBy : " + "\n" + e);
}
}
然后在applicationContext.xml里面把拦截器配上,用的是 jaxws:outInterceptors 表响应拦截
<!-- 自动扫描webService -->
<context:component-scan base-package="com."/>
<jaxws:endpoint implementor="#XcfService" address="/ThirdBayonetService">
<jaxws:outInterceptors>
<bean class="com.interceptor.ReceiveInterceptor"/>
</jaxws:outInterceptors>
</jaxws:endpoint>
总结
采用springmvc的Xcf搭建的webservice,本篇涉及的点是接收协议和响应封装
最后感谢: