拦截器功能类似于Filter, 但是比Filter的功能更细致. 拦截器是基于AOP实现.
提供了两种方案:
> 实现接口, HandlerInterceptor
> 继承父类, HandlerInterceptorAdapter
拦截器可以在我们访问Controller方法的时候,进行拦截,符合条件了才让通过,否则不让通过
登录验证拦截器:
有3个方法需要实现:
1、preHandle方法在进入控制器方法前被调用,通常用于控制器方法调用前的验证操作,例如:登录操作,返回值是一个布尔类型的值,为true才让访问控制器方法,否则不让访问
2、postHandle方法,在控制器方法执行结束,有返回值,并且在进入页面之前调用该方法
这里的modelAndView封装了控制器方法的返回值,我们在这里也可以进行返回结果的处理,例如:游戏中骂人的字变成******了
3、afterCompletion方法,流程结束后执行,通常用于统一异常处理
这里用以拦截没有登录就访问主页面信息:
package com.chenpeng.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.chenpeng.pojo.User;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 登录验证拦截器
*
* @author chenpeng
*
*/
public class LoginInterceptor implements HandlerInterceptor {
/**
* 在进入控制器方法前被调用
* 通常用于控制器方法调用前的验证操作, 例如: 登录验证
*
* @param handle - 代表要调用的控制器方法对象
* @return 布尔值, true表示可以继续访问, false表示停止访问, 不能继续访问时, 建议给出响应
* 或者可以进行页面的跳转
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handle) throws Exception {
System.out.println("LoginInterceptor.preHandle(1)");
User user = (User) request.getSession().getAttribute("user");
if(user == null) {
request.getSession().setAttribute("msg", "请先登录再访问!");
response.sendRedirect(request.getContextPath() + "/index.jsp");
return false;
}
return true;
}
/**
* 在控制器方法执行结束, 有返回值后, 并且在进入页面之前调用该方法
*
* @param modelAndView - 代表控制器方法的返回内容
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView)
throws Exception {
System.out.println("LoginInterceptor.postHandle(3)");
}
/**
* 流程结束后执行, 通常用于统一异常处理
* @param ex - 异常对象
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)
throws Exception {
System.out.println("LoginInterceptor.afterCompletion(5)");
}
}
需要在SpringMVC的配置文件中配置:
继承父类HandlerInterceptorAdapter,日志拦截器
它是一个抽象类,但是没有抽象方法
package com.chenpeng.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
/**
* 日志拦截器
*
* @author chenpeng
*
*/
public class LoggerInterceprtor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("[日志拦截器]: " + handler + " 要被调用了...");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("[日志拦截器]: " + handler + " 调用结束, modelAndView: " + modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("[日志拦截器]: " + handler + " 流程结束.");
}
}
我们可以在Controller方法执行前调用preHandle方法,方法执行之后调用postHandle方法,之后调用afterCompletion方法
配置文件
那么问题来了?
1. 两个拦截器的时候, 先执行哪个有谁决定?
谁先配置的,就先执行
当我们点击分页查询的时候:先执行了先配置的日志拦截器,然后执行了登录拦截器
控制台效果:
[日志拦截器]: public java.lang.String com.chenpeng.controller.UserController.selByPage(int,int,org.springframework.ui.Model) 要被调用了...
LoginInterceptor.preHandle(1)
- ==> Preparing: SELECT count(0) FROM t_user
- ==> Parameters:
- <== Columns: count(0)
- <== Row: 24
- <== Total: 1
- ==> Preparing: select id, login_name, login_pswd, name, birthday, reg_time from t_user LIMIT ?, ?
- ==> Parameters: 3(Integer), 3(Integer)
- <== Columns: id, login_name, login_pswd, name, birthday, reg_time
- <== Row: 4, zhouxingchi, 123, 周星驰, 1994-10-25, 2018-11-15 21:02:00.0
- <== Row: 5, zhourunfa, 123, 周润发, 1994-10-25, 2018-11-15 21:02:00.0
- <== Row: 6, zhangguorong, 123, 张国荣, 1994-10-25, 2018-11-16 21:02:00.0
- <== Total: 3
LoginInterceptor.postHandle(3)
[日志拦截器]: public java.lang.String com.chenpeng.controller.UserController.selByPage(int,int,org.springframework.ui.Model) 调用结束, mode
LoginInterceptor.afterCompletion(5)
[日志拦截器]: public java.lang.String com.chenpeng.controller.UserController.selByPage(int,int,org.springframework.ui.Model) 流程结束.
2. 两个拦截器有6个方法, 6个方法的执行顺序?
遵循栈的规则,先进后出的顺序
3. 多个拦截器的执行流程
多个拦截器通常被称为拦截器栈, 先配置的拦截器先执行. ,如果我们先配置的是登录拦截器,则为:下图