3.1. Root Resource Classes 根资源类

Root Resource Classes 是带有 @PATH 注解的,包含至少一个 @PATH 注解的方法或者方法带有 @GET@PUT@POST@DELETE 资源方法指示器的 POJO。资源方法是带有资源方法指示器(resource method designator)注解的方法。这一节就是展示如何使用 Java 对象内的注解创建一个 Jersey 的 RESTful 服务。

下面这段代码就是一个带有 JAX-RS 注解的简单示例,可以从这里下载。

Example 3.1. 简单hello world根资源类例子

  1. package org.glassfish.jersey.examples.helloworld;
  2. import javax.ws.rs.GET;
  3. import javax.ws.rs.Path;
  4. import javax.ws.rs.Produces;
  5. @Path("helloworld")
  6. public class HelloWorldResource {
  7. public static final String CLICHED_MESSAGE = "Hello World!";
  8. @GET
  9. @Produces("text/plain")
  10. public String getHello() {
  11. return CLICHED_MESSAGE;
  12. }
  13. }

下面看下 JAX-RS 里面的几个注解

3.1.1. @Path

@PATH 是一个URI的相对路径,在上面的例子中,设置的是本地的 URI 的 /helloworld。这事一个非常简单的关于 @PATH的例子,更有用的是你可以嵌入变量到 URIs 里面

URI 的路径模版是由 URIs 和嵌入 URI 语法的变量组成。变量在运行时将会被匹配到的 URI 的那部分多代替。例如下面的 @Path 注解

  1. @Path("/users/{username}")

按照这种类型的例子,一个用户会方便的填写他的名字,那么 Jersey 服务器也会按照这个 UIR 路径模板响应到这个请求。例如:用户输入了名字“Galileo”,那么服务器就会响应 http://example.com/users/Galileo

为了接收到用户名变量,@PathParam 用在接收请求的方法的参数上,例如:

Example 3.2. 指定的URI路径参数

  1. @Path("/users/{username}")
  2. public class UserResource {
  3. @GET
  4. @Produces("text/xml")
  5. public String getUser(@PathParam("username") String userName) {
  6. ...
  7. }
  8. }

它规定匹配正则表达式式要精确到大小写的,如果填写的话会覆盖默认的表达式 [^/]+? ,例如

  1. @Path("users/{username: [a-zA-Z][a-zA-Z_0-9]*}")

这个正则表达式匹配由大小写字符、横杠和数字组成的字符串,如果正则校验不通过,则返回404(没有找到资源)。

一个 @Path的内容是否以”/“开头都没有区别,同样是否以”/“结尾也没有什么区别

3.1.2. @GET, @PUT, @POST, @DELETE, … (HTTP 方法)

@GET, @PUT, @POST, @DELETE, @HEAD 是JAX-RS 定义的注解,它非常类似与 HTTP 的方法名。在上面的例子中,这些注解是通过HTTP的 GET 方法实现的。资源的响应就是HTTP的响应。

下面这个例子是存储服务的一个片段,是使用 PUT 方法处理创建或者修改存储容器:

Example 3.3. PUT 方法

  1. @PUT
  2. public Response putContainer() {
  3. System.out.println("PUT CONTAINER " + container);
  4. URI uri = uriInfo.getAbsolutePath();
  5. Container c = new Container(container, uri.toString());
  6. Response r;
  7. if (!MemoryStore.MS.hasContainer(c)) {
  8. r = Response.created(uri).build();
  9. } else {
  10. r = Response.noContent().build();
  11. }
  12. MemoryStore.MS.createContainer(c);
  13. return r;
  14. }

如果没有明确的定义的话,JAX-RS 运行的时候默认支持 HEAD 和 OPTIONS 方法。HEAD 运行时将调用 get 方法的实现(如果存在)和忽略响应实体(如果设置)。一个响应返回 OPTIONS 的方法取决于所要求的媒体类型在头文件中 ‘Accept’ 的定义。 OPTIONS 方法可以返回一组支持资源的方法在 头文件中 ‘Allow’ 或返回 WADL 文件的进行设置。更多信息见https://jersey.java.net/documentation/latest/wadl.html节。

3.1.3. @Produces

@Produces是定义返回值给客户端的 MIME 媒体类型。在下面这个例子里面,将会返回一个对应于text/plain的 MIME 媒体类型。@Produces 既可以应用在类上,也可以作用于方法上。这里是一个例子:

Example 3.4. 指定输出文件的MIME类型

  1. @Path("/myResource")
  2. @Produces("text/plain")
  3. public class SomeResource {
  4. @GET
  5. public String doGetAsPlainText() {
  6. ...
  7. }
  8. @GET
  9. @Produces("text/html")
  10. public String doGetAsHtml() {
  11. ...
  12. }
  13. }

这个 doGetAsPlainText 方法默认使用类水平的 @Produces 注解内容,也就是text/plain 。而 doGetAsHtml 方法使用方法水平上的@Produces,也就是text/html。也就是说方法水平层面的@Produces 会覆盖类层面的@Produces

如果一个资源类是能够生产多个 MIME 媒体类型,资源的方法的响应将会对应对于客户端来说最可接受的媒体类型。HTTP 请求头部宣布接受什么是最容易被接受的。例如,如果接受头部是 Accept: text/plain 然后dogetasplaintext 方法会被调用。如果接受标题是Accept: text/plain;q=0.9, text/htm,即客户可以接受 text/plaintext/html ,但更容易接收后者的媒体类型,然后 dogetashtml 方法会被调用。

@Produces 可以定义多个返回类型,例如:

Example 3.5. 使用多个返回类型

  1. @GET
  2. @Produces({"application/xml", "application/json"})
  3. public String doGetAsXmlOrJson() {
  4. ...
  5. }

无论application/xml或者application/json哪个匹配上了,都会执行 doGetAsXmlOrJson,如果两个都匹配了,那么会选择首先匹配的那个。

服务器也可选的指定个别媒体类型的品质因数。这些是客户端的决定的如何才是可接受的。例如:

Example 3.6. 服务器端内容协商

  1. @GET
  2. @Produces({"application/xml; qs=0.9", "application/json"})
  3. public String doGetAsXmlOrJson() {
  4. ...
  5. }

在上面的示例,如果客户端是接受application/xml或者 application/json,那么服务器总是发送application/json,因为 application/xml有一个较低的品质因数。

上面的例子是指明确清楚的 MIME 媒体类型。最好让它用常量来表示,这样可能会降低印刷错误。具体见 MediaType的常量字段值。

3.1.4. @Consumes

@Consumes注释是用来指定表示可由资源消耗的 MIME 媒体类型。上面的例子可以修改设置如下:

Example 3.7. 指定输入 MIME 类型:

  1. @POST
  2. @Consumes("text/plain")
  3. public void postClichedMessage(String message) {
  4. // Store the message
  5. }

在这个例子中,该 Java 方法将消耗表示确定的 MIME 媒体类型text/plain 。注意资源的方法返回 void 。这意味着没有内容返回,而是一个204 状态码响应(204是指“无内容”)将返回到客户端。

@Consumes既可以应用在类的水平上,也可以作用与方法的水平,而且声明可以不只一种类型。