RestEasy簡介

xz43發表於2015-05-11

簡介

RESTEasy

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 的一個實現,整合的一些亮點:

  • 不需要配置檔案,只要把JARs檔案放到類路徑裡面,新增 @Path 標註就可以了。
  •  完全的把 RESTEeasy 配置作為Seam 元件來看待。
  • HTTP 請求由Seam來提供,不需要一個額外的Servlet。
  • Resources 和providers可以作為 Seam components (JavaBean or EJB),具有全面的Seam injection,lifecycle, interception, 等功能支援。
  • 支援在客戶端與伺服器端自動實現GZIP解壓縮。

名詞解釋:

JAX-RS: Java API for RESTful Web Services是一個Java程式語言的應用程式介面,支援按照 表象化狀態轉變 (REST)架構風格建立Web服務Web服務. JAX-RS使用了Java SE 5引入的Java 標註來簡化Web服務客戶端和服務端的開發和部署。

規範內容

JAX-RS提供了一些標註將一個資源類,一個POJOJava類,封裝為Web資源。標註包括:

@Path,標註資源類或方法的相對路徑

@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/ 中配置如下:

    Archetype Created Web Application

    

        Resteasy

        

            org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher

        

        

            javax.ws.rs.Application

            com.restfully.shop.services.ShoppingApplication

        

    

    

        Resteasy

        /*

    

 

配置開關

Resteasy採用 元素來配置,引數如下:

 

引數名

預設值

描述

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來配置

  

      

         org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap

      

  

  <!-- ** INSERT YOUR LISTENERS HERE!!!! --&gt

  

      Resteasy

      

         org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher

      

  

  

      Resteasy

      /resteasy/*

  

 

使用ServletFilter來配置

    

        Resteasy

        

            org.jboss.resteasy.plugins.server.servlet.FilterDispatcher

        

        

            javax.ws.rs.Application

            com.restfully.shop.services.ShoppingApplication

        

    

    

        Resteasy

        /*

    

 

與Spring整合

   Archetype Created Web Application

  

      org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap

  

  

      org.jboss.resteasy.plugins.spring.SpringContextLoaderListener

  

  

      Resteasy

      org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher

  

  

      Resteasy

      /*

  

 

使用@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  意思為獲得所有的books呼叫的方法為getBooks

GET  意思為獲得ID為333的book呼叫的方法為getBook

PUT  新增一個ID為333的book呼叫的方法為addBook

DELETE  刪除一個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  就會呼叫到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段中。例如:

  1. @Path("/aaa{param}bbb")

"/aaa111bbb"會匹配,param=111

  1. @Path("/{name}-{zip}")

"/bill-02115" 會匹配,name=bill,zip=02115

  1. @Path("/foo{name}-{zip}bar")

"/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中的引數值,如:

頁面程式碼:

First name: 


Middle name: 

Last name: 

後臺程式碼

@Path("/")

public class NameRegistry {

   @Path("/resources/service")

   @POST

   public void addName(@FormParam("firstname") String first, @FormParam("lastname") String last) {...}

標註了@FormParam,會把表達裡面的值自動對映到方法的引數上去.

如果要取得Form裡面的所有屬性,可以透過在方法上增加一個MultivaluedMap form這樣的物件來獲得,如下:

@Path("/resources/service")

   @POST

   public void addName(@FormParam("firstname") String first, @FormParam("lastname") String last,MultivaluedMap 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("");

// 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 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 fromString(String str);

   String toString(T value);

}

實現類如下:

@Provider

      public static class POJOConverter implements StringConverter

      {

         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

{

   void setAnnotations(Annotation[] annotations);

   T fromString(String str);

}

實現類

public class DateFormatter implements StringParameterUnmarshaller

   {

      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;

}

}

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/9399028/viewspace-1649023/,如需轉載,請註明出處,否則將追究法律責任。