1、MVC 模式

2、SpringMVC常用注解

@Controller

声明该类为SpringMVC中的Controller

@RequestMapping

用于映射Web请求,包括访问路径和参数(类或方法上)

@ResponseBody

支持将返回值放在response内,而不是一个页面,通常用户返回json数据(返回值旁或方法上)

@RequestBody

允许request的参数在request体中,而不是在直接连接在地址后面。(放在参数前)

@PathVariable

用于接收路径参数,比@RequestMapping(“/hello/{name}”)申明的路径,将注解放在参数中前,即可获取该值,通常作为Restful的接口实现方法。

@RestController

该注解为一个组合注解,相当于@Controller和@ResponseBody的组合,注解在类上,意味着,该Controller的所有方法都默认加上了@ResponseBody。

@ControllerAdvice

通过该注解,我们可以将对于控制器的全局配置放置在同一个位置,注解了@Controller的类的方法可使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上, 这对所有注解了 @RequestMapping的控制器内的方法有效。

@ExceptionHandler

用于全局处理控制器里的异常

@InitBinder

用来设置WebDataBinder,WebDataBinder用来自动绑定前台请求参数到Model中。

@ModelAttribute

本来的作用是绑定键值对到Model里,在@ControllerAdvice中是让全局的@RequestMapping都能获得在此处设置的键值对。

@EnableWebMvc

在配置类中开启Web MVC的配置支持,如一些ViewResolver或者MessageConverter等,若无此句,重写WebMvcConfigurerAdapter方法(用于对SpringMVC的配置)。

3、SpringMVC中9个初始化对象

public class DispatcherServlet extends FrameworkServlet { 
    ......
    protected void initStrategies(ApplicationContext context) {
        //用于处理文件上传服务  文件解析器
        this.initMultipartResolver(context);
        //用于处理应用的国际化问题,本地化解析策略。
        this.initLocaleResolver(context);
        //用于定义一个主题
        this.initThemeResolver(context);
        //用于建立请求与控制器之间的映射关系
        this.initHandlerMappings(context);
        //用于根据Handler的类型定义不同的处理规则
        this.initHandlerAdapters(context);
        //当Handler处理出错后,会通过此将错误日志记录在log文件中,
        //默认实现类是SimpleMappingExceptionResolver。
        this.initHandlerExceptionResolvers(context);
        //将指定的ViewName按照定义的RequestToViewNameTranslators替换成想要的格式。
        this.initRequestToViewNameTranslator(context);
        //用于将View解析成页面。
        this.initViewResolvers(context);
        //用于生成FlashMap管理器。
        this.initFlashMapManager(context);
    }
}

4、映射器HandlerMapping与适配器HandlerAdapter

  1. HandlerMapping 负责建立请求与控制器之间的映射关系

  • RequestMappingHandlerMapping (与 @RequestMapping 匹配)

  • WelcomePageHandlerMapping    (/)

  • BeanNameUrlHandlerMapping    (与 bean 的名字匹配 以 / 开头)

  • RouterFunctionMapping        (函数式 RequestPredicate, HandlerFunction)

  • SimpleUrlHandlerMapping      (静态资源 通配符 / /img/)

  • 之间也会有顺序问题, boot 中默认顺序如上

  1. HandlerAdapter 负责实现对各种各样的 handler 的适配调用

  • RequestMappingHandlerAdapter 处理:@RequestMapping 方法

  • 参数解析器、返回值处理器体现了组合模式

  • SimpleControllerHandlerAdapter 处理:Controller 接口

  • HandlerFunctionAdapter 处理:HandlerFunction 函数式接口

  • HttpRequestHandlerAdapter 处理:HttpRequestHandler 接口 (静态资源处理)

  • 这也是典型适配器模式体现

5、SpringMVC拦截器

SpringMVC中的拦截器需要实现HandlerInterceptor

SpringMVC中的拦截器有三个抽象方法:

preHandle:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true 为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法

postHandle:控制器方法执行之后执行postHandle()

afterComplation:处理完视图和模型数据,渲染视图完毕之后执行afterComplation()

6、SpringMVC的运行流程

  • DispatcherServlet:前端控制器,不需要工程师开发,由框架提供

作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求

  • HandlerMapping:处理器映射器,不需要工程师开发,由框架提供

作用:根据请求的url、method等信息查找Handler,即控制器方法

  • Handler:处理器,需要工程师开发

作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理

  • HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供

作用:通过HandlerAdapter对处理器(控制器方法)进行执行

  • ViewResolver:视图解析器,不需要工程师开发,由框架提供

作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、RedirectView

  • View:视图

作用:将模型数据通过页面展示给用户

7、原理&运行过程细节

当浏览器发送一个请求 http://localhost:8080/hello 后,请求到达服务器,其处理流程是:

  1. 服务器提供了 DispatcherServlet,它使用的是标准 Servlet 技术

  • 路径:默认映射路径为 /,即会匹配到所有请求 URL,可作为请求的统一入口,也被称之为前控制器

  • jsp 不会匹配到 DispatcherServlet

  • 其它有路径的 Servlet 匹配优先级也高于 DispatcherServlet

  • 创建:在 Boot 中,由 DispatcherServletAutoConfiguration 这个自动配置类提供 DispatcherServlet 的 bean

  • 初始化:DispatcherServlet 初始化时会优先到容器里寻找各种组件,作为它的成员变量

  • HandlerMapping,初始化时记录映射关系

  • HandlerAdapter,初始化时准备参数解析器、返回值处理器、消息转换器

  • HandlerExceptionResolver,初始化时准备参数解析器、返回值处理器、消息转换器

  • ViewResolver

  1. DispatcherServlet 会利用 RequestMappingHandlerMapping 查找控制器方法

  • 例如根据 /hello 路径找到 @RequestMapping("/hello") 对应的控制器方法

  • 控制器方法会被封装为 HandlerMethod 对象,并结合匹配到的拦截器一起返回给 DispatcherServlet

  • HandlerMethod 和拦截器合在一起称为 HandlerExecutionChain(调用链)对象

  1. DispatcherServlet 接下来会:

  2. 调用拦截器的 preHandle 方法

  3. RequestMappingHandlerAdapter 调用 handle 方法,准备数据绑定工厂、模型工厂、ModelAndViewContainer、将 HandlerMethod 完善为 ServletInvocableHandlerMethod

  • @ControllerAdvice 全局增强点1️⃣:补充模型数据

  • @ControllerAdvice 全局增强点2️⃣:补充自定义类型转换器

  • 使用 HandlerMethodArgumentResolver 准备参数

  • @ControllerAdvice 全局增强点3️⃣:RequestBody 增强

  • 调用 ServletInvocableHandlerMethod

  • 使用 HandlerMethodReturnValueHandler 处理返回值

  • @ControllerAdvice 全局增强点4️⃣:ResponseBody 增强

  • 根据 ModelAndViewContainer 获取 ModelAndView

  • 如果返回的 ModelAndView 为 null,不走第 4 步视图解析及渲染流程

  • 例如,有的返回值处理器调用了 HttpMessageConverter 来将结果转换为 JSON,这时 ModelAndView 就为 null

  • 如果返回的 ModelAndView 不为 null,会在第 4 步走视图解析及渲染流程

  1. 调用拦截器的 postHandle 方法

  2. 处理异常或视图渲染

  • 如果 1~3 出现异常,走 ExceptionHandlerExceptionResolver 处理异常流程

  • @ControllerAdvice 全局增强点5️⃣:@ExceptionHandler 异常处理

  • 正常,走视图解析及渲染流程

  1. 调用拦截器的 afterCompletion 方法