拦截器主要用于拦截用户请求,并做相应的处理,十分常用。
拦截器的常见用法:
- 判断用户是否登录。比如购物网站用户将商品添加到购物车时,用拦截器判断用户是否登录,如未登录,则不能将商品添加到购物车(转到登录页面)。
- 进行权限验证。验证已登录的用户是否有相应的操作权限。
- 记录请求信息的日志。
拦截器的使用步骤
(1)编写拦截器类
实现拦截器有2种方式:
- 实现HandlerInterceptor接口(常用),或继承HandlerInterceptor接口的实现类
- 实现WebRequestInterceptor接口,或继承WebRequestInterceptor接口的实现类
HandlerInterceptor接口的三个方法:
-
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
在controller中的业务方法之前执行,返回值表示是否有后续操作。
true——继续执行后续操作;
fasle——不再执行后续操作,即不再执行此拦截器的代码、不再执行后续的其它拦截器,不再调用controller中的业务方法来处理请求。
-
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
在controller中业务方法调用之后、视图解析之前执行。
可对Model、View作出进一步修改。
-
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
在视图渲染结束之后执行,即在整个请求完成后执行,可以做一些资源清理、日志记录的工作。
三个方法对应在三个时间点进行拦截处理。一般我们只使用preHandler()。
完整的执行流程:
- 调用preHandle(),如果返回true,继续往下执行;如果返回false,至此结束。
- 调用controller中的业务方法
- 调用postHandle()
- 解析视图,渲染视图
- 调用afterCompletion()
示例 将商品加入购物车,用拦截器验证用户是否已登录
新建包com.chy.interceptor,包下新建类LoginInterceptor:
public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //session中有user的信息就通过,否则给出提示信息,重定向到登录页面 HttpSession session = request.getSession(); //登录成功时要将user放到session中 User user = (User)session.getAttribute("user"); if(user!=null) return true; //转发到登录页面 request.setAttribute("msg","您尚未登录,请先登录!"); request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response); return false; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
(2)在spring mvc的配置文件中配置要使用的拦截器
<!--配置要使用的拦截器--> <mvc:interceptors> <!--一个interceptor配置一个拦截器 --> <mvc:interceptor> <!-- 要拦截的请求,**表示拦截该地址下的所有请求 --> <mvc:mapping path="/product/purchase/**" /> <!-- 使用的拦截器类 --> <bean class="com.chy.interceptor.LoginInterceptor" /> </mvc:interceptor> <mvc:interceptor> <!--拦截所有对controller中业务方法的请求--> <mvc:mapping path="/**" /> <!--可指定不拦截的请求--> <mvc:exclude-mapping path=""/> <bean class="" /> </mvc:interceptor> </mvc:interceptors>
拦截器是在业务方法调用前后进行拦截,拦截的前提是要调用业务方法,即拦截器只拦截对controller中业务方法的请求,不拦截对视图的直接请求。
<mvc:mapping />指定要拦截的业务方法,<mvc:exclude-mapping />指定<mvc:mapping />中的哪些路径不被拦截。
有顺序要求:
<mvc:mapping path="" /> <mvc:exclude-mapping path=""/> <bean class="" />
<mvc:exclude-mapping />可选。
多个拦截器的执行顺序
去的时候拦截器的执行顺序,和配置文件中拦截器的前后顺序一致。
回来的时候拦截器的执行顺序,和去的时候相反。
比如:
<!--配置要使用的拦截器--> <mvc:interceptors> <!--拦截器1 --> <mvc:interceptor></mvc:interceptor> <!--拦截器2--> <mvc:interceptor></mvc:interceptor> </mvc:interceptors>
假设这2个拦截器都拦截相同的请求。
去的时候依次执行:拦截器1的preHandler()、拦截器2的preHandler(),和配置顺序相同;
回来的时候依次执行:拦截器2的postHandler()、拦截器1的postHandler();和配置顺序相反;
再次回来的时候依次执行:拦截器2的afterCompletion()、拦截器1的afterCompletion(),和配置顺序相反。