一、简介
- springMVC 框架是 MVC 开发模式的一种解决方案, 同样按照 Model - View - Controller 三层架构 将 业务、视图、数据进行分离开发,在其中,springMVC 充当控制层
- springMVC 有一个前端控制器(或者叫 核心控制器 ,或者叫 分发器) DispatcherServlet,所有springMVC的设计都是围绕这个DispatcherServlet 展开的。
- springMVC的后端控制器通过三个组件配合完成:
- HandlerMapping(映射处理器)
- Controller(控制器)
- ViewResolver( 视图解析器)
下面通过一个示意图来解析一下springMVC的原理,以及理解一下框架的核心:DispatcherServlet
1、用户请求,请求被springMVC的 前端控制器DispatcherServlet捕获,
tip: 在这个DispatcherServlet中 (配置在web.xml中) , 有指定 springMVC 的配置文件(即图中的<servletName>-servlet.xml)
2、DispatcherServlet 对捕获的的URL进行解析,得到请求资源标识符(URI)。根据这个URI, 调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回
tip:这个简单的理解就是:DispatcherServlet将捕获的请求URL发送给映射处理器(HandlerMapping),HandlerMapping 去匹配 这个URL到后端控制器(Controller)的映射(为什么要去匹配?因为要去调用的具体的controller层方法啊,而这个映射过程配置在HandlerMapping中),最后把匹配的结果返回给了DispatcherServlet(这个理解没有去考虑其中的什么拦截器等等很多的细节,只是为了理解它的过程,大佬轻喷)
3、.DispatcherServlet根据获得的Handler(第二步返回的),选择一个合适的HandlerAdapter(适配器),执行相应的Controller。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)
4、提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
a 、 HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
b、 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
c 、 数据格式化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等
d 、 数据验证:验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
5、Handler执行完成后,向DispatcherServlet返回一个ModelAndView对象;
6、根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet;
7、 ViewResolver结合Model和View,来渲染视图
8、将渲染结果返回给客户端。
二、配置一个简单的springMVC实现
第一步:导jar包(框架就是这样,导各种的jar,写配置,然后去使用)
<dependencies>
<!--配置javaee相关jar 的依赖信息-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<!-- 指定jar包的作用范围,provided表示不打包,因为容器中有这个包,会冲突 -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.1.2</version>
</dependency>
<!--配置javaee相关jar 的依赖信息 结束-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.31</version>
</dependency>
<!-- springmvc的jar -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- springmvc依赖的jar -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<!-- mybatis的jar -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
</dependencies>
第二步:web.xml 中配置前端控制器(DispatcherServlet)
<servlet>
<description>配置springMVC 核心控制器, 作用:捕获用户请求</description>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 如果没有指定配置文件,默认回去 /WEB-INF 目录下寻找 <servletName>-servlet.xml 命名的文件,
像这里,默认会去寻找 /WEB-INF/dispatcherServlet-servlet.xml 文件
-->
<init-param>
<description>指定springMVC的配置文件</description>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!-- *.action表示捕获所有的以 .action 结尾的用户请求 -->
<url-pattern>*.action</url-pattern>
</servlet-mapping>
第三部:配置springMVC 的配置文件,这里上面配置的是 springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置 映射处理器 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello.action">helloSpringMVC</prop>
</props>
</property>
</bean>
<!-- 配置 后端控制器 (这里配置的是框架自带的控制器ParameterizableViewController) -->
<bean id="helloSpringMVC" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
<property name="viewName" value="login/login"></property>
</bean>
<!-- 配置 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
上面的配置中:
1、映射处理器中 prop 注入的值helloSpringMVC是后端处理器中bean的id,这样就匹配到了 用户请求 “hello.action” 时调用的controller,
2、这个controller中指定了视图的名称为 “login/login”,这个controller 会返回一个ModelAndView 对象 封装 处理的数据和视图的名称,
3、最后到视图处理器时,根据 ModelAndView 封装的数据和视图名称 来渲染视图 返回给用户,像这里,视图的名称是 "login/login" ,
在视图解析器中又指定了视图的前缀和后缀, 连接起来,就是一个完整的路径 "/login/login.jsp" ,即最后用户会跳转到这个 /login/login.jsp这个页面
运行的结果:
项目的结构:
实际的应用中,后端控制器肯定都是我们自己去编写的, 在自定义的控制器中去 封装视图的名称,调用业务逻辑方法处理请求并封装返回数据,这个在下一篇中再详细记录
最后贴一下简化版(流水账版)的springMVC的工作流程:
用户请求 ----> DispatcherServlet 捕获请求URL,解析得到请求资源标识符URI,调用映射处理器 ----> HandlerMapping(映射处理器,处理url到控制层程序的映射关系) ----> DispatcherServlet ----> HandlerAdapter ----> HandlerAdapter执行相应的 controller ,返回ModelAndView(封装返回数据和视图名称) ----> DispatcherServlet ----> ViewResolver(视图解析器,指定跳转的页面) ----> 响应到客户端(用户)