JAX-RS 方式的 RESTful Web Service 开发
2019獨角獸企業重金招聘Python工程師標準>>>
Web Service?目前在風格上有兩大類,一個是基于?SOAP?協議,一個是完全遵循?HTTP?協議規范的RESTful?風格。?SOAP?方式的?web service?已經很成熟了,應用也很廣,已經成為?Web Service?的工業標準。不過?RESTful Web Service?現在勢頭越來越猛,特別是其靈活性以及與?Ajax?的完美結合,讓人愛不釋手,很有必要了解一下。?RESTful?就是一種架構風格,是對?HTTP?協議的完全遵循。像是人們經歷了無止境的對?HTTP?引申、擴展之路后的一種回歸,讓?web service?開發者重新做回?HTTP?協議的信徒。?RESTful?倡導用?HTTP?協議中的?verb?與實際數據操作的增刪改查相對應,如?HTTP?中的?PUT?、?GET?、?POST?、DELETE?分別對應?web?系統中數據的改、查、增、刪的操作。當然?RESTful?支持的?http verb?還不僅限于上述?4?個,還有像其他的?HEAD,OPTION?……等,不過上述?4?個已經夠我們日常使用了。
目前?Web Service?的框架很多,不過我只用過?CXF?,所以我還是以?apache-cxf2.2.2?為例介紹一下?RESTful Web Service?的開發。
比較常見的?RESTful Web Service?的發布有?JAX-RS?風格、?Provider?方式、?Servlet?方式、?HTTPBinding?,也許還有其他方式,不過我只知道這些了。總的感覺最偷懶的方式是采用?Servlet?方式發布?Web Service?,說是?Web Service?發布,其實就是轉換下對?Servlet?的認識,?Servlet?本身就支持對?HTTP?請求中各種動作的支持,所以?Servlet?原生就是一種?RESTful Web Service?。不過這種方式我覺得有些不夠時尚。?Povider?的方式我了解了一下,需要實現?Provider?接口,感覺很受拘束。正在我對?RESTful?喪失興趣的時候,發現了?JAX-RS?風格,?JAX-RS?就像是一個清純?MM?,服務端配置完成,而且配置非常的清秀。而且也非常的平易近人,客戶端調用方式很靈活。接下來我就把她介紹給大家。
1.??????環境搭建
在本示例中采用了?Web Project?的方式,?Web?工程建立的過程就不再贅述了,只列舉一下環境需要的?jar包。如下:
下面是我本地工程中的?jar?,僅供參考。
注:如果要在?RESTful?服務中直接返回?json?數據格式的話,?jsr311-api-1.0.jar?必不可少。
2.??????服務開發
我們以簡單的一個客戶信息服務為例進行介紹。服務的業務實現大家不用太在意,關注服務開發的過程就好了。
2.1???開門見山
首先我們先構造一個客戶的?VO?。
package com.harvey.cxf.demo.rest.rs.vo; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "Customer") @XmlAccessorType(XmlAccessType.FIELD) public class Customer { private long id; private String name; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }接下來以?CustomerService?作為客戶服務的實現類
先以最常見的查詢某一客戶信息為例,如下:
@Path("/") public class CustomerService { …… //普通路徑參數方式GET請求 @GET @Path("/customers/{id}") public Customer getCustomer(@PathParam("id") String id) { …… } }假設我們的服務最終發布地址為?http://127.0.0.1:8080/customerservice?的話,如果要查詢某一客戶的信息的話,我們只需發送?GET?請求?http://127.0.0.1:8080/customerservice/customers/123?,或者直接在瀏覽器中輸入該?url就可直接訪問該服務。其中?url?中傳入的?123?會自動適配到服務中的?{id}?參數。這樣一個簡單的處理?GET?請求的RESTful Web service?就開發完了。
2.2?參數處理
在上面的例子中我們看到,?client?在服務請求時傳遞參數是通過的請求路徑的方式傳入的。如之前的http://127.0.0.1:8080/customerservice/customers/123?,?客戶?ID123?作為了路徑一部分。對應的服務器端的參數配置采用了?@PathParam?(?"id"?) String id?。?
除了支持路徑傳遞的方式之外,我們還可以在請求時的查詢參數中指定。比如還是查詢某一客戶的信息,server?端代碼可以如下:
此時該服務訪問?url?則為:
http://127.0.0.1:8080/customerservice/customers/getCustomerById?id=123
說著這,也許會有聽眾要問了(也許沒人問):之前提到的都是簡單參數,這個容易,那么對于一些復雜bean?參數該怎么處理呢?
這個問題問得好,接下來我就舉例說明下。說例子之前再重復一遍啊,看例子時千萬不要糾結于代碼的業務邏輯,只看技術實現方式。
…… @GET @Path("/customers/getCust") public Customer getCustomer(@QueryParam("")Customer cust) { …… }這個例子中需要傳入之前聲明的客戶信息類作為參數。參數處理方式為?QueryParam?,所以這時候我們訪問url?格式類似以下:
http://127.0.0.1:8080/customerservice/customers/getCust?id=123&name=xiaoming
如果參數?bean?還包括其他屬性,用?&?符號依次追加就好了。還通常的?web?訪問沒什么區別。
如果你覺得上述用查詢字串的方式不夠個性的話,可以采用另外一種:?@MatrixParam
Server?端代碼如下:
…… @GET @Path("/customers/getCustByMat") public Customer getCustomerByMat(@MatrixParam("")Customer cust) { …… }這時候我們再訪問時就可以用下面的形式了:
http://127.0.0.1:8080/customerservice/customers/getCustByMat;id=123;name=xiaoming
如果?cusmomer?還有其他屬性,直接在后面追加就可以了,參數之間用?;?分隔?.
以上我們用到的參數雖然采用的處理方式的注解各不相同,但是都是有注解的。接下來出場的這個就屬于特殊人物了。有請?body?參數出場……
…… @POST @Path("/addCustomer") public Customer addCustomer(String body) { …… }這個?body?參數是?JAX-RS?中比較特殊的,它前面沒有任何注解,它代表的是請求的?body?內容或者請求的inputstream?,自動解析映射為字符串參數。因為之前我們的例子都是?GET?請求,消息中是沒有?body?的,所以細心的聽眾可能會發現我們這次的服務的?verb?配置為了?@POST?。
2.3?請求、應答數據格式
之前的示例中我們的方法都返回了?Customer?,但是我們的系統是一個?RESTful web service?啊,客戶端接收到的肯定是一個?HTTP?的?response?消息,那么返回的?Customer?是怎樣的一個消息內容呢?
默認情況下?reponse?消息的?Customer?會以?xml?的格式返回。類似于:
<Customer><id>123</id><name>skdjl</name></Customer>
客戶端調用?server?端服務,得到上述的?xml?字串結果,然后進行后續處理。
既然這說的默認情況,言外之意就是說還有很多其他情況了,不過需要配置一下。就不得不說下@Produces注解了。@Produces就是表示server端返回的數據格式類型,具體包括application/xml, application/json, application/text……,其實就是我們常見的web端的content-type中的類型。如果我們設置為application/json,自然返回的數據格式為json形式。另一個注解:@Consumes,就是與@Produces相對應的。@Consumes是設定的客戶端發送的請求數據的格式,對應支持的類型與@Produces相同。具體配置如下:
…… @POST @Path("/addCustomerUseBean") @Produces("application/json") @Consumes("application/xml") public Customer addCustomerUseBean(Customer cust) { …… }?這個例子的意思是客戶端傳入?Customer?作為參數,傳遞格式為?xml?風格,?server?端應答的數據格式為json?風格。我們當然也可以在類注解中加入?@Produces?和?@Consumes?作為服務整體的?request?和?response風格,具體服務方法如果不設定的話采用類的?@Produces?和?@Consumes?的設定。
3????????服務配置
服務開發完成之后,我們要做的就是把服務發布出去。發布方式也很靈活,可以采用編碼的方式,也可以和spring?結合用配置的方式。在下面的例子中我們采用后者。配置的內容不再做過多的解釋,大家看一下就能明白。
3.1???web.xml?的配置
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>DEMO</display-name> <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> <listener> <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class> </listener> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class> org.apache.cxf.transport.servlet.CXFServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>3.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:aop="http://www.springframework.org/schema/aop" xmlns:cxf="http://cxf.apache.org/core" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml"/> <jaxrs:server id="customerService" address="/customerservice"> <jaxrs:serviceBeans> <ref bean="customerServiceBean"/> </jaxrs:serviceBeans> </jaxrs:server> <bean id="customerServiceBean" class="com.harvey.cxf.demo.rest.rs.server.CustomerService"/> </beans>然后啟動我們的?web?程序,服務就發布完成了。可以在瀏覽器中敲入:
http://127.0.0.1:8080/customerservice/customers/1?測試服務是否正常。
從上面的例子也許你能發現,我們雖然是做的RESTful的例子,但是具體提供的服務verb中很多都是帶有動作的成分比如getCustomer,addCustomer等等,這些詞匯的存在預示著我們的服務雖然采用了RESTful的技術,但是并沒有遵循ROA(面向資源的架構)的理念,真正的ROA信徒看到上面的例子可能會非常不爽。因為畢竟RESTful和ROA才是青梅竹馬。不過正如前面提到的,大家值關注技術實現就好了。
4????????客戶端調用
我們的服務發布完成了,接下來我們可以做一個測試?client?程序進行?測試。對于?RESTful?的調用方式很多,可以用?java?的?Connect?方式,也可以用?apche?的?httpclint?,另外還可以用?cxf?提供的?WebClient?進行,等等。后面的?client?代碼中分別采用幾種調用方式,在這里我們不必拘泥,可以任意選用自己熟悉的方式。
轉載于:https://my.oschina.net/liuyuantao/blog/711109
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的JAX-RS 方式的 RESTful Web Service 开发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux常用系统管理命令(top、fr
- 下一篇: AWS EC2 Run Command特