拦截器简介
过滤器可以拦截请求,拦截器也能拦截请求,那过滤器和拦截器有啥区别?看下面这张图就明白了。 拦截器有三个方法,分别是
- preHandle,发生在请求被控制器方法处理前。
perHandle方法的返回值是boolean类型,true或false。 true,表示放行,即调用控制器方法。 false,表示拦截,即不调用控制器方法。 - postHandle,发生在请求被控制器方法处理后。
- afterCompletion,发生在视图渲染后。
为了更好地理解以上三个方法,可以查阅下DispatcherServlet的源码。
实现一个拦截器
现在来实现一个拦截器。 首先,新建一个基本的maven项目,这里不赘述,仅附上部分代码。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a th:href="@{/testInterceptor}">测试拦截器</a>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
success
</body>
</html>
package com.example.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class TestController {
@RequestMapping("/testInterceptor")
public String testInterceptor(){
return "success";
}
}
然后,在java目录下新建Package:com.example.mvc.interceptors,在该包下新建类FirstInterceptor,内容如下,
package com.example.mvc.interceptors;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FirstInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("FirstInterceptor-->preHandle");
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("FirstInterceptor-->postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("FirstInterceptor-->afterCompletion");
}
}
FirstInterceptor实现了接口HandlerInterceptor的perHandle、postHandle和afterCompletion方法。 接着,在配置文件springMVC.xml中配置拦截器,如下所示,
<mvc:interceptors>
<bean class="com.example.mvc.interceptors.FirstInterceptor"/>
</mvc:interceptors>
最后,启动应用。 IDEA控制器仅打印出:FirstInterceptor–>preHandle。这是因为preHandle的返回值是false,表示拦截,即不调用控制器方法,所以后面的postHandle、afterCompletion也不会对请求进行拦截处理。
不妨让preHandle返回true试试,如下, IDEA控制台打印出的信息如下:
21:29:47.058 [http-nio-8080-exec-1] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK
21:29:47.138 [http-nio-8080-exec-5] DEBUG org.springframework.web.servlet.DispatcherServlet - GET "/interceptor/", parameters={}
21:29:47.138 [http-nio-8080-exec-5] DEBUG org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapped to ParameterizableViewController [view="index"]
FirstInterceptor-->preHandle
FirstInterceptor-->postHandle
FirstInterceptor-->afterCompletion
21:29:47.141 [http-nio-8080-exec-5] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK
07-Dec-2021 21:29:52.964 信息 [Catalina-utility-1] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程序部署到目录 [D:\tomcat\webapps\manager]
07-Dec-2021 21:29:53.017 信息 [Catalina-utility-1] org.apache.catalina.startup.HostConfig.deployDirectory Web应用程序目录[D:\tomcat\webapps\manager]的部署已在[52]毫秒内完成
21:29:56.724 [http-nio-8080-exec-4] DEBUG org.springframework.web.servlet.DispatcherServlet - GET "/interceptor/testInterceptor", parameters={}
21:29:56.736 [http-nio-8080-exec-4] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped to com.example.mvc.controller.TestController#testInterceptor()
FirstInterceptor-->preHandle
FirstInterceptor-->postHandle
FirstInterceptor-->afterCompletion
21:29:56.782 [http-nio-8080-exec-4] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK
即,访问根路径/时,IDEA控制台打印了: FirstInterceptor–>preHandle FirstInterceptor–>postHandle FirstInterceptor–>afterCompletion。 访问/testInterceptor时,IDEA控制台也打印了: FirstInterceptor–>preHandle FirstInterceptor–>postHandle FirstInterceptor–>afterCompletion。 也就是说,拦截器FirstInterceptor对所有的浏览器请求都进行了拦截。
拦截器的配置
拦截器的配置方法有三种。
<mvc:interceptors>
<bean class="com.example.mvc.interceptors.FirstInterceptor"/>
</mvc:interceptors>
首先,需要在拦截器的类上添加注解@Component,将该拦截器注册为IoC容器的bean,如下。
package com.example.mvc.interceptors;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class FirstInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("FirstInterceptor-->preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("FirstInterceptor-->postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("FirstInterceptor-->afterCompletion");
}
}
同时,必须能够扫描到该拦截器,如下。
<context:component-scan base-package="com.example.mvc.controller,com.example.mvc.interceptors"></context:component-scan>
当然,也可以这样写,
<context:component-scan base-package="com.example.mvc"></context:component-scan>
最后,使用ref配置拦截器。
<mvc:interceptors>
<ref bean="firstInterceptor"/>
</mvc:interceptors>
- 第三种,使用interceptor。
第一种、第二种方法,会对浏览器的所有请求进行拦截,不能指定拦截规则。 使用interceptor时,可以设置拦截规则,指定拦截哪些请求路径,不拦截哪些请求路径。
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/"/>
<ref bean="firstInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<mvc:mapping path="/**"/> ,mapping 表示要拦截,/** 代表所有的请求路径,故拦截所有的请求路径。 <mvc:exclude-mapping path="/"/> ,exclude-mapping ,表示不要拦截,即不拦截根路径。
重启应用,IDEA控制台打印出如下信息:
21:50:23.901 [http-nio-8080-exec-1] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK
21:50:23.978 [http-nio-8080-exec-4] DEBUG org.springframework.web.servlet.DispatcherServlet - GET "/interceptor/", parameters={}
21:50:23.978 [http-nio-8080-exec-4] DEBUG org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapped to ParameterizableViewController [view="index"]
21:50:23.983 [http-nio-8080-exec-4] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK
07-Dec-2021 21:50:29.323 信息 [Catalina-utility-2] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程序部署到目录 [D:\tomcat\webapps\manager]
07-Dec-2021 21:50:29.378 信息 [Catalina-utility-2] org.apache.catalina.startup.HostConfig.deployDirectory Web应用程序目录[D:\tomcat\webapps\manager]的部署已在[54]毫秒内完成
21:50:33.199 [http-nio-8080-exec-5] DEBUG org.springframework.web.servlet.DispatcherServlet - GET "/interceptor/testInterceptor", parameters={}
21:50:33.211 [http-nio-8080-exec-5] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped to com.example.mvc.controller.TestController#testInterceptor()
FirstInterceptor-->preHandle
FirstInterceptor-->postHandle
FirstInterceptor-->afterCompletion
21:50:33.254 [http-nio-8080-exec-5] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK
访问根路径时,没有打印出信息。 访问/testInterceptor时,打印出如下信息: FirstInterceptor–>preHandle FirstInterceptor–>postHandle FirstInterceptor–>afterCompletion。
|