本文主要依据《Spring实战》第五章内容进行总结
Spring MVC框架是基于模型-视图-控制器(Model-View-Controller,MVC)模式实现,它能够构建像Spring框架那样灵活和松耦合的Web应用。
1、Spring MVC起步
1.1、Spring MVC如何处理客户端请求
Spring MVC处理客户端请求的过程可以参考如下所示的图示:
具体步骤如下:
- 客户端请求离开浏览器时①,会带有用户请求内容的信息,至少会包含请求的URL,但是还可能带有其他的信息,例如用户提交的表单信息;
- 请求会传递给Spring的DispatcherServlet,DispatcherServlet是一个前端控制器,主要负责将请求委托给应用程序的其他组件来执行实际的处理;
- DispatcherServlet要将请求发送给Spring MVC控制器(controller),控制器是一个用于处理请求的Spring组件,DispatcherServlet要确定将请求发送给哪个控制器,所以DispatcherServlet会查询一个或多个处理器映射(handler mapping)②,处理器映射根据请求的URL信息进行决策;
- 一旦选择了合适的控制器,DispatcherServlet会将请求发送给选中的控制器③,由控制器进行业务逻辑的处理;
- 控制器在完成逻辑处理后,通常会产生一些信息,这些信息需要返回给用户并在浏览器上显示,这些信息被称为模型(model),控制器要将模型数据打包,并且标示出用于渲染输出的视图名,然后将模型及视图名发送回DispatcherServlet④;
- 传递给DispatcherServlet的视图名不一定是真实对应的视图名称,可能是一个逻辑视图名,DispatcherServlet将会使用视图解析器(view resolver)⑤来将逻辑试图名匹配一个特定的试图实现;
- 请求最后到达真实视图⑥,在这里它交付模型数据,请求的任务也就完成了;
- 视图将使用模型数据渲染输出,这个输出会通过响应对象传递给客户端⑦。
1.2、搭建Spring MVC
1.2.1、配置DispatcherServlet
DispatcherServlet是Spring MVC的核心,它主要负责将请求路由到其它的组件之中,所以配置Spring MVC的第一步就是配置DispathcerServlet。
按照传统的Web框架,Servlet一般都是在web.xml中进行配置的,但在Servlet 3规范之后,我们可以通过Java代码的方式配置,只需要将Java类实现javax.servlet.ServletContainerInitializer接口即可,在Servlet 3.0环境中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果能发现的话,就会用它来配置Servlet容器。Spring提供了这个接口的实现SpringServletContainerInitializer,这个类又会反过来查找实现WebApplicationInitializer的类。在这里我们创建一个配置类SpringMvcInitializer:
public class SpringMvcInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {RootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {WebConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[] {
"/"};
}
}
在这里SpringMvcInitializer类扩展了AbstractAnnotationConfigDispatcherServletInitializer,而AbstractAnnotationConfigDispatcherServletInitializer实现了WebApplicationIntializer,所以部署到Servlet 3.0容器中的时候,容器就会自动发现它,并用它来配置Servlet上下文,在后面的章节,我们将会介绍如何使用web.xml配置DispathcerServlet。
我们可以看到,SpringMvcInitializer重写了三个方法,其中getServletMappings()方法会将一个或多个路径映射到DispatcherServlet上,在这里,它映射的是“/”,这表示它会是应用的默认Servlet,它会处理进入应用的所有请求。
1.2.2、两个应用上下文
我们可以看到,上面的SpringMvcInitializer配置类中除了getServletMappings()方法之外还有两个方法,这两个方法都是配置Spring应用上下文的。
当DispathcherServlet启动的时候,它会创建Spring应用上下文,并加载配置文件或配置类中声明的bean,在getServletConfigClasses()方法中,我们要求DispatcherServlet加载应用上下文时,使用定义在WebConfig配置类中的bean。
但是在Spring Web应用中,通常还会有另外一个应用上下文,另外的这个应用上下文就是由ContextLoaderListener创建的。
实际上,AbstractAnnotationConfigDispatcherServletInitializer会同时创建DispatcherServlet和ContextLoaderListener,getServletConfigClasses()方法返回的带有@Configuration注解的类将会用来定义DispatcherServlet应用上下文中的bean,getRootConfigClasses()方法返回的带有@Configuration注解的类将会用来配置ContextLoaderListener创建的应用上下文的bean。
通常情况下,DispathcerServlet加载包含Web组件的bean,如控制器、视图解析器以及处理器映射,而ContextLoaderListener要加载应用中的其他bean,这些bean通常是驱动应用后端的中间层和数据层组件。
1.2.3、启用Spring MVC
配置好DispatcherServlet之后,我们需要创建Spring MVC的配置WebConfig,下面示例是最简单的Spring MVC配置:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter{
}
最简单的Spring MVC配置就是一个带有@EnableWebMVC注解的类,它可以启用Spring MVC,但是它还有不少的问题需要解决:
- 没有配置视图解析器,这样的话,Spring会默认使用BeanNameViewResolver;
- 没有启用组件扫描,这样的话,Spring只能找到显式声明在配置类中的控制器;
- Dispatcher会映射为应用的默认Servlet,它会处理所有的请求,包括静态资源的请求。
所以我们需要稍微调整一下上面的配置:
@Configuration
@EnableWebMvc
@ComponentScan("web")
public class WebConfig extends WebMvcConfigurerAdapter{
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configure) {
configure.enable();
}
}
可以看到,在这个配置类中,我们使用@EnableWebMvc启用Spring MVC&#