springMVC详解

目录

一、spring mvc核心类与接口
二、spring mvc核心流程图
三、DispatcherServlet说明
四、springMVC.xml配置文件片段讲解(未使用默认配置文件名)
五、请求如何映射到具体的Action方法?
六、Spring中的拦截器
七、如何实现全局的异常处理?

一、spring mvc 核心类与接口

DispatcherServlet -- 前置控制器

HandlerMapping接口 -- 处理请求的映射

HandlerMapping接口的实现类:

SimpleUrlHandlerMapping 通过配置文件,把一个URL映射到Controller

DefaultAnnotationHandlerMapping || RequestMappingHandlerMapping 通过注解,把一个URL映射到Controller

HandlerAdapter 接口 -- 处理请求的映射

AnnotationMethodHandlerAdapter || RequestMappingHandlerAdapter 通过注解,把一个URL映射到Controller类的方法上

Controller接口 -- 控制器

由于我们使用@Controller注解,添加了该注解的类就可以担任控制器(action)的职责

HandlerInterceptor 接口 -- 拦截器

我们自己实现这个接口,来完成拦截器的工作

ViewResolver接口的实现类

UrlBasedViewResolver类 通过配置文件,把一个视图名交给到一个View来处理

InternalResourceViewResolver类,比上面的类,加入了JSTL的支持

HandlerExceptionResolver 接口 -- 异常处理接口

二、spring mvc 核心流程图![流程图]

三、DispatcherServlet说明

使用spring mvc,配置的第一步就是DispatcherServlet

DispatcherServlet是一个servlet,所以可以配置多个servlet。DispatcherServlet是前置控制器,配置在web.xml中。拦截配置的所有请求,servlet拦截规则需要自己定义,把拦截下来的请求根据某某规则分发到我们自己定义的controller的method中处理。

某某规则:是根据在spring mvc.xml文件里面配置的handlerMapping接口的实现类不同而不同

 <servlet>
   <servlet-name>mvc-dispatcher</servlet-name>
   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
   <init-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>classpath:/META-INF/spring/mvc-servlet.xml</param-value>
   </init-param>
   <!--启动顺序,让这个Servlet随Servletp容器一起启动-->
   <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>mvc-dispatcher</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

mvc-dispatcher表示这个servlet的名字是mvc-dispatcher,可以有多个DispatcherServlet,通过名字来区分,每个DispatcherServlet都有自己的WebApplicationContext上下文对象,同时保存的ServletContext中和Request对象中。

在DispatcherServlet的初始化过程中,框架会在web应用的web-INF文件夹下寻找名为[servlert-name]-servlet.xml的配置文件,生成文件中定义的bean。当在*中指明了配置文件的文件名时,则使用该配置文件。

其中*这里有多种可使用写法

1、不写,使用默认值: /WEB-INF/-servlet.xml

2、/META-INF/spring/mvc-servlet.xml

3、classpath*:resource文件夹下的配置文件

4、多个值用英文豆粉分隔

4、springMVC.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"  
    xmlns:tx="http://www.springframework.org/schema/tx"  
    xmlns:context="http://www.springframework.org/schema/context"     
    xmlns:mvc="http://www.springframework.org/schema/mvc"     
    xsi:schemaLocation="http://www.springframework.org/schema/beans    
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd    
    http://www.springframework.org/schema/tx    
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd   
    http://www.springframework.org/schema/context   
    http://www.springframework.org/schema/context/spring-context-3.0.xsd   
    http://www.springframework.org/schema/mvc   
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">  
  
  
    <!-- 自动扫描的包名 -->  
    <context:component-scan base-package="com.app,com.core,JUnit4" ></context:component-scan>  
       
    <!-- 默认的注解映射的支持 -->  
    <mvc:annotation-driven />  
       
    <!-- 视图解释类 -->  
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
        <property name="prefix" value="/WEB-INF/jsp/"/>  
        <property name="suffix" value=".jsp"/><!--可为空,方便实现自已的依据扩展名来选择视图解释类的逻辑  -->  
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />  
    </bean>  
       
    <!-- 拦截器 -->  
    <mvc:interceptors>  
        <bean class="com.core.mvc.MyInteceptor" />  
    </mvc:interceptors>        
       
    <!-- 对静态资源文件的访问  方案一 (二选一) -->  
    <mvc:default-servlet-handler/>  
       
    <!-- 对静态资源文件的访问  方案二 (二选一)-->  
    <mvc:resources mapping="/images/**" location="/images/" cache-period="31556926"/>  
    <mvc:resources mapping="/js/**" location="/js/" cache-period="31556926"/>  
    <mvc:resources mapping="/css/**" location="/css/" cache-period="31556926"/>  
 
</beans>   

<context:component-scan />扫描指定的包中的类上的注解,常用的注解有:

@Controller 声明Action组件

@Service 声明service组件

@Repository 声明Dao组件

@Component 泛指组件,不好归类

@RequestMapping("/index") 请求映射

@Resource 用于注入,(j2ee提供)默认按名称装配,@Resource(name="beanName")

@Autowired 用于注入,(spring)提供,默认按类型装配

@Transactional( rollbackFor={Exception.class}) 事务管理

<mvc:annotation-driven />是一种简写形式,完全可以手动代替这种简写形式,简写形式可让初学者快速应用默认的配置方案,<mvc:annotation-driven />会自动注册DefaultAnnotationHandlerMapping,AnnotationMethodHandlerAdapter 这两个bean,是springMVC为@Controller分发请求时所必须的。并提供了时间类型转换、XML转换、读写JSON的转换等数据绑定支持

mvc:interceptors 是一种简写形式,通过前面的大图,我们知道可以配置多个handlerMapping,mvc:interceptors 会为每一个handlerMapping注入一个拦截器,不过建议手动为handlerMapping注入一个拦截器

mvc:default-servlet-handler/ 使用默认的servlet来相应静态文件

<mvc:resources mapping="/images/" location="/images/" cache-period="31556926"/> 匹配URL  /images/  的URL被当做静态资源,由Spring读出到内存中再响应http。

使用mvc:default-servlet-handler/这个配置会把“/*" url,注册到SimpleUrlHandlerMapping的urlMap中,把对静态资源的访问由HandlerMapping转到org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler处理并返回,DefaultServletHttpRequestHandler使用的就是各个Servlet容器自己使用的默认servlet。将静态资源交给web容器去处理,而不通过spring mvc处理。

5、请求如何映射到具体的Action方法?

这里只讲基于注解的映射:可以使用DefaultAnnotationHandlerMapping || RequestMappingHandlerMapping

<!-- 请求映射 Handler,把一个url映射到controller类上 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
			<!-- 拦截器 -->    
			<property name="interceptors">  
	        <list>  
				<bean />
	        </list>  
	    </property>  
	</bean>

<bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter" /> 
	
	<bean id="jsonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />

	<!-- Handler 适配器配置, 通过注解,把一个url映射到controller类的方法上,执行真实页面处理器的处理请求 -->
	<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
		<property name="messageConverters">
			<list>
				<ref bean="stringHttpMessageConverter"/>
				<ref bean="jsonHttpMessageConverter"/>
			</list>
		</property>
	</bean>

在Controller类上使用@Controller,@RequestMapping("/home"),在method上使用@RequestMapping("/index")。当http请求请求发送到服务端会根据url来查找应该执行哪个controller下面的哪个action,我理解为url为java代码的一个路由关系。

spring mvc 的核心类 DispatcherServlet在初始化时会初始化HandlerMapping与HandlerAdaper,

HandlerMapping主要是调用BeanFactoryUtils.beansOfTypeIncludingAncestors,其中一种是非常重要的HandlerMapping是RequestMappingHandlerMapping,我们通过在controller方面上加@RequestMapping注释来配合使用,系统会将我们配置的RequestMapping信息注册到其中。mappingRegistry中包含有所有的路由信息。

代码如下:


  private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;

		if (this.detectAllHandlerMappings) {
			// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
				// We keep HandlerMappings in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		//不加载全部的先省略

		//加载默认的逻辑先省略
	}

DispatcherServlet核心方法:doDispatch,三个重要步骤:

  • getHandler,获取页面处理器,通俗点就是获取由哪个Controller来执行,包含方法信息以及方法参数等信息。

  • getHandlerAdapter,获取HandlerAdapter,它包含一个handle方法,负责调用真实的页面处理器进行请求处理并返回一个ModelAndView。HandlerAdpter里面有一些常见的处理,比如消息转移,参数处理等,详见此图:里面的argumentResolvers可以用来处理请求的参数,messageConverts是作消息转换等等。

  • HandlerAdapter.handle,执行真实页面处理器的处理请求

6、Spring中的拦截器

spring为我们提供了

org.springframework.web.servlet.HandlerInterceptor接口

org.springframework.web.servlet.handler.HandlerInterceptorAdapter适配器

实现这个接口或者继承这个适配器类,可以非常方便的实现自己的拦截器

拦截器中有以下三个方法

action前执行:

public boolean preHandle();

生成视图前执行

public void postHandle();

最后执行,可用于释放资源

public void afterCompletion();

分别用于实现预处理、后处理(调用了method并返回了ModelAndView,但还未进行页面渲染)、返回处理(页面已渲染)

在preHandle()中可以进行编码、安全处理、拦截请求等操作、

在postHandle()中有机会修改ModelAndView、

在postHandle()中可以根据ex判断是否发生了异常

使用拦截器

自定义一个拦截器,要实现HandlerInterceptor接口或继承HandlerInterceptorAdapter适配器

方案一、

<mvc:interceptors>   
    <bean class="com.app.mvc.MyInteceptor" />   
</mvc:interceptors> 

方案二、

<mvc:interceptors >     
  <mvc:interceptor>     
        <mvc:mapping path="/user/*" /> <!-- /user/*  -->     
        <bean class="com.mvc.MyInteceptor"></bean>     
    </mvc:interceptor>     
</mvc:interceptors>   

spring没有总的拦截器,不过在springmvc的配置文件里使用mvc:interceptors 会为每一个handlerMapping注入一个拦截器,总有一个拦截器可以找到处理器,最多也只找到一个处理器,所以这个拦截器总是会被执行的,这就起到了总连接器作用,如果是REST风格的URL,静态资源也会被拦截下来

方案三 handlerMapping上的拦截器、

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">        
 <property name="interceptors">        
     <list>        
         <bean class="com.mvc.MyInteceptor"></bean>       
     </list>        
 </property>        
</bean>

使用这种风格的拦截器不会拦截静态资源,因为精准的注入了拦截器。

如果是使用<mvc:annotation-driven />来自动注册handlerMapping就无法使用方案三这种拦截器方式,因为自动注册了DefaultAnnotationHandlerMapping 这个bean,推荐人工培植DefaultAnnotationHandlerMapping ,这样就可以给interceptors注入拦截器了。

七、如何实现全局的异常处理?

posted @ 2017-12-22 16:18  修电线的  阅读(296)  评论(1编辑  收藏  举报