Java直通车系列20【Spring MVC】(拦截器)

目录

拦截器概述

拦截器的工作原理

拦截器的使用步骤

拦截器接口方法解释

场景示例

1. 创建拦截器类

2. 配置拦截器

3. 创建控制器

4. 测试拦截器

其他常见场景


拦截器概述

在 Spring MVC 中,拦截器(Interceptor)是一种可以在请求处理的不同阶段进行预处理和后处理的组件。它类似于 Servlet 中的过滤器(Filter),但拦截器是 Spring MVC 框架特有的,主要用于对控制器方法的调用进行拦截和处理。拦截器可以在请求到达控制器之前、控制器方法执行之后以及视图渲染完成之后执行特定的逻辑,从而实现诸如权限验证、日志记录、性能监控等功能。

拦截器的工作原理

Spring MVC 的拦截器基于 Java 的反射机制和 AOP(面向切面编程)思想实现。当一个请求进入 Spring MVC 框架时,DispatcherServlet 会根据配置的拦截器链,依次调用拦截器的预处理方法。如果所有拦截器的预处理方法都返回 true,则请求会继续传递到控制器的处理方法;如果某个拦截器的预处理方法返回 false,则请求将被拦截,后续的拦截器和控制器方法都不会执行。在控制器方法执行完成后,拦截器的后处理方法会被依次调用,最后在视图渲染完成后,拦截器的完成处理方法会被调用。

拦截器的使用步骤

  1. 创建拦截器类:实现 HandlerInterceptor 接口或继承 HandlerInterceptorAdapter 类(HandlerInterceptorAdapter 是 HandlerInterceptor 的一个抽象实现类,在 Spring 5.3 及以后版本已被弃用),重写其中的方法。
  2. 配置拦截器:在 Spring MVC 的配置文件中注册拦截器,并指定拦截的 URL 模式。

拦截器接口方法解释

HandlerInterceptor 接口定义了三个方法:

  1. preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):在控制器方法执行之前被调用。如果返回 true,则继续执行后续的拦截器和控制器方法;如果返回 false,则请求处理流程终止,后续的拦截器和控制器方法都不会执行。可以在该方法中进行权限验证、日志记录等操作。
  2. postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView):在控制器方法执行之后、视图渲染之前被调用。可以在该方法中对 ModelAndView 对象进行修改,如添加额外的模型数据。
  3. afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex):在视图渲染完成之后被调用。无论请求处理过程中是否发生异常,该方法都会被执行。可以在该方法中进行资源清理、日志记录等操作。

场景示例

1. 创建拦截器类
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class LoggingInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("Pre-handle method is called. Request URL: " + request.getRequestURL());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Post-handle method is called.");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("After-completion method is called.");
    }
}

在上述代码中,LoggingInterceptor 类实现了 HandlerInterceptor 接口,并重写了三个方法。preHandle 方法在请求处理前打印请求的 URL,postHandle 方法在控制器方法执行后打印信息,afterCompletion 方法在视图渲染完成后打印信息。

2. 配置拦截器

如果使用 Java 配置,可以通过实现 WebMvcConfigurer 接口来配置拦截器:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoggingInterceptor())
                .addPathPatterns("/**"); // 拦截所有请求
    }
}

在上述代码中,WebConfig 类实现了 WebMvcConfigurer 接口,重写了 addInterceptors 方法,将 LoggingInterceptor 拦截器注册到拦截器链中,并指定拦截所有请求(addPathPatterns("/**"))。

3. 创建控制器
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {

    @GetMapping("/hello")
    @ResponseBody
    public String sayHello() {
        return "Hello, World!";
    }
}

在上述代码中,HelloController 类包含一个处理 /hello 请求的方法,返回一个简单的字符串。

4. 测试拦截器

当访问 http://localhost:8080/hello 时,控制台会输出以下信息:

Pre-handle method is called. Request URL: http://localhost:8080/hello
Post-handle method is called.
After-completion method is called.

这表明拦截器的三个方法按顺序被调用,实现了对请求处理过程的拦截和日志记录。

其他常见场景

  • 权限验证:在 preHandle 方法中检查用户是否具有访问某个资源的权限,如果没有则返回 false 并跳转到登录页面。
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.servlet.HandlerInterceptor;

public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        if (session.getAttribute("user") == null) {
            response.sendRedirect("/login");
            return false;
        }
        return true;
    }
}
  • 性能监控:在 preHandle 方法中记录请求开始时间,在 afterCompletion 方法中记录请求结束时间,计算请求处理时间。
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;

public class PerformanceInterceptor implements HandlerInterceptor {

    private ThreadLocal startTime = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        startTime.set(System.currentTimeMillis());
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        long endTime = System.currentTimeMillis();
        long executionTime = endTime - startTime.get();
        System.out.println("Request URL: " + request.getRequestURL() + ", Execution time: " + executionTime + " ms");
        startTime.remove();
    }
}

通过使用拦截器,可以在不修改控制器代码的情况下,对请求处理过程进行增强和扩展,提高代码的可维护性和复用性。

你可能感兴趣的:(Java直通车,java,spring,mvc,开发语言)