RestEasy技術說明前端
簡介java
RESTEasyweb
RESTEasy是JBoss的一個開源項目,提供各類框架幫助你構建RESTful Web Services和RESTful Java應用程序。它是JAX-RS規範的一個完整實現並經過JCP認證。做爲一個JBOSS的項目,它固然能和JBOSS應用服務器很好地集成在一塊兒。可是,它也能在任何運行JDK5或以上版本的Servlet容器中運行。RESTEasy還提供一個RESTEasy JAX-RS客戶端調用框架。可以很方便與EJB、Seam、Guice、Spring和Spring MVC集成使用。支持在客戶端與服務器端自動實現GZIP解壓縮。正則表達式
RESTEasy 項目是 JAX-RS 的一個實現,集成的一些亮點:spring
名詞解釋:express
JAX-RS: Java API for RESTful Web Services是一個Java編程語言的應用程序接口,支持按照 表象化狀態轉變 (REST)架構風格建立Web服務Web服務[1]. JAX-RS使用了Java SE 5引入的Java 標註來簡化Web服務客戶端和服務端的開發和部署。編程
規範內容json
JAX-RS提供了一些標註將一個資源類,一個POJOJava類,封裝爲Web資源。標註包括:bootstrap
@Path,標註資源類或方法的相對路徑api
@GET,@PUT,@POST,@DELETE,標註方法是用的HTTP請求的類型
@Produces,標註返回的MIME媒體類型
@Consumes,標註可接受請求的MIME媒體類型
@PathParam,@QueryParam,@HeaderParam,@CookieParam,@MatrixParam,@FormParam,分別標註方法的參數來自於HTTP請求的不一樣位置,例如@PathParam來自於URL的路徑,@QueryParam來自於URL的查詢參數,@HeaderParam來自於HTTP請求的頭信息,@CookieParam來自於HTTP請求的Cookie。
REST
詳細介紹
如何配置
單獨配置
在 WEB-INF/web.xml 中配置以下:
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.restfully.shop.services.ShoppingApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
配置開關
Resteasy採用 <context-param>元素來配置,參數以下:
參數名 |
默認值 |
描述 |
resteasy.servlet.mapping.prefix |
no default |
If the url-pattern for the Resteasy servlet-mapping is not /* |
resteasy.scan |
FALSE |
Automatically scan WEB-INF/lib jars and WEB-INF/classes directory for both @Provider and JAX-RS resource classes (@Path, @GET, @POST etc..) and register them |
resteasy.scan.providers |
FALSE |
Scan for @Provider classes and register them |
resteasy.scan.resources |
FALSE |
Scan for JAX-RS resource classes |
resteasy.providers |
no default |
A comma delimited list of fully qualified @Provider class names you want to register
|
resteasy.use.builtin.providers
|
TRUE |
Whether or not to register default, built-in @Provider classes. (Only available in 1.0-beta-5 and later)
|
resteasy.resources
|
no default
|
A comma delimited list of fully qualified JAX-RS resource class names you want to register
|
resteasy.jndi.resources
|
no default
|
A comma delimited list of JNDI names which reference objects you want to register as JAX-RS resources
|
javax.ws.rs.Application
|
no default
|
Fully qualified name of Application class to bootstrap in a spec portable way
|
resteasy.media.type.mappings
|
no default
|
Replaces the need for an Accept header by mapping file name extensions (like .xml or .txt) to a media type. Used when the client is unable to use a Accept header to choose a representation (i.e. a browser). See JAX-RS Content Negotiation chapter for more details.
|
resteasy.language.mappings
|
no default
|
Replaces the need for an Accept-Language header by mapping file name extensions (like .en or .fr) to a language. Used when the client is unable to use a Accept-Language header to choose a language (i.e. a browser). See JAX-RS Content Negotiation chapter for more details
|
使用ServletContextListener來配置
<web-app>
<listener>
<listener-class>
org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
</listener-class>
</listener>
<!-- ** INSERT YOUR LISTENERS HERE!!!! -->
<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>/resteasy/*</url-pattern>
</servlet-mapping>
</web-app>
使用ServletFilter來配置
<web-app>
<filter>
<filter-name>Resteasy</filter-name>
<filter-class>
org.jboss.resteasy.plugins.server.servlet.FilterDispatcher
</filter-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.restfully.shop.services.ShoppingApplication</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Resteasy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
與Spring集成
<web-app>
<display-name>Archetype Created Web Application</display-name>
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<listener>
<listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</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>/*</url-pattern>
</servlet-mapping>
</web-app>
使用@Path,@Get,@Post等標註
示例:
@Path("/library")
public class Library {
@GET
@Path("/books")
public String getBooks() {...}
@GET
@Path("/book/{isbn}")
public String getBook(@PathParam("isbn") String id) {
// search my database and get a string representation and return it
}
@PUT
@Path("/book/{isbn}")
public void addBook(@PathParam("isbn") String id, @QueryParam("name") String name) {...}
@DELETE
@Path("/book/{id}")
public void removeBook(@PathParam("id") String id {...}
}
如下操做都是針對library這個資源的
GET http://myhost.com/services/library/books 意思爲得到全部的books調用的方法爲getBooks
GET http://myhost.com/services/library/book/333 意思爲得到ID爲333的book調用的方法爲getBook
PUT http://myhost.com/services/library/book/333 新增一個ID爲333的book調用的方法爲addBook
DELETE http://myhost.com/services/library/book/333 刪除一個ID爲333的book調用的方法爲removeBook
@Path這個標註能夠在類上也能夠在方法上,若是類和方法上都有的話,那麼方法上的路徑是級聯的如上面例子的/library/book/
@Path和使用正則表達式匹配路徑
@Path不只僅接收簡單的路徑表達式,也可使用正則表達式:
@Path("/resources)
public class MyResource {
@GET
@Path("{var:.*}/stuff")
public String get() {...}
}
以下操做就能得到該資源
GET /resources/stuff
GET /resources/foo/stuff
GET /resources/on/and/on/stuff
表達式的格式爲:
"{" variable-name [ ":" regular-expression ] "}"
正則表達式部分是可選的,當未提供時,則會匹配一個默認的表達式"([]*)"
@Path("/resources/{var}/stuff")
會匹配以下路徑
GET /resources/foo/stuff
GET /resources/bar/stuff
下面的則不會匹配
GET /resources/a/bunch/of/stuff
@PathParam
@PathParam 參數標註是用來獲取映射路徑上的變量值供方法使用
@Path("/library")
public class Library {
@GET
@Path("/book/{isbn}")
public String getBook(@PathParam("isbn") String id) {
// search my database and get a string representation and return it
}
}
GET http://myhost.com/services/library/book/333 就會調用到getBook方法,id的值就會被自動映射爲333
@Path中的變量名要和@PathParam中的變量名一致,參數類型能夠是任意類型,一個String,一個Java對象,注意若是是Java對象時,這個對象要擁有一個帶String類型參數的構造器或者一個返回值爲String的靜態valueOf方法,例如:
構造器方式:
@GET
@Path("/book/{isbn}")
public String getBook(@PathParam("isbn") ISBN id) {...}
public class ISBN {
public ISBN(String str) {...}
}
valueOf方式:
public class ISBN {
public static ISBN valueOf(String isbn) {...}
}
這樣作的目的是底層會把請求的參數經過String的方式傳遞的前端,構造對象的方式由業務層來本身構建
@PathParam高級使用
容許指定一個或多個路徑參數在一個URI段中。例如:
"/aaa111bbb"會匹配,param=111
"/bill-02115" 會匹配,name=bill,zip=02115
"/foobill-02115bar " 會匹配,name=bill,zip=02115
正則表達式方式例子:
@GET
@Path("/aaa{param:b+}/{many:.*}/stuff")
public String getIt(@PathParam("param") String bs, @PathParam("many") String many) {...}
GET /aaabb/some/stuff bs=bb,many=some
GET /aaab/a/lot/of/stuff bs= b,many=a/lot/of
@QueryParam
@QueryParam這個標註是給經過?的方式傳參得到參數值的,如:
GET /books?num=5&index=1
@GET
public String getBooks(@QueryParam("num") int num,@QueryParam("index") int index) {
...
}
這裏同上面的@PathParam,參數類型能夠是任意類型
@HeaderParam
這個標註時用來得到保存在HttpRequest頭裏面的參數信息的,如:
@PUT
public void put(@HeaderParam("Content-Type") MediaType contentType, ...)
這裏同上面的@PathParam,參數類型能夠是任意類型
@CookieParam
用來獲取保存在Cookie裏面的參數,如:
@GET
public String getBooks(@CookieParam("sessionid") int id) {
...
}
@FormParam
用來獲取Form中的參數值,如:
頁面代碼:
<form method="POST" action="/resources/service">
First name:
<input type="text" name="firstname">
<br>
Middle name:
<input type="text" name="middlename">
Last name:
<input type="text" name="lastname">
</form>
後臺代碼
@Path("/")
public class NameRegistry {
@Path("/resources/service")
@POST
public void addName(@FormParam("firstname") String first, @FormParam("lastname") String last) {...}
標註了@FormParam,會把表達裏面的值自動映射到方法的參數上去.
若是要取得Form裏面的全部屬性,能夠經過在方法上增長一個MultivaluedMap<String, String> form這樣的對象來得到,以下:
@Path("/resources/service")
@POST
public void addName(@FormParam("firstname") String first, @FormParam("lastname") String last,MultivaluedMap<String, String> form) {...}
@Form
上面已經說的幾種標註都是一個屬性對應一個參數的,那麼若是屬性多了,定義的方法就會變得很差閱讀,此時最好有個東西可以把上面的幾種自動標註自動封裝成一個對象,@Form這個標註就是用來實現這個功能的,如:
public class MyForm {
@FormParam("stuff")
private int stuff;
@HeaderParam("myHeader")
private String header;
@PathParam("foo")
public void setFoo(String foo) {...}
}
@POST
@Path("/myservice")
public void post(@Form MyForm form) {...}
@DefaultValue
在以上標註使用的時候,有些參數值在沒有值的狀況下若是須要有默認值,則使用這個標註,如:
@GET
public String getBooks(@QueryParam("num") @DefaultValue("10") int num) {...}
知足JAX-RS規範的 Resource Locators和子資源
資源處理類定義的某個方法能夠處理某個請求的一部分,剩餘部分由子資源處理類來處理,如:
@Path("/")
public class ShoppingStore {
@Path("/customers/{id}")
public Customer getCustomer(@PathParam("id") int id) {
Customer cust = ...; // Find a customer object
return cust;
}
}
public class Customer {
@GET
public String get() {...}
@Path("/address")
public String getAddress() {...}
}
當咱們發起GET /customer/123這樣的請求的時候,程序會先調用 ShoppingStore的 getCustomer這個方法,而後接着調用 Customer裏面的 get方法
當咱們發起GET /customer/123/address這樣的請求的時候,程序會先調用 ShoppingStore的 getCustomer這個方法,而後接着調用 Customer裏面的 getAddress 方法
JAX-RS Content Negotiation
@Consumes
咱們從頁面提交數據到後臺的時候,數據的類型能夠是text的,xml的,json的,可是咱們在請求資源的時候想要請求到同一個資源路徑上面去,此時怎麼來區分處理呢?使用@Consumes標註,下面的例子將說明:
@Consumes("text/*")
@Path("/library")
public class Library {
@POST
public String stringBook(String book) {...}
@Consumes("text/xml")
@POST
public String jaxbBook(Book book) {...}
當客戶端發起請求的時候,系統會先找到全部匹配路徑的方法,而後根據content-type找到具體的處理方法,好比:
POST /library
content-type: text/plain
就會執行上面的 stringBook這個方法,由於這個方法上面沒有標註@ Consumes,程序找了全部的方法沒有找到標註 @ Consumes(「text/plain」)這個類型的,因此就執行這個方法了.若是請求的content-type=xml,好比:
POST /library
content-type: text/xml
此時就會執行 jaxbBook這個方法
@Produces
當服務器端實行完成相關的邏輯須要返回對象的時候,程序會根據@Produces返回相應的對象類型
@Produces("text/*")
@Path("/library")
public class Library {
@GET
@Produces("application/json")
public String getJSON() {...}
@GET
public String get() {...}
若是客戶端發起以下請求
GET /library
那麼則會調用到get方法而且返回的格式是json類型的
這些標註能不能寫多個呢?答案是能夠的,可是系統只認第一個
Content Marshalling/Providers
這個東西是用來根據消息題格式來組裝對象或者根據對象生成相應的消息體的,默認的對應關係以下
Media Types |
Java Type
|
application/*+xml, text/*+xml, application/*+json, application/*+fastinfoset, application/atom+*
|
JaxB annotated classes
|
application/*+xml, text/*+xml
|
org.w3c.dom.Document
|
*/*
|
java.lang.String javax.activation.DataSource java.io.File byte[]
|
application/x-www-form-urlencoded
|
javax.ws.rs.core.MultivaluedMap
|
text/plain
|
primtives, java.lang.String, or any type that has a String constructor, or static valueOf(String) method for input, toString() for output
|
生成 JavaScript API
RESTEasy可以生成JavaScript API使用AJAX來執行 JAX-RS操做,好比:
@Path("orders")
public interface Orders {
@Path("{id}")
@GET
public String getOrder(@PathParam("id") String id){
return "Hello "+id;
}
}
以上代碼能夠在js裏面經過var order = Orders.getOrder({id: 23});
這種方式來調用,很酷吧,這裏應該是跟Google的一項技術相似的Java代碼能夠經過js方式來調用
經過JavaApi調用資源
上面介紹了生成jsapi的方式調用,另外若是別的應用須要經過Java的方式調用資源該怎麼處理呢,下面的例子將說明:
ClientRequest request = new ClientRequest("http://localhost:8080/rest/services/demoservice/child/22222");
// request.header("custom-header", "value");
// We're posting XML and a JAXB object
// request.body("application/xml", someJaxb);
// we're expecting a String back
ClientResponse<Object> response = request.get(Object.class);
if (response.getStatus() == 200) // OK!
{
Object str = response.getEntity();
System.out.println(str);
}
把資源當作一個標準servlet接收處理方法
咱們能夠把一個資源url當作一個接收servlet請求的處理類或者處理方法
對@PathParam, @QueryParam, @MatrixParam, @FormParam, and @HeaderParam參數的處理
@PathParam, @QueryParam, @MatrixParam, @FormParam, and @HeaderParam標註傳遞的參數類型是String型的,對於這些參數咱們的方法可能但願接收的參數是通過轉換後的對象類型的參數,好比以下的方法:
void put(@QueryParam("pojo")POJO q, @PathParam("pojo")POJO pp,@MatrixParam("pojo")POJO mp,@HeaderParam("pojo")POJO hp);
這裏的Put方法須要的是一個Pojo類型的參數,可是@PathParam, @QueryParam, @MatrixParam, @FormParam, and @HeaderParam傳遞的都是String類型的,怎麼是怎麼轉換爲對象的呢?
可使用StringConverter或者StringParamUnmarshaller
StringConverter
package org.jboss.resteasy.spi;
public interface StringConverter<T>
{
T fromString(String str);
String toString(T value);
}
實現類以下:
@Provider
public static class POJOConverter implements StringConverter<POJO>
{
public POJO fromString(String str)
{
System.out.println("FROM STRNG: " + str);
POJO pojo = new POJO();
pojo.setName(str);
return pojo;
}
public String toString(POJO value)
{
return value.getName();
}
}
FromString就是你本身須要實現的如何把接收的String參數轉換爲Pojo類
toString方法是用來把Pojo對象轉換爲String
如今已經可以把String參數轉換爲對象了,咱們更進一步的想使用一些自定義的標註來作一些邏輯,好比說日期的格式化,就要使用下面的StringParamUnmarshaller
StringParamUnmarshaller
package org.jboss.resteasy.spi;
public interface StringParameterUnmarshaller<T>
{
void setAnnotations(Annotation[] annotations);
T fromString(String str);
}
實現類
public class DateFormatter implements StringParameterUnmarshaller<Date>
{
private SimpleDateFormat formatter;
public void setAnnotations(Annotation[] annotations)
{
DateFormat format = FindAnnotation.findAnnotation(annotations, DateFormat.class);
formatter = new SimpleDateFormat(format.value());
}
public Date fromString(String str)
{
try
{
return formatter.parse(str);
}
catch (ParseException e)
{
throw new RuntimeException(e);
}
}
}
使用方式:
@Path("/datetest")
public class Service
{
@GET
@Produces("text/plain")
@Path("/{date}")
public String get(@PathParam("date") @DateFormat("MM-dd-yyyy") Date date)
{
System.out.println(date);
Calendar c = Calendar.getInstance();
c.setTime(date);
Assert.assertEquals(3, c.get(Calendar.MONTH));
Assert.assertEquals(23, c.get(Calendar.DAY_OF_MONTH));
Assert.assertEquals(1977, c.get(Calendar.YEAR));
return date.toString();
}
}
在實際使用中,咱們有些參數值並非經過以上方式來傳遞的,好比說咱們要對session進行操做,那麼應該怎麼辦呢,resteasy並無直接提供使用自定義標註的方法,因此咱們可使用以上的 StringParamUnmarshaller來變通的實現
首先定義自定義標註
@Retention(RetentionPolicy.RUNTIME)
@StringParameterUnmarshallerBinder(SessionOperator.class)
public @interface Session {
public String value();
}
@StringParameterUnmarshallerBinder(SessionOperator.class)是用來指明這個自定義標註是哪一個具體的類來處理, SessionOperator這個類就是Session這個自定義標註的處理類
public class SessionOperator implements StringParameterUnmarshaller{
public void setAnnotations(Annotation[] annotations) {
}
public Object fromString(String str) {
return null;
}
}