在Spring MVC中,控制器只是方法上添加了@RequestMapping注解 的类,这个注解声明了它们所要处理的请求。
假设控制器类要处理对“/”的请求, 并渲染应用的首页。程序清单5.3所示的HomeController可能是最 简单的Spring MVC控制器类了。
程序清单5.3 HomeController:超级简单的控制器
* package com.spring.mvc.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import static org.springframework.web.bind.annotation.RequestMethod.GET; /** * 声明一个控制器 * @author huyingqi */ @Controller public class HomeController { @RequestMapping(value = "/",method = GET ) public String home(){ //视图名为home return "home"; } }
在上述内容中,我们可以注意到HomeController带有@Controller注解。
HomeController是一个构造型注解,基于@Component注解。
实际上,你也可以让HomeController带有@Component注解,它的效果是一样的。但在表意性上可能会有所差别,无法确定HomeController是什么类型的组件。
HomeController中唯一的方法是home()方法,它带有@RequestMapping注解。
在home()方法中,并没有做太多的事情,它只是返回一个String类型的"home"。这个字符串将被Spring MVC解释为要渲染的视图名称。DispatcherServlet会要求视图解析器将这个逻辑名称解析为实际的视图。
鉴于我们配置InternalResourceViewResolver的方式,视图 名“home”将会解析为“/WEB-INF/views/home.jsp”路径的JSP 。现在, 我们会让Spittr应用的首页相当简单,如下所示。
程序清单5.4 Spittr应用的首页,定义为一个简单的JSP
[图片]
这个JSP并没有太多需要注意的地方。它只是欢迎应用的用户,并提 供了两个链接:一个是查看Spittle列表,另一个是在应用中进行 注册。图5.2展现了此时的首页是什么样子的。
在本章完成之前,我们将会实现处理这些请求的控制器方法。但现在,让我们对这个控制器发起一些请求,看一下它是否能够正常工作。测试控制器最直接的办法可能就是构建并部署应用,然后通过浏 览器对其进行访问,但是自动化测试可能会给你更快的反馈和更一致 的独立结果。所以,让我们编写一个针对HomeController的测 试。
[图片]
图5 .2 当前的Spittr首页
5.2.1 测试控制器
让我们再审视一下HomeController。如果你眼神不太好的话,你 甚至可能注意不到这些注解,所看到的仅仅是一个简单的POJO 。我 们都知道测试POJO是很容易的。因此,我们可以编写一个简单的类 来测试HomeController,如下所示:
程序清单5.5 HomeControllerTest:测试HomeController
package com.spring.mvc; import com.spring.mvc.controller.HomeController; import org.junit.Assert; import org.junit.Test; public class HomeControllerTest { @Test public void testHomePage() throws Exception { HomeController homeController = new HomeController(); Assert.assertEquals("home",homeController.home()); } } -
在程序清单5.5中的测试非常简单,它只测试了home()方法的行为。测试直接调用home()方法,并断言返回的字符串包含"home"值。这个测试并没有从Spring MVC控制器的角度进行测试,它没有断言当接收到针对"/“的GET请求时会调用home()方法。由于返回的值正好是"home”,所以也没有真正判断"home"是否是视图的名称。
然而,从Spring 3.2开始,我们可以使用控制器的方式来测试Spring MVC中的控制器,而不仅仅作为POJO进行测试。Spring现在提供了一种模拟Spring MVC并执行HTTP请求的机制。这样,在测试控制器时,就不需要启动Web服务器和Web浏览器了。
为了演示如何测试Spring MVC控制器,我们重写了HomeControllerTest,并使用了Spring MVC中的新测试特性。程序清单5.6展示了新的HomeControllerTest。
程序清单5.6 改进HomeControllerTest
新版本的测试相比之前的版本只多了几行代码,但它更完整地测试了HomeController。这次测试不是直接调用home()方法并测试返回值,而是发起了对"/“的GET请求,并断言结果视图的名称为"home”。首先,它使用HomeControllerMockMvcBuilders.standaloneSetup()创建一个MockMvc实例,并调用build()方法进行构建。然后,使用MockMvc实例执行针对"/"的GET请求,并设置期望得到的视图名称。
5.2.2 定义类级别的请求处理
现在,已经为HomeController编写了测试,那么我们可以做一些重构,并通过测试来保证不会对功能造成什么破坏。
我们可以做的一件事就是拆分@RequestMapping,并将其路径映射部分放到类级别 上。
程序清单5.7展示了这个过程。
程序清单5.7 拆分HomeController中的@RequestMapping
- package com.spring.mvc.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import static org.springframework.web.bind.annotation.RequestMethod.GET; /** * 声明一个控制器 * @author huyingqi */ @Controller. ——>将控制器映射到“/” @RequestMapping("/) public class HomeController { @RequestMapping(method = GET ) //处理GET请求 public String home(){ //视图名为home return "home"; ——> 视图名为home } }
在这个新版本的HomeController中,路径被转移到类级别的@RequestMapping上,而HTTP方法仍然映射在方法级别上。
对于HomeController来说,只有一个控制器方法。
换句话说,我们实际上没有改变任何功能,只是将一些代码移动了位置,但HomeController所做的事情与之前相同。由于我们现在有了测试,可以确保在这个过程中没有破坏原有的功能。
当我们在修改@RequestMapping时,还可以对HomeController 做另外一个变更。
@RequestMapping的value属性能够接受一 个String类型的数组。
到目前为止,我们给它设置的都是一个 String类型的“/” 。
但是,我们还可以将它映射到对“/homepage”的 请求,只需将类级别的@RequestMapping改为如下所示:
- - @Controller. ——>将控制器映射到“/” @RequestMapping("/","/homepage") public class HomeController { }
现在,HomeController的home ()方法能够映射到对“/”和“/homepage”的GET请求。
5.2.3 传递模型数据到视图中
目前,只需要一个能够获取Spittle列表的Repository,下面是一个足够实现功能的SpittleRepository的示例。
public. interface Spilttlerepository{ List<Spittle> findSpittleRepository(long max,int count); }
findSpittles ()方法接受两个参数。
根据您提供的内容,我将尝试梳理一下:
让它满足程序清单5.9的预期。如下的SpittleController实现将 会满足以上测试的要求。
程序清单5.10 SpittleController:在模型中放入最新的spittle 列表
[图片]
[图片]
图5.3为显示效果,能够让你对它在Web浏览器中是什么样子有个可视 化的印象。
尽管SpittleController很简单,但是它依然比 HomeController更进一步了。不过,SpittleController和 HomeController都没有处理任何形式的输入。现在,让我们扩 展SpittleController,让它从客户端接受一些输入。
图5 .3 控制器中的Spittle模型数据将会作为请求参数,并在Web页面上渲染为列 表的形式