一、Interceptor (拦截器)介绍
1、介绍
拦截器(Interceptor)同 Filter 过滤器一样,它俩都是面向切面编程——AOP 的具体实现(AOP切面编程只是一种编程思想而已)。
你可以使用 Interceptor 来执行某些任务,例如在 Controller 处理请求之前编写日志,添加或更新配置......
在 Spring中,当请求发送到 Controller 时,在被Controller处理之前,它必须经过 Interceptors(0或多个)。
Spring Interceptor是一个非常类似于Servlet Filter 的概念 。
2、作用
- 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算 PV(Page View)等;
- 权限检查:如登录检测,进入处理器检测是否登录;
- 性能监控:通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间。(反向代理,如 Apache 也可以自动记录)
- 通用行为:读取 Cookie 得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取 Locale、Theme 信息等,只要是多个处理器都需要的即可使用拦截器实现
3、自定义 Interceptor拦截器的实现
org.springframework.web.servlet.HandlerInterceptor
接口org.springframework.web.servlet.handler.HandlerInterceptorAdapter
类,并且需要重写下面下面 3 个方法:1、preHandler(HttpServletRequest request, HttpServletResponse response, Object handler)
方法在请求处理之前被调用。该方法在 Interceptor 类中最先执行,2、postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
方法在当前请求处理完成之后,3、afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)
方法需要在当前对应的 Interceptor 类的 postHandler二、代码实现拦截器
1、写一个继承拦截器的类
写一个类继承HandlerInterceptor 接口并重写preHandle、postHandle、afterCompletion三个方法
public class MyHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
long startTime = System.currentTimeMillis();
System.out.println("\n-------- LogInterception.preHandle --- ");
System.out.println("Request URL: " + request.getRequestURL());
System.out.println("Start Time: " + System.currentTimeMillis());
request.setAttribute("startTime", startTime);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("\n-------- LogInterception.postHandle --- ");
System.out.println("Request URL: " + request.getRequestURL());
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("\n-------- LogInterception.afterCompletion --- ");
long startTime = (Long) request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
System.out.println("Request URL: " + request.getRequestURL());
System.out.println("End Time: " + endTime);
System.out.println("Time Taken: " + (endTime - startTime));
}
}
2、写一个关于配置拦截器的类
下面的代码只简单调用了一个拦截方法
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyHandlerInterceptor()).addPathPatterns("/**");
}
}
3、自定义 Controller 验证拦截器
@Controller
public class AppController {
@RequestMapping("/index")
public String index(Model model){
System.out.println("创建拦截器成功!!");
return "index";
}
}
运行界面:
然后访问web网址,运行结果如下
web界面如下:
控制台打印如下:
可见,拦截器创建是成功的,但web界面是出现了错误,错误如下:
2023-12-14 20:45:13.017 ERROR 18260 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Circular view path [index]: would dispatch back to the current handler URL [/index] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)] with root cause