转载:http://blog.csdn.net/superdog007/article/details/25614039
http://blog.csdn.net/xtu_xiaoxin/article/details/8796499
http://blog.csdn.net/zxr85/article/details/5548588
一旦Http请求到来,DispatcherSevlet将负责将请求分发。DispatcherServlet可以认为是Spring提供的前端控制器,所有的请求都有经过它来统一分发。在DispatcherServlet将请求分发给Spring Controller之前,需要借助于Spring提供的HandlerMapping定位到具体的Controller。HandlerMapping能够完成客户请求到Controller之间的映射。其中,Spring为Controller接口提供了若干实现,例如Spring默认使用的BeanNameUrlHandlerMapping。还有,SimpleUrlHandlerMapping,CommonsPathMapHandlerMapping。Spring Controller将处理来自DispatcherServlet的请求,能够接受HttpServletRequest和HttpServletResponse。Spring为Controller接口提供了若干实现类,位于org.springframework.web.servlet.mvc包中。由于Controller需要为并发用户处理上述请求,因此实现Controller接口时,必须保证线程安全并且可重用。
一旦Controller处理完客户请求,则返回ModelAndView对象给DispatcherServlet前端控制器。ModelAndView中包含了模型(Model)和视图(View)。从宏观角度考虑,DispatcherServlet是整个Web应用的控制器;从微观角度考虑,Controller是单个Http请求处理过程中的控制器,而ModelAndView是Http请求过程中返回的模型和视图。前端控制器返回的视图可以是视图的逻辑名,或者实现了View接口的对象。View对象能够渲染客户响应结果。其中,ModelAndView中的模型能够供渲染View时使用。借助于Map对象能够存储模型。
如果ModelAndView返回的视图只是逻辑名,则需要借助Spring提供的视图解析器(ViewResoler)在Web应用中查找View对象,从而将响应结果渲染给客户。DispatcherServlet将View对象渲染出的结果返回个客户。
大概流程如下:
1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;
2. DispatcherServlet 对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象 (包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)
4. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
5. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
6. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;
7. ViewResolver 结合Model和View,来渲染视图
8. 将渲染结果返回给客户端。
Spring会创建一个全局的WebApplicationContext上下文,称为根上下文 (root WebApplicationContext),保存在 ServletContext 中,key是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE属性的值。可以使用工具类取出上下文:WebApplicationContextUtils.getWebApplicationContext(ServletContext);
DispatcherServlet是一个Servlet,可以同时配置多个,每个DispatcherServlet有一个自己的 WebApplicationContext上下文,这个上下文继承了根上下文中所有东西。 保存在ServletContext中,key是"org.springframework.web.servlet.FrameworkServlet.CONTEXT"+Servlet名称。当一个Request对象产生时,会把这个WebApplicationContext上下文保存在Request对象中,key是DispatcherServlet.class.getName() + ".CONTEXT"。可以使用工具类取出上下文:RequestContextUtils.getWebApplicationContext(request);DispatcherServlet的上下文是通过配置servlet的contextConfigLocation来加载的,默认实现是XmlWebApplicationContext。
DispatcherServlet的上下文仅仅是 Spring MVC的上下文,而Spring加载的上下文是通过ContextLoaderListener来加载的。一般spring web项目中同时会使用这两种上下文,前者仅负责MVC相关bean的配置管理(如ViewResolver、Controller、 MultipartResolver等),后者则负责整个spring相关bean的配置管理 (如相关Service、DAO等)。因此在/WEB-INF/[server-name]-servlet.xml中配置的Bean一般只针对Spring MVC有效,而在ContextLoaderListener配置文件下配置的bean则对整个spring有效。
如果通过 WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext) 来试图获取DispatcherServlet加载的applicationContext时,就会抛出"No WebApplicationContext found: no ContextLoaderListener registered?"的异常。
1: <?xml version="1.0" encoding="UTF-8"?>
2: <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3: xmlns="http://java.sun.com/xml/ns/javaee"
4: xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
5: http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
6:
7: id="WebApp_ID" version="3.0">
8: <display-name>mvc</display-name>
9:
10: <context-param>
11: <param-name>contextConfigLocation</param-name>
12: <param-value>/WEB-INF/applicationContext.xml</param-value>
13: </context-param>
14:
15: <!-- Spring 容器启动监听器 -->
16: <listener>
17: <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
18: </listener>
19:
20: <listener>
21: <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
22: </listener>
23:
24:
25: <!-- SpringMVC的核心控制器(前端控制器) -->
26: <servlet>
27: <servlet-name>springmvc</servlet-name>
28: <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
29: <!-- 指定配置文件的全名,如果不指定,则为这里的servlet-name的属性值+"-servlet.xml" -->
30: <init-param>
31: <param-name>contextConfigLocation</param-name>
32: <param-value>/WEB-INF/springmvc-servlet.xml</param-value>
33: </init-param>
34: <!-- 启动服务器时创建此serlvet核心对象 -->
35: <load-on-startup>1</load-on-startup>
36: </servlet>
37:
38: <servlet-mapping>
39: <servlet-name>springmvc</servlet-name>
40: <url-pattern>/</url-pattern>
41: </servlet-mapping>
42: </web-app>
1: <?xml version="1.0" encoding="UTF-8"?>
2: <beans xmlns="http://www.springframework.org/schema/beans"
3: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
4: xmlns:context="http://www.springframework.org/schema/context"
5: xmlns:mvc="http://www.springframework.org/schema/mvc"
6: xsi:schemaLocation="http://www.springframework.org/schema/beans
7: http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
8: http://www.springframework.org/schema/tx
9: http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
10: http://www.springframework.org/schema/context
11: http://www.springframework.org/schema/context/spring-context-3.0.xsd
12: http://www.springframework.org/schema/mvc
13: http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
14:
15: <!-- 自动扫描 -->
16: <context:component-scan base-package="com.zero.mvc.controller" />
17:
18: <mvc:annotation-driven />
19: <!-- <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"> </bean>
20: <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> </bean>
21: 自动注册DefaultAnnotationHandlerMapping与 AnnotationMethodHandlerAdapter
22: 两个bean, 是spring MVC为@Controllers分发请求所必须的。 并提供了数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,
23: 读写XML的支持(JAXB),读写JSON的支持(Jackson)
24: -->
25:
26: <!-- 控制器类,name表示访问的URI路径,class表示对应的action类 -->
27: <bean name="/welcome.html" class="com.zero.mvc.controller.WelcomeController"></bean>
28:
29: <!-- ViewResolver ,视图解析器,框架提供了好多解析器,这里举例其中的一种 -->
30: <bean
31: class="org.springframework.web.servlet.view.InternalResourceViewResolver">
32: <property name="prefix" value="/WEB-INF/jsp/"></property>
33: <property name="suffix" value=".jsp"></property>
34: <!--prefix+ view + suffix -->
35: </bean>
36:
37: <!-- 总拦截器,拦截所有url,用于处理权限 -->
38: <mvc:interceptors>
39: <bean class="com.zero.mvc.inteceptor.MyInteceptor" />
40: </mvc:interceptors>
41:
42: <!-- 总错误处理 -->
43: <bean id="exceptionResolver"
44: class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
45: <property name="defaultErrorView">
46: <value>error</value>
47: </property>
48: <property name="defaultStatusCode">
49: <value>500</value>
50: </property>
51: <property name="warnLogCategory">
52: <value>org.springframework.web.servlet.handler.SimpleMappingExceptionResolver
53: </value>
54: </property>
55: </bean>
56: </beans>
1: <?xml version="1.0" encoding="UTF-8"?>
2: <beans xmlns="http://www.springframework.org/schema/beans"
3: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
4: xmlns:mvc="http://www.springframework.org/schema/mvc"
5: xsi:schemaLocation="http://www.springframework.org/schema/mvc
6: http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
7: http://www.springframework.org/schema/beans
8: http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
9: http://www.springframework.org/schema/context
10: http://www.springframework.org/schema/context/spring-context-3.0.xsd">
11:
12: <!-- 注解扫描包 -->
13: <context:component-scan base-package="com.zero.mvc.vo" />
14:
15: <bean id="client" class="com.zero.mvc.vo.Client">
16: </bean>
17:
18: </beans>
1: package com.zero.mvc.controller;
2:
3: import javax.servlet.http.HttpServletRequest;
4: import javax.servlet.http.HttpServletResponse;
5:
6: import org.springframework.stereotype.Controller;
7: import org.springframework.ui.Model;
8: import org.springframework.web.bind.annotation.RequestMapping;
9: import org.springframework.web.bind.annotation.RequestMethod;
10: import org.springframework.web.bind.annotation.RequestParam;
11: import org.springframework.web.bind.annotation.ResponseBody;
12: import org.springframework.web.context.WebApplicationContext;
13: import org.springframework.web.context.support.WebApplicationContextUtils;
14: import org.springframework.web.servlet.support.RequestContextUtils;
15:
16: import com.zero.mvc.vo.Client;
17:
18: @Controller
19: @RequestMapping(value = "/hello", method = { RequestMethod.GET,
20: RequestMethod.POST })
21: public class MyController {
22: @RequestMapping("/hello1")
23: // 当url有 ?name=xxx 也没关系
24: public String print1(HttpServletRequest request) {
25: System.out.println("/hello1");
26: // 根上下文
27: WebApplicationContext ct1 = WebApplicationContextUtils
28: .getWebApplicationContext(request.getSession()
29: .getServletContext());
30:
31: // DispatcherServlet的WebApplicationContext上下文springmvc上下文
32: // DispatcherServlet的上下文仅仅是 Spring MVC的上下文
33: WebApplicationContext ct2 = RequestContextUtils
34: .getWebApplicationContext(request);
35: try {
36: System.out.println(111);
37: System.out.println(ct1);
38: System.out.println(ct1 == ct2);
39: System.out.println(ct1.containsBean("client"));
40: System.out.println(ct2.containsBean("client"));
41: } catch (Exception e) {
42: e.printStackTrace();
43: }
44: return "welcome";
45: }
46:
47: @RequestMapping("/hello2")
48: // url必须有 ?name=xxx
49: public String print2(@RequestParam("name") String name) {
50: System.out.println("/hello2");
51: System.out.println(name);
52: return "welcome";
53: }
54:
55: @RequestMapping("/hello3")
56: // url可有 ?name=xxx 也可没有
57: // 没有时name=null
58: public String print3(String name) {
59: System.out.println("/hello3");
60: System.out.println(name);
61: return "welcome";
62: }
63:
64: // 传值给前端
65: @RequestMapping(value = "/hello4")
66: public String print4(Model model) {
67: System.out.println("/hello3");
68: model.addAttribute("name", "zero");
69: // model.addAttribute(object);//直接以object的类型作为key
70: return "welcome";
71: }
72:
73: @RequestMapping(value = "/update")
74: @ResponseBody
75: public Client req(HttpServletRequest request, HttpServletResponse response) {
76: System.out.println("json");
77: Client client = new Client();
78: client.setAge(26);
79: client.setName("zero");
80: return client;
81: }
82: }
1: package com.zero.mvc.controller;
2:
3: import javax.annotation.Resource;
4:
5: import org.springframework.stereotype.Controller;
6: import org.springframework.web.bind.annotation.RequestMapping;
7: import org.springframework.web.bind.annotation.RequestMethod;
8:
9: import com.zero.mvc.vo.Client;
10:
11: @Controller
12: @RequestMapping(value = "/spring", method = { RequestMethod.GET,
13: RequestMethod.POST })
14: public class SController {
15:
16: @Resource(name = "client")
17: private Client client;
18:
19: @RequestMapping(value = "/hello")
20: public String get() {
21: System.out.println(11111);
22: return "welcome";
23: }
24: }
1: package com.zero.mvc.controller;
2:
3: import javax.servlet.http.HttpServletRequest;
4: import javax.servlet.http.HttpServletResponse;
5:
6: import org.springframework.web.servlet.ModelAndView;
7: import org.springframework.web.servlet.mvc.AbstractController;
8:
9: public class WelcomeController extends AbstractController {
10:
11: @Override
12: protected ModelAndView handleRequestInternal(HttpServletRequest request,
13: HttpServletResponse response) throws Exception {
14: System.out.println("welcome");
15: return new ModelAndView("welcome");
16: }
17: }
1: package com.zero.mvc.inteceptor;
2:
3: import javax.servlet.http.HttpServletRequest;
4: import javax.servlet.http.HttpServletResponse;
5:
6: import org.springframework.web.servlet.HandlerInterceptor;
7: import org.springframework.web.servlet.ModelAndView;
8:
9: public class MyInteceptor implements HandlerInterceptor {
10:
11: @Override
12: // 最后执行,可用于释放资源,可以根据ex是否为null判断是否发生了异常,进行日志记录。
13: public void afterCompletion(HttpServletRequest request,
14: HttpServletResponse response, Object handler, Exception arg3)
15: throws Exception {
16: //配置了<bean id="exceptionResolver"
17: //class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"/>
18: //后(全局的异常处理),ex一直都为空,也就是说这里记错误日志不行
19: //只有不使用全局的异常处理时,这里ex才不为空
20: //ex不为空时,记错误日志
21: System.out.println("拦截器:---------释放资源--------");
22:
23:
24: }
25:
26: @Override
27: //控制器执行完,生成视图之前可以执行
28: // 有机会修改ModelAndView
29: public void postHandle(HttpServletRequest request,
30: HttpServletResponse response, Object handler, ModelAndView arg3)
31: throws Exception {
32: System.out.println("拦截器:Action执行完,生成视图之前执行");
33: }
34:
35: @Override
36: // Action之前执行,可以进行编码、安全控制等处理
37: public boolean preHandle(HttpServletRequest request,
38: HttpServletResponse response, Object handler) throws Exception {
39: // 这里进行权限控制工作
40: System.out.println("拦截器:*********Action之前执行**********");
41: // return false;//不执行后续
42: return true;// 执行后续
43: }
44:
45: }
1: package com.zero.mvc.vo;
2:
3: public class Client {
4: private String name;
5: private int age;
6:
7: public String getName() {
8: return name;
9: }
10:
11: public void setName(String name) {
12: this.name = name;
13: }
14:
15: public int getAge() {
16: return age;
17: }
18:
19: public void setAge(int age) {
20: this.age = age;
21: }
22:
23: }
applicationContext.xml相当与声明一个Spring容器来管理自己的实体bean,而springmvc-servlet.xml是SpringMVC的bean容器,管理controller等。访问 http://localhost:8080/mvc/hello/hello1 时会打印一下内容。
1: 拦截器:*********Action之前执行**********
2: /hello1
3: 111
4: Root WebApplicationContext: startup date [Sun Jan 11 17:24:49 CST 2015]; root of context hierarchy
5: false
6: true
7: true
8: 拦截器:Action执行完,生成视图之前执行
9: 拦截器:---------释放资源--------