最近在学习SpringMVC,想写点东西记录以备以后查阅,感觉还少点什么,迟迟未动手;今天看到这位仁兄的Blog:http://86asm.iteye.com/blog/932564写的挺好,于是在他的基础上添加些自己的东西;
SpringMVC框架的核心构件
1、Dispatcher Servlet
2、Controller
3、Handler Mapping
4、ViewResolver & View
5、Interceptors
6、LocalResolver
7、Validate
SpringMVC框架实现的功能
1. 以Controller为中心完成对系统流程的控制管理
2. 对请求数据的收集
3. 对传入的参数进行验证
4.更加请求调用相应的业务逻辑完成数据处理
5. 将处理结果返回给试图
6. 国际化的支持
7. 提供不同视图的支持方案
8. 标签库
9. 拦截器
10. 对文件上传、下载的支持
Spring MVC的原理框图
整个处理过程从一个HTTP请求开始:
1)DispatcherServlet接收到请求后,根据对应配置文件中配置的处理器映射,找到对应的处理器映射项(HandlerMapping),根据配置的映射规则,找到对应的处理器(Handler)。
2)调用相应处理器中的处理方法,处理该请求,处理器处理结束后会将一个ModelAndView类型的数据传给DispatcherServlet,这其中包含了处理结果的视图和视图中要使用的数据。
3)DispatcherServlet根据得到的ModelAndView中的视图对象,找到一个合适的ViewResolver(视图解析器),根据视图解析器的配置,DispatcherServlet将视图要显示的数据传给对应的视图,最后给浏览器构造一个HTTP响应。
DispatcherServlet是整个Spring MVC的核心。它负责接收HTTP请求组织协调Spring MVC的各个组成部分。其主要工作有以下三项:
1)截获符合特定格式的URL请求。
2)初始化DispatcherServlet上下文对应的WebApplicationContext,并将其与业务层、持久化层的WebApplicationContext建立关联。
3)初始化Spring MVC的各个组成组件,并装配到DispatcherServlet中。
在SpringMVC三层架构的解决方案中,模型层和控制层的实现类都在配置文件中配置,控制层的代码可以通过Spring的依赖注入直接调用模型层的代码,降低了控制层代码编写的难度和两层之间的耦合度。Spring框架中使用的Singleton设计模式大大减少了创建的模型层类实例的数量,提高了程序运行的速度。Spring支持多种视图实现,比如tiles、jsp、velocity、freemaker等,在视图层Spring使用一个单独的配置文件控制视图的实现。控制层和视图层解偶,使得改变数据的显示方式变得容易。
DispatcherServlet是怎么把请求映射到对应的处理器上的?
Spring MVC中的DispatcherServlet收到一个请求后经过HandlerMapping会得到一个处理器链(HandlerExecutionChain)对象。它包括了处理这个请求的处理器和若干个对请求进行拦截处理的拦截器(HandlerInterceptor)。
处理器链的工作原理如下图:
通过图示我们可以发现,处理器链在处理请求的时候首先要经过所有的拦截器,然后通过HandlerAdapter来执行处理器。
HandlerExecutionChain定义了如下的两个接口方法:
Object getHandler():返回处理请求的处理器对象。
HandlerInterceptor[] getInterceptors():返回处理器调用前后的拦截器数组。
拦截器HandlerInterceptor接口定义了如下3个方法:
boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler):在请求到达Handler之前,先执行这个前置方法。
void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView):在请求被处理器执行后执行。
void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex):在相应被渲染后执行。
HandlerAdapter接口定义如下:
ModelAndView handle(HttpServletRequest request,HttpServletResponse response,Object handler):使用处理器处理请求。
boolean supports(Object handler):判断处理器适配器是否支持这个Handler类型。
下面我们回过头来再来了解一下HandlerMapping。HandlerMapping的作用就是根据请求产生一个HandlerExecutionChain。具有如下几个属性:
interceptors:拦截器列表。
defaultHandler:默认处理器。
order:处理器的优先级。
alwaysUseFullPath:boolean类型,用于设定映射是绝对路径还是相对路径。默认值为false,相对路径。
urlPathHelper:指定分析URL时的UrlPathhelper。
---------------------------------------------------------------------------------
如果这位仁兄有异议,告知 必删之!
引言
1.MVC :Model-View-Control
框架性质的C 层要完成的主要工作:封装web 请求为一个数据对象、调用业务逻辑层来处理数据对象、返回处理数据结果及相应的视图给用户。
2. 简要概述springmvc
Spring C 层框架的核心是 DispatcherServlet,它的作用是将请求分发给不同的后端处理器,也即 使用了一种被称为Front Controller 的模式(后面对此模式有简要说明)。 Spring 的C 层框架使用了后端控制器来、映射处理器和视图解析器来共同完成C 层框架的主要工作。并且spring 的C 层框架还真正地把业务层处理的数据结果和相应的视图拼成一个对象,即我们后面会经常用到的ModelAndView 对象。
一、入门实例
1. 搭建环境
在spring 的官方API 文档中,给出所有包的作用概述,现列举常用的包及相关作用:
org.springframework.aop-3.0.5.RELEASE.jar :与Aop 编程相关的包
org.springframework.beans-3.0.5.RELEASE.jar :提供了简捷操作bean 的接口
org.springframework.context-3.0.5.RELEASE.jar :构建在beans 包基础上,用来处理资源文件及国际化。
org.springframework.core-3.0.5.RELEASE.jar :spring 核心包
org.springframework.web-3.0.5.RELEASE.jar :web 核心包,提供了web 层接口
org.springframework.web.servlet-3.0.5.RELEASE.jar :web 层的一个具体实现包,DispatcherServlet也位于此包中。
后文全部在spring3.0 版本中进行,为了方便,建议在搭建环境中导入spring3.0 的所有jar 包(所有jar 包位于dist 目录下)。
2. 编写HelloWorld 实例
步骤一、建立名为springMVC_01_helloword ,并导入上面列出的jar 包。
步骤二、编写web.xml 配置文件,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>spmvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!--
建立 spmvc-servlet.xml 文件,它的命名规则: servletname-servlet.xml,这样web.xml文件就会自动加载spmvc-servlet.xml
否则就要手动加载:
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/config/spring/webmvc-config.xml
</param-value>
</init-param>
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
简要说明 :DispatcherServlet 就是一个Servlet ,也是对请求进行转发的核心Servlet 。在这里即所有.do 的请求将首先被DispatcherServlet 处理,而DispatcherServlet 它要作的工作就是对请求进行分发(也即是说把请求转发给具体的Controller )。可以简单地认为,它就是一个总控处理器,但事实上它除了具备总控处理理器对请求进行分发的能力外,还与spring 的IOC 容器完全集成在一起,从而可以更好地使用spring 的其它功能。在这里还需留意 < servlet-name > spmvc </ servlet-name > ,下面步骤三会用到。
步骤三、建立 spmvc-servlet.xml 文件,它的命名规则: servlet-name-servlet.xml 。它的主要代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- URL Mapping -->
<bean id="simpleUrlHandlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/helloWorld.do">helloController</prop>
</props>
</property>
</bean>
<bean id="helloController" class="com.wy.controller.HelloWorldController"></bean>
<!-- 视图解析 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
说明: hello.do 的请求将给名为 helloControl 的 bean 进行处理。
步骤四、完成 HelloWordController.java 的编写,代码如下:
package com.wy.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class HelloWordController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView mav = new ModelAndView("hello.jsp");
mav.addObject("message", "Hello World!");
return mav;
}
}
说明 :ModelAndView 对象是包含视图和业务数据的混合对象,即是说通过此对象,我们可以知道所返回的相应页面(比如这里返回hello.jsp 页面),也可以在相应的页面中获取此对象所包含的业务数据(比如这里message-hello worrld )。
步骤五、在当前项目web 根目录下编写hello.jsp ,主要代码如下:
< body >
世界,你好!
获取值: ${message }
</ body >
步骤六:输入 .../hello.do 进行测试。
4. 简析spring mvc 工作原理
(1 )启动服务器,根据web.xml 的配置加载前端控制器(也称总控制器) DispatcherServlet 。在加载时、会完成一系列的初始化动作。
(2 )根据servlet 的映射请求(上面的helloWorld 实例中针对.do 请求),并参照“控制器配置文件”(即spmvc-servlet.xml 这样的配置)文件,把具体的请求分发给特定的后端控制器进行处理(比如上例会分发给HelloWorld 控制器进行处理)
(3 )后端控制器调用相应的逻辑层代码,完成处理并返回视图对象( ModelAndView )给前端处理器。
(4 )前端控制器根据后端控制器返回的 ModelAndView 对象,并结合一些配置(后面有说明),返回一个相应的页面给客户端。
小结 :这种Front Controller 模式常应用在主流的web 框架中,比如典型的struts1.x 框架.Front Controller 模式:所有请求先交给一个前端处理器(总控处理器)处理,然后前端处理器会参照一些配置文件再把具体的请求交给相应的后端处理器。后端处理器调用逻辑层代码,并根据逻辑返回相应的视图对象给前端控制器。然后前端控制器再根据视图对象返回具体的页面给客户端(提示:和spring mvc 一样,在struts1.x 中前端控制器是Servlet, 而在struts2 中前端控制器是Filter )。
概述 Front Controller 模式:前端控制器预处理并分发请求给后端控制器,后端控制器进行真正的逻辑处理并返回视图对象,前端控器器根据视图对象返回具体页面给客户端。
5. 初识spring mvc 的视图
在前面的HelloWorld 实例中,在HelloWorld.java 中返回 ModelAndView mav = new ModelAndView( "hello.jsp" ) 参数为 hello.jsp ,它会对应于当前项目根目录下的 hello.jsp 页面。但 spring mvc 为我们提供了一个特别的视图定位方式,下面改进前面的 HelloWord 实例:
改进一 :在 spmvc-servlet.xml 中增加如下代码:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/" />
<property name="suffix" value=".jsp" />
</bean>
改进二 :在HelloWorld.java 重新定义返回的 ModelAndView 对象,即把 ModelAndView mav = new ModelAndView( "hello.jsp" ) 改为 ModelAndView mav = new ModelAndView( "hello" )
改进三 :在/WEB-INF/page 目录下建立hello.jsp 页面
进行上面三个改进操作后,重新访问hello.do 会访问到WEB-INF/page/hello.jsp 页面。
简析视图定位 :当返回 ModelAndView 对象名称为hello 时,会给hello 加上前后缀变成
/WEB-INF/page/hello.jsp 。因此在给前后缀赋值时,应特别注意它和返回的 ModelAndView 对象能否组成一个正确的文件全路径。在前面的“简析spring mvc 工作原理(4) ”点中提到在根据ModelAndView 对象返回页面时,会结合一些配置。这里就是结合了视图定位方式,给viewName 加上前后缀进行定位。