使用视图控制器
到目前为止,我们已经为 Taco Cloud 应用编写了 3 个控制器。这 3 个控制器尽管服务于应用程序的不同功能,但基本上遵循相同的编程模型:
-
它们都使用了 @Controller 注解,表明它们是控制器类,并且应该被 Spring 的组件扫描功能自动发现并初始化为 Spring 应用上下文中的 bean;
-
除 HomeController 之外的控制器都在类级别使用了 @RequestMapping 注解,据此定义该控制器所处理的基本请求模式;
-
它们都有一个或多个带 @GetMapping 或 @PostMapping 注解的方法,这些注解指明了该由哪个方法来处理某种类型的请求。
我们所编写的大部分控制器都将遵循这个模式。但是,如果一个控制器非常简单,不需要填充模型或处理输入(在我们的场景中,也就是 HomeController),那么还有另外一种方式来定义控制器。请参考程序清单2.16学习如何声明视图控制器——只将请求转发到视图而不做其他事情的控制器。
package tacos.web;
import org.springframework.context.annotation.Configuration;
import
org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
}
关于 WebConfig,最需要注意的事情就是它实现了 WebMvcConfigurer 接口。WebMvcConfigurer 定义了多个方法来配置 Spring MVC,尽管只是一个接口,却提供了所有方法的默认实现,只需要我们覆盖所需的方法。在本例中,我们覆盖了 addViewControllers 方法。
addViewControllers() 方法会接收一个 ViewControllerRegistry 对象,我们可以使用它注册一个或多个视图控制器。在这里,我们调用 registry 的 addViewController() 方法,将 “/” 传递进去,视图控制器将会针对该路径执行 GET 请求。这个方法会返回 ViewControllerRegistration 对象,我们马上基于该对象调用 setViewName() 方法,用它指明当请求 “/” 的时候要转发到 “home” 视图上。
如前文所述,我们用配置类中的几行代码就替换了 HomeController 类。现在,我们可以删除 HomeController 了,应用的功能应该和之前完全一样。唯一需要注意的是,我们要重新找到第 1 章中的 HomeControllerTest 类,从 @WebMvcTest 注解中移除对 HomeController 的引用,这样测试类的编译才不会报错。
在这里,我们创建了一个新的 WebConfig 配置类来存放视图控制器的声明。但是,所有的配置类都可以实现 WebMvcConfigurer 接口并覆盖 addViewController 方法。举例来说,我们可以将相同的视图控制器声明添加到 TacoCloudApplication 引导类中,如下所示:
@SpringBootApplication
public class TacoCloudApplication implements WebMvcConfigurer {
public static void main(String[] args) {
SpringApplication.run(TacoCloudApplication.class, args);
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
}
采用扩展已有配置类的方式能够避免创建新的配置类,从而减少项目中制品的数量。但是,我倾向于为每种配置(Web、数据、安全等)创建新的配置类,来保持应用的引导配置类尽可能整洁和简单。
在视图控制器方面,或者更具体地讲,在控制器将请求所转发到的视图方面,到目前为止,我们都是使用 Thymeleaf 来实现所有的视图。我很喜欢 Thymeleaf,但是你可能想要为你的应用选择不同的模板模型。让我们来看一下 Spring 所能支持的众多视图方案。