什麼是WebService,顧名思義,就是基於Web的服務,它使用Http方式接收和響應外部系統的某種請求,從而實現遠程調用。WebService實際上就是依據某些標準,不關心對方使用的是何種語言,實現對外部其它應用程序提供跨平臺、跨語言服務的一種技術。html
使用WebService,咱們能夠調用互聯網上查詢天氣信息的Web服務,而後將其嵌入到咱們的程序中,當用戶從咱們的網點看到天氣信息的時候,他會覺得咱們爲他提供了不少的信息服務,但其實咱們什麼也沒有作,只是簡單調用了一下服務器上的一端代碼而已。java
以前曾經說過Spring的遠程調用,實際上WebService的功能和Spring的遠程調用徹底相同,WebService的本質也就是遠程調用,只不過Spring和WebService的實現原理不相同而已。比較WebService和Spring的遠程調用:web
1.Spring遠程調用在網絡上傳輸的是「串行化對象」,而WebService在網絡上傳輸的是XML字符串。spring
2.Spring遠程調用效率更高,由於它傳輸的是真正的「數據」,而爲了知足傳輸的XML的規範,WebService須要將數據進行一層層的封裝,好比服務端須要傳遞給客戶端一個大小爲100的List<Student>list,使用Spring的遠程調用直接傳遞該對象到網絡流便可,可是使用WebService卻必須得將數據進行嚴格的規整以使其知足XML的規範(示例,實際上的傳輸規範並非這樣):瀏覽器
<List> <Student> <id>1</id> <name>小張</name> <sex>男</sex> <age>13</age> <phone>111111111</phone> <email>11111@123.com</email> </Student> <Student> <id>2</id> <name>小李</name> <sex>女</sex> <age>15</age> <phone>2222222</phone> <email>22222@123.com</email> </Student> ...此處省略98個Student... </List>
這樣致使的問題就是傳輸了大量的「無用字符」,也就是大量的標籤了,實際上在上述的例子中標籤所佔據的字符數量幾乎和要傳遞的數據量同樣多,其效率之低是顯而易見的。服務器
3.spring遠程調用要求兩個程序都使用spring環境(java環境),可是WebService能夠實現跨平臺通訊,也就是說即便兩個程序之間使用的不是同一種語言,好比一個PHP的程序和Java的程序,他們也可以相互通訊,這是WebService的最大賣點。網絡
4.在不考慮通用性的狀況下,若是程序兩端都使用了Spring,那麼就使用Spring的遠程調用;若是平臺語言不相同,則使用WebService;若是考慮到通用性,即須要向大衆提供服務,那麼必定得使用Webservice。eclipse
全名爲WebService Description Language ,翻譯過來就是Web服務描述語言。它使用XML描述服務的地址,服務提供的方法以及參數列表、返回值類型等,實際上就是一個Web服務的說明書,好比webxml.com.cn網站提供了天氣預報查詢的服務,對應的WSDL就是:http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx?wsdl工具
全名爲Simple Object Access Protocol,翻譯過來就是簡單對象訪問協議,SOAP是一種XML語言的協議,用於在網絡上傳輸數據。學習
SOAP=XML+HTTP
SOAP是基於Http協議的,SOAP的組成:Envelope,這是必須的部分,以XML根元素的形式出現;Headers,可選;Body,必須的部分,包含要執行的服務器上的方法和發送到服務器上的數據。
1 package com.kdyzm.ws; 2 3 import javax.jws.WebService; 4 import javax.xml.ws.Endpoint; 5 6 @WebService 7 public class MyWsServer { 8 public String calculate(int input){ 9 return input*input+""; 10 } 11 public static void main(String[] args) { 12 Endpoint.publish("http://localhost:9090/ws", new MyWsServer()); 13 System.out.println("server ready ......"); 14 } 15 }
OK,一個最簡單的WebService服務就發佈了。
對以上的代碼的說明:在Java中,使用EndPoint類發佈服務,使用該類發佈服務的方法是publish方法,該方法由兩個參數,一個參數是發佈服務的地址,另一個參數是提供服務的類;當執行到publish方法的時候,程序會新開一個線程專門用於提供服務,主線程會繼續執行下去,因此下面的打印的代碼會不受影響的執行。
另外,提供服務的類至少應當提供一個非靜態方法不然服務啓動不起來。
如何查看wsdl?在瀏覽器上輸入http://localhost:9090/ws?wsdl,回車便可查看wsdl內容:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is 3 JAX-WS RI 2.1.6 in JDK 6. --> 4 <!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is 5 JAX-WS RI 2.1.6 in JDK 6. --> 6 <definitions 7 xmlns="http://schemas.xmlsoap.org/wsdl/" 8 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 9 xmlns:tns="http://ws.kdyzm.com/" 10 xmlns:xsd="http://www.w3.org/2001/XMLSchema" 11 targetNamespace="http://ws.kdyzm.com/" 12 name="MyWsServerService"> 13 <types> 14 <xsd:schema> 15 <xsd:import namespace="http://ws.kdyzm.com/" 16 schemaLocation="http://localhost:9090/ws?xsd=1"></xsd:import> 17 </xsd:schema> 18 </types> 19 <message name="calculate"> 20 <part name="parameters" element="tns:calculate"></part> 21 </message> 22 <message name="calculateResponse"> 23 <part name="parameters" element="tns:calculateResponse"></part> 24 </message> 25 <portType name="MyWsServer"> 26 <operation name="calculate"> 27 <input message="tns:calculate"></input> 28 <output message="tns:calculateResponse"></output> 29 </operation> 30 </portType> 31 <binding name="MyWsServerPortBinding" type="tns:MyWsServer"> 32 <soap:binding transport="http://schemas.xmlsoap.org/soap/http" 33 style="document"></soap:binding> 34 <operation name="calculate"> 35 <soap:operation soapAction=""></soap:operation> 36 <input> 37 <soap:body use="literal"></soap:body> 38 </input> 39 <output> 40 <soap:body use="literal"></soap:body> 41 </output> 42 </operation> 43 </binding> 44 <service name="MyWsServerService"> 45 <port name="MyWsServerPort" binding="tns:MyWsServerPortBinding"> 46 <soap:address location="http://localhost:9090/ws"></soap:address> 47 </port> 48 </service> 49 </definitions>
若是能力足夠高的話,直接閱讀wsdl文件就可以直接向服務器請求並獲取服務了,可是通常來講這麼作很是的複雜,爲了提升開發效率,在java環境下咱們使用wsimport命令生成本地調用代碼,而後直接使用這些生成的代碼就能夠了。
wsimport命令是jdk提供的命令,可是應當注意的是,該命令只是在jdk1.6.0_24及以上的版本才提供,因此若是使用了jdk1.5的版本確定不能支持。
wsimport命令可以解析指定的wsdl文件並將根據wsdl文件中的配置生成對應的java代碼並將其編譯成class文件。
wsimport命令的經常使用參數:
-d <目錄名>:將會生成.class文件,默認參數,就算不使用該參數也會自動加上。
-s <目錄名>:將會生成java文件
-p <生成的包名>:將生成的類放到指定的目錄下。
步驟:使用命令生成本地調用代碼:wsimport -s . http://localhost:9090/ws?wsdl
任務執行完畢以後,會在當前目錄下生成一個文件夾,文件夾中存放着全部將要使用到的java類和編譯以後的.class文件
將全部的class文件刪除掉,以後將文件夾直接拷貝到項目中便可使用。
注意事項:若是是咱們本身發佈的服務,咱們使用wsimport命令確定可以解析成功,可是若是咱們使用網絡上其它站點提供的服務,那麼在生成本地調用代碼的時候頗有可能會生成失敗。好比咱們常常回到這個網站上找相關的免費服務:http://www.webxml.com.cn/zh_cn/index.aspx,在這個網站上有一個「天氣預報查詢」的服務,它也提供了一個wsdl文檔,可是咱們在解析該文檔生成本地調用代碼的時候會生成失敗。解決方法參考:http://blog.sina.com.cn/s/blog_924d6a570102w203.html
以以前發佈的服務爲例。
新建一個普通類型的java工程,將文件夾中的全部.class文件刪除掉以後,將包括文件夾在內的全部文件都拷貝到項目中。
將生成的代碼拷貝到項目中以後頗有可能會報錯,提示Service類中沒有對應的構造方法,解決方法參考 http://blog.sina.com.cn/s/blog_924d6a570102w21v.html
接下來只須要使用這些類就能夠了,如何使用這些類,應當參考wsdl文檔。
客戶端的測試代碼:
1 package com.kdyzm.test; 2 3 import com.kdyzm.ws.MyWsServer; 4 import com.kdyzm.ws.MyWsServerService; 5 6 public class Main { 7 public static void main(String[] args) { 8 MyWsServerService myWsServerService=new MyWsServerService(); 9 MyWsServer myWsServer=myWsServerService.getMyWsServerPort(); 10 String result=myWsServer.calculate(2); 11 System.out.println(result); 12 } 13 }
控制檯輸出結果是4(客戶端)。
java ee版本的eclipse中(java ee視圖)提供了一種專門用於WebService的瀏覽器,名字爲Web Service Exployer
直接進入到該視圖中,而後切換到WSDL Page視圖,並點擊clear按鈕,最終顯示的界面以下:
在地址欄中輸入wsdl的地址,這裏是http://localhost:9090/ws?wsdl,並回車
接下來會顯示出全部的服務(類)和服務下的方法,圖略。
下一步就是單擊方法名,而後給方法添加實參發出請求以後查看請求的時候的請求信息和響應信息,這裏仍是以2爲例,最終結果是這樣的:
顯示返回值是4,而後單擊source
這也不是我想要的,直接對着框框右鍵「查看源代碼」,能夠看到SOAP的請求信息和SOAP的響應信息:
請求信息:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://ws.kdyzm.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <q0:calculate> <arg0>2</arg0> </q0:calculate> </soapenv:Body> </soapenv:Envelope>
響應信息:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns2:calculateResponse xmlns:ns2="http://ws.kdyzm.com/"> <return>4</return> </ns2:calculateResponse> </S:Body> </S:Envelope>
能夠看到不管是請求信息仍是響應信息都是以Envelope爲根節點,並且接下來都是Body節點,這點是符合SOAP協議的規範的。