5.3.1 处理查询参数

在 Spittr 应用中,我们可能需要处理的一件事就是展现分页的 Spittle 列表。在现在的 SpittleController 中,它只能展现最新的 Spittle,并没有办法向前翻页查看以前编写的 Spittle 历史记录。如果你想让用户每次都能查看某一页的 Spittle 历史,那么就需要提供一种方式让用户传递参数进来,进而确定要展现哪些 Spittle 集合。

在确定该如何实现时,假设我们要查看某一页 Spittle 列表,这个列表会按照最新的 Spittle 在前的方式进行排序。因此,下一页中第一条的 ID 肯定会早于当前页最后一条的 ID。所以,为了显示下一页的 Spittle,我们需要将一个 Spittle 的 ID 传入进来,这个 ID 要恰好小于当 前页最后一条 Spittle 的 ID。另外,你还可以传入一个参数来确定要展现的 Spittle 数量。

为了实现这个分页的功能,我们所编写的处理器方法要接受如下的参 数:

  • before 参数(表明结果中所有 Spittle 的 ID 均应该在这个值之前)。

  • count 参数(表明在结果中要包含的 Spittle 数量)。

为了实现这个功能,我们将程序清单 5.10 中的 spittles() 方法替换为使用 before 和 count 参数的新 spittles() 方法。我们首先添加一个测试,这个测试反映了新 spittles() 方法的功能。

程序清单 5.11 用来测试分页 Spittle 列表的新方法
@Test
public void shouldShowRecentSpittles() throws Exception {
  List<Spittle> expectedSpittles = createSpittleList(50);
  SpittleRepository mockRepository = mock(SpittleRepository.class);
  when(mockRepository.findSpittles(238900, 50))
    .thenReturn(expectedSpittles);

  SpittleController controller = new SpittleController(mockRepository);
  MockMvc mockMvc = standaloneSetup(controller)
      .setSingleView(new InternalResourceView("/WEB-INF/views/spittles.jsp"))
      .build();

  mockMvc.perform(get("/spittles?max=238900&count=50"))
    .andExpect(view().name("spittles"))
    .andExpect(model().attributeExists("spittleList"))
    .andExpect(model().attribute("spittleList", hasItems(expectedSpittles.toArray())));
}

这个测试方法与程序清单 5.9 中的测试方法关键区别在于它针对 /spittles 发送 GET 请求,同时还传入了 max 和 count 参数。它测试了这些参数存在时的处理器方法,而另一个测试方法则测试了没有这些参数时的情景。这两个测试就绪后,我们就能确保不管控制器发生什么样的变化,它都能够处理这两种类型的请求:

@RequestMapping(method=RequestMethod.GET)
public List<Spittle> spittles(
  @RequestParam("max") long max,
  @RequestParam("count") int count) {
    return spittleRepository.findSpittles(max, count);
}

SpittleController 中的处理器方法要同时处理有参数和没有参数的场景,那我们需要对其进行修改,让它能接受参数,同时,如果这些参数在请求中不存在的话,就使用默认值 Long.MAX_VALUE 和 20。@RequestParam 注解的default-Value 属性可以完成这项任务:

@RequestMapping(method=RequestMethod.GET)
public List<Spittle> spittles(
  @RequestParam(value="max", defaultValue=MAX_LONG_AS_STRING) long max,
  @RequestParam(value="count", defaultValue="20") int count) {
    return spittleRepository.findSpittles(max, count);
}

现在,如果 max 参数没有指定的话,它将会是 Long 类型的最大值。因为查询参数都是 String 类型的,因此 defaultValue 属性需要 String 类型的值。因此,使用 Long.MAX_VALUE 是不行的。我们可以将 Long.MAX_VALUE 转换为名为 MAX_LONG_AS_STRING 的 String 类型常量:

private static final String MAX_LONG_AS_STRING = Long.toString(Long.MAX_VALUE);

尽管 defaultValue 属性给定的是 String 类型的值,但是当绑定到方法的 max 参数时,它会转换为 Long 类型。

如果请求中没有 count 参数的话,count 参数的默认值将会设置为 20。

请求中的查询参数是往控制器中传递信息的常用手段。另外一种方式也很流行,尤其是在构建面向资源的控制器时,这种方式就是将传递参数作为请求路径的一部分。让我们看一下如何将路径变量作为请求路径的一部分,从而实现信息的输入。

Last updated