引用的博客:
1. 博客园的用户有爱JJ 的文章:浅谈SpringMMV中HandlerExecutionChain之handler、interceptor
https://blog.csdn.net/turbo_zone/article/details/84571477
2.csdn的用户 夜宿山寺的文章:Spring源码解析之HandlerMapping源码解析
https://blog.csdn.net/king_is_everyone/article/details/51446260
3. csdn的用户 小雨的光 的文章:SpringMVC源码-控制器Handler到底是个什么
https://blog.csdn.net/qq_28802119/article/details/82993266
参考博客:
来自csdn的用户 叹息你永远不懂我的心 的博客 SpringMVC handlerMapping映射过程记录
https://blog.csdn.net/lkx444368875/article/details/78949631
目录
1.3.2 HandlerMapping与HandlerAdapter的关系
前言:在前面的(一)中,我们已经接触过SpringMVC的框架以及配置器了,在这篇文章中,主要对这几个配置器进行深入的探究。
1.框架
1.1 框架结构
1.2 框架流程
第一步:用户发送请求到DispatcherSerlvet前端控制器
第二步:DispatcherServlet收到请求后调用HandlerMapping处理器映射器
第三步:HandlerMapping根据请求url找到对应的Handler,并将Handler跟HandlerInterceptor结合塞到HandlerExecutionChain,(拦截器handlerInterceptor不是必要的,可以没有)。注意这是一个链,可以有多个handler和handlerInterceptor(ps:这里不是调用Handler执行,只是根据url确定使用哪个Handler)。将HandlerExecutionChain返回给前端控制器
第四步:前端控制器将HandlerExecutionChain传递给HandlerAdapter,让HandlerAdapter调用对应的handler执行业务操作
第五步:HandlerAdapter收到HandlerExeecutionChain后使用getHandler()将Handle取出,执行Handler,有了适配器可以通过适配器去扩展对不同Handler执行方式(比如:原始servlet开发,注解开发)
第六步:Handler执行完毕生成ModelAndView,将ModelAndView返回给HandlerAdapter(ModelAndView: SpringMVC的一个对象,对model和view进行封装)
第七步:HandlerAdapter将ModelAndView返回给DispatcherSerlvet
第八步:DispatcherSerlvet调用ViewResolver视图解析器处理
第九步:ViewResolver视图解析器通过逻辑视图名称解析将ModelAndView解析为具体View ,并将View返回给DispatcherSerlvet(view:SpringMVC视图封装对象,提供了很多view,比如jsp、freemarker、pdf、execel.......)
第十步:DispatcherSerlvet调用View各自的方法渲染视图(即将模型数据填充至视图中)
第十一步:DispatcherSerlvet将渲染后的View返回给客户端
小结:可以看到在框架中,DispatcherSerlvet是绝对的主角,相当于大脑,进行各种调度。里面有几个明显的组件,我们得详细介绍一下
1.3 组件详解
在SpringMVC的各个组件中,其中需要程序员开发的组件有handler,view,DispatcherSerlvet(DispatcherSerlvet严格来说不算是我们开发,我们只是配置),用绿色标记;用黄色标记的是SpringMvc的三大组件
1.3.1详解
- DispatcherServlet(前端控制器)
用户请求第一步是先到达DispatcherSerlvet,它相当于mvc模式中的c,是整个流程控制的中心,由它调用其他组件来处理用户的请求。DispatcherServlet的存在降低了组件之间的耦合性
- Handler(处理器)
Handler是对请求进行处理的最小单位,一般为controller类的一个方法。(推荐看一下最上面的引用博客3)。
- HandlerMapping(处理器映射器)
HandlerMapping就是起到一个定位的作用,将你的url请求和对应的处理函数handler建立一个映射关系,这个映射关系以HandlerExectionChain的形式生成。换一个解释:HandlerMapping会把请求映射为HandlerExecutionChain类型的handler对象 ¹
要注意的是并没有HandlerMapping类,只有HandlerMapping接口,并且这个接口封装了唯一的方法getHandler(),返回值是HandlerExecuteChain(你会觉得为什么,为什么不直接是handler呢,看下面HandlerAdapter的两张图就知道了。因为HandlerExecutionChain还包含了HandlerIntercept,而且HandlerAdapter确实使用的是handler,但是这个handler是从HandlerExecutionChain取出来的)
这是HandlerMapping接口的简短解释
HandlerExecutionChain中包含了handler对象以及handler的interceptors拦截器
(不知道你们理解了没有,没理解的可以参考开头引用的1 2 两篇文章)
- HandlerAdapter(处理器适配器)
处理器适配器,调用相对应的handler处理用户的请求。而这个handler就是HandlerMapping里url映射的handler,在源码中是调用getHandlerAdapter(Handler handler),HandlerExectionChain
- View(视图)
最终显示的界面,springmvc框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。
- ViewResolver(视图解析器)
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户
1.3.2 HandlerMapping与HandlerAdapter的关系
可以参考博客园的用户 有爱jj的这篇博客:https://blog.csdn.net/turbo_zone/article/details/84571477
处理器映射器HandlerMapping,处理器适配器HandlerAdapter,视图解析器ViewResolver被称为SpringMVC的三大组件,接下来就是如何配置三大组件
1.4 配置三大组件
前面提到6个组件只有三个是我们自己编写配置的,那另外三个呢?其实这三个SpringMVC已经在自带的配置文件DispatcherServlet.properties中配置了
DispatcherServlet文件的位置
DispatcherSerlvet中三大组件的默认配置类型
但是在SpringMVC 3.1开始,就废除了这三个组件中默认的配置类型,因此需要我们自己配置。
下面的配置都是以注解方式进行配置
1.4.1 配置处理器映射器(注解式)
当你在springmvc.xml指定了映射器的种类为RequestMappingHandlerMapping(注解式处理器映射器)之后,通过@controller找到controller层,再通过@RequestMapping找到被映射的方法
根据@RequestMapping里定义的请求url匹配@RequestMapping标记的方法,匹配成功了返回一个HandlerExecutionChain给前端控制器。就是起到一个定位映射的作用,找到并保存url请求和handler(处理函数)间的mapping关系。
配置方法:
在springmvc.xml中
<!-- 配置处理器映射器HandlerMapping-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
1.4.2 配置处理器适配器
根据处理器映射器携带的url与handler的关系找到对应的handler,执行handler
配置方法:
在springmvc.xml中
<!--配置处理器适配器HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
ps:直接配置处理器映射器和处理器适配器比较麻烦,可以使用注解驱动来加载。SpringMVC使用<mvc:annotation-driven>自动加载RequestMappingHandlerMapping和RequestMappingHandlerAdapter
配置方法:
在springmvc.xml中
<!--配置驱动,代替配置处理器映射器和处理器适配器 -->
<mvc:annotation-driven/>
1.4.3 配置视图解析器
视图解析器使用SpringMVC框架默认的InternalResourceViewResolver,这个视图解析器支持JSP视图解析
配置方法:
在springmvc.xml中
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置逻辑视图的前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 配置逻辑视图的后缀 -->
<property name="suffix" value=".jsp" />
</bean>
与前面不同,这里在bean中添加了两个子标签property,用于配置bean的属性,里面填写的是逻辑视图的前缀和后缀。当你填写后,你在handler中添加视图时就不需要再加前缀和后缀了
比如在上一篇文章举的例子中,controller层的ItemController类的queryItemList()方法中。演示一下加了前缀,后缀以及未加的情况
@RequestMapping("/itemList.action")
public ModelAndView queryItemList() {
// 创建页面需要显示的商品数据
List<Item> list = new ArrayList<>();
list.add(new Item(1, "1华为 荣耀8", 2399, new Date(), "质量好!1"));
list.add(new Item(2, "2华为 荣耀8", 2399, new Date(), "质量好!2"));
list.add(new Item(3, "3华为 荣耀8", 2399, new Date(), "质量好!3"));
list.add(new Item(4, "4华为 荣耀8", 2399, new Date(), "质量好!4"));
list.add(new Item(5, "5华为 荣耀8", 2399, new Date(), "质量好!5"));
list.add(new Item(6, "6华为 荣耀8", 2399, new Date(), "质量好!6"));
// 创建ModelAndView,用来存放数据和视图
ModelAndView modelAndView = new ModelAndView();
// 设置数据到模型中
modelAndView.addObject("itemList", list);
// 设置视图jsp,需要设置视图的物理地址
// modelAndView.setViewName("/WEB-INF/jsp/itemList.jsp");
// 配置好视图解析器前缀和后缀,这里只需要设置逻辑视图就可以了。
// 视图解析器根据前缀+逻辑视图名+后缀拼接出来物理路径
modelAndView.setViewName("itemList");
return modelAndView;
}