一、原理
Spring MVC基于模型-视图-控制器(Model-View-Controller,MVC)模式实现,它能够帮你构建像Spring框架那样灵活和松耦合的Web应用程序,将请求处理的逻辑和视图中的渲染实现解耦。
1、DispatcherServlet是Spring MVC的核心 。Spring MVC 中的请求页面都会委托给DispatcherServlet来执行处理。
2、DispatcherServlet需要知道将请求发送给哪个控制器,所以DispatcherServlet会查询一个或多个处理器映射(handler mapping) 来确定请求的下一站在哪里。
3、到了控制器(controller),请求会卸下其负载(用户提交的信息)并耐心等待控制器处理这些信息。
4、控制器在处理完成后,通常会产生一些信息,这些信息称为模型(model)。但是这个模型到底是渲染哪个页面的呢?所以控制器还会返回视图相关的东西。Spring 有个思想就是前后端分离,为了和视图解耦,所以控制器只返回了视图名。即,这里控制器返回了模型和视图名(modelAndViews)。
tips:Model 实际上就是一个Map(也就是key-value对的集合),它会传递给视图,这样数据就能渲染到客户端了,当调用addAttribute()方法并且不指定key的时候,那么key会根据值的对象类型推断确定,比如 List<Spittle>,那么推断他的 key 就是 spittleList。如果你希望使用非Spring类型的话,那么可以用java.util.Map来代替Model。
5、MVC 要怎么依靠一个视图名找到对应的视图呢?答案就是 视图解析器(view resolver)。
6、视图解析器(ViewResolver )接口会根据试图名和Locale对象返回一个View实例。View 接口的任务就是接受Model 以及Servlet的request和response对象,并将输出结果渲染到response中。
7、视图 (比如 JSP)。最终会被相应的容器(比如Tomcat)解析成 HTML 页面,并响应用户的请求。
tips:实际上,设计良好的控制器本身只处理很少甚至不处理工作,而是将业务逻辑委托给一个或多个服务对象进行处理。
二、使用 Java 配置
按照传统的方式,像 DispatcherServlet 这样的Servlet会配置在web.xml文件中 ,但是,借助于Servlet 3规范和Spring 3.1的功能增强,这种方式已经不是唯一的方案了 。我们会使用Java将DispatcherServlet配置在Servlet容器中。开始前,我们先来理解下 DispatcherServlet 和 Servlet 监听器(也就是ContextLoaderListener) 这两个应用上下文 。
DispatcherServlet 上下文:当DispatcherServlet启动的时候,它会创建Spring应用上下文,并加载配置文件或配置类(即带有@configuration注解的配置类)中所声明的bean,主要是Web 组件中的 bean, 包括 控制器(controller)、映射器(handler mapping)、视图解析器(view resolver)等。
ContextLoaderListener 上下文:这个上下文 由 ContextLoaderListener 创建,主要负责加载应用中的其他 bean 。这些bean通常是驱动应用后端的中间层和数据层组件。
1、实现:
我们通过继承 AbstractAnnotationConfigDispatcherServletInitializer 类来配置SpringMVC,以作为传统 XML 配置的替代方案。实际上,AbstractAnnotationConfigDispatcherServletInitializer 会 同时创建 DispatcherServlet 和 ContextLoaderListener 。当然,我们需要手动配置我们的映射路径、视图解析器 并启用组件扫描 以及一系列我们可以自定义的配置。当然,如果我们没有配置视图解析器,SpringMVC 会启用默认的视图解析器(通过查找 ID 与视图名称相匹配的Bean,并且这个Bena 要实现View 接口)。如果没有配置路径映射,DispatcherServlet会映射为应用的默认Servlet,所以它会处理所有的请求,包括对静态资源的请求,如图片和样式表等。
public class SplittrWebAppInitailzer extends AbstractAnnotationConfigDispatcherServletInitializer { /*返回会创建ContextLoaderListener 上下文*/ @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[]{RootConfig.class}; } /*返回会创建 DispatcherServlet 上下文*/ @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[]{WebConfig.class}; } /*配置路径映射*/ @Override protected String[] getServletMappings() { return new String[]{"/"}; } }