服務器主動向android手機端推送消息---------Web Service技術解析

Web Service不是框架,更甚至不是一種技術,而是一種跨平臺、跨語言的規範。是爲了解決不同語言所編寫的應用之間如何相互調的需求場景,集中解決:遠程調用、跨平臺調用和跨語言調用。

Web Service在實際中的用途;1、Linux上的java應用,去調用Windows平臺上的C應用。2、不同公司的業務整合,業務整合就要帶來不同公司的系統整合,不同公司的系統可能存在平臺不同、語言不同的問題。

W3C組織對WebService的定義如下,它是一個軟件系統,爲了支持跨網絡的機器間相互操作交互而設計。WebService服務通常被定義爲一組模塊化的API,它們可以通過網絡進行調用,來執行遠程系統的請求服務。以 HTTP 協議爲基礎,通過XML進行客戶端和服務器端通信的框架/組件。  

有兩個關鍵點:

1. 服務端提供的功能 通過 xml 描述

2. 第一步中的描述的功能 嵌入到HTTP協議中,使得能通過HTTP協議進行通信(所謂的 SOAP )。


採用這兩個技術的目的主要是:

1. 跨平臺 支持 HTTP 協議的主機和服務器 都能夠建立通信聯繫 並且大部分的主機和服務器 (99.999% 以上 將支持 HTTP 協議。一般而言,不同目標主機之間的通信,需要通過防火牆,打開某個端口 , HTTP 協議的優勢在於,防火牆一般不會封掉 80 端口 這樣就可以方便,安全的通信。


2. 跨語言 任何語言都支持 XML 文本解析 這個的目的是爲了實現不同語言之間的通信 通信的內容,是被xml 限制的,因此這樣進行通信,能跨越語言障礙,即, Java 開發的服務端,客戶端可以用 訪問 可以用javaVB 等訪問 反之亦然。

當然, 架構比我們上面說到的圖要更爲複雜,上面只是說明了一來一回的通信 實際情況還需要考慮以下問題 ,參照圖例說明:

1. 服務器端 (Provider) 提供統一的標準化服務。 就像開辦一個公司 即 Server Provider), 工商行政管理局,註冊一下公司地址和性質。 目的是 別人要用公司的服務,從工商管理局就知道你的地址。這樣統一的做法,是方便所有的公司以及所有需要公司提供服務的客戶。 並且這些信息是最大限度的公開。


2. 客戶端 (Requester) 到註冊中心 (Registry) 拿到公司的基本信息之後 去找到這個公司 然後使用該公司提供的服務。


注意上面圖中的基本步驟的標號 現解釋如下

1. Provider節點提供好服務後 首先註冊到節點Registry

和 3. Requester節點到Regitry節點查信息找到需要的Provider及其提供的 Service

4. Requester 使用 Provider 提供的服務

其細節部分的流程圖如下圖所示:


1. Client有需要,想調用一個服務,但不知道哪裏去調用 但知道 UDDI Registry 上可以查到。

2. 果然 UDDI 記錄了某個一個叫做 Web Server A 的服務器能提供這樣的服務。

3. 於是 Client 去 Web Server A, 詢問確切的調用方法。

4. Web Server A 看到 Client 提出的確切方法查詢之後, 立即返回給它一個 WSDL 描述的 xml 文檔這裏記錄他能提供的各類方法接口 .

5. Client瞭解到這些之後,將這些 xml 的接口方法,封裝成爲 HTTP 請求 發給 Web Server A. 這些封裝方式採用的是標準的SOAP方式 實質是滿足 HTTP 協議的一些 SOAP 的報文消息。

6. Web Server A 迴應的也是HTTP協議的SOAP。這樣雙方的請求--響應完全暢通。

上面我們看到的是應用原理圖,進一步深入,Webservice協議架構圖如下圖所示:


上面我們詳細介紹了發現Service(UDDI), Service提供的接口描述(WSDL), 調用Service(SOAP), 以及傳輸(HTTP)的的整個過程。這個技術的核心是SOAP

SOAP+HTTP 協議已經足夠成熟,不用我們自己通過xml生成帶有SOAP變遷的HTML腳本,有很多工具可以幫住我們實現。事實上,開發起來還是相當簡便的。 應用開發可分爲如下兩種情況:

情況 A:已知存在 Web Service, 客戶端的開發可以通過以下步驟 

1. 通過UDDI,查找到Client程序需要的Web Service的位置

2 . 通過 WebService 找到 WSDL 接口描述文件

3 . 通過工具,將步驟 得到的 WSDL 文件,生成一個 Client Stub, 這個實質上是代碼 也就是打了一個樁。把這個stub的代碼歸併到 Client 程序中

4.  每次Client需要調用WebService的時候,直接調用步驟4生成的Stub接口,就實現了對 Server 端的調用。

情況B:Server 端的開發,同樣無需做解析SOAP這樣的事,框架會幫我們做好。大致步驟如下 :

1 . 實現 WebServer 需要提供的所有功能

2 . 利用WSDL文件(或者IDL)生成Server Stub, 這些代碼將負責接收從外界獲得的請求,並將其轉發給 Web Server Service Implementation(實現代碼)。當 Service Implementation 的代碼處理完,產生結果之後,又會把結果交給 Server Stub, 然後Server Stub可以產生一個SOAP 的響應 . Server Stub + Server Implementation 合在一起 稱爲 Web Service Container, 個就是讓發送到 WebService 的 HTTP 請求,直接送到 Server Stub 上面的。


Web Service整體處理過程是:對於服務器端就是將已經實現了的應用接口暴露出來供他人調用。對於客戶端來說就是根據WSDL文件來產生對應的客戶端代碼,這樣我們客戶端就可以根據生成的代碼來調用服務器端所暴露出來的接口程序了。

上面說的都是理論,肯定會有點暈。下面通過幾個簡單的例子我們就會清楚瞭解Web Service了。

在開發Web Service時有很多工具,我用的是CFX。

Apache CXF = Celtix + XFireApache CXF 的前身是叫Apache CeltiXfire,現在已經正式更名爲Apache CXF 了,以下簡稱CXFCXF繼承了 Celtix 和 XFire 兩大開源項目的精華,提供了對 JAX-WS全面的支持,並且提供了多種 Binding Data BindingTransport 以及 Format的支持,並且可以根據實際項目的需要,採用 Code First 或者 WSDL First 來輕鬆地實現 Web Services 的發佈和使用。我用的版本是apache-cxf-2.4.0

下載完成後,將其解壓到任意文件夾,我解壓到了D:\。解壓後進入bin目錄會看到*.bat批處理文件,我們以後開發過程中就要用到這些文件。爲了方便使用將bin目錄添加到系統環境變量Path中。例如我的就是將D:\apache-cxf-2.4.0\bin添加到系統環境變量Path的尾端。

添加好後,我們就開始做第一個例子:

每個Web Service組件需要2個部分,接口和實現類。首先開發Web Service服務器端,分爲3個步驟

1、開發一個Web Service業務接口,該接口要用@WebService修飾,代碼如下:


package org.fkjava.cxf.ws;

import javax.jws.WebService;

/*Web Service業務接口,該接口要用@WebService修飾,注意@WebService的位置*/
@WebService
public interface HelloWorld {
	
	public String sayHi(String name);

}

2、開發一個Web Service實現類,實現類也需要用@WebService修飾,代碼如下:


package org.fkjava.cxf.ws.impl;

import java.util.Date;

import javax.jws.WebService;

import org.fkjava.cxf.ws.HelloWorld;

/*endpointInterface爲接口名,注意是完整的接口名(包括完整的包名和類名,serviceName爲服務名可以隨便取,這裏也是注意@WebService的位置*/
@WebService(endpointInterface="org.fkjava.cxf.ws.HelloWorld"
		,serviceName="HelloWorldWs")
public class HelloWorldWs implements HelloWorld {


	public String sayHi(String name) {
		return name + ",您好" + "現在時間是:" + new Date();
	}

}

3、發佈Web Service,發佈Web Service是通過在main函數中處理的,代碼如下:

package main;

import javax.xml.ws.Endpoint;

import org.fkjava.cxf.ws.HelloWorld;
import org.fkjava.cxf.ws.impl.HelloWorldWs;

public class ServerMain {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		HelloWorld hw = new HelloWorldWs();
		/*調用Endpoint的publish方法發佈Web Service,第一個參數是綁定的服務地址,也就是本機的IP地址,
		注意IP地址後面還要跟一個服務名(隨便取),這個名字在獲得WSDL文件時要用*/
		Endpoint.publish("http://192.168.1.117/fkjava", hw);
		System.out.println("Web Service暴露成功");
	}

}


要發佈Web Service還需要引入一些jar包,這些jar包可以在剛纔解壓的apache-cxf-2.4.0\lib目錄下找到,在我本機的絕對路徑就是D:\apache-cxf-2.4.0\lib下可以找到這些jar包。

要在java Project中引入jar包可以右擊工程-->Build Path-->Add Libraries-->User Library-->User Libraries

-->new->cfx2.4(這個是新建的報名,自己取)-->選中剛新建的cfx2.4-->Add External JARS-->選擇要添加的jar包

(可多選)。

整個工程和引入的jar包如下所示:


運行這個工程,然後再瀏覽器重輸入:http://192.168.1.117/fkjava?wsdl(http://192.168.1.117/fkjava

就是主函數中Endpoint.publish("http://192.168.1.117/fkjava", hw)語句的第一個參數)。回車可得WSDL描述文件:

WSDL(Web Service Definition Language)是Web Service描述語言,任何語言實現了Web Service ,都需要提供、

並暴露WSDL文檔。我們的客戶端就是根據WSDL文檔來生成與服務器端對應的客戶端代碼的。

到此,服務器端開發完成,下面來看客戶端。

1、調用CXF提供的wsdl2java工具,根究WSDL文檔生成相應的java代碼。

首先在eclipse中建一個空的java Project: WS_Client


然後使用cfx工具來生成客戶端代碼,操作如下:在cmd中進入剛纔建立的空的工程WS_Client中的src目錄,然後利用wsdl2java來生成客戶端代碼。



這裏wsdl2java是apache-cxf-2.4.0\bin下的批處理文件,因爲之前我們以將此目錄配置到環境變量Path中,所以在此可以直接使用,紅圈中wsdl2java 後面的地址就是產生前面WSDL文檔的地址,當然這裏也可以將之前產生的WSDL文檔內容保存爲文件,然後用wsdl2java + 此文件也可以產生客戶端代碼,但有了地址我們就不需要那麼麻煩了。此時再看剛纔建立的空工程WS_Client中已經有了cfx工具自動生成的代碼(F5刷新下),這些代碼就是服務器端所暴露的應用接口的代理,其中提供的方法與服務器端暴露出來的方法一一對應。


2、找到wsdl2java所生成的類中,一個繼承了Service的類,該類的實例可當成工廠來用(就是上面的org.jkjava.cxf.impl.HelloWorldWs.java中的類,一般也是*.impl中的類)。下面給出部分代碼:

@WebServiceClient(name = "HelloWorldWs", 
                  wsdlLocation = "http://192.168.1.117/fkjava?wsdl",
                  targetNamespace = "http://impl.ws.cxf.fkjava.org/") 
public class HelloWorldWs extends Service {

    public final static URL WSDL_LOCATION;

    public final static QName SERVICE = new QName("http://impl.ws.cxf.fkjava.org/", "HelloWorldWs");
    public final static QName HelloWorldWsPort = new QName("http://impl.ws.cxf.fkjava.org/", "HelloWorldWsPort");
    static {

從上可看到class HelloWorldWs extends Service。

3、在工程中添加包含main方法的類,調用Service子類的實例的getXXXPort(這裏XXX通常都是繼承了Service的類的類名)方法,返回遠程Web Service的代理。代碼如下:

package lee;

import org.fkjava.cxf.ws.HelloWorld;
import org.fkjava.cxf.ws.impl.HelloWorldWs;

public class ClientMain {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		HelloWorldWs factory = new HelloWorldWs();
		/*這裏的HelloWorld是客戶端的HelloWorld,擁有預付氣短HelloWorld向同的方法,
		 此處返回的只是遠程Web Service的代理*/
		HelloWorld hw = factory.getHelloWorldWsPort();
		//相當於調用遠程服務器端HelloWorld中的sayHi()方法。
		System.out.println(hw.sayHi("孫悟空"));

	}

}

這時客戶端工程目錄爲:

這時運行客戶端工程就可以看到控制檯輸出:孫悟空,您好現在時間是:Wed Aug 21 01:07:23 CST 2013。調用服務器端的代碼成功。

這裏需要注意因爲調用的是服務器端的服務,所以客戶端要想運行成功,服務器端必須得是開着的。

第一個例子結束,下篇我們來看下第二個例子。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章