目录
[toc]
一、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>
表示这个servlet的名字是mvc-dispatcher,可以有多个DispatcherServlet,通过名字来区分,每个DispatcherServlet都有自己的WebApplicationContext上下文对象,同时保存的ServletContext中和Request对象中。
在DispatcherServlet的初始化过程中,框架会在web应用的web-INF文件夹下寻找名为[servlert-name]-servlet.xml的配置文件,生成文件中定义的bean。当在中指明了配置文件的文件名时,则使用该配置文件。
其中这里有多种可使用写法
1、不写,使用默认值: /WEB-INF/
2、
3、
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>
@Controller 声明Action组件
@Service 声明service组件
@Repository 声明Dao组件
@Component 泛指组件,不好归类
@RequestMapping("/index") 请求映射
@Resource 用于注入,(j2ee提供)默认按名称装配,@Resource(name="beanName")
@Autowired 用于注入,(spring)提供,默认按类型装配
@Transactional( rollbackFor={Exception.class}) 事务管理
使用
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的配置文件里使用
方案三 handlerMapping上的拦截器、
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<bean class="com.mvc.MyInteceptor"></bean>
</list>
</property>
</bean>
使用这种风格的拦截器不会拦截静态资源,因为精准的注入了拦截器。
如果是使用