SpringMVC interceptor:下列参考的blog文章
Spring MVC简介
SpringMVC 拦截器实现原理和登录实现
SpringMVC拦截器详解[附带源码分析]
学习SpringMVC——拦截器
*********************
1-1 拦截器
拦截器是指通过统一拦截从浏览器发往服务器的请求来完成功能的增强。
使用场景:解决请求的共性问题(如:乱码问题,权限验证等)
===2 拦截器的实现==========================
---2-1 拦截器工作原理-------------------------------------------
SpringMVC可以通过配置过滤器解决乱码问题(过滤器与拦截器非常相似)
拦截器工作原理与过滤器非常相似
---2-2 拦截器实现-------------------------------------------
1.编写拦截器类实现HandlerInterceptor接口
实现下列三个接口
2.将拦截器注册进SpringMVC框架中
SpringMVC的默认配置文件中注册拦截器:
1)添加了MVC命名空间:xmlns:mvc="http://www.springframework.org/schema/mvc"
2)添加了SpringMVC的格式描述符文件xsd文件
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<?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:p="http://www.springframework.org/schema/p"
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/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">
加入1)2)之后才能使用<mvc:>标签
<mvc:interceptors>
<!--这个类就是我们自定义的Interceptor -->
<bean id="commonInterceptor" class="org.shop.interceptor.CommonInterceptor"></bean>
</mvc:interceptors>3.配置拦截器的拦截规则
<mvc:interceptors>
<mvc:interceptor>
<!--
/**的意思是所有文件夹及里面的子文件夹
/*是所有文件夹,不含子文件夹
/是web项目的根目录
<mvc:mapping path="/**" /> -->
<mvc:mapping path="/viewAll.form" />
<!-- 需排除拦截的地址 -->
<!-- <mvc:exclude-mapping path="/userController/login"/> -->
<bean id="commonInterceptor" class="org.shop.interceptor.CommonInterceptor"></bean> <!--这个类就是我们自定义的Interceptor -->
</mvc:interceptor>
<!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法 -->
</mvc:interceptors>
---2-3 拦截器方法介绍-------------------------------------------
HandlerInterceptor 接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。
preHandle(): 这个方法在业务处理器处理请求之前被调用,SpringMVC 中的Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor 。每个Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值Boolean 类型的,当它返回为false 时,表示请求结束,后续的Interceptor 和Controller 都不会再执行;当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。
参数:Object handler表示的是呗拦截的请求的目标对象
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
-------------------------------------------------------------
postHandle():这个方法在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。postHandle 方法被调用的方向跟preHandle 是相反的,也就是说先声明的Interceptor 的postHandle 方法反而会后执行。
参数:ModelAndView modelAndView,可以通过ModelAndView参数来改变现实的视图,或者修改发往视图的方法
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception;
-----------------------------------------------------
afterCompletion():该方法也是需要当前对应的Interceptor 的preHandle 方法的返回值为true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。
并不常用。
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class CommonInterceptor extends HandlerInterceptorAdapter{
private final Logger log = LoggerFactory.getLogger(CommonInterceptor.class);
public static final String LAST_PAGE = "lastPage";
/**
* 在业务处理器处理请求之前被调用
* 如果返回false
* 从当前的拦截器往回执行所有拦截器的afterCompletion(),再退出拦截器链
*
* 如果返回true
* 执行下一个拦截器,直到所有的拦截器都执行完毕
* 再执行被拦截的Controller
* 然后进入拦截器链,
* 从最后一个拦截器往回执行所有的postHandle()
* 接着再从最后一个拦截器往回执行所有的afterCompletion()
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
if ("GET".equalsIgnoreCase(request.getMethod())) {
RequestUtil.saveRequest();
}
log.info("==============执行顺序: 1、preHandle================");
String requestUri = request.getRequestURI();
String contextPath = request.getContextPath();
String url = requestUri.substring(contextPath.length()); if ("/userController/login".equals(url)) {
return true;
}else {
String username = (String)request.getSession().getAttribute("user");
if(username == null){
log.info("Interceptor:跳转到login页面!");
request.getRequestDispatcher("/page/index.jsp").forward(request, response);
return false;
}else
return true;
}
}
/**
* 在业务处理器处理请求执行完成后,生成视图之前执行的动作
* 可在modelAndView中加入数据,比如当前时间
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
log.info("==============执行顺序: 2、postHandle================");
if(modelAndView != null){ //加入当前时间
modelAndView.addObject("haha", "测试postHandle");
}
}
/**
* 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等
* 当有拦截器抛出异常时,会从当前拦截器往回执行所有的拦截器的afterCompletion()
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
log.info("==============执行顺序: 3、afterCompletion================");
}
}
---2-4 多个拦截器应用-------------------------------------------
<mvc:interceptors>
<!--这个类就是我们自定义的Interceptor -->
<bean id="commonInterceptor1" class="org.shop.interceptor.CommonInterceptor1"></bean> <bean id="commonInterceptor2" class="org.shop.interceptor.CommonInterceptor2"></bean>
</mvc:interceptors>
执行顺序:
---2-5 拦截器其他实现方式-------------------------------------------
实现WebRequestInterceptor接口来实现拦截器。
与HandlerInterceptor接口类似,区别是WebRequestInterceptor的preHandle没有返回值。还有WebRequestInterceptor是针对请求的,接口方法参数中没有response。
向SpringMVC框架注册的写法不变
弊端:区别是WebRequestInterceptor的preHandle没有返回值,不能终止请求
3-1 拦截器使用场景
使用原则:处理所有请求的共同问题
1 解决乱码问题
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
request.setCharacterEncodeing("utf-8");
System.out.println("preHandle going");
return true;
}
2 解决权限验证问题
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
request.setCharacterEncodeing("utf-8");
System.out.println("preHandle going");
//对用户是否登录进行判断,
if(request.getSession().getAttribute("user")==null){
//如果没有登录,种植请求,并发送到登录页面
request.getRequestDispatcher("/login.jsp").forward(request,response);
return false;
}
return true;
}
4 拦截器和过滤器的区别
过滤器Filter依赖于Servlet容器,基于回调函数,过滤范围大
拦截器Intercpetor依赖于框架容器,基于反射机制,只过滤请求
拦截器可以处理Web应用中请求的一些共性问题,可以减少重复代码,便于维护