2.5 Spring MVC执行的流程

2.5 Spring MVC执行的流程

下面将对开发Spring MVC应用的过程进行总结,以让读者对Spring MVC有一个大致的了解。

2.5.1 Spring MVC应用的开发步骤

下面简单介绍 Spring MVC应用的开发步骤。

1 web.xml中定义前端控制器

web.xml文件中定义前端控制器DispatcherServlet来拦截用户请求。
由于Web应用是基于请求/响应架构的应用,所以不管哪个MVC Web框架,都需要在web.xml中配置该框架的核心ServletFilter,这样才可以让该框架介入Web应用。
例如,开发Spring MVC应用的第1步就是在web.xml文件中增加如下配置片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- 定义前端控制器 -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- springmvc-config.xml文件的路径 -->
<param-value>WEB-INF/springmvc-config.xml</param-value>
</init-param>
<!-- 项目启动时加载前端控制器 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 让spring mvc的前端控制器拦截的请求的模式 -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<!-- 拦截所有的请求 -->
<url-pattern>/</url-pattern>
</servlet-mapping>

2 定义包含表单数据的JSP页面

如果需要以POST方式提交请求,则定义包含表单数据的JSP页面。如果仅仅只是以GET方式发送请求,则无须经过这一步。

3 定义处理用户请求的Handle类

定义处理用户请求的Handle类,该类可以实现Controller接口或使用@Controller注解来实现。这一步也是所有MVC框架中必不可少的,因为这个DispatcherServlet就是MVC中的C,也就是前端控制器,该控制器负责接收请求,并将请求分发给对应的Handle类,该Handle类负责调用后台业务逻辑代码来处理请求。

创建Controller实例 调用其方法来处理请求

可能有读者会产生疑问: Controller并未接收到用户请求,它怎么能够处理用户的请求呢?
MVC框架的底层机制是:前端控制器DispatcherServlet接收到用户请求后,通常会对用户请求进行简单预处理,例如解析、封装参数等,然后通过反射来创建Controller实例,并调用Controller的指定方法来处理用户请求:

  • 如果是实现Controller接口的Controller,则调用的是handlRequest方法,
  • 如果是使用基于注解的控制器,则可以调用任意方法

如何知道创建哪个Controller接口的实例

这里又产生了一个问题:当Servlet拦截用户请求后,它如何知道创建哪个Controller接口的实例呢?
有两种解决方案:

  1. 利用xml配置文件:例如在xml配置文件中描述hello请求对应使用HelloController类。这就可以让MVC框架知道当接收到hello请求时要创建哪个Controller接口的实例。
  2. 利用注解:例如使用注解@Controller描述一个类,并使用注解@RequestMapping(value="/hello")描述hello请求对应的方法。这样也可以让MVC框架知道要创建哪个Controller接口的实例并调用哪个方法处理请求。

控制器分类

根据上面的介绍不难发现,在Spring MVC框架中,控制器实际上由两个部分组成:

  1. 即拦截所有用户请求和处理请求的通用代码都由前端控制器DispatcherServlet完成,
  2. 而实际的业务控制(调用后台业务逻辑代码,返回处理结果等)则由Controller处理。

4 配置Handle

使用xml配置Handle

Java领域的绝大部分MVC框架都非常喜欢使用xml文件来进行配置管理,这在以前是一种思维定势。即配置哪个请求对应哪个Controller,从而让前端控制器根据该配置来创建合适的Controller实例,并调用该Controller的业务控制方法。
例如,可以采用如下代码片段来配置Handle:

1
2
<!-- 配置Handle,映射"/hello"请求 -->
<bean name="/hello" class="org.fkit.controller.HelloController"/>

使用注解来配置Handle

Spring2.5之后,推荐使用注解来配置Handle:

1
2
3
4
5
6
7
8
9
10
package org.fkit.controller;
......
@Controller
public class HelloController
{
......
@RequestMapping(value = "/hello")
public ModelAndView hello(){......}
......
}

上面的配置片段指定如果用户请求URLhello,则使用org.fkit.controller.Hellocontroller来处理。现在几乎所有的MVC框架都使用”约定优于配置”的思想,也就是采用约定方式来规定用户请求地址和Handle之间的对应关系。

5 编写视图资源

Handle处理用户请求结束后,通常会返回一个ModelAndView对象,该对象中应该包含返回的视图名或视图名模型,这个视图名就代表需要显示的物理视图资源。如果Handle需要把一些数据传给视图资源,则可以通过模型对象实现。

经过上面5个步骤,即可基本完成一个Spring MVC处理流程的开发,也就是可以执行一次完整的请求→响应过程。

2.5.2 Spring MVC执行的流程

上一节所介绍的Spring MVC应用的开发流程实际上是按请求→响应的流程来开发的,下面通过一个流程图来介绍请求→响应的完整流程。图2.5显示了一次请求→响应的完整流程。
这里有一张图片

Spring MVC 请求响应工作流程

按安照图2.5中所标识的序号, Spring MVC请求→响应的完整工作流程如下

  1. 用户向服务器发送请求,请求被Spring的前端控制器DispatcherServlet截获。
  2. DispatcherServlet对请求URL(统一资源定位符)进行解析,得到URI(请求资源标识符)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象,包括Handler对象以及Handler对象对应的拦截器,这些对象会被封装到一个HandlerExecutionChain对象当中返回。
  3. DispatcherServlet根据获得的Handler,选择一个合适的HandlerAdapterHandlerAdapter会被用于处理多种Handler,调用Handler实际处理请求的方法,例如hello方法。
  4. 提取请求中的模型数据,开始执行Handler(也就是Controller)。在填充Handler的入参过程中,根据配置Spring将帮你做一些额外的工作:
  • 消息转换。将请求消息(如JSONXML等数据)转换成一个对象,将对象转换为指定的响应信息。
  • 数据转换。对请求消息进行数据转换,如String转换成IntegerDouble等。
  • 数据格式化。对请求消息进行数据格式化,如将字符串转换成格式化数字或格式化日期等。
  • 数据验证。验证数据的有效性(长度、格式等),验证结果存储到BindingResultError中。
  1. handler执行完成后,向DispatcherServlet返回一个ModelAndView对象, ModelAndView对象中应该包含视图名视图名模型.
  2. 根据返回的ModelAndView对象,选择一个合适的ViewResolver(视图解析器)返回给DispatcherServlet
  3. ViewResolver结合ModelView来渲染视图。
  4. 将视图渲染结果返回给客户端。

只需要开发Handler即可

以上8个步骤, DispatcherServletHandlerMappingHandlerAdapterViewResolver等对象协同工作,来完成Spring MVC请求→响应的整个工作流程,这些对象所完成的工作对于开发者来说都是不可见的,开发者并不需要关心这些对象是如何工作的,开发者只需要在Handler(也就是Controller)当中完成对请求的业务处理
提示关于DispatcherServletHandlerMappingHandlerAdapterViewResolver等对象协同工作的知识,对于还不了解Spring MVC的读者来说,可能会感觉很难理解,因为这一节的知识涉及Spring MVC的源代码和Spring MVC的设计思想,建议初学者学习完Spring MVC的知识之后再回过头来看本节的内容。