java呼叫webservice介面 幾種方法
webservice的 釋出一般都是使用WSDL(web service descriptive language)檔案的樣式來發布的,在WSDL檔案裡面,包含這個webservice暴露在外面可供使用的介面。今天搜尋到了非常好的 webservice provider列表
http://www.webservicex.net/WCF/default.aspx
這上面列出了70多個包括很多方面的free webservice provider,utilities->global weather就可以獲取全球的天氣預報。
下面我們來看Java如何通過WSDL檔案來呼叫這些web service:
注意,以下的程式碼並沒有經過真正的測試,只是說明這些情況,不同版本的Axis相差很大,大家最好以apache網站上的例子為準,這裡僅僅用於說明其基本用法。
1,直接AXIS呼叫遠端的web service
我覺得這種方法比較適合那些高手,他們能直接看懂XML格式的WSDL檔案,我自己是看不懂的,尤其我不是專門搞這行的,即使一段時間看懂,後來也就忘記了。直接呼叫模式如下:
import java.util.Date; import java.text.DateFormat; import org.apache.axis.client.Call; import org.apache.axis.client.Service; import javax.xml.namespace.QName; import java.lang.Integer; import javax.xml.rpc.ParameterMode; public class caClient { public static void main(String[] args) { try { String endpoint = "http://localhost:8080/ca3/services/caSynrochnized?wsdl"; // 直接引用遠端的wsdl檔案 // 以下都是套路 Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress(endpoint); call.setOperationName("addUser");// WSDL裡面描述的介面名稱 call.addParameter("userName", org.apache.axis.encoding.XMLType.XSD_DATE, javax.xml.rpc.ParameterMode.IN);// 介面的引數 call.setReturnType(org.apache.axis.encoding.XMLType.XSD_STRING);// 設定返回型別 String temp = "測試人員"; String result = (String) call.invoke(new Object[] { temp }); // 給方法傳遞引數,並且呼叫方法 System.out.println("result is " + result); } catch (Exception e) { System.err.println(e.toString()); } } }
2,直接SOAP呼叫遠端的webservice
這種模式我從來沒有見過,也沒有試過,但是網路上有人貼出來,我也轉過來
import org.apache.soap.util.xml.*; import org.apache.soap.*; import org.apache.soap.rpc.*; import java.io.*; import java.net.*; import java.util.Vector; public class caService { public static String getService(String user) { URL url = null; try { url = new URL( "http://192.168.0.100:8080/ca3/services/caSynrochnized"); } catch (MalformedURLException mue) { return mue.getMessage(); } // This is the main SOAP object Call soapCall = new Call(); // Use SOAP encoding soapCall.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); // This is the remote object we're asking for the price soapCall.setTargetObjectURI("urn:xmethods-caSynrochnized"); // This is the name of the method on the above object soapCall.setMethodName("getUser"); // We need to send the ISBN number as an input parameter to the method Vector soapParams = new Vector(); // name, type, value, encoding style Parameter isbnParam = new Parameter("userName", String.class, user, null); soapParams.addElement(isbnParam); soapCall.setParams(soapParams); try { // Invoke the remote method on the object Response soapResponse = soapCall.invoke(url, ""); // Check to see if there is an error, return "N/A" if (soapResponse.generatedFault()) { Fault fault = soapResponse.getFault(); String f = fault.getFaultString(); return f; } else { // read result Parameter soapResult = soapResponse.getReturnValue(); // get a string from the result return soapResult.getValue().toString(); } } catch (SOAPException se) { return se.getMessage(); } } }
3,使用wsdl2java把WSDL檔案轉成本地類,然後像本地類一樣使用,即可。
這是像我這種懶人最喜歡的方式,仍然以前面的global weather report為例。
首先 java org.apache.axis.wsdl.WSDL2Java http://www.webservicex.net/globalweather.asmx.WSDL
原本的網址是http://www.webservicex.net/globalweather.asmx?WSDL,中間個各問號,但是Linux下面它不能解析,所以去掉問號,改為點號。
那麼就會出現4個檔案:
GlobalWeather.java
GlobalWeatherLocator.java
GlobalWeatherSoap.java
GlobalWeatherSoapStub.java
其中GlobalWeatherSoap.java是我們最為關心的介面檔案,如果你對RMI等SOAP實現的具體細節不感興趣,那麼你只需要看介面檔案即可,
在使用的時候,引入這個介面即可,就好像使用本地類一樣。
一:webService介紹
1.什麼是webService
webService是一種使用http傳輸SOAP協議資料的遠端呼叫技術
2.webService三要素
SOAP:規範XML標籤
WSDL:服務端的使用說明書
UDDI:目錄
二:webService入門小程式
1.服務端
(1)、開發步驟
A、建立介面
package com.webservice.jaxws;
public interface WeatherService {
//查詢天氣的方法
public String queryWeather(String cityName);
}
B、建立實現類,在實現類上加入@WebService註解,該註解的作用是標識該實現類是webservice的服務類,釋出該實現類中的public方法
package com.webservice.jaxws;
import javax.jws.WebService;
/**
* 天氣查詢的實現類
* @author Administrator
*
*/
@WebService
public class WeatherServiceImpl implements WeatherService {
//查詢天氣
public String queryWeather(String cityName) {
System.out.println(cityName + "天氣是:晴天");
return "晴";
}
}
C、釋出服務,使用EndPoint類中的publish()方法釋出,引數分別為服務訪問的地址和服務的實現類
package com.webservice.jaxws;
import javax.jws.WebService;
/**
* 天氣查詢的實現類
* @author Administrator
*
*/
@WebService
public class WeatherServiceImpl implements WeatherService {
//查詢天氣
public String queryWeather(String cityName) {
System.out.println(cityName + "天氣是:晴天");
return "晴";
}
}
D、測試服務是否釋出成功,閱讀使用說明書,確認要呼叫的類、方法、引數等
● WSDL訪問地址:
● WSDL說明書閱讀方式:從下往上閱讀
E、如何釋出SOAP1.2版本的服務端
● 引入第三方jar包
● 在服務實現類上加入註解 @BindingType(SOAPBinding.SOAP12HTTP_BINDING)
package com.webservice.jaxws;
import javax.jws.WebService;
import javax.xml.ws.BindingType;
import javax.xml.ws.soap.SOAPBinding;
/**
* 天氣查詢的實現類
* @author Administrator
*
*/
@WebService
@BindingType(SOAPBinding.SOAP12HTTP_BINDING)
public class WeatherServiceImpl implements WeatherService {
//查詢天氣
public String queryWeather(String cityName) {
System.out.println(cityName + "天氣是:晴天");
return "晴";
}
}
2.客戶端
(1)、開發步驟
A、在工作空間建立用於存放使用wsimport命令生成的客戶端程式碼的java工程
B、使用jdk提供的wsimport命令生成客戶端程式碼
● wsimport命令是jdk提供的,作用是根據使用說明書生成客戶端程式碼,wsimport只支援SOAP1.1客戶端的生成
● wsimport常用引數
-d:預設引數,用於生成.class檔案
-s:生成.java檔案
-p:指定生成java檔案的包名,不指定則為WSDL說明書中namespace值得倒寫
C、在doc視窗進入java工程專案的src目錄,執行wsimport命令
D、在Eclipse中重新整理java專案,將生成的客戶端程式碼copy到客戶端工程中
E、建立服務檢視,類名從<service>標籤的name屬性獲取
F、獲取服務實現類,檢視例項呼叫getProt()方法,實現類的類名從portType的name屬性獲取
G、呼叫查詢方法,方法名從portType下的operation標籤的name屬性獲取
package com.webservice.client;
import com.webservice.jaxws.WeatherServiceImpl;
import com.webservice.jaxws.WeatherServiceImplService;
public class Client {
public static void main(String[] args) {
//建立檢視
WeatherServiceImplService wsis = new WeatherServiceImplService();
//獲取服務實現類
WeatherServiceImpl wsi = wsis.getPort(WeatherServiceImpl.class);
//呼叫查詢方法
String weather = wsi.queryWeather("北京");
System.out.println(weather);
}
}
三:webService三要素詳解
1.WSDL
(1)、定義
WSDL即web服務描述語言,它是服務端的使用說明書,是XML格式的文件,說明服務地址、服務類、方法、引數和返回值,是伴隨服務釋出成功,自動生成的
(2)、文件結構
● <service> 服務檢視,webservice的服務結點,它包括了服務端點
● <binding> 為每個服務端點定義訊息格式和協議細節
● <portType> 服務端點,描述 web service可被執行的操作方法,以及相關的訊息,通過binding指向portType
● <message> 定義一個操作(方法)的資料引數(可有多個引數)
● <types> 定義 web service 使用的全部資料型別
2.SOAP
(1)、定義
SOAP即簡單物件訪問協議(Simple Object Access Protocol),使用http傳送XML格式的資料,他不是webservice的專有協議
(2)、結構 SOAP = HTTP + XML
(3)、協議的格式
Envelope:必須有,此元素將整個 XML 文件標識為一條SOAP訊息
Header:可選元素,包含頭部資訊
Body:必須有,包含所有呼叫和響應資訊
Fault:可選元素,提供有關在處理此訊息時所發生的錯誤資訊
(4)、版本
A、SOAP1.1
● 請求
POST /weather HTTP/1.1
Accept: text/xml, multipart/related
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://jaxws.ws.itcast.cn/WeatherInterfaceImpl/queryWeatherRequest"
User-Agent: JAX-WS RI 2.2.4-b01
Host: 127.0.0.1:54321
Connection: keep-alive
Content-Length: 211
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body><ns2:queryWeather xmlns:ns2="http://jaxws.ws.itcast.cn/"><arg0>北京</arg0></ns2:queryWeather>
</S:Body>
</S:Envelope>
● 響應
HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: text/xml; charset=utf-8
Date: Fri, 04 Dec 2015 03:45:56 GMT
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:queryWeatherResponse xmlns:ns2="http://jaxws.ws.itcast.cn/"><return>晴</return></ns2:queryWeatherResponse>
</S:Body>
</S:Envelope>
B、SOAP1.2
● 請求
POST /weather HTTP/1.1
Accept: application/soap+xml, multipart/related
Content-Type: application/soap+xml; charset=utf-8;
action="http://jaxws.ws.itcast.cn/WeatherInterfaceImpl/queryWeatherRequest"
User-Agent: JAX-WS RI 2.2.4-b01
Host: 127.0.0.1:54321
Connection: keep-alive
Content-Length: 209
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope">
<S:Body><ns2:queryWeather xmlns:ns2="http://jaxws.ws.itcast.cn/"><arg0>北京</arg0></ns2:queryWeather>
</S:Body>
</S:Envelope>
● 響應
HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: application/soap+xml; charset=utf-8
Date: Fri, 04 Dec 2015 03:55:49 GMT
<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope">
<S:Body>
<ns2:queryWeatherResponse xmlns:ns2="http://jaxws.ws.itcast.cn/"><return>晴</return></ns2:queryWeatherResponse>
</S:Body>
</S:Envelope>
C、SOAP1.1 和 SOAP1.2的區別
● 相同點
請求方式都是POST
協議格式都一樣,都有envelope和body
● 不同點
①、資料格式不同
SOAP1.1:text/xml;charset=utf-8
SOAP1.2:application/soap+xml;charset=utf-8
②、名稱空間不同
四:webservice客戶端的四種呼叫方式
1.生成客戶端呼叫方式
(1)、開發步驟
A、wisimport生成客戶端程式碼
B、建立服務檢視
C、獲取實現類
D、呼叫查詢方法
2.service程式設計實現呼叫
(1)、開發步驟
A、wisimport生成客戶端程式碼
B、使用serivce類建立服務檢視
C、獲取服務實現類
D、呼叫查詢方法
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import cn.itcast.mobile.MobileCodeWSSoap;
/**
*
* <p>Title: ServiceClient.java</p>
* <p>Description:Service程式設計實現客戶端</p>
*/
public class ServiceClient {
public static void main(String[] args) throws IOException {
//建立WSDL地址,不是服務地址
URL url = new URL("http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl");
//建立服務名稱
//1.namespaceURI - 名稱空間地址
//2.localPart - 服務名稱
QName qname = new QName("http://WebXml.com.cn/", "MobileCodeWS");
//Service建立檢視
//引數:
//1.wsdlDocumentLocation - 使用說明書地址
//2.serviceName - 服務名稱
Service service = Service.create(url, qname);
//獲取實現類
MobileCodeWSSoap mobileCodeWSSoap = service.getPort(MobileCodeWSSoap.class);
//呼叫查詢方法
String result = mobileCodeWSSoap.getMobileCodeInfo("188888888", "");
System.out.println(result);
}
}
特點:方便管理,是一個標準的開發方式
3.HttpURLConnection呼叫方式
(1)、開發步驟
A、建立服務地址
B、開啟服務地址的一個連線
C、設定連線引數
● 注意
a、POST必須大寫,如果小寫會出如下異常:
b、如果不設定輸入輸出,會報如下異常:
D、組織SOAP協議資料,傳送給伺服器
E、接收服務端的響應
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
*
* <p>Title: HttpClient.java</p>
* <p>Description:HttpURLConnection呼叫方式</p>
*/
public class HttpClient {
public static void main(String[] args) throws IOException {
//1:建立服務地址
URL url = new URL("http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx");
//2:開啟到服務地址的一個連線
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//3:設定連線引數
//3.1設定傳送方式:POST必須大寫
connection.setRequestMethod("POST");
//3.2設定資料格式:Content-type
connection.setRequestProperty("content-type", "text/xml;charset=utf-8");
//3.3設定輸入輸出,新建立的connection預設是沒有讀寫許可權的,
connection.setDoInput(true);
connection.setDoOutput(true);
//4:組織SOAP協議資料,傳送給服務端
String soapXML = getXML("1866666666");
OutputStream os = connection.getOutputStream();
os.write(soapXML.getBytes());
//5:接收服務端的響應
int responseCode = connection.getResponseCode();
if(200 == responseCode){//表示服務端響應成功
InputStream is = connection.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String temp = null;
while(null != (temp = br.readLine())){
sb.append(temp);
}
System.out.println(sb.toString());
is.close();
isr.close();
br.close();
}
os.close();
}
/**
* <?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<getMobileCodeInfo xmlns="http://WebXml.com.cn/">
<mobileCode>string</mobileCode>
<userID>string</userID>
</getMobileCodeInfo>
</soap:Body>
</soap:Envelope>
* @param phoneNum
* @return
*/
public static String getXML(String phoneNum){
String soapXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
+"<soap:Body>"
+"<getMobileCodeInfo xmlns=\"http://WebXml.com.cn/\">"
+"<mobileCode>"+phoneNum+"</mobileCode>"
+"<userID></userID>"
+"</getMobileCodeInfo>"
+" </soap:Body>"
+"</soap:Envelope>";
return soapXML;
}
}
4.Ajax呼叫方式
<!doctype html>
<html lang="en">
<head>
<title>Ajax呼叫方式</title>
<script type="text/javascript">
function queryMobile(){
//建立XMLHttpRequest物件
var xhr = new XMLHttpRequest();
//開啟連結
xhr.open("post","http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx",true);
//設定content-type
xhr.setRequestHeader("content-type","text/xml;charset=utf-8");
//設定回撥函式
xhr.onreadystatechange=function(){
//判斷客戶端傳送成功&&服務端響應成功
if(4 == xhr.readyState && 200 == xhr.status){
alert(xhr.responseText);
}
}
//組織SOAP協議資料
var soapXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
+"<soap:Body>"
+"<getMobileCodeInfo xmlns=\"http://WebXml.com.cn/\">"
+"<mobileCode>"+document.getElementById("phoneNum").value+"</mobileCode>"
+"<userID></userID>"
+"</getMobileCodeInfo>"
+" </soap:Body>"
+"</soap:Envelope>";
alert(soapXML);
//傳送請求
xhr.send(soapXML);
}
</script>
</head>
<body>
手機號歸屬地查詢:<input type="text" id="phoneNum" /><input type="button" value="查詢" onclick="javascript:queryMobile();"/>
</body>
</html>
五、深入開發:用註解修改WSDL內容
1.WebService的註解都位於javax.jws包下:
@WebService-定義服務,在public class上邊
targetNamespace:指定名稱空間
name:portType的名稱
portName:port的名稱
serviceName:服務名稱
endpointInterface:SEI介面地址,如果一個服務類實現了多個介面,只需要釋出一個介面的方法,可通過此註解指定要釋出服務的介面。
@WebMethod-定義方法,在公開方法上邊
operationName:方法名
exclude:設定為true表示此方法不是webservice方法,反之則表示webservice方法
@WebResult-定義返回值,在方法返回值前邊
name:返回結果值的名稱
@WebParam-定義引數,在方法引數前邊
name:指定引數的名稱
作用:
通過註解,可以更加形像的描述Web服務。對自動生成的wsdl文件進行修改,為使用者提供一個更加清晰的wsdl文件。
當修改了WebService註解之後,會影響客戶端生成的程式碼。呼叫的方法名和引數名也發生了變化,必須重新生成客戶端程式碼
示例:
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.ws.BindingType;
import javax.xml.ws.soap.SOAPBinding;
/**
*
* <p>Title: WeatherInterfaceImpl.java</p>
* <p>Description:SEI實現類</p>
*/
@WebService(
targetNamespace="http://service.itcast.cn",
name="WeatherWSSoap",
portName="WeatherWSSoapPort",
serviceName="WeatherWS"
)
@BindingType(SOAPBinding.SOAP12HTTP_BINDING)
public class WeatherInterfaceImpl implements WeatherInterface {
@WebMethod(
operationName="getWeather",
exclude=false
)
@Override
public @WebResult(name="result")String queryWeather(@WebParam(name="cityName")String cityName) {
System.out.println("from client..."+cityName);
String weather = "晴";
return weather;
}
}