|
最近項目上要調(diào)用其他系統(tǒng)的WebService(Axis搭建),由于接收數(shù)據(jù)較大耗時4分鐘左右,所以要設(shè)置超時時間,而且系統(tǒng)中已有jar包的原因,導(dǎo)致許多方法都不能用,最終用HttpClient。 方法一:使用JaxWsDynamicClientFactory調(diào)用WebService Java代碼  public static Object call(String wsdl,String method,String requestStr){ JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance(); Client client = factory.createClient(wsdl); HTTPConduit conduit = (HTTPConduit) client.getConduit(); HTTPClientPolicy policy = new HTTPClientPolicy(); long timeout = 10 * 60 * 1000;// policy.setConnectionTimeout(timeout); policy.setReceiveTimeout(timeout); conduit.setClient(policy); //動態(tài)invoke方法 Object[] os =client.invoke(method,requestStr); return os[0]; }
方法二:使用JaxWsProxyFactoryBean調(diào)用WebService 原理:使用JaxWsProxyFactoryBean類生成本地的代理類。 首先創(chuàng)建接口,然后通過JaxWsProxyFactoryBean調(diào)用。 Java代碼  @WebService public interface IDataService { @WebMethod @WebResult String getData(@WebParam String requestData); } public static String call(String wsdl, String requestStr) { JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setServiceClass(IDataService.class); factory.setAddress(wsdl); IDataService service = (IDataService) factory.create(); // 設(shè)置超時時間 org.apache.cxf.endpoint.Client proxy = ClientProxy.getClient(service); HTTPConduit conduit = (HTTPConduit) proxy.getConduit(); HTTPClientPolicy policy = new HTTPClientPolicy(); long timeout = 10 * 60 * 1000;// policy.setConnectionTimeout(timeout); policy.setReceiveTimeout(timeout); conduit.setClient(policy); // 發(fā)出請求 return service.getData(requestStr); }
方法三:使用wsimport命令構(gòu)建WebService客戶端 首先使用wsimport命令構(gòu)建客戶端,然后用下面的方法調(diào)用。 Java代碼  public static String call(String requestData) { // 構(gòu)建的客戶端代碼 IDataService_Service factory = new IDataService_Service(); IDataService service = factory.getDataSharedWebService(); long timeout = 30 * 60 * 1000;// 30分鐘 // 設(shè)置超時時間 // 當(dāng)前起作用的配置 ((BindingProvider) service).getRequestContext().put("javax.xml.ws.client.connectionTimeout", timeout); ((BindingProvider) service).getRequestContext().put("javax.xml.ws.client.receiveTimeout", timeout); // 網(wǎng)上搜到的其他設(shè)置超時的方法,當(dāng)前項目沒有起作用 ((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("sun.net.client.defaultConnectTimeout", timeout); ((BindingProvider) service).getRequestContext().put("sun.net.client.defaultReadTimeout", timeout); try { // 調(diào)用WebService return service.getData(requestData); } catch (Exception e) { log.error(e.getMessage()); } return null; }
也可以用cxf的wsdl2java命令構(gòu)建客戶端,調(diào)用方式一樣,但是如何設(shè)置超時時間沒有試。 方法四:使用HttpClient調(diào)用WebService 使用commons-httpclient-3.1,依賴jar包(commons-codec.jar、commons-logging.jar)。 Java代碼  public String call(String wsdl, String requestData) { try { // requestData可以直接用soapui中請求的數(shù)據(jù),注意<![CDATA[]]>的使用 PostMethod postMethod = new PostMethod(wsdl); byte[] b = requestData.getBytes("UTF-8"); InputStream in = new ByteArrayInputStream(b, 0, b.length); RequestEntity re = new InputStreamRequestEntity(in, "text/xml; charset=utf-8"); postMethod.setRequestEntity(re); // 設(shè)置header SOAPAction,不設(shè)置的話,會報異常:no SOAPAction // header,但是SOAPAction的好像任意值都可以 String soapAction = "XX"; postMethod.setRequestHeader("SOAPAction", soapAction); HttpClient client = new HttpClient(); // 設(shè)置超時(不知道默認(rèn)是多久,沒有設(shè)置的時候,也沒有報錯,設(shè)置下保險些) int timeout = 10 * 60 * 1000; client.getHttpConnectionManager().getParams().setConnectionTimeout(timeout); client.getHttpConnectionManager().getParams().setSoTimeout(timeout); // int status = client.executeMethod(postMethod); if (status == 200) {// 成功 InputStream is = postMethod.getResponseBodyAsStream(); /** * 獲取的結(jié)果可以參考用soapui調(diào)用時的返回值, * 如果約定的返回值是XML,并不會像soapui一樣把xml用<![CDATA[]]>包含起來,要注意解析的方法, * 不知道soapui如何處理的,暫時沒時間研究。 */ return getResponseXML(is); } else { log.error("調(diào)用Webservice出錯;錯誤代碼為:" + status); } } catch (Exception e) { log.error(e.getMessage()); } return null; } public String getResponseXML(InputStream response) throws Exception { // 根據(jù)具體的返回值寫的解析 SAXReader reader = new SAXReader(); Document document = reader.read(response); Element root = document.getRootElement(); List<Element> childElements = root.elements(); for (Element child : childElements) { List<Element> datas = child.selectNodes("getOrgInfoResponse/getOrgInfoResponse"); for (Element node : datas) { // 返回約定的xml return node.getText(); } } return null; }
總結(jié)下這次遇到的問題: 1.異常:java.lang.NoSuchFieldError: QUALIFIED jar包沖突,刪除jar包(如果可以的話,不能刪除就用HttpClient的方式)。由于項目中第三方工具需要XmlSchema-1.3.x.jar,而cxf-2.5作為客戶端時需要用到xmlschema-core-2.0.1.jar導(dǎo)致前三種方式都不能用。 2.超時 由于接收數(shù)據(jù)較大,時間較長,必須設(shè)置超時時間。 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 沒有設(shè)置SOAPAction,設(shè)置方式:postMethod.setRequestHeader("SOAPAction", soapAction),soapAction的值是什么好像并不影響結(jié)果。
|