查找的API地址:http://docs.oracle.com/javaee/6/api/
REST 最大的贡献是带来了 HTTP 协议的复兴。为什么叫复兴呢?本来 HTTP 的功能挺丰富的,可惜长期以来只被用作传输数据,大好青年被埋没了。楼主记得刚开始学 Servlet 的时候,一向是把 doGet 和 doPost 两个方法一视同仁的,因为书上这么教,很多 Web 框架也这么搞,以至于弄了很久才搞清楚 GET 和 POST 是两种不同的请求。现在 REST 拍砖说道,HTTP 早就定义好了一堆操作,以前一直被混淆使用,现在应该重新赋予它们本来的意义了,而且如果充分发挥 HTTP 的功能,完全能够胜任分布式应用的开发(传说中的 SOA).
SOA 的理念在于将系统设计为一系列可重用的、解耦的、分布式的服务。这也不是新鲜玩意儿了,早期有 CORBA,稍晚有 SOAP 等等.REST 作为后起之秀,能够快速崛起,也必有其非同寻常的特色.
特色看这里:http://my.oschina.net/zhaoqian/blog/90321 中间的REST关键原则也就是REST的特色.
而JAX-RS就是SUN用于简化和标准化用 Java 开发 REST 风格的 Web 服务.
一共支持两种类型:单请求对象或单例对象。
单请求对象意味着每来一个请求,就创建一个服务对象,在请求结束时销毁。
单例对象则意味着只有一个服务对象处理所有的请求,从而可以在多个请求间维持服务状态。
JAX-RS 服务可通过继承 javax.ws.rs.core.Application 来定义,其中的 getClasses 方法返回单请求对象的类型,getSingletons 方法返回单例对象的类型。这两个方法是可选的。
在 Java EE 6 环境中,如果这两个方法都返回 null 或者空集合,那么应用程序中的所有 JAX-RS 都将被部署。
这时可以用CDI的@javax.inject.Singleton 或者EJB的@javax.ejb.Singleton 注解来指定单例对象。
如果电影服务的上下文根路径为 http://localhost/ms,而楼主希望将服务部署到 http://localhost/ms/rest 下面,只需要写一个类:
@ApplicationPath("rest") public class RestApplication extends Application { }
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <display-name></display-name> <servlet> <display-name>JAX-RS REST Servlet</display-name> <servlet-name>JAX-RS REST Servlet</servlet-name> <servlet-class> com.sun.jersey.spi.container.servlet.ServletContainer </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <!--这里下面就是Web.xml声明所有服务的相对基址,话说其实还是用@ApplicationPath好--> <servlet-mapping> <servlet-name>JAX-RS REST Servlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
完整的DEMO在此处:http://my.oschina.net/zhaoqian/blog/89227
上面已经有2个注解了,一个是@Path一个是@ApplicationPath.
下面是其他一些常用的注解.
至于其他的3个,用的少,也就无视了.不过还是写写好了又个印象.
@head用于请求获取由Request-URI所标识的资源的响应消息报头.
@OPTIONS 请求查询服务器的性能,或查询与资源相关的选项和需求.
@TRACE 请求服务器回送收到的请求信息,主要用语测试或诊断.。
这三个基本和CRUD没啥关系,用于开发测试的倒是,所以也很少用到.
还有2个比较重要的注解,和CRUD息息相关:
@Produces(MediaType.APPLICATION_JSON) 或 @Consumes(MediaType.APPLICATION_JSON)
@PathParam,@QueryParam,@HeaderParam,@CookieParam,@MatrixParam,@FormParam,分别标注方法的参数来自于HTTP请求的不同位置,例如@PathParam来自于URL的路径,@QueryParam来自于URL的查询参数,@HeaderParam来自于HTTP请求的头信息,@CookieParam来自于HTTP请求的Cookie.
MediaType JAX-RS 内置了很多格式,具体类型请查阅API,看本文头顶.
前面已经见过用 @Path("{id}") 和 @PathParam("id") 来匹配路径参数 id。这种匹配方式可以被嵌入到 @Path 注解中的任何地方,从而匹配多个参数,例如下面的代码用来查找 ID 在某一范围内的电影:
@GET @Path("{min}~{max}") @Produces(MediaType.APPLICATION_JSON) public List<Movie> findMovies(@PathParam("min") int min, @PathParam("max") int max) {
于是,GET /ms/rest/movie/5~16 就将返回 ID 为 5 到 16 的电影。此处的 min 和 max 已被自动转换为 int 类型。JAX-RS 支持多种类型的自动转换,详见 @PathParam的文档。
根据 HTTP 规范,参数可能会编码。默认情况下,JAX-RS 会自动解码。如果希望得到未解码的参数,只需在参数上再加个 @Encoded 注解。该注解适用于大多数 JAX-RS 注入类型,但并不常用。
模板参数虽然灵活,也可能会带来歧义。例如想用 {firstName}-{lastName} 匹配一个人的姓名,但恰好某人的名(lastName)含有“-”字符,像 O-live K 这种,匹配后就会变成姓 live-K,名 O。这种场景很难避免,一种简单的解决方法就是对参数值进行两次编码,然后在服务端代码解码一次,因为 JAX-RS 默认会进行一次解码,或者加上 @Encoded 注解,自己进行两次解码。
另外,在一个复杂系统中,多个 @Path 可能会造成路径混淆,例如 {a}-{b} 和 {a}-z 都能匹配路径 a-z。虽然 JAX-RS 定义了一些规则来指定匹配的优先级,但这些规则本身就比较复杂,并且也不能完全消除混淆。楼主认为,设计一个 REST 系统的核心就是对 URI 的设计,应当小心处理 URI 的结构,合理分类,尽量保证匹配的唯一性,而不要过度使用晦涩的优先级规则。楼主将在下一篇文章介绍优先级规则。
查询参数很常见,就是在 URI 的末尾跟上一个问号和一系列由“&”分隔的键值对,例如查询 ID 为 5 到 16 的电影也可以设计为 /ms/rest/movie?min=5&max=16。JAX-RS 提供了 QueryParam 来注入查询参数:
@GET @Produces(MediaType.APPLICATION_JSON) public List<Movie> findMovies(@DefaultValue("0") @QueryParam("min") int min, @DefaultValue("0") @QueryParam("max") int max) {
查询参数是可选的。如果 URI 没有设定某个查询参数,JAX-RS 就会根据情况为其生成 0、空字符串之类的默认值。如果要手动设定默认值,需要像上面的代码一样用@DefaultValue 注解来指定。另外还可以加上 Encoded 注解来得到编码的原始参数。
有的查询参数是一对多的键值对,例如 /xyz?a=def&a=pqr,这种情况只需将注入的参数类型改为 List 即可。
其他用到补充...