webservice

     前面大致將了一些cxf實現webservice服務,此次對webservice作一個更爲詳細的總結.

     webservice的應用場景:

 1.用戶公共接口的接口服務.

       面向互聯網公開的接口,例如:某公司產品促銷介紹、股票信息查詢等,因爲webservice使用的soap協議是一個標準協議,其它公司使用標準協議通信,方便系統開發和維護。比如:便民網站的天氣查詢接口、火車時刻查詢接口等。

2.用戶內部接口服務.

        一個大的系統平臺是由若干個系統組成,系統與系統之間存在數據訪問需求,爲了減少系統與系統之間的耦合性可以將接口抽取出來提供單獨的接口服務供它系統調用,如下圖是企業ERP系統的接口服務圖.


       webservice能夠優點:

1 、採用xml支持跨平臺遠程調用。

2、基於http的soap協議,可跨越防火牆。

3、支持面向對象開發。

4、有利於軟件和數據重用,實現鬆耦合。

       webservice缺點

        由於soap是基於xml傳輸,本身使用xml傳輸會傳輸一些無關的東西從而效率不高,隨着soap協議的完善,soap協議增加了許多內容,這樣就導致了使用soap協議進行數據傳輸的效率不高。

         Webservice簡介

  • Web service 即web服務,它是一種跨編程語言和跨操作系統平臺的遠程調用技術即跨平臺遠程調用技術。
  • 採用標準SOAP(Simple Object Access Protocol)  協議傳輸,soap屬於w3c標準。Soap協議是基於http的應用層協議,soap協議傳輸是xml數據。採用wsdl作爲描述語言即webservice使用說明書,wsdl屬w3c標準。
  • xml是webservice的跨平臺的基礎,XML主要的優點在於它既與平臺無關,又與廠商無關。
  • XSD,W3C爲webservice制定了一套傳輸數據類型,使用xml進行描述,即XSD(XML Schema Datatypes),任何編程語言寫的webservice接口在發送數據時都要轉換成webservice標準的XSD發送。
  • 當前非SOAP協議的webService以輕量爲首要目標,比如http rest方式也是webservice的一種方式,或者直接使用http自定義數據協議,比如http傳輸json數據,http傳輸xml數據等。

       Webservice三要素:

        1.soap

         SOAP即簡單對象訪問協議(Simple Object Access Protocal) 是一種簡單的基於 XML 的協議,它使應用程序通過 HTTP 來交換信息,簡單理解爲soap=http+xml。

Soap協議版本主要使用soap1.1、soap1.2。

        SOAP不是webservice的專有協議,其他應用協議也使用soap傳輸數據。例如,SMTP、tr069等

          2.wsdl

          WSDL 是基於 XML的用於描述Web Service及其函數、參數和返回值。通俗理解Wsdlwebservice的使用說明書。

          3.uddi

        UDDI 是一種目錄服務,通過它,企業可註冊並搜索 Web services。企業將自己提供的Web Service註冊在UDDI,也可以使用別的企業在UDDI註冊的web service服務,從而達到資源共享。 UDDI旨在將全球的webservcie資源進行共享,促進全球經濟合作。

        目前大部分企業使用webservice並不是必須使用UDDI,因爲用戶通過WSDL知道了web service的地址,可以直接通過WSDL調用webservice。

     Webservice開發規範

       JAVA 中共有三種WebService 規範,分別是JAX-WS(JAX-RPC)、JAXM&SAAJ、JAX-RS。

       1.JAX-WS

        JAX-WS  的全稱爲 Java API for XML-Based Webservices,早期的基於SOAPJAVAWeb服務規範JAX-RPCJava API For XML-Remote Procedure Call)目前已經被JAX-WS規範取代。從java5開始支持JAX-WS2.0版本,Jdk1.6.0_13以後的版本支持2.1版本,jdk1.7支持2.2版本。

      2.AXM&SAAJ

       JAXM(JAVA API For XML Message)主要定義了包含了發送和接收消息所需的API,SAAJ(SOAP With Attachment API For Java,JSR 67)是與JAXM 搭配使用的API,爲構建SOAP 包和解析SOAP 包提供了重要的支持,支持附件傳輸等,JAXM&SAAJ 與JAX-WS 都是基於SOAP 的Web 服務,相比之下JAXM&SAAJ 暴漏了SOAP更多的底層細節,編碼比較麻煩,而JAX-WS 更加抽象,隱藏了更多的細節,更加面向對象,實現起來你基本上不需要關心SOAP 的任何細節.

      3.JAX-RS

    JAX-RS JAVA針對REST(Representation StateTransfer)風格制定的一套Web服務規範,由於推出的較晚,該規範(JSR 311,目前JAX-RS的版本爲1.0)並未隨JDK1.6一起發行。

     Webservice與Socket(Socket與Webservice的區別、TCP/IP協議、HTTP協議)

       

     

        Webservice採用soap協議進行通信,底層基於socket通信,webservice不需專門針對數據流的發送和接收進行處理,是一種跨平臺的面向對象遠程調用技術。

  • Socket  是基於TCP/ip的傳輸層協議
  • Webservice是基於http協議傳輸數據,http是基於tcp的應用層協議
  • Webservice採用了基於httpsoap協議傳輸數據。
  • Socket接口通過操作流編程傳輸數據,不支持面向對象。
  • Webservice 接口支持面向對象,最終webservice將對象進行序列化後通過流傳輸
   Socket優點:
  • Socket採用tcp、udp底層協議通信,傳輸速度快,適用於傳輸大數量的數據。
  • socket具有平臺無關性,java寫的socket的客戶端可以訪問c寫的socket服務端。
   Socket缺點

  接口傳輸的數據需要手動解析,socket通信的接口協議需要自定義,比如:自定義一種字符串拼接的格式,比如自定義的xml數據,自定義麻煩之處在接口調用方和接口服務端需要互相討論確定接口的協議內容,不方便,好處:適用於傳輸大數量的數據。



      webservice技術拓展

        雖然java中定義webservice開發規範採用soap協議,但由於soap協議本身的缺點現在更多的webservice接口則直接採用http+自定義協議通信,比如http傳輸json串、http傳輸自定義格式的數據,因爲這樣做比soap協議更快捷,例如某些第三方支付公司的支持接口就直接採用http原始協議通信、http rest方式通信。

        webservice即web服務,只要這個計算機在互聯網內,它對外提供的服務接口都可以認爲是一個webservice,除了使用http、soap進行通信外如果要保證性能可以直接使用tcp,比如採用socket方式,但是socket方式需要手動通過流編程解析數據,有些麻煩,如果有保證傳輸速度及跨平臺的前提下基於面向對象開發服務接口及客戶端程序的技術最好不過,hessian框架就可以保證傳輸速度及在跨平臺的前提下基於面向對象開發遠程調用接口。

        總結:webservice可以實現的技術有好多,socket、http、soap方式、hessian等,在實際應用時根據具體的需求和場景去選擇應用技術。

      webservice技術選型

          1. 協議約定

         你作爲客戶端要調用別人的接口,對方服務接口用的是什麼協議客戶端一般也用什麼協議,比如服務端採用socket,客戶端使用socket方式通信,服務端使用對外提供soap方式的webservice,客戶端使用soap協議與服務端通信。

          2. 通用性

         對於一個webservice主要考慮接口的通用性時,在不要求性能的前提下可以使用soap協議。

如果要考慮接口的通用性還要考慮接口的性能可以採用http+自定義協議,比如http+json串,因爲http本身就是web應用中的基礎協議,json格式的數據也成爲當前web開發中流行數據格式。

         3.高性能

         對於一個webservice主要作爲內部系統之間通信使用,比如:聯通、移動公司內部的若干系統之間進行數據傳輸,這類接口主要考慮的是性能,可以直接採用socket通信、hessian等,幾種技術性能從高到低是:socket>hessian>http>soap。

        4.開發規範

        當然要注意,有些正規的公司會制定自己公司的開發規範,比如內部系統接口統一採用hessian,統一採用http,並不總是使用性能最高的方式,因爲公司會綜合考慮自己的人力資源情況在有限的成本下使用最合適的技術纔是公司在進行技術選型時所遵循的原則。

      webservice 與http關係

     http與webservice之間的關係,可以用一句話描述:Webservice採用了基於http的soap協議傳輸數據。
      webservice的三要素soap,wsdl,uddi並未涉及網絡通信(soap協議與http通信協議是有本質區別的),soap只是應用協議,並非通信協議,它所依賴的下層通信方式不單單是HTTP,也有SOAP over SMTP, SOAP over TCP,由於HTTP協議羣衆基礎廣,開發調試方便,所以,成了WebService中最爲流行的方式(HTTP也是TCP上性能比較差的協議,因爲HTTP是基於TCP的,有3次握手,再加上HTTP是個文本傳輸協議(雖然也可以傳二進制的附件,但業務邏輯還是文本用的多),又有很多複雜的HEADER。所以人們發明了一些更高效的通信協議來做遠程調用,比如ACE、ICE、Corba、淘寶的HSF)。
        http協議傳輸的都是字符串了,webservice則是包裝成了更復雜的對象.webservice就是使用soap協議得到你想要的東西,相比httpservice能處理些更加複雜的數據類型.
        soap基於http通信(見下文soap),發送的就是一個post的http請求,請求內容格式text/xml(soap1.2是application/soap+xml),返回text/xml.webservice接受xml格式的請求進行解析,印射到相應的server方法中進行出處理.用jdk的wsimport或者cxf的wsdl2java生產的客戶端,其主要的代碼就是將請求封裝成xml,解析返回的xml數據.(reference)
        jaxws是一個標準的webservice服務,jaxrs一些get或者post更像是httpservice(post中soap的xml請求更像webservice)
       webservice Examples

1.jax-ws

      jaxws註解的作用主要是用來規範webservice的接口,使用註解可以指定服務名稱、portType名稱、接口參數名稱等。

     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註解之後,會影響客戶端生成的代碼。調用的方法名和參數名也發生了變化

注意事項

      @WebMethod對所有非靜態的公共方法對外暴露爲服務.

  • 對於靜態方法或非public方法是不可以使用@WebMethod註解的.
  • 對public方法可以使用@WebMethod(exclude=true)定義爲非對外暴露的服務。

       如果修改webservice的接口內容,比如namespaceportType,必須要重新生成客戶端調用代碼。

 服務端(新建jar項目)

sei

package service;

/*編寫SEI(Service Endpoint Interface),SEI在webservice中稱爲portType,在java中稱爲接口*/
public interface WeatherInterface {
	//根據城市名稱查詢天氣信息
	public String queryWeather(String cityName)throws Exception;

}
sei impl

package service;

import javax.jws.WebService;

//@WebService標識此類可以發佈爲webservice服務
@WebService
public class WeatherInterfaceImpl implements WeatherInterface {

	//如果此方法被調用執行說明客戶端請求天氣查詢
	@Override
	public String queryWeather(String cityName) throws Exception {
		System.out.println("from client..."+cityName);
		//查詢天氣 
		//使用靜態數據表示查詢天氣結果
		//...
		//天氣查詢結果
		String result="晴";
		//如果方法返回值,說明服務端向客戶端響應查詢結果
		return result;
	}

}
server

package service;

import javax.xml.ws.Endpoint;

public class WeatherServer {
	public static void main(String[] args) {
		//發佈天氣查詢服務
		//第一個參數:服務地址
		//第二個參數:提供的java對象,實現SEI的實現類對象
		Endpoint.publish("http://127.0.0.1:12345/weather", new WeatherInterfaceImpl());
	}

}

訪問http://127.0.0.1:12345/weather?wsdl 返回

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<!--
 Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. 
-->
<!--
 Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. 
-->
<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://service/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://service/" name="WeatherInterfaceImplService">
<types>
<xsd:schema>
<xsd:import namespace="http://service/" schemaLocation="http://127.0.0.1:12345/weather?xsd=1"/>
</xsd:schema>
</types>
<message name="queryWeather">
<part name="parameters" element="tns:queryWeather"/>
</message>
<message name="queryWeatherResponse">
<part name="parameters" element="tns:queryWeatherResponse"/>
</message>
<message name="Exception">
<part name="fault" element="tns:Exception"/>
</message>
<portType name="WeatherInterfaceImpl">
<operation name="queryWeather">
<input wsam:Action="http://service/WeatherInterfaceImpl/queryWeatherRequest" message="tns:queryWeather"/>
<output wsam:Action="http://service/WeatherInterfaceImpl/queryWeatherResponse" message="tns:queryWeatherResponse"/>
<fault message="tns:Exception" name="Exception" wsam:Action="http://service/WeatherInterfaceImpl/queryWeather/Fault/Exception"/>
</operation>
</portType>
<binding name="WeatherInterfaceImplPortBinding" type="tns:WeatherInterfaceImpl">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="queryWeather">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
<fault name="Exception">
<soap:fault name="Exception" use="literal"/>
</fault>
</operation>
</binding>
<service name="WeatherInterfaceImplService">
<port name="WeatherInterfaceImplPort" binding="tns:WeatherInterfaceImplPortBinding">
<soap:address location="http://127.0.0.1:12345/weather"/>
</port>
</service>
</definitions>
       解析wsdl

      簡述wsdl

  • WSDL 指網絡服務描述語言(Web Services Description Language)。
  • WSDL是一種使用 XML 編寫的文檔。這種文檔可描述某個 Web service。它可規定服務的位置,以及此服務提供的操作(或方法)。
  • WSDL 是一種 XML 文檔
  • WSDL 用於描述網絡服務
  • WSDL 也可用於定位網絡服務
        wsdl結構

<service>    服務視圖,webservice的服務結點,它包括了服務端點

<binding>     爲每個服務端點定義消息格式和協議細節

<portType>   服務端點,描述 web service可被執行的操作方法,以及相關的消息,通過binding指向portType

<message>   定義一個操作(方法)的數據參數(可有多個參數)

<types>        定義 web service 使用的全部數據類型

       建議閱讀習慣:從下往上讀先找到服務視圖,通過binging找到protType,找到了protType就找到了我們要調用的webservice方法。

客戶端
       運用jdk自帶的webservice生成工具Wsimport
       wsimport是jdk自帶的webservice客戶端工具,可以根據wsdl文檔生成客戶端調用代碼(java代碼).當然,無論服務器端的WebService是用什麼語言寫的,都可以生成調用webservice的客戶端代碼,服務端通過客戶端代碼調用webservice。 

       wsimport.exe位於JAVA_HOME\bin目錄下.

       常用參數爲:

-d<目錄>  - 將生成.class文件。默認參數。

-s<目錄> - 將生成.java文件。

-p<生成的新包名> -將生成的類,放於指定的包下。

(wsdlurl) - http://server:port/service?wsdl,必須的參數。

        示例:

C:/> wsimport –s . http://127.0.0.1:1234/weather?wsdl

注意:-s不能分開,-s後面有個小點

運行後會在指定目錄下(如上述命令就是c盤下)生成一大坨代碼,新建一個client客戶端jar(客戶端一般和服務端是分開的),複製生成的代碼





編寫WeatherClient

package service;

import service.Exception_Exception;
import service.WeatherInterfaceImpl;
import service.WeatherInterfaceImplService;

public class WeatherClient {

	public static void main(String[] args) throws Exception_Exception {

		// 使用生成的調用代碼創建代理對象,代理對象就是portType的代理對象,代理對象內部最終發起socket請求

		// 創建一個服務視圖的對象
		WeatherInterfaceImplService weatherInterfaceImplService = new WeatherInterfaceImplService();

		// 通過服務視圖創建portType的代理對象
		WeatherInterfaceImpl weatherInterfaceImplPort = weatherInterfaceImplService
				.getWeatherInterfaceImplPort();

		// 調用portType的方法
		String resultString = weatherInterfaceImplPort.queryWeather("北京");

		System.out.println("天氣查詢結果:" + resultString);

	}

}
       運行client,結果----天氣查詢結果:晴

       查看上面的生成的代碼中,訪問通過"http://127.0.0.1:12345/weather?wsdl"獲取wsdl(xml結構),根據其說明去訪問相應的接口,返回值有諸多註解都帶xml,也就是說返回也是xml, 也就驗證了上面的基於xml的數據傳輸.值得一提的是,此處不同於jaxrs,jaxrs進行了rest風格的印射,是可以通過url(或http請求)直接訪問

2.調用公網查詢天氣預報

      天氣預報公網http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl

      直接使用wsimport -s . url會報s:schema出錯(jaxb不支持),需要將wsdl下載下來(另存爲C:\Users\admin\Desktop\temp\WeatherWebService.xml)進行更改

      <s:element ref="s:schema" /><s:any />改成 <s:any minOccurs="2" maxOccurs="2"/>,一共有三處需要修改,建議查找<s:element ref="s:schema" />,修改時把<s:any />也要刪掉,執行cmd進入C:\Users\admin\Desktop\temp\,執行wsimport -s . WeatherWebService.xml,將生產代碼拷入新建的jar中

新建client訪問

package cn.com.webxml;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;

import cn.com.webxml.ArrayOfString;
import cn.com.webxml.WeatherWebService;
import cn.com.webxml.WeatherWebServiceSoap;

public class WeatherClient {

	public static void main(String[] args) throws IOException {

		 //######################通過Wsimport訪問####################
		// 創建服務視圖對象
		WeatherWebService weatherWebService = new WeatherWebService();

		// 通過服務視圖對象創建portType的代理對象
		WeatherWebServiceSoap weatherWebServiceSoap = weatherWebService
				.getWeatherWebServiceSoap();
		
		//調用portType的方法
		ArrayOfString arrayOfString = weatherWebServiceSoap.getWeatherbyCityName("北京");
		//遍歷公網天氣查詢服務返回的類型
		for(String message:arrayOfString.getString()){
			System.out.println(message);
		}
		
		 //######################通過service訪問####################
/*		//定義url,參數爲wsdl地址
		URL url = new URL("file:/C:/Users/admin/Desktop/temp/WeatherWebService.xml");
		//定義qname,第一個參數是命名空間,第二個參數名稱是wsdl裏邊的服務名
		QName qName = new QName("http://WebXml.com.cn/", "WeatherWebService");
		//創建服務視圖
		Service service = Service.create(url, qName);
		//通過服務視圖得到服務端點
		WeatherWebServiceSoap weatherWebServiceSoap =service.getPort(WeatherWebServiceSoap.class);
		//調用webservice
		ArrayOfString arrayOfString = weatherWebServiceSoap.getWeatherbyCityName("鄭州");
		List<String> resultlist = arrayOfString.getString();
		//查詢天氣查詢結果
		for(String result:resultlist){
			System.out.println(result);
		}*/
		
/*		######################通過service訪問與通過Wsimport訪問的區別####################
		Wsimport生成代碼調用webservice無法指定webservice的地址,使用生成的服務視圖類獲取服務端點(postType)實例。
		Service調用Webservice可以指定webservice的地址,只需要服務端點的接口即可獲取服務端點實例。*/
		

	}

}
運行ok.

3.soap協議

1.soap協議(1.1版本)

     使用TCP/IP Monitor可以監視tcp/ip協議的報文內容,由於http是基於Tcp的應用協議,而webservice是基於http實現,所以通過tcp/ip monitor可以監視webservice請求及響應的內容。以案例1爲例.

      eclipse設置tcp/ip monitor

     

     tcp/ip monitor監控的基本原理就是通過端口轉發(上述12345就是目的端口,999是轉發端口).

     啓動客戶端訪問

				URL url = new URL("http://127.0.0.1:999/weather?wsdl");
				//定義qname,第一個參數是命名空間,第二個參數名稱是wsdl裏邊的服務名
				QName qName = new QName("http://service/", "WeatherInterfaceImplService");
				//創建服務視圖
				Service service = Service.create(url, qName);
				//通過服務視圖得到服務端點
				WeatherInterfaceImpl weatherInterfaceImpl =service.getPort(WeatherInterfaceImpl.class);
				//調用webservice
				System.out.println(weatherInterfaceImpl.queryWeather("鄭州"));

request監控

GET /weather?wsdl HTTP/1.1
User-Agent: Java/1.7.0_72
Host: 127.0.0.1:999
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
###########以上是轉發,以下是監控內容###############
POST /weather HTTP/1.1
Accept: text/xml, multipart/related
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://service/WeatherInterfaceImpl/queryWeatherRequest"
User-Agent: JAX-WS RI 2.2.4-b01
Host: 127.0.0.1:999
Connection: keep-alive
Content-Length: 200

<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:queryWeather xmlns:ns2="http://service/"><arg0>鄭州</arg0></ns2:queryWeather></S:Body></S:Envelope>
response

HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: text/xml;charset=utf-8
Date: Mon, 31 Jul 2017 11:14:33 GMT

8cc
<?xml version='1.0' encoding='UTF-8'?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. --><!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. --><definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://service/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://service/" name="WeatherInterfaceImplService">
<types>
<xsd:schema>
<xsd:import namespace="http://service/" schemaLocation="http://127.0.0.1:999/weather?xsd=1"/>
</xsd:schema>
</types>
<message name="queryWeather">
<part name="parameters" element="tns:queryWeather"/>
</message>
<message name="queryWeatherResponse">
<part name="parameters" element="tns:queryWeatherResponse"/>
</message>
<message name="Exception">
<part name="fault" element="tns:Exception"/>
</message>
<portType name="WeatherInterfaceImpl">
<operation name="queryWeather">
<input wsam:Action="http://service/WeatherInterfaceImpl/queryWeatherRequest" message="tns:queryWeather"/>
<output wsam:Action="http://service/WeatherInterfaceImpl/queryWeatherResponse" message="tns:queryWeatherResponse"/>
<fault message="tns:Exception" name="Exception" wsam:Action="http://service/WeatherInterfaceImpl/queryWeather/Fault/Exception"/>
</operation>
</portType>
<binding name="WeatherInterfaceImplPortBinding" type="tns:WeatherInterfaceImpl">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="queryWeather">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
<fault name="Exception">
<soap:fault name="Exception" use="literal"/>
</fault>
</operation>
</binding>
<service name="WeatherInterfaceImplService">
<port name="WeatherInterfaceImplPort" binding="tns:WeatherInterfaceImplPortBinding">
<soap:address location="http://127.0.0.1:999/weather"/>
</port>
</service>
</definitions>
0

HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: text/xml; charset=utf-8
Date: Mon, 31 Jul 2017 11:14:33 GMT

6e
<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body>
7b
<ns2:queryWeatherResponse xmlns:ns2="http://service/"><return>晴 </return></ns2:queryWeatherResponse></S:Body></S:Envelope>
0
     可以看出request與reponse 的content-type都是text/xml

     soap協議包含的元素

  • 必需有 Envelope 元素,此元素將整個 XML文檔標識爲一條SOAP消息
  • 可選的 Header 元素,包含頭部信息
  • 必需有Body 元素,包含所有的調用和響應信息
  • 可選的 Fault 元素,提供有關在處理此消息所發生錯誤的信息
  soap消息基本結構

<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope" soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Header>
 ... ...
</soap:Header>
<soap:Body>
 ... ...
 <soap:Fault>
 ... ...
</soap:Fault>
</soap:Body>
 </soap:Envelope>

soap協議(1.2版本)

  Jaxws實現soap1.2需要加入jaxws擴展包,從sun下載jaxws-ri-2.2.8,解壓jaxws-ri-2.2.8並將lib下的jar包加載到java工程中。

  在SEI實現類上添加如下註解@BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)

request

GET /weather?wsdl HTTP/1.1
User-Agent: Java/1.7.0_72
Host: 127.0.0.1:999
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive

POST /weather HTTP/1.1
Accept: application/soap+xml, multipart/related
Content-Type: application/soap+xml; charset=utf-8;action="http://service/WeatherInterfaceImpl/queryWeatherRequest"
User-Agent: JAX-WS RI 2.2.4-b01
Host: 127.0.0.1:999
Connection: keep-alive
Content-Length: 198

<?xml version="1.0" ?><S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope"><S:Body><ns2:queryWeather xmlns:ns2="http://service/"><arg0>鄭州</arg0></ns2:queryWeather></S:Body></S:Envelope>
response

HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: text/xml;charset=utf-8
Date: Mon, 31 Jul 2017 11:49:32 GMT

8d8
<?xml version='1.0' encoding='UTF-8'?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.8 svn-revision#13980. --><!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.8 svn-revision#13980. --><definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:tns="http://service/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://service/" name="WeatherInterfaceImplService">
<types>
<xsd:schema>
<xsd:import namespace="http://service/" schemaLocation="http://127.0.0.1:999/weather?xsd=1"/>
</xsd:schema>
</types>
<message name="queryWeather">
<part name="parameters" element="tns:queryWeather"/>
</message>
<message name="queryWeatherResponse">
<part name="parameters" element="tns:queryWeatherResponse"/>
</message>
<message name="Exception">
<part name="fault" element="tns:Exception"/>
</message>
<portType name="WeatherInterfaceImpl">
<operation name="queryWeather">
<input wsam:Action="http://service/WeatherInterfaceImpl/queryWeatherRequest" message="tns:queryWeather"/>
<output wsam:Action="http://service/WeatherInterfaceImpl/queryWeatherResponse" message="tns:queryWeatherResponse"/>
<fault message="tns:Exception" name="Exception" wsam:Action="http://service/WeatherInterfaceImpl/queryWeather/Fault/Exception"/>
</operation>
</portType>
<binding name="WeatherInterfaceImplPortBinding" type="tns:WeatherInterfaceImpl">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="queryWeather">
<input>
<soap12:body use="literal"/>
</input>
<output>
<soap12:body use="literal"/>
</output>
<fault name="Exception">
<soap12:fault name="Exception" use="literal"/>
</fault>
</operation>
</binding>
<service name="WeatherInterfaceImplService">
<port name="WeatherInterfaceImplPort" binding="tns:WeatherInterfaceImplPortBinding">
<soap12:address location="http://127.0.0.1:999/weather"/>
</port>
</service>
</definitions>
0

HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: application/soap+xml; charset=utf-8
Date: Mon, 31 Jul 2017 11:49:32 GMT

6c
<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope"><S:Body>
7b
<ns2:queryWeatherResponse xmlns:ns2="http://service/"><return>晴 </return></ns2:queryWeatherResponse></S:Body></S:Envelope>
0

soap1.1與1.2的比較

     相同之處:

  • soap1.1和soap1.2都是使用post方法
  • 都包括Envelope和body

 

     內容類型context-type不同:

  • soap1.1使用text/xml
  • soap1.2使用application/soap+xml

 

      命名空間Envelope xmlns不同:

http測試

package service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class HttpRequestSoap {
	
	public static void main(String[] args) throws IOException {
		//webservice地址
		String webservice_url = "http://127.0.0.1:12345/weather";
		//發送的soap協議內容
		String soap_xml = soap_xml("鄭州");
		System.out.println(soap_xml);
		//創建url
		URL url = new URL(webservice_url);
		//創建http鏈接對象
		HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
		//設置請求方法
		httpURLConnection.setRequestMethod("POST");
		//設置Content-type
		httpURLConnection.setRequestProperty("Content-type", "text/xml;charset=\"utf-8\"");
		//使用http進行輸出
		httpURLConnection.setDoOutput(true);
		//使用http進行輸入
		httpURLConnection.setDoInput(true);
		
		//通過輸出流發送數據
		OutputStream outputStream = httpURLConnection.getOutputStream();
		outputStream.write(soap_xml.getBytes());
		outputStream.close();
		
		//接收服務端響應數據
		InputStream inputStream =  httpURLConnection.getInputStream();
		
		//使用buffer存在讀取的數據
		byte[] buffer = new byte[1024];
		
		//使用字節輸出流存儲讀取的數據
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		while(true){
			int len = inputStream.read(buffer);
			//如果流水讀取完則退出循環
			if(len == -1){
				break;
			}
			byteArrayOutputStream.write(buffer,0,len);
		}

		//得到響應數據
		String response_string = byteArrayOutputStream.toString();
		
		System.out.println(response_string);
	}
	//soap協議內容
	public static String soap_xml(String cityName){
		String soap_xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
				+ "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">"
				+ "<S:Body>"
				+ "<ns2:queryWeather xmlns:ns2=\"http://service/\">"
				+ "<arg0>"+ cityName  + "</arg0>"
				+ "</ns2:queryWeather>"
				+ "</S:Body>"
				+ "</S:Envelope>";
		
		return soap_xml;
	}


	
}

4.spring+webservice+jaxrs

5.spring+webservice+jaxws

jax-ws的配置與jaxrs的配置十分相似,此處照搬的官網給的源碼例子(參考cxf+spring).新建一個maven的web項目
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>stu</groupId>
		<artifactId>stu</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<artifactId>cxf</artifactId>
	<packaging>war</packaging>
	<dependencies>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-frontend-jaxws</artifactId>
			<version>3.1.12</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http</artifactId>
			<version>3.1.12</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http-jetty</artifactId>
			<version>3.1.12</version>
		</dependency>
		<dependency>
			<groupId>org.eclipse.jetty</groupId>
			<artifactId>jetty-webapp</artifactId>
			<version>9.2.21.v20170120</version>
		</dependency>

		<!-- spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.3.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>4.3.4.RELEASE</version>
		</dependency>

	</dependencies>
</project>
service
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
// START SNIPPET: service
package demo.spring.service;

import javax.jws.WebService;

@WebService
public interface HelloWorld {
    String sayHi(String text);
}
// END SNIPPET: service
serviceImpl
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
// START SNIPPET: service
package demo.spring.service;

import javax.jws.WebService;

@WebService(endpointInterface = "demo.spring.service.HelloWorld")
public class HelloWorldImpl implements HelloWorld {

    public String sayHi(String text) {
        System.out.println("sayHi called");
        return "Hello " + text;
    }
}
// END SNIPPET: service
server
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package demo.spring.service;

import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.webapp.WebAppContext;

public class Server {

    protected Server() throws Exception {
        System.out.println("Starting Server");

        /**
         * Important: This code simply starts up a servlet container and adds
         * the web application in src/webapp to it. Normally you would be using
         * Jetty or Tomcat and have the webapp packaged as a WAR. This is simply
         * as a convenience so you do not need to configure your servlet
         * container to see CXF in action!
         */
        org.eclipse.jetty.server.Server server = new org.eclipse.jetty.server.Server(9002);

        WebAppContext webappcontext = new WebAppContext();
        webappcontext.setContextPath("/");

        //此處對應你的war包
        webappcontext.setWar("target/cxf-0.0.1-SNAPSHOT.war");

        HandlerCollection handlers = new HandlerCollection();
        handlers.setHandlers(new Handler[] {webappcontext, new DefaultHandler()});

        server.setHandler(handlers);
        server.start();
        System.out.println("Server ready...");
        server.join();
    }

    public static void main(String args[]) throws Exception {
        new Server();
    }

}
client
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package demo.spring.client;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import demo.spring.service.HelloWorld;


public final class Client {

    private Client() {
    }

    public static void main(String args[]) throws Exception {
        // START SNIPPET: client
        ClassPathXmlApplicationContext context 
            = new ClassPathXmlApplicationContext(new String[] {"client-beans.xml"});

        HelloWorld client = (HelloWorld)context.getBean("client");

        String response = client.sayHi("Joe");
        System.out.println("Response: " + response);
        System.exit(0);
        // END SNIPPET: client
    }
}
web-info 下的兩個xml
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements. See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership. The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License. You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing,
  software distributed under the License is distributed on an
  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  KIND, either express or implied. See the License for the
  specific language governing permissions and limitations
  under the License.
-->
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee           http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>cxf</display-name>
    <servlet>
        <description>Apache CXF Endpoint</description>
        <display-name>cxf</display-name>
        <servlet-name>cxf</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>cxf</servlet-name>
        <url-pattern>/services/*</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>60</session-timeout>
    </session-config>
</web-app>
cxf-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
        Licensed to the Apache Software Foundation (ASF) under one
        or more contributor license agreements. See the NOTICE file
        distributed with this work for additional information
        regarding copyright ownership. The ASF licenses this file
        to you under the Apache License, Version 2.0 (the
        "License"); you may not use this file except in compliance
        with the License. You may obtain a copy of the License at
        
        http://www.apache.org/licenses/LICENSE-2.0
        
        Unless required by applicable law or agreed to in writing,
        software distributed under the License is distributed on an
        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
        KIND, either express or implied. See the License for the
        specific language governing permissions and limitations
        under the License.
-->
<!-- START SNIPPET: beans -->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<!--     <import resource="classpath:META-INF/cxf/cxf.xml"/>
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/> -->
    <jaxws:endpoint id="helloWorld" implementor="demo.spring.service.HelloWorldImpl" address="/HelloWorld"/>
</beans>
<!-- END SNIPPET: beans -->
resource目錄下的client-beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
        Licensed to the Apache Software Foundation (ASF) under one
        or more contributor license agreements. See the NOTICE file
        distributed with this work for additional information
        regarding copyright ownership. The ASF licenses this file
        to you under the Apache License, Version 2.0 (the
        "License"); you may not use this file except in compliance
        with the License. You may obtain a copy of the License at
        
        http://www.apache.org/licenses/LICENSE-2.0
        
        Unless required by applicable law or agreed to in writing,
        software distributed under the License is distributed on an
        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
        KIND, either express or implied. See the License for the
        specific language governing permissions and limitations
        under the License.
-->
<!-- START SNIPPET: beans -->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schema/jaxws.xsd">
    <bean id="client" class="demo.spring.service.HelloWorld" factory-bean="clientFactory" factory-method="create"/>
    <bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
        <property name="serviceClass" value="demo.spring.service.HelloWorld"/>
        <property name="address" value="http://localhost:9002/services/HelloWorld"/>
    </bean>
</beans>
<!-- END SNIPPET: beans -->
測試:先運行server ,然後運行client,打印Response: Hello Joe  ok.
webservice使用總結:

       Webservice發送xml數據其實是將xml數據作爲大字符串發送,工作量主要在解析xml數據上。雖然解析xml數據比較麻煩但是webservice接口簡單,大家遵守xml格式開發接口,這種方式在企業中也較常用。

       數據量大的xml建議使用SAX解析提高解析速度。

      soap協議支持面向對象開發,傳輸對象比傳輸xml方便,但是之所以企業中開發webservice採用xml描述請求和響應的數據是因爲xml數據格式是一種跨平臺的標準數據格式,企業在開發中會選擇一些標準的數據格式作爲接口協議,比如:xml、json。

    實際應用時根據企業中的開發需求確定是傳輸java對象還是xml串以及json串等。

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