RestEasy简介

RestEasy技术说明

简介

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服务[1]. 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

维基百科REST词条的解释

深入浅出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段中。例如:

  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中的参数值,如:

页面代码:

<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请求的处理类或者处理方法

jaxb介绍

对@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;

}

}

本文转自:http://my.oschina.net/bigyuan/blog/57409

RestEasy简介的更多相关文章

  1. RESTEASY ,从学会使用到了解原理。

    转载本文需注明出处:EAII企业架构创新研究院,违者必究.如需加入微信群参与微课堂.架构设计与讨论直播请直接回复公众号:“EAII企业架构创新研究院”.(微信号:eaworld) 1,背景知识; 1. ...

  2. java rest jax-rs 漫谈

    rest是什么 REST是英文RepresentationalState Transfer 的缩写,有中文翻译为“具象状态传输”.REST 这个术语是由 RoyFielding 在他的博士论文< ...

  3. zt 比较各JAX-RS实现:CXF,Jersey,RESTEasy,Restlet

    http://news.misuland.com/20080926/1222396399411.html JavaSE/EE执行委员批准了JSR 311 JAX-RS作为支持RESTful web服务 ...

  4. ASP.NET Core 1.1 简介

    ASP.NET Core 1.1 于2016年11月16日发布.这个版本包括许多伟大的新功能以及许多错误修复和一般的增强.这个版本包含了多个新的中间件组件.针对Windows的WebListener服 ...

  5. MVVM模式和在WPF中的实现(一)MVVM模式简介

    MVVM模式解析和在WPF中的实现(一) MVVM模式简介 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在 ...

  6. Cassandra简介

    在前面的一篇文章<图形数据库Neo4J简介>中,我们介绍了一种非常流行的图形数据库Neo4J的使用方法.而在本文中,我们将对另外一种类型的NoSQL数据库——Cassandra进行简单地介 ...

  7. REST简介

    一说到REST,我想大家的第一反应就是“啊,就是那种前后台通信方式.”但是在要求详细讲述它所提出的各个约束,以及如何开始搭建REST服务时,却很少有人能够清晰地说出它到底是什么,需要遵守什么样的准则. ...

  8. Microservice架构模式简介

    在2014年,Sam Newman,Martin Fowler在ThoughtWorks的一位同事,出版了一本新书<Building Microservices>.该书描述了如何按照Mic ...

  9. const,static,extern 简介

    const,static,extern 简介 一.const与宏的区别: const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量. 执行时刻:宏是预编 ...

随机推荐

  1. Android -- 与WEB交互在同一个会话Session中通信

    Session与Cookie Cookie和Session都为了用来保存状态信息,都是保存客户端状态的机制,它们都是为了解决HTTP无状态的问题而所做的努力. Session可以用Cookie来实现, ...

  2. 我给女朋友讲编程html系列(3) --html中的超链接标签-a标签 和 框架frame与框架集frameset

    我们浏览网页的时候,当单击某段文字或图片时,就会打开一个新的网页,这里面就使用了超链接. 就比如下图是一个导航类网页,当你单击某个链接就会打开新的网页. 比如,我拿我的qq空间“金河访谈”举例,新建一 ...

  3. Careercup - Google面试题 - 5692127791022080

    2014-05-08 22:09 题目链接 原题: Implement a class to create timer object in OOP 题目:用OOP思想设计一个计时器类. 解法:我根据自 ...

  4. 如何实现SAP的RFC函数调用(原创)

    连接sap系统需要通过sap javaconnect来连接,对于sapjco.jar系列文件有32位与64位之分[32位用的JAR版本是 2.1.10 (2011-05-10) ,64位用的JAR版本 ...

  5. myBatis自动生成相关代码文件配置(Maven)

    pom.xml文件添加配置 <build> <finalName>generator</finalName> <plugins> <!-- mav ...

  6. Netsharp快速入门(之19) 平台常用功能(插件操作)

    作者:秋时 暗影  转载须说明出处 6.2     插件操作 6.2.1  停用/启用 1.在平台工具-插件管理,右击对应的插件可以使用启用和停用功能.插件停用后会把所有相关的页签.程序集.服务全部停 ...

  7. hadoop学习日志

    Hadoop思想之源:Google 面对的数据和计算难题 ——大量的网页怎么存储 ——搜索算法 带给我们的关键技术和思想 ——GFS ——Map-Reduce ——Bigtable Hadoop创始人 ...

  8. C# Winform常见的Editor及其它经验

    1.新建一个自定义Editor,继承自.NET自带的Editor,override某些方法,再附加到属性中: public class MyCollectionEditor : CollectionE ...

  9. HDOJ 2152 Fruit(母函数)

    Fruit Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  10. MYSQL注入天书之数据库增删改介绍

    Background-4 增删改函数介绍 在对数据进行处理上,我们经常用到的是增删查改.接下来我们讲解一下mysql 的增删改.查就是我们上述总用到的select,这里就介绍了. 增加一行数据.Ins ...