47.2. 使用 JAX-RS API
47.2.1. JAX-RS 注解类型
标准 JAX-RS API 指定可用于将值注入字段、bean 属性和方法参数的注解。注解可以被分成三个不同的类型:
47.2.2. 注入请求 URI 中的数据
概述
设计 RESTful Web 服务的最佳实践之一是,每个资源应具有唯一的 URI。开发人员可以使用这个原则来为底层资源实施提供良好的信息。在为资源设计 URI 模板时,开发人员可以构建模板,使其包含可注入到资源实施中的参数信息。开发人员还可利用查询和列表参数,将信息馈送到资源实施中。
从 URI 的路径获取数据
获取资源信息的更常见机制之一是通过为资源创建 URI 模板时使用的变量。这可以通过 javax.ws.rs.PathParam
注解来完成。@PathParam
注释具有一个用于标识要注入数据的 URI 模板变量的单个参数。
在 例 47.1 “注入 URI 模板变量的数据” 中,@PathParam
注释指定 URI 模板变量 颜色
的值被注入到 itemColor
字段中。
例 47.1. 注入 URI 模板变量的数据
import javax.ws.rs.Path; import javax.ws.rs.PathParam ... @Path("/boxes/{shape}/{color}") class Box { ... @PathParam("color") String itemColor; ... }
@PathParam
注释支持的数据类型与 “支持的数据类型”一节 中描述的数据类型不同。@PathParam
注释注入数据的实体必须是以下类型之一:
PathSegment
该值将是路径匹配部分的最后一个部分。
List<PathSegment>
该值将是与指定模板参数匹配的路径网段对象列表。
-
原语,如
int
、char
或long
-
具有 buildor 的对象,它接受单个
String
参数 -
具有接受单个
String
参数的静态valueOf()
方法的对象
使用查询参数
在 Web 上传递信息的一种常见方法是使用 URI 中的 查询参数。查询参数出现在 URI 的末尾,并通过问号(?
)与 URI 的资源位置部分隔开。它们由一个或多个名称值对组成,其中 name 和 value 用等号(=
)分开。当指定多个查询参数时,对通过分号()或 符号(和)相互分离。
例 47.2 “带有查询字符串的 URI” 显示带有查询参数的 URI 的语法。
例 47.2. 带有查询字符串的 URI
http://fusesource.org?name=value;name2=value2;...
您可以使用 分号 或 符号来分隔查询参数,但不能两者。
javax.ws.rs.QueryParam
注解提取查询参数的值,并将其注入 JAX-RS 资源。该注释采用单个参数来标识从中获取并注入到指定字段、bean 属性或参数中的查询参数。@QueryParam
注释支持 “支持的数据类型”一节 中描述的类型。
例 47.3 “使用查询参数中的数据的资源方法” 显示一个资源方法,它将查询参数 id
的值注入到方法的 id
参数中。
例 47.3. 使用查询参数中的数据的资源方法
import javax.ws.rs.QueryParam; import javax.ws.rs.PathParam; import javax.ws.rs.POST; import javax.ws.rs.Path; ... @Path("/monstersforhire/") public class MonsterService { ... @POST @Path("/{type}") public void updateMonster(@PathParam("type") String type, @QueryParam("id") String id) { ... } ... }
要处理 HTTP POST
到 /monstersforhire/daikaiju?id=jonas the updateMonster()
方法 的类型
,并将 id
设置为 jonas
。
使用列表参数
URI 列表参数(如 URI 查询参数)是 name/value 对,可以提供附加信息选择资源。与查询参数不同,列表参数可能会出现 URI 中的任何位置,它们使用分号(;
)与 URI 的层次路径片段分离。/mostersforhire/daikaiju;id=jonas 有一个称为 id
和 /monstersforhire/japan;type=daikaiju/flying;wingspan=40 有两个列表参数,即 type
和 wingspan
。
在计算资源 URI 时,不会评估列表参数。因此,用于定位适当的资源以处理请求 URI /monstersforhire/japan;type=daikaiju/flying;wingspan=40 是 /monstersforhire/japan/flying。
matrix 参数的值通过 javax.ws.rs.MatrixParam
注解注入字段、参数或 bean 属性。该注释采用单个参数来标识从中提取值并注入到指定字段、bean 属性或参数的 matrix 参数的名称。@MatrixParam
注释支持 “支持的数据类型”一节 中描述的类型。
例 47.4 “使用列表参数中的数据的资源方法” 显示资源方法,它将列表参数值注入方法参数和 id
。
例 47.4. 使用列表参数中的数据的资源方法
import javax.ws.rs.MatrixParam; import javax.ws.rs.POST; import javax.ws.rs.Path; ... @Path("/monstersforhire/") public class MonsterService { ... @POST public void updateMonster(@MatrixParam("type") String type, @MatrixParam("id") String id) { ... } ... }
要处理 HTTP POST
到 /monstersforhire;type=daikaiju;id=whale,updateMonster()
方法 的类型
被设置为 daikaiju
,并将 id
设置为 whale
。
JAX-RS 一次性评估 URI 中的所有列表参数,因此无法对 URI 中的列表参数位置实施约束。例如 /monstersforhire/japan;type=daikaiju/flying;wingspan=40 , /monstersforhire/japan/flying;type=daikaiju;wspan=40, 和 /monstersforre/japan; type=daikaiju;wingspan=40/flying 均被视为使用 JAX-RS API 实施的 RESTful Web 服务。
禁用 URI 解码
默认情况下,所有请求 URI 被解码。因此,URI /monster/night%20stalker 和 URI /monster/night stalker 具有等同的。自动 URI 解码可让您轻松在 ASCII 字符集外发送字符作为参数。
如果您不想自动解码 URI,您可以使用 javax.ws.rs.Encode 注解来
取消激活 URI 解码。该注解可用于在以下级别上取消激活 URI 解码:
-
类级别 - 使用
@En
code 注释处理类可取消激活类中所有参数、字段和 bean 属性的 URI 解码。 -
方法级别 - 使用
@En
code 注释处理方法可取消激活类所有参数的 URI 解码。 -
参数/字段级别-使用
@En
code 注释停用类所有参数的 URI 解码参数或字段。
例 47.5 “禁用 URI 解码” 显示 getMonster()
方法不使用 URI 解码的资源。addMonster()
方法只禁用 type
参数的 URI decoding。
例 47.5. 禁用 URI 解码
@Path("/monstersforhire/") public class MonsterService { ... @GET @Encoded @Path("/{type}") public Monster getMonster(@PathParam("type") String type, @QueryParam("id") String id) { ... } @PUT @Path("/{id}") public void addMonster(@Encoded @PathParam("type") String type, @QueryParam("id") String id) { ... } ... }
错误处理
如果尝试使用其中一个 URI 注入注解注入数据时,会产生一个错误,则将生成 WebApplicationException 异常嵌套原始异常。WebApplicationException 异常的状态设置为 404
。
47.2.3. 注入 HTTP 邮件标头中的数据
概述
在正常情况下,在请求消息中传递 HTTP 标头会传递消息的通用信息,如何在传输中处理它,以及有关预期响应的详情。虽然几种标准标头通常被识别和使用,但 HTTP 规范允许任何 name/value 对用作 HTTP 标头。JAX-RS API 提供了将 HTTP 标头信息注入资源实施的简单机制。
最常用的 HTTP 标头之一是 cookie。Cookie 允许 HTTP 客户端和服务器在多个请求/响应序列间共享静态信息。JAX-RS API 提供了一个注释,将来自 Cookie 的数据直接注入到资源实施中。
注入 HTTP 标头的信息
javax.ws.rs.HeaderParam
注解用于将 HTTP 标头字段的数据注入到参数、字段或 bean 属性中。它具有一个参数,用于指定从中提取值并注入到资源实施中的 HTTP 标头字段的名称。关联的参数、字段或 bean 属性必须符合 “支持的数据类型”一节 中描述的数据类型。
注入 If-Modified-Since 标头 显示将 HTTP If-Modified-Since
标头的值注入类 最旧的Date
字段的代码。
注入 If-Modified-Since 标头
import javax.ws.rs.HeaderParam; ... class RecordKeeper { ... @HeaderParam("If-Modified-Since") String oldestDate; ... }
从 Cookie 注入信息
Cookie 是特殊的 HTTP 标头类型。它们由一个或多个名称/值对组成,它们传递到第一个请求的资源实施。在第一个请求后,cookie 在提供程序和消费者之间通过每条消息。只有消费者生成请求后才能更改 Cookie。Cookie 通常用于在多个请求/响应序列间维护会话,存储用户设置和其他可保留的数据。
javax.ws.rs.CookieParam
注解从 cookie 的项中提取值,并将其注入资源实施中。它取一个参数,用于指定要从中提取值的 cookie 字段的名称。除了 “支持的数据类型”一节 中列出的数据类型外,@CookieParam
的实体也可以是一个 Cookie
对象。
例 47.6 “注入 cookie” 显示将 handle
cookie 的值注入到 CB
类中的字段的代码。
例 47.6. 注入 cookie
import javax.ws.rs.CookieParam; ... class CB { ... @CookieParam("handle") String handle; ... }
错误处理
如果尝试使用 HTTP 消息注入注解注入数据时出现一个错误,则生成 WebApplicationException 异常嵌套原始异常。WebApplicationException 异常的状态设置为 400
。
47.2.4. 注入 HTML 格式的数据
概述
HTML 表单是一种从用户获取信息的简单方法,也易于创建。表单数据可用于 HTTP GET
请求和 HTTP POST
请求:
- GET
-
作为 HTTP
GET
请求的一部分发送表单数据时,数据会作为一组查询参数附加到 URI。“使用查询参数”一节 中讨论从查询参数注入数据。 - POST
-
当将数据作为 HTTP
POST
请求的一部分发送时,数据会被放入 HTTP 消息正文中。可使用支持表单数据的常规实体参数处理表单数据。它还可通过使用@FormParam
注释来提取数据并将组件注入资源方法参数来处理。
使用 @FormParam 注释来注入表单数据
javax.ws.rs.FormParam
注解从表单数据中提取字段值,并将值注入资源方法参数。该注释采用单个参数来指定从中提取值的字段键。关联的参数必须符合 “支持的数据类型”一节 中描述的数据类型。
JAX-RS API Javadoc指出可以将 @FormParam
注释放在不同的字段、方法和参数上。但是,@FormParam
注释仅在放置在资源方法参数上时才有意义。
示例
将表单数据注入资源方法参数 显示将表单数据注入参数的资源方法。这个方法假定客户端表单包含三个字段:标题
、标签
和 正文
,其中包含字符串数据。
将表单数据注入资源方法参数
import javax.ws.rs.FormParam; import javax.ws.rs.POST; ... @POST public boolean updatePost(@FormParam("title") String title, @FormParam("tags") String tags, @FormParam("body") String post) { ... }
47.2.5. 指定要注入的默认值
概述
要为更可靠的服务实现提供,您可能需要确保将任何可选参数设置为默认值。这在输入长 URI 字符串以来从查询参数和列表参数中获取的值特别有用。您可能还想为从 cookie 中提取的参数设置默认值,因为请求的系统可能没有正确的信息来构造带有所有值的 cookie。
javax.ws.rs.DefaultValue
注解可以和以下注入注解结合使用:
-
@PathParam
-
@QueryParam
-
@MatrixParam
-
@FormParam
-
@HeaderParam
-
@CookieParam
@DefaultValue
注释指定在请求中不存在与注入注释对应的数据时将使用的默认值。
语法
设置参数的默认值的语法 显示使用 @DefaultValue
注释的语法。
设置参数的默认值的语法
import javax.ws.rs.DefaultValue; ... void resourceMethod(@MatrixParam("matrix") @DefaultValue("value) int someValue, ... ) ...
该注释必须在参数、bean 或 字段之前使用,它将起作用。相对于带注入注解的 @DefaultValue
注释的位置无关紧要。
@DefaultValue
注释使用一个参数。此参数是根据注入注解提取正确的数据,则将注入字段的值。该值可以是任意 String
值。该值应当与关联字段的类型兼容。例如,如果关联的字段是 int
,则默认值 blue
会导致异常。
处理列表和集合
如果注解参数的类型,an 或字段是 List、Set 或 SortedSet,则生成的集合将具有从提供的默认值映射的单个条目。
示例
设置默认值 显示使用 @DefaultValue
为注入值的字段指定默认值的两个示例。
设置默认值
import javax.ws.rs.DefaultValue; import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; import javax.ws.rs.GET; import javax.ws.rs.Path; @Path("/monster") public class MonsterService { @Get public Monster getMonster(@QueryParam("id") @DefaultValue("42") int id, @QueryParam("type") @DefaultValue("bogeyman") String type) { ... } ... }
当 GET
请求发送到 baseURI/monster 时,调用 设置默认值 中的 getMonster()
方法。这个方法需要两个查询参数,即 id
和 type
,并附加到 URI。因此,使用 URI baseURI/monster?id=1&type=fomóiri 的 GET
请求会返回 Fomóiri,其 ID 为 1。
由于 @DefaultValue
注释都放在这两个参数上,因此如果查询参数被省略,则 getMonster()
方法可以正常使用。发送到 baseURI/monster 的
请求等同于使用 URI baseURI/monster?id=42&type=bogeyman 的 GET 请求。
GET
47.2.6. 将参数注入 Java Bean
概述
当通过 REST 发布 HTML 表单时,服务器端的一个通用模式是创建一个 Java Bean,以封装以形式接收的所有数据(以及来自其他参数和 HTML 标头的数据)。通常,创建此 Java bean 将是一个两个步骤:资源方法通过注入(例如,将 @FormParam
注释添加到其方法参数),然后调用 bean 的构造器,以表单数据传递。
使用 JAX-RS 2.0 @BeanParam
注释,可以在一个步骤中实施此模式。表单数据可以直接注入到 bean 类的字段,并且 bean 本身由 JAX-RS 运行时自动创建。例如,这最易于说明。
注入目标
@BeanParam
注释可以附加到资源方法参数、资源字段或 bean 属性。但是,参数目标是唯一可与所有资源类生命周期一起使用的目标类型。其他类型的目标仅限于每个请求的生命周期。这个情况在 表 47.1 “@BeanParam Injection Targets” 中进行了概述。
目标 | 资源类别生命周期 |
---|---|
| All |
| per-request(默认) |
| per-request(默认) |
没有 BeanParam 注解的示例
以下示例演示了如何使用传统方法以 Java Bean 捕获表单数据(不使用 @BeanParam
):
// Java import javax.ws.rs.POST; import javax.ws.rs.FormParam; import javax.ws.rs.core.Response; ... @POST public Response orderTable(@FormParam("orderId") String orderId, @FormParam("color") String color, @FormParam("quantity") String quantity, @FormParam("price") String price) { ... TableOrder bean = new TableOrder(orderId, color, quantity, price); ... return Response.ok().build(); }
在本例中,orderTable
方法处理了一个表单,用于排序来自 furniture 网站的表数量。当订购表单后,表单值将注入到
方法的参数中,使用注入的表单数据显式创建 orderTable
TableOrder
类的实例。
带有 BeanParam 注解的示例
上一示例可以重构为利用 @BeanParam
注释。使用 @BeanParam
方法时,表单参数可以直接注入到 bean 类的字段( TableOrder
)。实际上,您可以使用 bean 类中的任何标准 JAX-RS 参数注释:包括 @PathParam
、@QueryParam
、@FormParam
、@MatrixParam
、@CookieParam
和 @HeaderParam
。处理表单的代码可以重构如下:
// Java import javax.ws.rs.POST; import javax.ws.rs.FormParam; import javax.ws.rs.core.Response; ... public class TableOrder { @FormParam("orderId") private String orderId; @FormParam("color") private String color; @FormParam("quantity") private String quantity; @FormParam("price") private String price; // Define public getter/setter methods // (Not shown) ... } ... @POST public Response orderTable(@BeanParam TableOrder orderBean) { ... // Do whatever you like with the 'orderBean' bean ... return Response.ok().build(); }
现在,表单注解已添加到 bean 类 tableOrder 中,您可以使用单个 @BeanParam
注释替换资源方法签名中的所有 @FormParam
注释,如所示。现在,当表单发布到 orderTable
资源方法中时,JAX-RS 运行时会自动创建 TableOrder
实例,orderBean
,并注入 bean 类上参数注解指定的所有数据。