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>

    该值将是与指定模板参数匹配的路径网段对象列表。

  • 原语,如 intcharlong
  • 具有 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 有两个列表参数,即 typewingspan

注意

在计算资源 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=whaleupdateMonster() 方法 的类型 被设置为 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