REST
RE presentational?S tate?T ransfer ;代表性狀態傳輸、具象狀態傳輸
REST定義了應該如何正確地使用Web標準,例如HTTP和URI。REST并非標準,而是一種開發 Web 應用的架構風格,可以將其理解為一種設計模式。
?
REST關鍵原則
1、為所有“事物”定義ID
含義:
在Web中,代表ID的統一概念是:URI。URI構成了一個全局命名空間,使用URI標識你的關鍵資源意味著它們獲得了一個唯一、全局的ID。
使用URI標識所有值得標識的事物,特別是應用中提供的所有“高級”資源,無論這些資源代表單一數據項、數據項集合、虛擬亦或實際的對象還是計算結果等。
好處:
使用唯一、全局統一的命名規則的好處,既適用于瀏覽器中的Web應用,也適用于機對機(machine-to-machine,m2m)通信。
?
2、將所有事物鏈接在一起
含義:
任何可能的情況下,使用鏈接指引可以被標識的事物(資源)。
正式描述:“超媒體被當作應用狀態引擎(Hypermedia as the engine of application state)”,有時簡寫為HATEOAS。這個描述的核心是超媒體 概念,換句話說:是鏈接 的思想
好處:
超媒體原則還有一個更重要的方面——應用“狀態” 。簡而言之,實際上服務器端為客戶端提供一組鏈接,使客戶端能通過鏈接將應用從一個狀態改變為另一個狀態。目前,只需要記住:鏈接是構成動態應用的非常有效的方式.
?
[html] ?view plain?copy ?print?
< order ?self ="http://example.com/customers/1234" > ??????< amount > 23</ amount > ??? ???< product ?ref ="http://example.com/products/4554" > ??? ???< customer ?ref ="http://example.com/customers/1234" > ??? ????</ customer > ??? ????</ product > ?? </ order > ??
?
?
?
3、使用標準方法
含義:
瀏覽器知道如何去處理URI的原因在于所有的資源都支持同樣的接口,一套同樣的方法集合。標準方法集合包含GET、POST\PUT、DELETE、HEAD和OPTIONS
為使客戶端程序能與你的資源相互協作,資源應該正確地實現默認的應用協議(HTTP),也就是使用標準的GET、PUT、POST和DELETE方法。
好處:
它使你的應用成為Web的一部分——應用程序為Web變成Internet上最成功的應用所做的貢獻,與它添加到Web中的資源數量成比例。采用RESTful方式,一個應用可能會向Web中添加數以百萬計的客戶URI
統一接口也使得所有理解HTTP應用協議的組件能與你的應用交互。通用客戶程序(generic client)就是從中受益的組件的例子,例如curl、wget、代理、緩存、HTTP服務器、網關還有Google、Yahoo!、MSN等等。
?
4、資源多重表述?
含義:
客戶程序如何知道該怎樣處理檢索到的數據,比如作為GET或者POST請求的結果?原因是,HTTP采取的方式是允許數據處理和操作調用之間關系分離的。
針對不同的需求提供資源多重表述
好處:
如果你為你的資源提供HTML和XML兩種表述方式,那這些資源不僅可以被你的應用所用,還可以被任意標準Web瀏覽器所用
?
5、無狀態通信
含義:
REST要求狀態要么被放入資源狀態中,要么保存在客戶端上。或者換句話說,服務器端不能保持除了單次請求之外的,任何與其通信的客戶端的通信狀態。
這樣做的最直接的理由就是可伸縮性—— 如果服務器需要保持客戶端狀態,那么大量的客戶端交互會嚴重影響服務器的內存可用空間
好處:
無狀態約束使服務器的變化對客戶端是不可見的,因為在兩次連續的請求中,客戶端并不依賴于同一臺服務器。
?
?
JAX-RS
?
J ava?A PI forR ESTful WebS ervices 旨在定義一個統一的規范,使得?Java?程序員可以使用一套固定的接口來開發 REST 應用,避免了依賴于第三方框架。是一個Java編程語言的應用程序接口,支持按照表象化狀態轉變 (REST) 架構風格創建Web服務Web服務。
與傳統的 servlet 模型相比,JAX-RS 提供了一種可行的、更為簡便、移植性更好的方式來在 Java 內實現 RESTful 服務。使用注釋讓您能夠輕松提供 Java 資源的路徑位置并將 Java 方法綁定到 HTTP 請求方法。一種可移植的數據綁定架構提供了一些本機的 Java 類型支持并允許進行序列化/反序列化處理的完全定制。javax.ws.rs.core.Application 子類的擴展以及 web.xml 內的相應清單表明了用最少的部署描述符配置就能進行輕松部署。
JAX-RS 的具體實現由第三方提供,例如 Sun 的參考實現?Jersey 、Apache 的?CXF? 以及 JBoss 的?RESTEasy 。
?
JAX-RS標注
JAX-RS提供了一些標注將一個資源類,一個POJO類,封裝為Web資源。標注包括:
@Path ,標注資源類或方法的相對路徑
@GET,@PUT,@POST,@DELETE ,標注方法是用的HTTP請求的類型,分別對應 4 種 HTTP 方法,用于對資源進行創建、檢索、更新和刪除的操作。
若要創建資源,應該使用 POST 方法; 若要檢索某個資源,應該使用 GET 方法; 若要更改資源狀態或對其進行更新,應該使用 PUT 方法; 若要刪除某個資源,應該使用 DELETE 方法。
@Produces ,標注返回的MIME媒體類型
@Consumes ,標注可接受請求的MIME媒體類型
@PathParam,@QueryParam,@HeaderParam,@CookieParam,@MatrixParam,@FormParam ,分別標注方法的參數來自于HTTP請求的不同位置,
?
@PathParam來自于URL的路徑, @QueryParam來自于URL的查詢參數, @HeaderParam來自于HTTP請求的頭信息, @CookieParam來自于HTTP請求的Cookie。
?
?
Resource類和Resource方法
?
Web 資源 作為一個?Resource 類 來實現,對資源的請求由?Resource 方法 來處理。
Resource 類或 Resource 方法被打上了 Path 標注,Path 標注的值是一個相對的 URI 路徑,用于對資源進行定位,路徑中可以包含任意的正則表達式以匹配資源。和大多數 JAX-RS 標注一樣,Path 標注是可繼承的,子類或實現類可以繼承超類或接口中的 Path 標注。
Resource 類是 POJO,使用 JAX-RS 標注來實現相應的 Web 資源。
Resource 類分為根 Resource 類 和子 Resource 類 ,區別在于子 Resource 類沒有打在類上的 @Path 標注。
Resource 類的實例方法打上了@Path 標注,則為?Resource 方法 或子 Resource 定位器 ,子 Resource 定位器上沒有任何 @GET、@POST、@PUT、@DELETE 或者自定義的 @HttpMethod
?
?
?
[java] ?view plain?copy ?print?
@Path ("/" )???public ?class ?BookkeepingService?{???????......??? ????@Path ("/person/" )?//資源方法;若無@POST,則為子資源定位器 ?? ????@POST ??? ????@Consumes ("application/json" )??? ????public ?Response?createPerson(Person?person)?{?//JSON?格式的請求體被自動映射為實體參數person ?? ????????......??? ????}??? ?? ????@Path ("/person/" )??? ????@PUT ??? ????@Consumes ("application/json" )??? ????public ?Response?updatePerson(Person?person)?{??? ????????......??? ????}??? ?? ????@Path ("/person/{id:\\d+}/" )?//正則表達式 ?? ????@DELETE ??? ????public ?Response?deletePerson(@PathParam ("id" )??? ????int ?id)?{??? ????????......??? ????}??? ?? ????@Path ("/person/{id:\\d+}/" )??? ????@GET ??? ????@Produces ("application/json" )??? ????public ?Person?readPerson(@PathParam ("id" )??? ????int ?id)?{??? ????????......??? ????}??? ?? ????@Path ("/persons/" )??? ????@GET ??? ????@Produces ("application/json" )??? ????public ?Person[]?readAllPersons()?{?//數組類型的返回值被自動映射為?JSON?格式的響應體——? ?? ????????......??? ????}??? ?? ????@Path ("/person/{name}/" )??? ????@GET ??? ????@Produces ("application/json" )??? ????public ?Person?readPersonByName(@PathParam ("name" )??? ????String?name)?{??? ????????......??? }???
?
?
注意:
Subresources Locators是指一個指定了@Path annotation,但未指定HttpMethod的annotation 最好是在一個interface中定義這個標注,然后實現這個interface
?
Resource方法參數類型、返回類型
Resource 方法合法的 參數類型 包括:
原生類型?——在客戶端如何發送原生類型?可否發送JSON類? 構造函數接收單個字符串參數,或者包含擁有一個static的valueOf(String)方法 List<T>,Set<T>,SortedSet<T>(T 為以上的 2 種類型) 用于映射請求體的實體參數
Resource 方法合法的返回值類型 包括:
void:狀態碼 204 和空響應體 Response:Response 的 status 屬性指定了狀態碼,entity 屬性映射為響應體 [java] ?view plain?copy ?print?
return ?Response.status(Status.OK).entity(JsonUtils.toString(result)).build();??GenericEntity:GenericEntity 的 entity 屬性映射為響應體,entity 屬性為空則狀態碼為 204,非空則狀態碼為 200 其它類型:返回的對象實例映射為響應體,實例為空則狀態碼為 204,非空則狀態碼為 200
對于錯誤處理,Resource 方法可以拋出非受控異常 WebApplicationException 或者返回包含了適當的錯誤碼集合的 Response 對象。
?
內容協商與數據綁定
?
Web 資源可以有不同的表現形式,服務端與客戶端之間需要一種稱為內容協商(Content Negotiation)的機制:
作為服務端,Resource 方法的@Produces ?標注用于指定響應體的數據格式(MIME 類型),@Consumes ?標注用于指定請求體的數據格式 ;
作為客戶端,Accept? 請求頭用于選擇響應體的數據格式,Content-Type ?請求頭用于標識請求體的數據格式。
——Produces=Accept?Consumes=Content-Type?
?
服務端:@Produces,@Consumes
?
[java] ?view plain?copy ?print?
@GET ??@Path (value="/{emailAddress:.+@.+\\.[a-z]+}" )??@Produces (value={"text/xml" ,?"application/json" })??public ?ContactInfo?getByEmailAddress(@PathParam (value="emailAddress" )???????String?emailAddress)?{?? ????...?? }????? ?? ?? @POST ??@Consumes (value={"text/xml" ,?"application/json" })??public ?void ?addContactInfo(ContactInfo?contactInfo)?{??????...?? }??
?
?
客戶端AngularJS:Accept,Content-Type
例如AngularJS發送請求:
[javascript] ?view plain?copy ?print?
$http({method:?'GET' ,?url:?'/someUrl' }).?? success(function (data,?status,?headers,?config)?{?? //?this?callback?will?be?called?asynchronously ??//?when?the?response?is?available ??}).?? error(function (data,?status,?headers,?config)?{?? //?called?asynchronously?if?an?error?occurs ??//?or?server?returns?response?with?an?error?status. ??});??
?
?
?
AngularJS Setting HTTP Headers
?
默認的HTTP頭:
The?$http? service will automatically add certain HTTP headers to all requests. These defaultscan be fully configured by accessing the$httpProvider.defaults.headers ?configurationobject, which currently contains this default configuration:
$httpProvider.defaults.headers.common?(headers that are common for all requests): Accept: application/json, text/plain, * / * X-Requested-With: XMLHttpRequest $httpProvider.defaults.headers.post: (header defaults for POST requests) Content-Type: application/json $httpProvider.defaults.headers.put?(header defaults for PUT requests) Content-Type: application/json
如何修改HTTP頭:
To add or overwrite these defaults, simply add or remove a property from these configuration objects. To add headers for an HTTP method other than POST or PUT, simply add a new objectwith the lowercased HTTP method name as the key, e.g.$httpProvider.defaults.headers.get['My-Header']='value'.
Additionally, the defaults can be set at runtime via the?$http.defaults? object in the same fashion.
?
e.g. 修改$httpProvider.defaults.headers (prevent angular.js $http object from sending X-Requested-With header)
?
[javascript] ?view plain?copy ?print?
angular.module('myModule' ,?[])?? ????.config(['$httpProvider' ,?function ($httpProvider)?{?? ????????delete ?$httpProvider.defaults.headers.common["X-Requested-With" ]?? ????}])??
?
?
e.g. 使用$http.defaults
[javascript] ?view plain?copy ?print?
$http({?? ????method:?'POST' ,?? ????url:?url,?? ????headers:?{'Content-Type' :?'application/x-www-form-urlencoded' },?//headers參數可以設置Accept、Content-Type???? ?? }).success(function ?()?{});??
?
?
?
?
?
Requests與Responses的序列化和反序列化
?
服務端:實現MessageBodyWriter、MessageBodyReader
JAX-RS 依賴于 MessageBodyReader 和 MessageBodyWriter 的實現來自動完成返回值到響應體的序列化以及請求體到實體參數的反序列化工作,其中,XML 格式的請求/響應數據與 Java 對象的自動綁定依賴于 JAXB 的實現。 用戶可以使用 Provider 標注來注冊使用自定義的 MessageBodyProvider,如 清單 6 所示,GsonProvider 類使用了 Google Gson 作為 JSON 格式的 MessageBodyProvider 的實現。
?
[java] ?view plain?copy ?print?
@Provider ???@Produces ("application/json" )???@Consumes ("application/json" )???public ?class ?GsonProvider?implements ?MessageBodyWriter<Object>,???????MessageBodyReader<Object>?{??? ?? ????private ?final ?Gson?gson;??? ?? ????public ?GsonProvider()?{??? ????????gson?=?new ?GsonBuilder().excludeFieldsWithoutExposeAnnotation().setDateFormat(??? ????????????????"yyyy-MM-dd" ).create();??? ????}??? ?? ????public ?boolean ?isReadable(Class<?>?type,?Type?genericType,?Annotation[]?annotations,??? ????????????MediaType?mediaType)?{??? ????????return ?true ;??? ????}??? ?? ????//MessageBodyReader.readFrom() ?? ????public ?Object?readFrom(Class<Object>?type,?Type?genericType,??? ????????????Annotation[]?annotations,?MediaType?mediaType,??? ????????????MultivaluedMap<String,?String>?httpHeaders,?InputStream?entityStream)??? ????????????throws ?IOException,?WebApplicationException?{??? ????????return ?gson.fromJson(new ?InputStreamReader(entityStream,?"UTF-8" ),?type);??? ????}??? ?? ????public ?boolean ?isWriteable(Class<?>?type,?Type?genericType,?Annotation[]?annotations,??? ????????????MediaType?mediaType)?{??? ????????return ?true ;??? ????}??? ?? ????public ?long ?getSize(Object?obj,?Class<?>?type,?Type?genericType,??? ????????????Annotation[]?annotations,?MediaType?mediaType)?{??? ????????return ?-1 ;??? ????}??? ?? ????//MessageBodyWriter.writeTo() ?? ????public ?void ?writeTo(Object?obj,?Class<?>?type,?Type?genericType,??? ????????????Annotation[]?annotations,?MediaType?mediaType,??? ????????????MultivaluedMap<String,?Object>?httpHeaders,?OutputStream?entityStream)??? ????????????throws ?IOException,?WebApplicationException?{??? ????????entityStream.write(gson.toJson(obj,?type).getBytes("UTF-8" ));??? ????}??? ?? }???
?
配置完成后,如何讓它生效呢?——可以通過擴展 javax.ws.rs.core.Application 類實現
?
[java] ?view plain?copy ?print?
public ?class ?ContactInfoApplicaiton?extends ?Application?{??????public ?Set<Class<?>>?getClasses()?{?? ????????Set<Class<?>>?classes?=?new ?HashSetSet<Class<?>>();?? ????????classes.add(ContactsResource.class );?? ????????classes.add(ContactInfoWriter.class );?? ????????classes.add(ContactInfoReader.class );?? ????}?? ?????? ????public ?SetSet<Object<?>>?getSingletons()?{?? ????????//?nothing?to?do,?no?singletons ?? ????}????? }??
然后配置web.xml
?
?
[html] ?view plain?copy ?print?
< web-app ?id ="WebApp_ID" ?version ="2.5" > ??????< servlet > ?? ????????< servlet-name > ContactInfoServlet</ servlet-name > ?? ????????< servlet-class > com.sample.RESTSystemServlet</ servlet-class > ?? ????????< init-param > ?? ????????????< param-name > javax.ws.rs.Application</ param-name > ?? ????????????< param-value > ?? ????????????????com.ibm.jaxrs.sample.organization.ContactInfoApplication?? ????????????</ param-value > ?? ????????</ init-param > ?? ????</ servlet > ?? ????< servlet-mapping > ?? ????????< servlet-name > ContactInfoServlet</ servlet-name > ?? ????????< url-pattern > /*</ url-pattern > ?? ????</ servlet-mapping > ?? </ web-app > ??
?
?
?
?
?
?
?
AngularJS Transforming Requests and Responses
Both requests and responses can be transformed using transform functions. By default, Angularapplies these transformations:
Request transformations:
If the?data?property of the request configuration object contains an object,serialize it intoJSON format.
Response transformations:
If XSRF prefix is detected, strip it (see Security Considerations section below). If JSON response is detected,?deserialize it using a JSON parser .
To globally augment or override the default transforms, modify the?$httpProvider.defaults.transformRequest ?and$httpProvider.defaults.transformResponse ?properties. These properties are by default an array of transform functions, which allows you topush?or?unshift?a new transformation function into the transformation chain. You can also decide to completely override any default transformations by assigning yourtransformation functions to these properties directly without the array wrapper.
?
Similarly, to?locally override the request/response transforms , augment thetransformRequest and/ortransformResponse properties of the configuration object passed into$http .
?
e.g.? local配置: 在發送請求時設置transformRequest:
?
?
?
[javascript] ?view plain?copy ?print?
$http({?? ????method:?'POST' ,?? ????url:?url,?? ????headers:?{'Content-Type' :?'application/x-www-form-urlencoded' },??? ????transformRequest:?function (obj)?{?? ????????var ?str?=?[];?? ????????for (var ?p?in ?obj)?? ????????str.push(encodeURIComponent(p)?+?"=" ?+?encodeURIComponent(obj[p]));?? ????????return ?str.join("&" );?? ????},?? ????data:?xsrf?? }).success(function ?()?{});??
?
?
e.g.?Global配置 : $httpProvider.defaults.transformRequest
?
[javascript] ?view plain?copy ?print?
var ?module?=?angular.module('myApp' );???? module.config(function ?($httpProvider)?{?? ????$httpProvider.defaults.transformRequest?=?function (data){?? ????????if ?(data?===?undefined)?{?? ????????????return ?data;?? ????????}?? ????????return ?$.param(data);?? ????}?? });??
?
?
?
RESTEasy
RESTEasy是JBoss提供的JAX-RS 的具體實現。、
web.xml:
?
[html] ?view plain?copy ?print?
<? xml ?version ="1.0" ?encoding ="UTF-8" ?> ??< web-app ?version ="2.5" ?xmlns ="http://java.sun.com/xml/ns/javaee" ?> ??????< context-param > ?? ????????< param-name > resteasy.providers</ param-name > ?? ????????< param-value > ?? ????????????org.jboss.resteasy.plugins.providers.DefaultTextPlain,?? ????????????org.jboss.resteasy.plugins.providers.ByteArrayProvider,?? ????????????org.jboss.resteasy.plugins.providers.InputStreamProvider,?? ????????????org.jboss.resteasy.plugins.providers.ByteArrayProvider,?? ????????????org.jboss.resteasy.plugins.providers.StringTextStar,?? ????????????org.jboss.resteasy.plugins.providers.FormUrlEncodedProvider?? ????????</ param-value > ?? ????</ context-param > ?? ????< context-param > ?? ????????< param-name > resteasy.scan</ param-name > ?? ????????< param-value > true</ param-value > ?? ????</ context-param > ?? ????< context-param > ?? ????????< param-name > resteasy.servlet.mapping.prefix</ param-name > ?? ????????< param-value > /web</ param-value > ?? ????</ context-param > ?? ?? ?? ????< listener > ?? ????????< listener-class > org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</ listener-class > ?? ????</ listener > ?? ????< servlet > ?? ????????< servlet-name > Resteasy</ servlet-name > ?? ????????< servlet-class > org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</ servlet-class > ?? ????</ servlet > ?? ????< servlet-mapping > ?? ????????< servlet-name > Resteasy</ servlet-name > ?? ????????< url-pattern > /web/*</ url-pattern > ?? ????</ servlet-mapping > ?? ?? ?? </ web-app > ??
?
?
?
?
?
?
?
?
參考資料
http://liugang594.iteye.com/category/218423
http://www.infoq.com/cn/articles/rest-introduction
http://www.ibm.com/developerworks/cn/web/wa-jaxrs/ 用 Java 技術創建 RESTful Web 服務
http://www.ibm.com/developerworks/cn/java/j-lo-jaxrs/ 使用 JAX-RS 簡化 REST 應用開發
http://www.ibm.com/developerworks/cn/webservices/ws-restful/ 基于 REST 的 Web 服務:基礎
總結
以上是生活随笔 為你收集整理的【REST】REST和JAX-RS相关知识介绍 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。