笔记27 接受请求的输入 ——通过路径参数接受输入
假设我们的应用程序需要根据给定的ID来展现某一个Spittle记 录。其中一种方案就是编写处理器方法,通过使用@RequestParam 注解,让它接受ID作为查询参数:
1 @RequestMapping(value = "/spittle", method = RequestMethod.GET) 2 public String showSpittle(@RequestParam("spittle_id") long spittleId, Model model) { 3 model.addAllAttributes(spittleRepository.findOne(spittleId)); 4 return "spittle"; 5 }
这个处理器方法将会处理形如“/spittles?spittle_id=12345”这样的 请求。尽管这也可以正常工作,但是从面向资源的角度来看这并不理 想。在理想情况下,要识别的资源(Spittle)应该通过URL路径进 行标示,而不是通过查询参数。对“/spittles/12345”发起GET请求要优 于对“/spittles?spittle_id=12345”发起请求。前者能够识别出要查 询的资源,而后者描述的是带有参数的一个操作——本质上是通过 HTTP发起的RPC。
1.修改测试方法:其中ID要在路径变量中 指定
1 private List<Spittle> createSpittleList(int count) { 2 List<Spittle> spittles = new ArrayList<Spittle>(); 3 for (int i = 0; i < count; i++) { 4 spittles.add(new Spittle("Spittle" + i, new Date())); 5 } 6 return spittles; 7 } 8 9 @Test 10 public void testSpittle() throws Exception { 11 12 Spittle spittle = new Spittle("hello", new Date()); 13 14 List<Spittle> expectedSpittle = new ArrayList<Spittle>(); 15 expectedSpittle.add(spittle); 16 SpittleRepository mockRepository = mock(SpittleRepository.class); 17 when(mockRepository.findOne(12345)).thenReturn(expectedSpittle); 18 19 SpittleController controller = new SpittleController(mockRepository); 20 21 MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); 22 23 mockMvc.perform(get("/spittles/12345")).andExpect(view().name("spittle")) 24 .andExpect(model().attributeExists("spittleList")) 25 .andExpect(model().attribute("spittleList", hasItems(expectedSpittle.toArray()))); 26 27 }
这个测试构建了一个mockRepository、一个控制器和 MockMvc,这与本章中我们所编写的其他测试很类似。这个测试中 最重要的部分是最后几行,它对“/spittles/12345”发起GET请求,然后 断言视图的名称是spittleList,并且预期的expectedSpittle对象放到了模型之中。
2.在SpittleController添加新的方法
1 @RequestMapping(value = "/{spittleId}", method = RequestMethod.GET) 2 public String showSpittle(@PathVariable("spittleId") long spittleId, Model model) { 3 model.addAttribute("spittleList", spittleRepository.findOne(spittleId)); 4 return "spittle"; 5 }
在@RequestMapping 路径中添加占位符。占位符的名称要用大括号(“{”和“}”)括起来。 路径中的其他部分要与所处理的请求完全匹配,但是占位符部分可以 是任意的值。
在showSpittle()方法的spittleId参数上添加了 @PathVariable("spittleId")注解,这表明在请求路径中,不 管占位符部分的值是什么都会传递到处理器方法的spittleId参数中。如果对“/spittles/54321”发送GET请求,那么将会把“54321”传递进 来,作为spittleId的值。
注:如果@PathVariable中没有value属性的话,它会假设占位符的名 称与方法的参数名相同。
showSpittle()方法会将参数传递到SpittleRepository的 findOne()方法中,用来获取某个Spittle对象,然后将Spittle 对象添加到模型中。
1 List<Spittle> findOne(long spittleId);
3.spittle.jsp用于展示查询的spittle
1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 2 <html> 3 <head> 4 <title>Spitter</title> 5 <link rel="stylesheet" 6 type="text/css" 7 href="<c:url value="/resources/style.css" />" > 8 </head> 9 <body> 10 <c:forEach items="${spittleList}" var="spittles" > 11 <div class="spittleView"> 12 <div class="spittleMessage"><c:out value="${spittles.message}" /></div> 13 <div> 14 <span class="spittleTime"><c:out value="${spittles.time}" /></span> 15 </div> 16 </div> 17 </c:forEach> 18 </body> 19 </html>
4.测试