SpringMVC的拦截器,你知道多少?
前言
springmvc的拦截器是基于aop思想实现和应用的,我们可以在某个方法甚至是字段被访问前进行拦截,加上我们想要执行的操作,非侵入式地添加上我们想要加入的功能和校验。拦截器也是我们学习springmvc所必须要掌握的一个知识点,本文将从拦截器的快速入门和应用进行介绍。
一、拦截器的接口方法介绍
要定义拦截器,需要先实现HandlerInterceptor接口,我们进入到这个接口中,可以看到里面一共只有三个方法
- preHandle 对接收到的请求进行前置处理,如果返回true才将请求放行给controller。如果返回false,则中断请求。
- postHandle 执行controller后,渲染视图之前调用
- afterCompletion 该方法在整个请求结束之后执行,当然前提依然是 preHandle方法的返回值为 true 才行。该方法一般用于资源清理工作
二、自定义自己的拦截器
定义拦截器的方法只需要实现上面的HandlerInterceptor接口即可
package com.xiaoming.util;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
/**
* 对接收到的请求进行前置处理,如果返回true才将请求放行给controller
* 如果返回false,执行中断请求
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle has done...");
return true;
}
/**
* 执行croller后,渲染视图之前调用
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle has done...");
}
/*
整个请求结束后执行
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion has done...");
}
}
在spring-mvc.xml文件中配置
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--对哪些资源执行拦截操作-->
<mvc:mapping path="/**"/>
<bean class="com.xiaoming.util.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
package com.xiaoming.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class TargetController {
@RequestMapping("/sayHi")
public ModelAndView sayHi() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name", "小明");
modelAndView.setViewName("index");
return modelAndView;
}
}
Controller.java
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello,${name}</title>
</head>
<body>
<h2>Hello,${name}</h2>
</body>
</html>
index.jsp
三、拦截器的执行顺序
在上个入门案例的基础上,我们新建一个拦截器,不同之处在于拦截器2的preHandle方法返回值是false,不进行放行
package com.xiaoming.util;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor2 implements HandlerInterceptor {
/**
* 对接收到的请求进行前置处理,如果返回true才将请求放行给controller
* 如果返回false,执行中断请求
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle222 has done...");
return false;
}
/**
* 执行croller后,渲染视图之前调用
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle222 has done...");
}
/*
整个请求结束后执行
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion222 has done...");
}
}
第二个拦截器
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--对哪些资源执行拦截操作-->
<mvc:mapping path="/**"/>
<bean class="com.xiaoming.util.MyInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<!--对哪些资源执行拦截操作-->
<mvc:mapping path="/**"/>
<bean class="com.xiaoming.util.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
spring-mvc.xml
将项目部署到tomcat后,访问http://localhost:8088/sayHi
控制台输出如下:
我们可以看到,两个拦截器的preHandle方法都正常执行了。
那么为什么postHandle方法没有执行呢?
因为拦截器2返回值为false,所以请求被拦截,无法到达controller,两个类的postHandle方法都不需要执行。
那么afterCompletion方法为什么被调用了呢?
这里的话我们要了解afterCompletion的调用时机,这个方法是在请求结束后调用的,preHandle不放行,请求自然就结束中断了,也就会执行拦截器的afterCompletion方法。
那么为什么只调用了拦截器1的afterCompletion方法呢?
是因为afterCompletion方法的执行还有一个前提,该拦截器的preHandle方法返回值为true。所以这里的话afterCompletion方法只调用了一次。
在实际项目开发中,我们常常使用拦截器来进行用户登录校验,如果用户已经登录则返回true放行,如果用户没有登录,则跳转到登录页面