经过前面的 AOP
(面向切面编程) 和 Transaction
(事务管理),这次来到了 MVC
(Web 应用,进行请求分发和处理)
Spring MVC 定义:
分离了控制器(Controller)、模型(Model)、分配器(Adapter)、视图(View)和处理程序对象(Handler,实际上调用的是 Controller 中定义的逻辑)。
基于 Servlet 功能实现,通过实现了 Servlet 接口的 DispatcherServlet 来封装其核心功能实现,通过将请求分派给处理程序,同时带有可配置的处理程序映射、视图解析、本地语言、主题解析以及上传文件支持。
同样老套路,本篇按照以下思路展开:
(1) 介绍如何使用
(2) 辅助工具类 ContextLoaderContext
(3) DispatcherServlet
初始化
(4) DispatcherServlet
处理请求
如何使用
代码结构如下:(详细代码可在文章末尾下载)
(1)配置 web.xml
在该文件中,主要配置了两个关键点:
1. contextConfigLocation
:使 Web
和 Spring
的配置文件相结合的关键配置
2. DispatcherServlet
: 包含了 SpringMVC
的请求逻辑,使用该类拦截 Web
请求并进行相应的逻辑处理
使用 IDEA
时,尽量选择默认条件和自动扫描加载 Web
配置文件,然后添加 tomcat
进行启动,具体配置请查阅 idea 创建java web项目ssm-gradle
(2) 配置 applicationContext.xml
可以在这里自定义想要加载的 bean
,或者设置数据库数据源、事务管理器等等 Spring
应用配置。
(3) 配置 spring-mvc.xml
使用了 InternalResourceViewResolver
,它是一个辅助 Bean
,这样配置的意图是:
在 ModelAndView
返回的视图名前加上 prefix
指定的前缀和 suffix
的后缀(我理解为用来解析和返回视图,以及将视图层进行统一管理,放到指定路径中)
(4) 创建 BookController
可以看出,与书中示例并不一样,使用的是更贴合我们实际开发中用到的 @RequestMapping
等注解作为例子。根据请求的 URL
路径,匹配到对应的方法进行处理。
(5) 创建 jsp
文件
按照现在前后端分离的大趋势,我其实并不想用 jsp
视图技术作为例子,但考虑到之前入门时也接触过,也为了跟我一样不会写前端的同学更好理解,所以还是记录一下如何使用 jsp
。
(6) 添加依赖 build.gradle
// 引入 spring-web 和 spring-webmvc,如果不是跟我一样使用源码进行编译,请到 mvn 仓库中寻找对应依赖 optional(project(":spring-web")) optional(project(":spring-webmvc")) // 引入这个依赖,使用 jsp 语法 https://mvnrepository.com/artifact/javax.servlet/jstl compile group: 'javax.servlet', name: 'jstl', version: '1.2'
(7) 启动 Tomcat
如何配置和启动,网上也有很多例子,参考资料 3 是个不错的例子,下面是请求处理结果:
http://localhost:8080/bookView (使用了 JSP 视图进行渲染)
http://localhost:8080/plain/value (前后端分离的话,常用的是这种,最后可以返回简单字符或者 json 格式的对象等)
在刚才的 web.xml
中有两个关键配置,所以现在学习下这两个配置具体是干啥的。
ContextLoaderContext
作用:在启动 web
容器时,自动装载 ApplicationContext
的配置信息。
下面是它的继承体系图:
这是一个辅助工具类,可以用来传递配置信息参数,在 web.xml
中,将路径以 context-param
的方式注册并使用 ContextLoaderListener
进行监听读取。
从图中能看出,它实现了 ServletContextListener
这个接口,只要在 web.xml
配置了这个监听器,容器在启动时,就会执行 contextInitialized(ServletContextEvent)
这个方法,进行应用上下文初始化。
public void contextInitialized(ServletContextEvent event) { initWebApplicationContext(event.getServletContext()); }
每个 Web
应用都会有一个 ServletContext
贯穿生命周期(在应用启动时创建,关闭时销毁),跟 Spring
中 ApplicationContext
类似,在全局范围内有效。
实际上初始化的工作,是由父类 ContextLoader
完成的:(简略版)
该函数主要是体现了创建 WebApplicationContext
实例的一个功能架构,实现的大致步骤如下:
1. WebApplicationContext
存在性的验证:
只能初始化一次,如果有多个声明,将会扰乱 Spring
的执行逻辑,所以有多个声明将会报错。
2. 创建 WebApplicationContext
实例:
createWebApplicationContext(servletContext);
如果按照默认策略,它将会从配置文件 ContextLoader.properties
中读取需要创建的实现类:XmlWebApplicationContext
3. 将实例记录在 servletContext
中
4. 映射当前的类加载器与创建的实例到全局变量 currentContextPerThread
中
通过以上步骤,完成了创建 WebApplicationContext
实例,它继承自 ApplicaitonContext
,在父类的基础上,追加了一些特定于 web
的操作和属性,可以把它当成我们之前初始化 Spring
容器时所用到的 ClassPathApplicaitonContext
那样使用。