在第二章中,我們演示了如何使用基本的POX-over-HTTP方法來實(shí)現(xiàn)Web服務(wù),同時(shí),我們也介紹了SOAP。SOAP現(xiàn)在已經(jīng)成為業(yè)界不可或缺的技術(shù)和標(biāo)準(zhǔn),因?yàn)楫?dāng)今大多數(shù)跨越合作伙伴的B2B的消息傳輸都是基于SOAP協(xié)議的。但SOAP(簡單對(duì)象訪問協(xié)議)是否象它的名字喻示的那樣“簡單”,人們?nèi)杂袪幾h。但有一點(diǎn)是毋庸置疑的,SOAP是一種開放的標(biāo)準(zhǔn),業(yè)界提供了支持SOAP開發(fā)的工具和框架,對(duì)SOAP進(jìn)行了廣泛的支持。幾乎所有的Web服務(wù)堆棧都采用了SOAP作為網(wǎng)絡(luò)傳輸協(xié)議,基于Java的Web服務(wù)框架更是如此。為了使用Java實(shí)現(xiàn)您自己的Web服務(wù),或者在Java代碼中訪問第三方提供的Web服務(wù),您需要了解,您有多種方法來實(shí)現(xiàn)Web服務(wù)。本章就來向您介紹在Java/J2EE環(huán)境下,實(shí)現(xiàn)Web服務(wù)的主要方法,它們分別是:
(1) 使用JAX-WS 2.0來實(shí)現(xiàn)Web服務(wù)
(2) 使用Apache Axis來實(shí)現(xiàn)Web服務(wù)
(3) 使用Spring來實(shí)現(xiàn)Web服務(wù)
(4) 使用XFire來實(shí)現(xiàn)Web服務(wù)
我們將通過代碼實(shí)例,從頭開始演示如何使用上面的四種技術(shù)框架來創(chuàng)建Web服務(wù),以及如何在代碼中訪問已有的Web服務(wù)。
使用JAX-WS 2.0來實(shí)現(xiàn)Web服務(wù)
JAX-WS是Java API for XML Web Service(XML Web服務(wù)的Java編程接口)的縮寫,JAX-WS2.0規(guī)范替代了以前的JAX-RPC1.0規(guī)范,它是基于JSR224規(guī)范的下一代Web服務(wù)開發(fā)的編程接口。
JAX-WS2.0基礎(chǔ)
JAX-WS2.0項(xiàng)目是在JAX-WS規(guī)范參考實(shí)現(xiàn)的代碼基的基礎(chǔ)上進(jìn)行開發(fā)和演變的,您可以通過https://jax-ws.dev.java.net/ 了解這個(gè)項(xiàng)目。現(xiàn)在,該項(xiàng)目既支持JAX-WS2.0規(guī)范,也支持JAX-WS2.1規(guī)范。
下面列出了JAX-WS2.0實(shí)現(xiàn)中的一些新特性:
(1) 直接支持基于JAXB2.0的數(shù)據(jù)綁定
(2) 支持最新的W3C和WS-I標(biāo)準(zhǔn)(如SOAP 1.2、WSDL 1.2和SAAJ 1.3等標(biāo)準(zhǔn))
(3) 對(duì)Java和WSDL之間映射的元素?fù)?jù)進(jìn)行了標(biāo)準(zhǔn)化
(4) 易于開發(fā)
(5) 使Web服務(wù)的升級(jí)變得簡單
(6) 對(duì)Web服務(wù)的處理器框架進(jìn)行了升級(jí)
(7) 支持異步RPC和非HTTP傳輸
JAX-WS2.0另一個(gè)令人振奮的特點(diǎn)是,它已經(jīng)包含在Java6標(biāo)準(zhǔn)版內(nèi),這意味著基于JAX-WS2.0的代碼和組件能在任何與J2EE兼容的服務(wù)器(如GlassFish服務(wù)器)上運(yùn)行,同時(shí),也可以在Java6標(biāo)準(zhǔn)版的環(huán)境下運(yùn)行,這對(duì)Java開發(fā)者來說確實(shí)是一個(gè)很大的優(yōu)勢(shì)。而此前只有.Net的開發(fā)者享有這項(xiàng)權(quán)利(.Net棧支持輕量級(jí)的Web服務(wù)開發(fā))。
在Java6平臺(tái)下,JAX-WS2.0提供了以下全新的API,用于創(chuàng)建Web應(yīng)用和Web服務(wù)。
API
API所在的包
JAX-WS
javax.xml.ws
SAAJ
javax.xml.soap
WS Metadata
javax.jws
在Java6標(biāo)準(zhǔn)版中實(shí)現(xiàn)Web服務(wù)
下面我們先從最簡單的Web服務(wù)入手,不使用任何應(yīng)用服務(wù)器和第三方Web服務(wù)器,而只是用Java6標(biāo)準(zhǔn)版及其自帶的工具,來開發(fā)并部署一個(gè)簡單的Web服務(wù)。
服務(wù)器及客戶端代碼
如前所述,我們現(xiàn)在就開始開發(fā)這個(gè)簡單的Web服務(wù),這是我們的第一個(gè)示例,具體代碼請(qǐng)參見“ch03\01_JaxWS\JavaStandAlone”目錄。(譯者注:本書代碼請(qǐng)從http://www.packtpub.com/files/code/3216_Code.zip處下載。)
服務(wù)器端代碼由三個(gè)Java文件構(gòu)成,位于\ch03\01_JaxWS\JavaStandAlone\Server\src目錄,下面是對(duì)代碼的詳細(xì)解釋:
Hello.java
Hello是一個(gè)Java接口,其源代碼如下:
public interface IHello{
String sayHello (String name);
}
HelloImpl.java
HelloImpl 實(shí)現(xiàn)了IHello接口中定義的業(yè)務(wù)邏輯方法,該方法將暴露出來作為Web服務(wù)。
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.WebMethod;
@WebService(name="IHello", serviceName="HelloService")
@SOAPBinding(style=SOAPBinding.Style.RPC)
public class HelloImpl implements IHello{
@WebMethod(operationName = "sayHello")
public String sayHello(String name){
System.out.println("HelloImpl.sayHello...");
return "\nHello From Server !! : " + name;
}
}
在上面的HelloImpl的實(shí)現(xiàn)代碼中,我們可以看到一個(gè)叫javax.jws.WebService的Java注解,這個(gè)@WebService注解是將一個(gè)普通類定義為Web服務(wù)發(fā)布對(duì)象(亦稱終端,endpoint),javax.jws.soap.SOAPBinding這個(gè)注解指明了如何將Web服務(wù)綁定到SOAP消息上。HelloImpl只聲明了一個(gè)方法sayHello,該方法帶@WebMethod的注解,這個(gè)注解將會(huì)把該方法暴露給客戶端。其實(shí),考試,大提示要?jiǎng)?chuàng)建一個(gè)JAX-WS服務(wù)并不需要IHello接口,我們這里只是讓大家保持良好的編程習(xí)慣而已?!elloServer.java
HelloServer是服務(wù)器端的主類,它利用javax.xml.ws.Endpoint來發(fā)布Web服務(wù),其代碼如下:
import javax.xml.ws.Endpoint;
public class HelloServer {
public static void main(String args[]) {
log("HelloServer.main : Creating HelloImpl...");
IHello iHello = new HelloImpl();
try{
// Create and publish the endpoint at the given address
log("HelloServer.main : Publishing HelloImpl...");
Endpoint endpoint1 =
Endpoint.publish("http://localhost:8080/Hello", iHello);
log("HelloServer.main : Published Implementor...");
}
catch (Exception e) {
System.err.println("ERROR: " + e);
e.printStackTrace(System.out);
}
System.out.println("HelloServer Exiting ...");
}
}
HelloClient.java
Web服務(wù)客戶端代碼只有一個(gè)Java源文件,位于ch03\01_JaxWS\JavaStandAlone\Client\src目錄。HelloClient依賴于HelloService和IHello這兩個(gè)類,在我們后面對(duì)客戶端代碼進(jìn)行編譯時(shí),這兩個(gè)類可以自動(dòng)生成。客戶端的源代碼非常簡單明了:
public class HelloClient {
public static void main(String args[]) {
log("HelloClient.main : Creating HelloImpl...");
HelloService helloService = null;
IHello helloImpl = null;
String gotFromServer = null;
try {
log("HelloClient.main : Creating HelloImplService...");
if (args.length != 0) {
helloService = new HelloService(new URL(args[0]), new QName(
args[1], args[2]));
} else {
helloService = new HelloService();
}
log("HelloClient.main : Retreiving HelloImpl...");
helloImpl = helloService.getIHelloPort();
log("HelloClient.main : Invoking helloImpl.sayHello(\"Binil\")...");
gotFromServer = helloImpl.sayHello("Binil");
log("HelloClient.main : gotFromServer : " + gotFromServer);
} catch (Exception e) {
System.err.println("ERROR: " + e);
e.printStackTrace(System.out);
}
}
}
首先,您得實(shí)例化HelloServer接口,該實(shí)例中含有連接到Web服務(wù)所必須的管道;然后,您將會(huì)得到Web服務(wù)的端口引用,這樣,您就可以通過端口引用調(diào)用遠(yuǎn)程的Web服務(wù)。
運(yùn)行服務(wù)器和客戶端
如果您沒有修改過本章下載代碼中的examples.PROPERTIES文件,請(qǐng)先修改這個(gè)文件,將其中的路徑指向您的開發(fā)環(huán)境。另外,在本章的下載的代碼中,您也會(huì)看到一個(gè)README文件,這個(gè)文件給出了如何編譯和運(yùn)行示例程序的具體說明。
為了編譯并啟動(dòng)服務(wù)器,您只需鍵入一個(gè)命令,請(qǐng)?jiān)诿钚兄星袚Q到ch03\01_JaxWS\JavaStandAlone目錄,并執(zhí)行下面的命令:
cd ch03\01_JaxWS\JavaStandAlone
ant server
一旦服務(wù)器起來并運(yùn)行,您就可以在另一個(gè)命令行窗口中執(zhí)行ant client命令。當(dāng)我們編譯客戶端代碼時(shí),我們還需要使用下面的ant任務(wù),從發(fā)布的Web服務(wù)中生成幾個(gè)客戶端類:
line="-keep
-d build
-p com.binildas.ws.javastandalone.simple
-s ${gensrc} http://localhost:8080/Hello?WSDL" />
客戶端代碼將依賴于上面這幾個(gè)自動(dòng)生成的類文件。運(yùn)行完GenSrc任務(wù)后,我們就可以開始編譯客戶端代碼,并向服務(wù)器發(fā)送Web請(qǐng)求,并把從服務(wù)器接收到的應(yīng)答打印在控制臺(tái)上,下面的命令將同時(shí)編譯和運(yùn)行客戶端:
cd ch03\01_JaxWS\JavaStandAlone
ant client
(1) 使用JAX-WS 2.0來實(shí)現(xiàn)Web服務(wù)
(2) 使用Apache Axis來實(shí)現(xiàn)Web服務(wù)
(3) 使用Spring來實(shí)現(xiàn)Web服務(wù)
(4) 使用XFire來實(shí)現(xiàn)Web服務(wù)
我們將通過代碼實(shí)例,從頭開始演示如何使用上面的四種技術(shù)框架來創(chuàng)建Web服務(wù),以及如何在代碼中訪問已有的Web服務(wù)。
使用JAX-WS 2.0來實(shí)現(xiàn)Web服務(wù)
JAX-WS是Java API for XML Web Service(XML Web服務(wù)的Java編程接口)的縮寫,JAX-WS2.0規(guī)范替代了以前的JAX-RPC1.0規(guī)范,它是基于JSR224規(guī)范的下一代Web服務(wù)開發(fā)的編程接口。
JAX-WS2.0基礎(chǔ)
JAX-WS2.0項(xiàng)目是在JAX-WS規(guī)范參考實(shí)現(xiàn)的代碼基的基礎(chǔ)上進(jìn)行開發(fā)和演變的,您可以通過https://jax-ws.dev.java.net/ 了解這個(gè)項(xiàng)目。現(xiàn)在,該項(xiàng)目既支持JAX-WS2.0規(guī)范,也支持JAX-WS2.1規(guī)范。
下面列出了JAX-WS2.0實(shí)現(xiàn)中的一些新特性:
(1) 直接支持基于JAXB2.0的數(shù)據(jù)綁定
(2) 支持最新的W3C和WS-I標(biāo)準(zhǔn)(如SOAP 1.2、WSDL 1.2和SAAJ 1.3等標(biāo)準(zhǔn))
(3) 對(duì)Java和WSDL之間映射的元素?fù)?jù)進(jìn)行了標(biāo)準(zhǔn)化
(4) 易于開發(fā)
(5) 使Web服務(wù)的升級(jí)變得簡單
(6) 對(duì)Web服務(wù)的處理器框架進(jìn)行了升級(jí)
(7) 支持異步RPC和非HTTP傳輸
JAX-WS2.0另一個(gè)令人振奮的特點(diǎn)是,它已經(jīng)包含在Java6標(biāo)準(zhǔn)版內(nèi),這意味著基于JAX-WS2.0的代碼和組件能在任何與J2EE兼容的服務(wù)器(如GlassFish服務(wù)器)上運(yùn)行,同時(shí),也可以在Java6標(biāo)準(zhǔn)版的環(huán)境下運(yùn)行,這對(duì)Java開發(fā)者來說確實(shí)是一個(gè)很大的優(yōu)勢(shì)。而此前只有.Net的開發(fā)者享有這項(xiàng)權(quán)利(.Net棧支持輕量級(jí)的Web服務(wù)開發(fā))。
在Java6平臺(tái)下,JAX-WS2.0提供了以下全新的API,用于創(chuàng)建Web應(yīng)用和Web服務(wù)。
API
API所在的包
JAX-WS
javax.xml.ws
SAAJ
javax.xml.soap
WS Metadata
javax.jws
在Java6標(biāo)準(zhǔn)版中實(shí)現(xiàn)Web服務(wù)
下面我們先從最簡單的Web服務(wù)入手,不使用任何應(yīng)用服務(wù)器和第三方Web服務(wù)器,而只是用Java6標(biāo)準(zhǔn)版及其自帶的工具,來開發(fā)并部署一個(gè)簡單的Web服務(wù)。
服務(wù)器及客戶端代碼
如前所述,我們現(xiàn)在就開始開發(fā)這個(gè)簡單的Web服務(wù),這是我們的第一個(gè)示例,具體代碼請(qǐng)參見“ch03\01_JaxWS\JavaStandAlone”目錄。(譯者注:本書代碼請(qǐng)從http://www.packtpub.com/files/code/3216_Code.zip處下載。)
服務(wù)器端代碼由三個(gè)Java文件構(gòu)成,位于\ch03\01_JaxWS\JavaStandAlone\Server\src目錄,下面是對(duì)代碼的詳細(xì)解釋:
Hello.java
Hello是一個(gè)Java接口,其源代碼如下:
public interface IHello{
String sayHello (String name);
}
HelloImpl.java
HelloImpl 實(shí)現(xiàn)了IHello接口中定義的業(yè)務(wù)邏輯方法,該方法將暴露出來作為Web服務(wù)。
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.WebMethod;
@WebService(name="IHello", serviceName="HelloService")
@SOAPBinding(style=SOAPBinding.Style.RPC)
public class HelloImpl implements IHello{
@WebMethod(operationName = "sayHello")
public String sayHello(String name){
System.out.println("HelloImpl.sayHello...");
return "\nHello From Server !! : " + name;
}
}
在上面的HelloImpl的實(shí)現(xiàn)代碼中,我們可以看到一個(gè)叫javax.jws.WebService的Java注解,這個(gè)@WebService注解是將一個(gè)普通類定義為Web服務(wù)發(fā)布對(duì)象(亦稱終端,endpoint),javax.jws.soap.SOAPBinding這個(gè)注解指明了如何將Web服務(wù)綁定到SOAP消息上。HelloImpl只聲明了一個(gè)方法sayHello,該方法帶@WebMethod的注解,這個(gè)注解將會(huì)把該方法暴露給客戶端。其實(shí),考試,大提示要?jiǎng)?chuàng)建一個(gè)JAX-WS服務(wù)并不需要IHello接口,我們這里只是讓大家保持良好的編程習(xí)慣而已?!elloServer.java
HelloServer是服務(wù)器端的主類,它利用javax.xml.ws.Endpoint來發(fā)布Web服務(wù),其代碼如下:
import javax.xml.ws.Endpoint;
public class HelloServer {
public static void main(String args[]) {
log("HelloServer.main : Creating HelloImpl...");
IHello iHello = new HelloImpl();
try{
// Create and publish the endpoint at the given address
log("HelloServer.main : Publishing HelloImpl...");
Endpoint endpoint1 =
Endpoint.publish("http://localhost:8080/Hello", iHello);
log("HelloServer.main : Published Implementor...");
}
catch (Exception e) {
System.err.println("ERROR: " + e);
e.printStackTrace(System.out);
}
System.out.println("HelloServer Exiting ...");
}
}
HelloClient.java
Web服務(wù)客戶端代碼只有一個(gè)Java源文件,位于ch03\01_JaxWS\JavaStandAlone\Client\src目錄。HelloClient依賴于HelloService和IHello這兩個(gè)類,在我們后面對(duì)客戶端代碼進(jìn)行編譯時(shí),這兩個(gè)類可以自動(dòng)生成。客戶端的源代碼非常簡單明了:
public class HelloClient {
public static void main(String args[]) {
log("HelloClient.main : Creating HelloImpl...");
HelloService helloService = null;
IHello helloImpl = null;
String gotFromServer = null;
try {
log("HelloClient.main : Creating HelloImplService...");
if (args.length != 0) {
helloService = new HelloService(new URL(args[0]), new QName(
args[1], args[2]));
} else {
helloService = new HelloService();
}
log("HelloClient.main : Retreiving HelloImpl...");
helloImpl = helloService.getIHelloPort();
log("HelloClient.main : Invoking helloImpl.sayHello(\"Binil\")...");
gotFromServer = helloImpl.sayHello("Binil");
log("HelloClient.main : gotFromServer : " + gotFromServer);
} catch (Exception e) {
System.err.println("ERROR: " + e);
e.printStackTrace(System.out);
}
}
}
首先,您得實(shí)例化HelloServer接口,該實(shí)例中含有連接到Web服務(wù)所必須的管道;然后,您將會(huì)得到Web服務(wù)的端口引用,這樣,您就可以通過端口引用調(diào)用遠(yuǎn)程的Web服務(wù)。
運(yùn)行服務(wù)器和客戶端
如果您沒有修改過本章下載代碼中的examples.PROPERTIES文件,請(qǐng)先修改這個(gè)文件,將其中的路徑指向您的開發(fā)環(huán)境。另外,在本章的下載的代碼中,您也會(huì)看到一個(gè)README文件,這個(gè)文件給出了如何編譯和運(yùn)行示例程序的具體說明。
為了編譯并啟動(dòng)服務(wù)器,您只需鍵入一個(gè)命令,請(qǐng)?jiān)诿钚兄星袚Q到ch03\01_JaxWS\JavaStandAlone目錄,并執(zhí)行下面的命令:
cd ch03\01_JaxWS\JavaStandAlone
ant server
一旦服務(wù)器起來并運(yùn)行,您就可以在另一個(gè)命令行窗口中執(zhí)行ant client命令。當(dāng)我們編譯客戶端代碼時(shí),我們還需要使用下面的ant任務(wù),從發(fā)布的Web服務(wù)中生成幾個(gè)客戶端類:
line="-keep
-d build
-p com.binildas.ws.javastandalone.simple
-s ${gensrc} http://localhost:8080/Hello?WSDL" />
客戶端代碼將依賴于上面這幾個(gè)自動(dòng)生成的類文件。運(yùn)行完GenSrc任務(wù)后,我們就可以開始編譯客戶端代碼,并向服務(wù)器發(fā)送Web請(qǐng)求,并把從服務(wù)器接收到的應(yīng)答打印在控制臺(tái)上,下面的命令將同時(shí)編譯和運(yùn)行客戶端:
cd ch03\01_JaxWS\JavaStandAlone
ant client