WebService技术详解CXF
WebService
WebService簡介
Web Service技術, 能使得運行在不同機器上的不同應用無須借助附加的、專門的第三方軟件或硬件, 就可相互交換數據或集成。依據Web Service規范實施的應用之間, 無論它們所使用的語言、 平臺或內部協議是什么, 都可以相互交換數據。
簡單的說,WebService就是一種跨編程語言和跨操作系統平臺的遠程調用技術。所謂跨編程語言和跨操作平臺,就是說服務端程序采用java編寫,客戶端程序則可以采用其他編程語言編寫,反之亦然。跨操作系統平臺則是指服務端程序和客戶端程序可以在不同的操作系統上運行。 遠程調用,就是一臺計算機的應用可以調用其他計算機上的應用。例如:支付寶,支付寶并沒有銀行卡等數據,它只是去調用銀行提供的接口來獲得數據。還有天氣預報等,也是氣象局把自己的系統服務以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交互的過程就是,WebService遵循SOAP協議通過XML封裝數據,然后由Http協議來傳輸數據。
JAVA WebService規范
Java 中共有三種WebService 規范,分別是JAXM&SAAJ、JAX-WS(JAX-RPC)、JAX-RS。
(1)JAX-WS:
JAX-WS(Java API For XML-WebService)。早期的基于SOAP 的JAVA 的Web 服務規范JAX-RPC(java API For XML-Remote Procedure Call)目前已經被JAX-WS 規范取代,JAX-WS 是JAX-RPC 的演進版本,但JAX-WS 并不完全向后兼容JAX-RPC,二者最大的區別就是RPC/encoded 樣式的WSDL,JAX-WS 已經不提供這種支持。JAX-RPC 的API 從JAVA EE5 開始已經移除,如果你使用J2EE1.4,其API 位于javax.xml.rpc.*包。JAX-WS(JSR 224)規范的API 位于javax.xml.ws.*包,其中大部分都是注解,提供API 操作Web 服務(通常在客戶端使用的較多,由于客戶端可以借助SDK 生成,因此這個包中的API 我們較少會直接使用)。
(2)JAXM&SAAJ:
JAXM(JAVA API For XML Message)主要定義了包含了發送和接收消息所需的API,相當于Web 服務的服務器端,其API 位于javax.messaging.*包,它是Java EE 的可選包,因此你需要單獨下載。
SAAJ(SOAP With Attachment API For Java,JSR 67)是與JAXM 搭配使用的API,為構建SOAP 包和解析SOAP 包提供了重要的支持,支持附件傳輸,它在服務器端、客戶端都需要使用。這里還要提到的是SAAJ 規范,其API 位于javax.xml.soap.*包。
JAXM&SAAJ 與JAX-WS 都是基于SOAP 的Web 服務,相比之下JAXM&SAAJ 暴漏了SOAP更多的底層細節,編碼比較麻煩,而JAX-WS 更加抽象,隱藏了更多的細節,更加面向對象,實現起來你基本上不需要關心SOAP 的任何細節。那么如果你想控制SOAP 消息的更多細節,可以使用JAXM&SAAJ。
(3)JAX-RS:
JAX-RS 是JAVA 針對REST(Representation State Transfer)風格制定的一套Web 服務規范,由于推出的較晚,該規范(JSR 311,目前JAX-RS 的版本為1.0)并未隨JDK1.6 一起發行。
WebService入門案例
服務端的實現
我們來實現一個天氣系統的案例,客戶端發送城市名稱,服務器端回應相應的天氣。
1. 編寫SEI(Service Endpoint Interface),SEI在webservice中稱為portType,在java中就是普通接口 public interface WeatherInterface {public String queryWeather(String cityName); } 2. 編寫SEI實現類,此類作為webservice提供服務類 @WebService //@WebService表示該類是一個服務類,需要發布其中的public的方法 public class WeatherInterfaceImpl implements WeatherInterface {@Overridepublic String queryWeather(String cityName) {System.out.println("獲取城市名"+cityName);String weather="暴雨"; return weather;}} 3. 第三步:發布服務,Endpoint類發布服務,publish方法,兩個參數:1.服務地址;2.服務實現類 public class WeatherServer {public static void main(String[] args) {Endpoint.publish("http://127.0.0.1:12345/weather", new WeatherInterfaceImpl());} } 4. 測試服務是否發布成功,通過閱讀wsdl,確定客戶端調用的接口、方法、參數和返回值存在,證明服務發布成功//我們在瀏覽器輸入 http://127.0.0.1:12345/weather?wsdl 來獲取wsdl文件進行閱讀//wsdl,是以XML文件形式來描述WebService的”說明書”,有了說明書,我們才可以知道如何使用或是調用這個服務.//現在我們還不知道怎么去閱讀,后面我們會詳解,只要能獲取到,就能確定WebService服務發布成功 1234567客戶端的實現
//客戶端調用服務有很多種方法,我們先用工具生成客戶端代碼,后面會詳解 //wsimport是jdk自帶的webservice客戶端工具,可以根據wsdl文檔生成客戶端調用代碼(java代碼).當然,無論服務器端的WebService是用什么語言寫的,都可以生成調用webservice的客戶端代碼。1.創建一個客戶端空項目,cmd命令行進入此項目的src目錄使用以下命令生成客戶端代碼 wsimport -s . http://127.0.0.1:12345/weather?wsdl-s是指編譯出源代碼文件,后面的.(點)指將代碼放到當前目錄下.最后面的http….是指獲取wsdl說明書的地址 2.編寫客戶端 public class WeatherClient {public static void main(String[] args) {//創建服務視圖,視圖是從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 Services Description Language), web服務描述語言,他是webservice服務端使用說明書,說明服務端接口、方法、參數和返回值,WSDL是隨服務發布成功,自動生成,無需編寫。
文檔結構
Service:相關端口的集合,包括其關聯的接口、操作、消息等。
Binding:特定端口類型的具體協議和數據格式規范
portType: 服務端點,描述 web service可被執行的操作方法,以及相關的消息,通過binding指向portType
message: 定義一個操作(方法)的數據參數
types: 定義 web service 使用的全部數據類型
閱讀方式
WSDL文檔應該從下往上閱讀。
1.先看service標簽,看相應port的binding屬性,然后通過值查找上面的binding標簽。
2.通過binding標簽可以獲得具體協議等信息,然后查看binding的type屬性
3.通過binding的type屬性,查找對應的portType,可以獲得可操作的方法和參數、返回值等。
4.通過portType下的operation標簽的message屬性,可以向上查找message獲取具體的數據參數信息。
SOAP
SOAP即簡單對象訪問協議,他是使用http發送的XML格式的數據,它可以跨平臺,跨防火墻,SOAP不是webservice的專有協議。
SOAP=http+xml
SOAP結構
必需的 Envelope 元素,可把此 XML 文檔標識為一條 SOAP 消息 可選的 Header 元素,包含頭部信息 必需的 Body 元素,包含所有的調用和響應信息 可選的 Fault 元素,提供有關在處理此消息所發生錯誤的信息我們來看一下我們上面天氣程序發送的數據的格式,這需要一個工具TCP/IP Monitor ,Eclipse自帶的Debug工具之一,用于捕獲Http、TCP/IP協議包。原理是一個代理服務,客戶端先把數據發送到代理服務,然后代理服務再把數據發送到服務器,這樣就能獲取請求數據和響應數據。
第一步:打開這個工具,選擇other,然后輸入TCP/IP Monitor
第二步:設置要代理的服務器
第三步:詳細設置
第一個參數是代理服務器端口,我們設置為54321 第二個參數是被代理服務器的地址,第三個參數是被代理服務器的端口 第四個參數要選擇為TCP/IP第四步:檢測是否設置成功,我們訪問代理服務器來獲得wsdl文件
第五步:設置成功后,我們需要改一下客戶端要連接的服務器,改成代理服務器的端口
將WeatherInterfaceImplService里的所有原來地址的端口改為54321第六步:我們啟動我們的客戶端,獲取請求數據和響應數據
請求 //先發送get請求,去獲得wsdl文件,然后獲得方法、參數等信息 GET /weather?wsdl HTTP/1.1 User-Agent: Java/1.8.0_111 Host: 127.0.0.1:54321 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://ws.cad.com/WeatherInterfaceImpl/queryWeatherRequest" User-Agent: JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e Host: 127.0.0.1:54321 Connection: keep-alive Content-Length: 203<?xml version="1.0" ?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns2:queryWeather xmlns:ns2="http://ws.cad.com/"> <arg0>北京</arg0> </ns2:queryWeather> </S:Body> </S:Envelope> 響應數據 HTTP/1.1 200 OK Date: Tue, 25 Jul 2017 05:05:58 GMT Transfer-encoding: chunked Content-type: text/xml;charset=utf-8//響應wsdl內容,來獲得方法、參數等信息 899 <?xml version="1.0" encoding="UTF-8"?><!-- Published by JAX-WS RI (http://jax-ws.java.net). RI's version is JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e. --><!-- Generated by JAX-WS RI (http://jax-ws.java.net). RI's version is JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e. --><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://ws.cad.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://ws.cad.com/" name="WeatherInterfaceImplService"> <types> <xsd:schema> <xsd:import namespace="http://ws.cad.com/" schemaLocation="http://127.0.0.1:54321/weather?xsd=1"></xsd:import> </xsd:schema> </types> <message name="queryWeather"> <part name="parameters" element="tns:queryWeather"></part> </message> <message name="queryWeatherResponse"> <part name="parameters" element="tns:queryWeatherResponse"></part> </message> <portType name="WeatherInterfaceImpl"> <operation name="queryWeather"> <input wsam:Action="http://ws.cad.com/WeatherInterfaceImpl/queryWeatherRequest" message="tns:queryWeather"></input> <output wsam:Action="http://ws.cad.com/WeatherInterfaceImpl/queryWeatherResponse" message="tns:queryWeatherResponse"></output> </operation> </portType> <binding name="WeatherInterfaceImplPortBinding" type="tns:WeatherInterfaceImpl"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"></soap:binding> <operation name="queryWeather"> <soap:operation soapAction=""></soap:operation> <input> <soap:body use="literal"></soap:body> </input> <output> <soap:body use="literal"></soap:body> </output> </operation> </binding> <service name="WeatherInterfaceImplService"> <port name="WeatherInterfaceImplPort" binding="tns:WeatherInterfaceImplPortBinding"> <soap:address location="http://127.0.0.1:54321/weather"></soap:address> </port> </service> </definitions> 0//響應數據 HTTP/1.1 200 OK Date: Tue, 25 Jul 2017 05:05:59 GMT Transfer-encoding: chunked Content-type: text/xml; charset=utf-8df <?xml version="1.0" ?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body><ns2:queryWeatherResponse xmlns:ns2="http://ws.cad.com/"><return>暴雨</return> </ns2:queryWeatherResponse> </S:Body> </S:Envelope> 0UDDI
UDDI 是一種目錄服務,企業可以使用它對 Web services 進行注冊和搜索。
如果我們要使用一種服務,但是不知道地址(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
還有天氣等服務,自己可以去實現一下。
該種方式使用簡單,但一些關鍵的元素在代碼生成時寫死在生成代碼中,不方便維護,所以僅用于測試。
二:service編程調用方式
public class MobileClient2 {public static void main(String[] args) throws IOException {//創建WSDL文件的URLURL wsdlDocumentLocation=new URL("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl"); //創建服務名稱//1.namespaceURI - 命名空間地址//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("XXXXXXX", null);System.out.println(message);}}該種方式可以自定義命名空間,服務視圖名等元素,方便以后維護,是一種標準的開發方式 。
三:HttpURLConnection調用方式
這種方式是由自己編寫客戶端,不再由工具生成,比較麻煩。
開發步驟: 第一步:創建服務地址第二步:打開一個通向服務地址的連接第三步:設置參數第四步:組織SOAP數據,發送請求第五步:接收服務端響應 public class MobileClient2 {public static void main(String[] args) throws IOException {//第一步:創建服務地址,不是WSDL地址URL url = new URL("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx");//第二步:打開一個通向服務地址的連接HttpURLConnection connection = (HttpURLConnection) url.openConnection();//第三步:設置參數//3.1發送方式設置:POST必須大寫connection.setRequestMethod("POST");//3.2設置數據格式:content-typeconnection.setRequestProperty("content-type", "text/xml;charset=UTF-8");//3.3設置輸入輸出,因為默認新創建的connection沒有讀寫權限,connection.setDoInput(true);connection.setDoOutput(true);//第四步:組織SOAP數據,發送請求String soapXML = getXML("XXXXXXX");OutputStream os = connection.getOutputStream();os.write(soapXML.getBytes());//第五步:接收服務端響應,打印int responseCode = connection.getResponseCode();if(200 == responseCode){//表示服務端響應成功InputStream is = connection.getInputStream();//將字節流轉換為字符流InputStreamReader isr = new InputStreamReader(is,"utf-8");//使用緩存區BufferedReader br = new BufferedReader(isr);StringBuilder sb = new StringBuilder();String temp = null;while(null != (temp = br.readLine())){sb.append(temp);}System.out.println(sb.toString());is.close();isr.close();br.close();}os.close();}//組織數據,將數據拼接一下public static String getXML(String phoneNum){String soapXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"+"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"+"<soap:Body>"+"<getMobileCodeInfo xmlns=\"http://WebXml.com.cn/\">"+"<mobileCode>"+phoneNum+"</mobileCode>"+"<userID></userID>"+"</getMobileCodeInfo>"+"</soap:Body>"+"</soap:Envelope>";return soapXML;} }使用注解修改WSDL內容
作用:
通過注解,可以更加形像的描述Web服務。對自動生成的wsdl文檔進行修改,為使用者提供一個更加清晰的wsdl文檔
CXF
CXF簡介
CXF是一個開源的WebService框架。Apache CXF = Celtix + XFire,開始叫 Apache CeltiXfire,后來更名為 Apache CXF 了,以下簡稱為 CXF。CXF 繼承了 Celtix 和 XFire 兩大開源項目的精華,提供了對 JAX-WS 全面的支持,并且提供了多種 Binding 、DataBinding、Transport 以及各種 Format 的支持,并且可以根據實際項目的需要,采用代碼優先(Code First)或者 WSDL 優先(WSDL First)來輕松地實現 Web Services 的發布和使用。
支持多種標準
- 支持 JAX-WS、 JAX-WSA、JSR-181 和 SAAJ;
- 支持 SOAP 1.1、1.2、WS-I BasicProfile、WS-Security、WS-Addressing、WS-RM 和 WS-Policy;
- 支持 WSDL 1.1 、2.0;
- 支持 MTOM;
它支持多種協議,比如:SOAP1.1,1,2、XML/HTTP、RESTful HTTP 或者 CORBA。CORBA(Common Object Request Broker Architecture公共對象請求代理體系結構,早期語言使用的WS。C,c++,C#)
Cxf是基于SOA總線結構,依靠spring完成模塊的集成,實現SOA方式。
靈活的部署:可以運行有Tomcat,Jboss,Jetty(內置),weblogic上面。
CXF入門案例
我們還以昨天的天氣服務為案例來看一下CXF的開發過程。
服務端的實現
1.創建一個空的java項目,創建一個lib目錄,將所有jar包放入lib目錄然后為工程引入jar包,選擇build path,然后Add JARS,只用選擇cxf-manifest.jar即可。 2.創建一個SEI接口,需要在接口上添加@WebService注解@WebService public interface WeatherInterface {public String queryWeather(String cityName); } 3.創建SEI接口實現類 public class WeatherInterfaceImpl implements WeatherInterface {public String queryWeather(String cityName) {if("河南".equals(cityName)) {return "熱爆炸";}else {return "冰雹";}} } 4.發布服務 public class WeatherServer {public static void main(String[] args) {//創建服務工廠BeanJaxWsServerFactoryBean jaxWsServerFactoryBean=new JaxWsServerFactoryBean();//設置服務接口jaxWsServerFactoryBean.setServiceClass(WeatherInterface.class);//設置服務實現類jaxWsServerFactoryBean.setServiceBean(new WeatherInterfaceImpl());//設置服務地址jaxWsServerFactoryBean.setAddress("http://127.0.0.1:12345/weather");//創建服務jaxWsServerFactoryBean.create();}} 5.訪問服務的wsdl文件地址,看服務是否發布成功http://127.0.0.1:12345/weather?wsdl發布SOAP1.2的服務端
SOAP分為1.1版本和1.2版本。JDK1.6并不支持1.2,我們可以通過CXF來發布SOAP1.2的服務端。
只需要在接口上添加注解 @BindingType(SOAPBinding.SOAP12HTTP_BINDING)。然后重新發布服務即可
客戶端的實現
Wsdl2java命令是CXF提供的生成客戶端的工具,他和wsimport類似,可以根據WSDL生成客戶端代碼 Wsdl2java常用參數: -d,指定輸出目錄 -p,指定包名,如果不指定該參數,默認包名是WSDL的命名空間的倒序 Wsdl2java支持SOAP1.1和SOAP1.2 1.我們先創建一個客戶端項目,然后引入jar包,和上面一樣,使用Add JARS選擇cxf-manifest.jar即可然后使用工具生成客戶端wsdl2java -p com.cad.cxf -d . http://127.0.0.1:12345/weather?wsdl 2.創建客戶端 public class WeatherClient {public static void main(String[] args) {JaxWsProxyFactoryBean jaxWsProxyFactoryBean=new JaxWsProxyFactoryBean();//設置服務接口jaxWsProxyFactoryBean.setServiceClass(WeatherInterface.class); //設置服務地址jaxWsProxyFactoryBean.setAddress("http://127.0.0.1:12345/weather");//獲取服務接口實例WeatherInterface weatherInterface=(WeatherInterface) jaxWsProxyFactoryBean.create();//調用方法String message=weatherInterface.queryWeather("河南");System.out.println(message);}}CXF+Spring整合發布SOAP模式的服務
服務端的實現
1.創建WEB項目,導入jar包 1 2.創建SEI接口 @WebService @BindingType(SOAPBinding.SOAP12HTTP_BINDING) public interface WeatherInterface {public String queryWeather(String cityName); } 3.創建SEI實現類 public class WeatherInterfaceImpl implements WeatherInterface {public String queryWeather(String cityName) {if("河南".equals(cityName)) {return "熱爆炸";}else {return "冰雹";}} } 4.配置spring配置文件,applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsdhttp://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsdhttp://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd"><!--jaxws:server發布SOAP協議的服務 ,對JaxWsServerFactoryBean類封裝--> <!--serviceClass屬性是服務接口,address代表地址,因為我們是web服務,不需要輸入ip。serviceBean是服務實現類--> <jaxws:server serviceClass="com.cad.cxf.WeatherInterface" address="/weather"><jaxws:serviceBean><ref bean="weatherInterfaceImpl"/></jaxws:serviceBean> </jaxws:server> <bean name="weatherInterfaceImpl" class="com.cad.cxf.WeatherInterfaceImpl"></bean> </beans> 5.配置web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"><display-name>CXFSpringDemo</display-name>//配置Tomcat啟動時加載Spring配置文件 <context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>//配置CXF提供的Servlet<servlet><servlet-name>CXF</servlet-name><servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class></servlet><servlet-mapping><servlet-name>CXF</servlet-name><url-pattern>/ws/*</url-pattern></servlet-mapping><welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list> </web-app> 6.部署到Tomcat下,發布服務,并訪問 http://localhost:8080/CXFSpringDemo/ws/weather?wsdl客戶端的實現
1.創建項目,導入jar包,生成客戶端 wsdl2java -p com.cad.cxf -d . http://localhost:8080/CXFSpringDemo/ws/weather?wsdl 2.配置Spring文件 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsdhttp://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsdhttp://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd"><!-- <jaxws:client實現客戶端 ,對JaxWsProxyFactoryBean類封裝--> <!-- address是服務地址,servicelass是服務接口,返回服務實現類--> <jaxws:client id="weatherClient" address="http://localhost:8080/CXFSpringDemo/ws/weather" serviceClass="com.cad.cxf.WeatherInterface"/> </beans> 3.通過Spring容器獲取服務實現類,調用方法 public class WeatherClient {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");WeatherInterface weatherInterface = (WeatherInterface) context.getBean("weatherClient");String message=weatherInterface.queryWeather("河南");System.out.println(message);}}CXF發布REST模式的服務
REST即表述性狀態傳遞(英文:Representational State Transfer,簡稱REST),是一種軟件架構風格。
因為REST模式的Web服務與復雜的SOAP和XML-RPC對比來講明顯的更加簡潔,越來越多的web服務開始采用REST風格設計和實現rest服務采用HTTP 做傳輸協議,REST 對于HTTP 的利用實現精確的資源定位。
例如: 非rest方式:http://ip:port/queryUser.action?userType=student&id=001 Rest方式:http://ip:port/user/student/query/001 1.創建一個項目,導入CXF jar包 1 2.創建一個實體類 Student @XmlRootElement(name="student")可以實現XML和對象之間的轉換,name屬性指定根元素@XmlRootElement(name="student") public class Student {private int id;private String name;private Date birthday;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}} 3.創建SEI接口 @WebService //@Path("/student")就是指定訪問該接口的路徑 @Path("/Student") public interface StudentInterface {//指定請求方式,如果服務端發布的時候指定的是GET(POST),那么客戶端訪問時必須使用GET(POST@GET//指定服務數據類型,可以是XML,json等數據類型@Produces(MediaType.APPLICATION_XML)//@Path("/query/{id}")指定該方法的路徑,“{id}”指參數,多個參數,以“/”隔開,放到“{}”中@Path("/query/{id}")public Student queryStudent(@PathParam("id")int id);@GET@Produces(MediaType.APPLICATION_XML)@Path("/queryList/{name}")public List<Student> queryList(@PathParam("name")String name); } 4.創建SEI實現類 public class StudentInterfaceImpl implements StudentInterface {@Overridepublic Student queryStudent(int id) {Student s=new Student();s.setId(666);s.setName("張三");s.setBirthday(new Date());return s;}@Overridepublic List<Student> queryList(String name) {Student s=new Student();s.setId(666);s.setName("張三");s.setBirthday(new Date());Student s2=new Student();s2.setId(888);s2.setName("李四");s2.setBirthday(new Date());List<Student> l=new ArrayList<Student>();l.add(s);l.add(s2);return l;}} 5.發布服務 public class StudentServer {public static void main(String[] args) {JAXRSServerFactoryBean jaxrsServerFactoryBean=new JAXRSServerFactoryBean();//設置服務實現類jaxrsServerFactoryBean.setServiceBean(new StudentInterfaceImpl());//設置資源類,如果有多個資源類,可以以“,”隔開,例如Student.class StudentInterface.class都是資源類,但是StudentInterfaceImpl里面已經包含了Student.class StudentInterface.class,所以不用重復指定jaxrsServerFactoryBean.setResourceClasses(StudentInterfaceImpl.class); //設置服務地址jaxrsServerFactoryBean.setAddress("http://127.0.0.1:12345/Class");//發布服務jaxrsServerFactoryBean.create();}} 6.測試服務 訪問query方法 http://127.0.0.1:12345/Class/Student/query/001 訪問queryList方法 http://127.0.0.1:12345/Class/Student/queryList/xxx如果服務端發布時指定請求方式是GET(POST),客戶端必須使用GET(POST)訪問服務端,否則會報異常。
如果在同一方法上同時指定XML和JSON媒體類型,在GET請求下,默認返回XML,在POST請求下,默認返回JSON
CXF+Spring整合發布REST模式的服務
1.創建web項目,引入jar包1 2.創建一個實體類 Student @XmlRootElement(name="student")可以實現XML和對象之間的轉換,name屬性指定根元素@XmlRootElement(name="student") public class Student {private int id;private String name;private Date birthday;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}} 3.創建SEI接口 @WebService //@Path("/student")就是指定訪問該接口的路徑 @Path("/Student") public interface StudentInterface {//指定請求方式,如果服務端發布的時候指定的是GET(POST),那么客戶端訪問時必須使用GET(POST@GET//指定服務數據類型,可以是XML,json等數據類型@Produces(MediaType.APPLICATION_XML)//@Path("/query/{id}")指定該方法的路徑,“{id}”指參數,多個參數,以“/”隔開,放到“{}”中@Path("/query/{id}")public Student queryStudent(@PathParam("id")int id);@GET@Produces(MediaType.APPLICATION_XML)@Path("/queryList/{name}")public List<Student> queryList(@PathParam("name")String name); } 4.創建SEI實現類 public class StudentInterfaceImpl implements StudentInterface {@Overridepublic Student queryStudent(int id) {Student s=new Student();s.setId(666);s.setName("張三");s.setBirthday(new Date());return s;}@Overridepublic List<Student> queryList(String name) {Student s=new Student();s.setId(666);s.setName("張三");s.setBirthday(new Date());Student s2=new Student();s2.setId(888);s2.setName("李四");s2.setBirthday(new Date());List<Student> l=new ArrayList<Student>();l.add(s);l.add(s2);return l;}} 第五步:配置Spring配置文件,applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsdhttp://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsdhttp://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd"><!-- <jaxrs:server發布REST的服務 ,對JAXRSServerFactoryBean類封裝--> <jaxrs:server address="/user"><jaxrs:serviceBeans><ref bean="studentInterface"/></jaxrs:serviceBeans></jaxrs:server><!-- 配置服務實現類 --><bean name="studentInterface" class="com.cad.rest.StudentInterfaceImpl"/> </beans> 6.配置web.xml文件 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"><display-name>ws_2_cxf_spring_server</display-name><!-- 設置spring的環境 --><context-param><!--contextConfigLocation是不能修改的 --><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 配置CXF的Servlet --><servlet><servlet-name>CXF</servlet-name><servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class></servlet><servlet-mapping><servlet-name>CXF</servlet-name><url-pattern>/ws/*</url-pattern></servlet-mapping><welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list> </web-app> 7.部署到Tomcat中,發布服務,測試一下 http://127.0.0.1:8080/CXFRestDemo/ws/user/Student/query/100綜合案例:手機歸屬地查詢
1.創建web項目,導入 CXF jar包 1 2.生成公網提供的手機歸屬地查詢的客戶端 wsdl2java -p com.cad.mobile -d . http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl 3.編寫我們自己的SEI接口 @WebService public interface MobileInterface {public String queryMobile(String phoneNum); } 4.編寫我們的SEI實現類 ,里面調用公網客戶端的查詢方法,我們在Spring配置客戶端,然后注入即可 public class MobileInterfaceImpl implements MobileInterface {//公網客戶端,提供set方法 以便注入private MobileCodeWSSoap mobileClient;//調用公網的查詢方法public String queryMobile(String phoneNum) {return mobileClient.getMobileCodeInfo(phoneNum, "");}public MobileCodeWSSoap getMobileClient() {return mobileClient;}public void setMobileClient(MobileCodeWSSoap mobileClient) {this.mobileClient = mobileClient;}} 5.配置Spring 配置文件 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsdhttp://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsdhttp://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd"><!-- 配置公網客戶端 --><jaxws:client id="mobileClient" address="http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx" serviceClass="com.cad.mobile.MobileCodeWSSoap"/> <!-- <jaxws:server發布我們的服務--> <jaxws:server address="/mobile" serviceClass="com.cad.server.MobileInterface"><jaxws:serviceBean><ref bean="mobileServer"/></jaxws:serviceBean></jaxws:server> <!-- 配置我們的服務實現類 --><bean name="mobileServer" class="com.cad.server.MobileInterfaceImpl"><property name="mobileClient" ref="mobileClient"/></bean> </beans> 6.創建查詢頁面 <body><form action="MobileServlet" method="post">手機號歸屬地查詢:<input type="text" name="phoneNum"><input type="submit" value="查詢"><br>查詢結果:${result}</form></body> 7.創建處理的Servlet@WebServlet("/MobileServlet") public class MobileServlet extends HttpServlet {private MobileInterface mobileServer;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//獲取頁面的電話號String phoneNum = request.getParameter("phoneNum");if(null != phoneNum && !"".equals(phoneNum)){//獲取Spring容器ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());//獲取我們的服務實現類mobileServer = (MobileInterface) context.getBean("mobileServer");//調用查詢方法String result = mobileServer.queryMobile(phoneNum);request.setAttribute("result", result);}//請求轉發 request.getRequestDispatcher("/index.jsp").forward(request, response);}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// TODO Auto-generated method stubdoGet(request, response);}} 8.配置web.xml<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"><display-name>MobileDemo</display-name><welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list><context-param><!--contextConfigLocation是不能修改的 --><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 配置CXF的Servlet --><servlet><servlet-name>CXF</servlet-name><servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class></servlet><servlet-mapping><servlet-name>CXF</servlet-name><url-pattern>/ws/*</url-pattern></servlet-mapping></web-app> 9.部署Tomcat,訪問測試總結
以上是生活随笔為你收集整理的WebService技术详解CXF的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 趣学python3(40)--TCP服务
- 下一篇: ajax中return取不到值的问题