说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正。若在阅读时有任何的问题,也可通过评论提出,本人将根据自身能力对问题进行一定的解答。
手撸Spring系列是笔者本人首次尝试的、较为规范的系列博客,将会围绕Spring框架分为IOC/DI 思想
、Spring MVC
、AOP 思想
、Spring JDBC
四个模块,并且每个模块都会分为理论篇
、源码篇
、实战篇
三个篇章进行讲解(大约12篇文章左右的篇幅)。从原理出发,深入浅出,一步步接触Spring源码并手把手带领大家一起写一个 迷你版的Spring框架 ,促进大家进一步了解Spring的本质!
由于源码篇涉及到源码的阅读,可能有小伙伴没有成功构建好Spring源码的阅读环境,笔者强烈建议:想要真正了解Spring,一定要构建好源码的阅读环境再进行研究,具体构建过程可查看笔者此前的博客:《如何构建Spring5源码阅读环境》
前言
手撸Spring系列经过前面四篇的讲解,IOC/DI
已经是告一段落了。接下来笔者将继续向各位读者朋友们讲述Spring另一大模块Spring MVC
!!
Spring MVC 处理流程
Spring MVC 处理流程如下:
- 用户发送
request
请求到前端控制器DispatcherServlet
。 - 前端控制器
DispatcherServlet
通过request
请求的url
地址,向映射器HandlerMapping
请求调用对应的处理器handler
。 - 映射器
HandlerMapping
通过url
地址生产处理器执行链并返回。 DispatcherServlet
根据处理器Handler获取处理器适配器HandlerAdapter
执行HandlerAdapter
处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作。- 适配器执行处理器,即执行
Controller
中的方法。 - 处理器完成业务逻辑后返回
ModelAndView
。 - 适配器将处理器的处理结果返回给前端控制器
DispatcherServlet
。 - 将
ModelAndView
中的view名称传给viewReslover
。 viewReslover
通过view名称返回具体的view
。- 将
ModelAndView
中的model
注入到view
。 - 将最终经过视图渲染的
view
页面响应给用户。
Spring MVC 九大组件
以下九大组件的介绍摘抄自书籍:《Spring 5 核心原理》——谭勇德(Tom)
1.HandlerMapping
HandlerMapping
是用来查找Handler
的,也就是查找处理器,具体的表现形式可以是类,也可以是方法。比如,标注了@RequestMapping
的每个方法都可以看成一个Handler
。Handler负责实际的请求处理,在请求到达后,HandlerMapping
的作用便是找到请求相应的处理器Handler
和Interceptor
。
2.HandlerAdapter
从名字上看,HandlerAdapter
是一个适配器。因为Spring MVC 中Handler
可以是任何形式的,只要是能够处理请求便可。但是把请求交给Servlet
的时候,由于Servlet的方法结构都是doService(HttpServletRequest req, HttpServletResponse resp)
形式的,要让固定的Servlet处理方法调用Handler
来进行处理,这一步工作便是HandlerAdaptter
要做的事。
3.HandlerExceptionResolver
从组件的名字上看,HandlerExceptionResolver
是用来处理Handler
产生的异常情况的组件。具体来说,此组件的作用事根据异常设置ModelAndView
,之后交给渲染方法进行渲染,渲染方法会将ModelAndView
渲染成页面。不过要注意,HandlerExceptionResolver
只用于解析对请求做处理阶段产生的异常,渲染阶段的异常不归他管,这也是Spring MVC 组件设计的一大原则——分工明确、互不干涉。
4.ViewResolver
ViewResolver
即视图解析器,相信大家对这个组件应该很熟悉了。通常在Spring MVC 的配置文件中,都会配上一个实现类来进行视图解析。这个组件的主要作用是将String
类型的视图名称和Locale
解析为View
类型的视图,只有一个resolveViewName()
方法。从方法的定义可以看出,Controller
层返回的String
类型的视图名viewName
最终会在这里被解析成为View
。View是用来渲染页面的,也就是说,他会将程序返回的参数和数据填入模板中,生成HTML
文件。ViewResolver
在这个过程中主要做两件大事:ViewResolver会找到渲染所用的模板(第一件大事)和所用的技术(第二件大事,其实也即是找到视图的类型,如JSP)并填入参数。默认情况下,Spring MVC 会为我们自动配置一个InternalResourceViewResolver
,是针对JSP类型视图的。
5.RequestToViewNameTranslator
RequestToViewNameTranslator组件的作用是从请求中获取ViewName
。因为iewResolver
根据ViewName
查找View
,但有的Handler
处理完成之后,没有设置View
,也没有设置ViewName
,便要通过哦这个组件来从请求中查找ViewName
。
6.LocaleResolver
ViewResolver
组件的resolveViewName()
方法需要两个参数,一个是视图名,另一个就是Locale
。参数Locale是从哪来的?这就是LocaleResolver
组件要做的事。LocaleResolver用于从请求中解析出Locale,比如在中国Locale
当然就是zh-CN
,用来表示一个区域。这个组件也是i18n
的基础。
7.ThemeResolver
从名字便可以看出,ThemeResolver
组件是用来解析主题的。主题就是样式、图片及他们所形成的显示效果的集合。Spring MVC 中一套主题对应一个properties
文件,里面存放着与当前主题相关的所有资源,如图片、CSS样式等。创建主题非常简单,只需要准备好资源,然后新建一个“主题名.properties”并将资源设置进去,放在classpath
下,之后便可以在页面中使用了。Spring MVC 中与主题有关的类有ThemeResolver
、ThemeSource
和Theme
。ThemeResolver负责从请求中解析出主题名,ThemeSource
则给了根据主题名找到具体的主题,其抽象也是Theme
,可以通过Theme来获取主题和具体的资源。
8.MultipartResolver
MultipartResolver
是一个大家很熟悉的组件,用于处理上传请求,通过将普通的请求包装成MultipartHttpServletRequest
来实现。MultipartHttpServletRequest可以通过getFile()
方法直接获得文件。如果上传多个文件,还可以调用getFileMap()
方法得到Map<FileName, File>
这样的结构。MultipartResolver的作用就是封装普通的请求,使其拥有文件上传功能。
9.FlashMapManager
说到FlashMapManager
组件,得先说一下FlashMap
。
FlashMap
用于重定向时得参数传递,比如在处理用户订单时,为了避免重复提交,可以处理完post
请求后重定向到一个get
请求,这个get
请求可以用来显示订单详细之类的信息。这样做虽然可以避免用户重新提交订单的问题,但在这个页面要显示订单的信息,这些数据从哪里获取呢?因为重定向是没有传递参数这一功能的,如果不想把参数写进URL
(其实也不推荐这么做,除了URL有长度限制,把参数都直接暴露也不安全),那么就可以通过FlashMap
来传递。只需要在重定向之前将要传递的数据写入请求(可以通过ServletRequestAttributes.getReauest()
方法获得)的属性OUTPUT_FLASH_MAP_ATTRIBUTE
中,这样在重定向之后的Handler
中Spring就会自动将其设置到Model
中,在显示订单信息的页面上就可以直接从Model
中获取数据。
FlashMapManager
就是用来管理FlashMap
的