Java程式設計師從笨鳥到菜鳥(七十一)WebService 一種遠端呼叫技術
原文連結:https://blog.csdn.net/c99463904/article/details/76018436 非常感謝作者
前言
隨著 web 應用程式的廣泛使用,不同應用程式之間的通訊也變得更加頻繁,如支付寶獲取銀行介面來獲取相應的賬戶資訊,各種天氣預報軟體獲取氣象局天氣資訊的介面來呈現給使用者等等。
WebService 簡介
簡單的說,WebService 就是一種跨程式語言和跨作業系統平臺的遠端呼叫技術。遠端呼叫技術就是一臺計算機的應用可以呼叫其他計算機上的應用
WebService 原理
XML、SOAP 和 WSDL 就是構成 WebService 平臺的三大技術
- WebService 採用 http 協議來在客戶端和服務端之間傳輸資料,WebService 使用 XML 來封裝資料,XML 主要的優點就是跨平臺
- WebService 通過 http 協議傳送請求和接收結果時,傳送的請求內容和結果內容都採用 XML 格式封裝,並增加了一些特定的 HTTP 訊息頭,以說明 HTTP 訊息的內容格式,這些特定的 HTTP 訊息頭和 XML 內容格式就是 SOAP 協議規定的
- WebService 伺服器端首先要通過一個 WSDL 檔案來說明自己有什麼服務可以對外呼叫。簡單的說,WSDL 就像一個說明書,用於描述 WebService 及其方法、引數和返回值。WSDL 檔案儲存在 Web 伺服器上,通過一個 URL 就可以訪問。客戶端在呼叫一個 WebService 的服務之前,要知道該服務的 WSDL 檔案的地址。WebService 服務提供商可以通過兩種方式來暴露 WSDL 檔案地址:1、註冊到 UDDI 伺服器,以便被人查詢;2、直接告訴客戶端呼叫者。
WebService 入門案例
以模擬獲取所在地區的天氣為例
服務端實現:
天氣查詢介面:
- 編寫SEI(Service Endpoint Interface),SEI在webservice中稱為portType,在java中就是普通介面
package server; /** * @author 明割 * @Description 編寫 SEI(Service EndPoint Interface) SEI 在 web service中稱為portType,在java中就是普通介面 * @date 2018年12月20日 下午3:55:15 * @since JDK 1.8 * @version 1.0 * @Copyright 2018 All rights reserved **/ public interface WeatherInterface { public String queryWeather(String cityName); }
天氣查詢介面實現:
2. 編寫SEI實現類,此類作為webservice提供服務類
package server;
import javax.jws.WebService;
/**
* @author 明割
* @Description web service 服務端
* @date 2018年12月20日 下午3:49:20
* @since JDK 1.8
* @version 1.0
* @Copyright 2018 All rights reserved
**/
@WebService // @WebService 表示該類是一個服務類,需要釋出其中的 public 方法
public class WeatherInterfaceImpl implements WeatherInterface{
@Override
public String queryWeather(String cityName) {
// TODO Auto-generated method stub
System.out.println("獲取城市名:" + cityName);
String weather = "天晴";
return weather;
}
}
主函式(釋出應用):
3. 第三步:釋出服務,Endpoint類釋出服務,publish方法,兩個引數:1.服務地址;2.服務實現類
package server;
import javax.xml.ws.Endpoint;
/**
* @author 明割
* @Description 釋出應用
* @date 2018年12月20日 下午4:00:27
* @since JDK 1.8
* @version 1.0
* @Copyright 2018 All rights reserved
**/
public class WeatherServer {
public static void main(String[] args) {
Endpoint.publish("http://localhost:8080/weather", new WeatherInterfaceImpl());
System.out.println("weather service publish success-");
}
}
4、測試服務是否開啟成功,通過閱讀wsdl,確定客戶端呼叫的介面、方法、引數和返回值存在,證明服務釋出成功
// 在瀏覽器端輸入 http://localhost:8080/weather?wsdl 來獲取 wsdl 檔案進行閱讀
輸入網址之後,服務開啟成功,顯示 wsdl 文件,如下圖:
客戶端實現
// 先使用工具生成客戶端程式碼
// wsimport 是 jdk 自帶的 WebService 客戶端工具,可以根據 wsdl 文件生成客戶端呼叫程式碼
// 1、建立一個客戶端孔祥明,cmd 進入 jdk bin 目錄下
使用如下命令生成客戶端程式碼:(注意 keep 後面網址換成自己客戶端釋出時的網址)
wsimport -s 專案 src 路徑 -p client -keep http:localhost:8080/weather?wsdl
CMD 顯示如下資訊:
正在解析 WSDL...
正在生成程式碼...
正在編譯程式碼...
前往 eclipse 重新重新整理客戶端的專案,下圖會有生成之後的專案結構
2、編寫客戶端程式碼
package client;
/**
* @author 明割
* @Description 客戶端程式碼
* @date 2018年12月20日 下午4:23:31
* @since JDK 1.8
* @version 1.0
* @Copyright 2018 All rights reserved
**/
public class WeaherClient {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 建立伺服器檢視,檢視是從 wsdl 檔案的 service 標籤的 name 屬性獲取
WeatherInterfaceImplService weatherInterfaceImplService = new WeatherInterfaceImplService();
// 獲取服務實現類,實現類從 wsdl 檔案的 portType 的 name 屬性獲取
WeatherInterfaceImpl weatherInterfaceImpl = weatherInterfaceImplService.getPort(WeatherInterfaceImpl.class);
// 獲取查詢方法,從 portType 的 operation 標籤獲取
String weather = weatherInterfaceImpl.queryWeather("北京");
System.out.println("天氣為:" + weather);
}
}
執行結果:
天氣為:天晴
至此,我們完成了客戶端可以獲取遠端服務端的資料,接下來詳解各個部分。
WSDL
wsdl(Web Service Description Language),web 服務描述語言,是 webservice 服務端使用說明書,說明服務端介面、方法、引數和返回值,WSDL 是隨服務釋出成功,自動生成,無需編寫。
文件結構
1、Service:相關埠的集合,包括其關聯的介面、操作、訊息等
2、Binding:特定埠型別的具體協議和資料格式規範
3、portType:服務端點,描述 web service 可被執行的操作方法,以及相關訊息,通過 binding 指向 portType
4、message:定義一個操作(方法)的資料引數
5、type:定義 web service 使用的全部資料型別
閱讀方式
WSDL 文件應該從下往上閱讀:
- 先看 service 標籤,看相應 port 的 binding 屬性,然後通過值查詢上面的 binding 標籤
- 通過 binding 標籤可以獲得具體協議等資訊,然後檢視 binding 的 type 屬性
- 通過 binding 的 type 屬性,查詢對應的 portType,可以獲得可操作的方法和引數、返回值等
- 通過 portType 下的 operation 標籤的 message 屬性,可以向上查詢 message 獲取具體的資料引數資訊
SOAP
SOAP 即簡單物件訪問協議,他使用 http 傳送的 XML 格式的資料,它可以跨平臺,跨防火牆,SOAP 不是 webservice 的專有協議。
SOAP = http + xml
SOAP 結構
1、必需的 Envelop 元素,可把此 XML 文件標識為一條 SOAP 訊息
2、可選的 Header 元素,包含頭部資訊
3、必需的 Body 元素,包含所有的呼叫和響應資訊
4、可選的 Fault 元素,提供相關在批處理此訊息所發生錯誤的資訊
先看下上面天氣程式傳送的資料的格式,這需要一個工具 TCP/IP Monitor,Eclipse 自帶的 Debug 工具之一,用於鋪貨 Http、TCP/IP 協議包。原理是一個代理伺服器,客戶端先把資料傳送到代理伺服器,然後代理伺服器再把資料傳送到服務端,這樣就能獲取請求資料和響應資料
設定代理伺服器
第一步:Windows -> Show View -> other
第二步:搜尋 TCP/IP Monitor,右上角下拉箭頭,選 property
第三步:詳細設定
第一個引數是代理伺服器埠,我們設定 12345
第二個引數是被代理伺服器的地址
第三個引數是被代理伺服器的埠
第四個引數要選擇為 TCP/IP
第四步:設定完之後在 TCP/IP Monitor 有剛才設定的資訊,需要注意 Status 那一項,如果是關閉停止狀態下就需要開啟,之後使用 代理代理埠獲取 wsdl 檔案
第五步:設定成功只有,需要更改一下客戶端要連線的伺服器,改成代理伺服器的埠
將 WeatherInterfaceImplService 裡的所有原來的地址的埠改為 12345
UDDI
UDDI 是一種目錄服務,企業可以使用它對 Web Service 進行註冊和搜尋,如果我們需要一種服務,但是不知道地址(wsdl 等),就可以在 UDDI 中查詢,但是在大部分情況下,都是直到服務地址的
WebService 的客戶端呼叫方式
一、生成客戶端的方式
wsimport是jdk自帶的webservice客戶端工具,可以根據wsdl文件生成客戶端呼叫程式碼(java程式碼).
wsimport.exe位於JAVA_HOME\bin目錄下
常用引數為:
-d<目錄> - 將生成.class檔案。預設引數。
-s<目錄> - 將生成.java檔案。
-p<生成的新包名> -將生成的類,放於指定的包下
例子:
呼叫公網的手機歸屬地查詢服務
公網服務地址(裡面有很多免費呼叫的服務)
http://www.webxml.com.cn/zh_cn/index.aspx
第一步:wsimport 生成客戶端程式碼
wsimport -p cn.cad.mobile -s 專案src路徑 -p client -keep http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl
會出現一些警告,是因為服務端提供的一些方法是SOAP1.2標準的,這個工具沒有實現SOAP1.2標準的生成方式。
第二步:檢視 wsdl 檔案,獲取我們需要的資訊
第三步:根據獲取到的服務名等資訊來建立我們的客戶端
這種方式使用簡單,但一些關鍵的元素在程式碼生成時寫在生成程式碼中,不方便維護
二、service 程式設計呼叫方式
/**
* @author 明割
* @Description service 程式設計呼叫方式
* @date 2018年12月21日 下午3:11:17
* @since JDK 1.8
* @version 1.0
* @Copyright 2018 All rights reserved
**/
public class MobileClient2 {
public static void main(String[] args) throws IOException{
// 建立 WSDL 檔案的 URL
URL wsdlDocumentLocation = new URL("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl");
// 建立服務名稱
// 1、namespaceURL - 名稱空間地址
// 2、localPart - 服務檢視名
QName serviceName = new QName("http://WebXml.com.cn/", "MobileCodeWS");
Service service = Service.create(wsdlDocumentLocation, serviceName);
// 獲取服務實現類
MobileCodeWSSoap mobileCodeWSSoap = service.getPort(MobileCodeWSSoap.class);
// 呼叫方法
String message = mobileCodeWSSoap.getMobileCodeInfo("18720996704", null);
System.out.println("號碼歸屬地為:" + message);
}
}
這種方式可以自定義名稱空間,服務檢視名等元素,方便以後維護,是一種標準的開發方式
三、HttpURLConnection 呼叫方式
這種方式是自己編寫客戶端,不再由工具生成,稍微麻煩
開發步驟:
第一步:建立服務地址
第二步:開啟一個通向服務地址的連線
第三步:設定引數
第四步:組織 SOAP 資料,傳送請求
第五步:接收服務端響應
使用註解修改 WSDL 內容
作用:
使用註解,可以更加形象的描述 web 服務。對自動生成的 wsdl 文件進行修改,為使用者提供一個更加清晰的 wsdl 文件
WebService 的註解都位於 javax.jws 包下:
@WebService - 定義服務,在類上邊
targetNameSpace: 指定名稱空間
name: portType 的名稱
portName: port 的名稱
serviceName: 服務名稱
endpointInterface: SEI 介面地址,如果一個服務類實現了多個介面,只需釋出一個介面的方法,可通過此註解指定釋出服務的介面。
@WebMethod - 定義方法,在公開方法上邊
operationName: 方法名
exclude: 這隻為 true 表示此方法不是 webservice 方法,反之則表示 webservice 方法,預設是 false
@WebResult - 定義返回值,在方法返回值前邊
name: 返回結果值的名稱
程式碼實現:
package server;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
/**
* @author 明割
* @Description web service 服務端
* @date 2018年12月20日 下午3:49:20
* @since JDK 1.8
* @version 1.0
* @Copyright 2018 All rights reserved
**/
//@WebService 表示該類是一個服務類,需要釋出其中的 public 方法
@WebService(
targetNamespace = "http://service.cad.cnm",
portName = "WeatherSOAPPort",
serviceName = "WeatherWSS",
name = "WeatherSOAP"
)
public class WeatherInterfaceImpl implements WeatherInterface{
@WebMethod(
operationName = "getWeather",
exclude = false
)
@Override
public @WebResult(name = "result") String queryWeather(@WebParam(name = "cityName")String cityName) {
// TODO Auto-generated method stub
System.out.println("獲取城市名:" + cityName);
String weather = "天晴";
return weather;
}
}
重新發布服務之後,檢視 wsdl 檔案,發現已經做了相應的更改
SOAP、HTTP、TCP/IP 之間的關係