最近项目上要调用其他系统的WebService(Axis搭建),由于接收数据较大耗时4分钟左右,所以要设置超时时间,而且系统中已有jar包的原因,导致许多方法都不能用,最终用HttpClient。
方法一:使用JaxWsDynamicClientFactory调用WebService
Java代码
publicstaticObjectcall(Stringwsdl,Stringmethod,StringrequestStr){
JaxWsDynamicClientFactoryfactory=JaxWsDynamicClientFactory.newInstance();
Clientclient=factory.createClient(wsdl);
HTTPConduitconduit=(HTTPConduit)client.getConduit();
HTTPClientPolicypolicy=newHTTPClientPolicy();
longtimeout=10*60*1000;//
policy.setConnectionTimeout(timeout);
policy.setReceiveTimeout(timeout);
conduit.setClient(policy);
//动态invoke方法
Object[]os=client.invoke(method,requestStr);
returnos[0];
}
方法二:使用JaxWsProxyFactoryBean调用WebService
原理:使用JaxWsProxyFactoryBean类生成本地的代理类。
首先创建接口,然后通过JaxWsProxyFactoryBean调用。
Java代码
@WebService
publicinterfaceIDataService{
@WebMethod
@WebResult
StringgetData(@WebParamStringrequestData);
}
publicstaticStringcall(Stringwsdl,StringrequestStr){
JaxWsProxyFactoryBeanfactory=newJaxWsProxyFactoryBean();
factory.setServiceClass(IDataService.class);
factory.setAddress(wsdl);
IDataServiceservice=(IDataService)factory.create();
//设置超时时间
org.apache.cxf.endpoint.Clientproxy=ClientProxy.getClient(service);
HTTPConduitconduit=(HTTPConduit)proxy.getConduit();
HTTPClientPolicypolicy=newHTTPClientPolicy();
longtimeout=10*60*1000;//
policy.setConnectionTimeout(timeout);
policy.setReceiveTimeout(timeout);
conduit.setClient(policy);
//发出请求
returnservice.getData(requestStr);
}
方法三:使用wsimport命令构建WebService客户端
首先使用wsimport命令构建客户端,然后用下面的方法调用。
Java代码
publicstaticStringcall(StringrequestData){
//构建的客户端代码
IDataService_Servicefactory=newIDataService_Service();
IDataServiceservice=factory.getDataSharedWebService();
longtimeout=30*60*1000;//30分钟
//设置超时时间
//当前起作用的配置
((BindingProvider)service).getRequestContext().put("javax.xml.ws.client.connectionTimeout",timeout);
((BindingProvider)service).getRequestContext().put("javax.xml.ws.client.receiveTimeout",timeout);
//网上搜到的其他设置超时的方法,当前项目没有起作用
((BindingProvider)service).getRequestContext().put("com.sun.xml.ws.connect.timeout",timeout);
((BindingProvider)service).getRequestContext().put("com.sun.xml.ws.request.timeout",timeout);
((BindingProvider)service).getRequestContext().put("com.sun.xml.internal.ws.connect.timeout",timeout);
((BindingProvider)service).getRequestContext().put("com.sun.xml.internal.ws.request.timeout",timeout);
((BindingProvider)service).getRequestContext().put(".client.defaultConnectTimeout",timeout);
((BindingProvider)service).getRequestContext().put(".client.defaultReadTimeout",timeout);
try{
//调用WebService
returnservice.getData(requestData);
}catch(Exceptione){
log.error(e.getMessage());
}
returnnull;
}
也可以用cxf的wsdl2java命令构建客户端,调用方式一样,但是如何设置超时时间没有试。
方法四:使用HttpClient调用WebService
使用commons-httpclient-3.1,依赖jar包(commons-codec.jar、commons-logging.jar)。
Java代码
publicStringcall(Stringwsdl,StringrequestData){
try{
//requestData可以直接用soapui中请求的数据,注意<![CDATA[]]>的使用
PostMethodpostMethod=newPostMethod(wsdl);
byte[]b=requestData.getBytes("UTF-8");
InputStreamin=newByteArrayInputStream(b,0,b.length);
RequestEntityre=newInputStreamRequestEntity(in,
"text/xml;charset=utf-8");
postMethod.setRequestEntity(re);
//设置headerSOAPAction,不设置的话,会报异常:noSOAPAction
//header,但是SOAPAction的好像任意值都可以
StringsoapAction="XX";
postMethod.setRequestHeader("SOAPAction",soapAction);
HttpClientclient=newHttpClient();
//设置超时(不知道默认是多久,没有设置的时候,也没有报错,设置下保险些)
inttimeout=10*60*1000;
client.getHttpConnectionManager().getParams().setConnectionTimeout(timeout);
client.getHttpConnectionManager().getParams().setSoTimeout(timeout);
//
intstatus=client.executeMethod(postMethod);
if(status==200){//成功
InputStreamis=postMethod.getResponseBodyAsStream();
/**
*获取的结果可以参考用soapui调用时的返回值,
*如果约定的返回值是XML,并不会像soapui一样把xml用<![CDATA[]]>包含起来,要注意解析的方法,
*不知道soapui如何处理的,暂时没时间研究。
*/
returngetResponseXML(is);
}else{
log.error("调用Webservice出错;错误代码为:"+status);
}
}catch(Exceptione){
log.error(e.getMessage());
}
returnnull;
}
publicStringgetResponseXML(InputStreamresponse)throwsException{
//根据具体的返回值写的解析
SAXReaderreader=newSAXReader();
Documentdocument=reader.read(response);
Elementroot=document.getRootElement();
List<Element>childElements=root.elements();
for(Elementchild:childElements){
List<Element>datas=child.selectNodes("getOrgInfoResponse/getOrgInfoResponse");
for(Elementnode:datas){
//返回约定的xml
returnnode.getText();
}
}
returnnull;
}
总结下这次遇到的问题:
1.异常:java.lang.NoSuchFieldError: QUALIFIED
jar包冲突,删除jar包(如果可以的话,不能删除就用HttpClient的方式)。由于项目中第三方工具需要XmlSchema-1.3.x.jar,而cxf-2.5作为客户端时需要用到xmlschema-core-2.0.1.jar导致前三种方式都不能用。
2.超时
由于接收数据较大,时间较长,必须设置超时时间。
3.异常:javax.xml.bind.UnmarshalException:unexpected element (uri:"", local:"getDataResponse").Expected elements are <{http://xxx/xx}getOrgInfoResponse>
是namespace的问题,如果用JaxWsProxyFactoryBean的方式,要修改@WebResult中targetNamespace;如果用wsimport命令的方式,需要修改类GetDataResponse中属性getDataResponse的注解中namespace的值。
4.异常:no SOAPAction header
没有设置SOAPAction,设置方式:postMethod.setRequestHeader("SOAPAction", soapAction),soapAction的值是什么好像并不影响结果。