SpringMVC 拦截器(Interceptor):请求预处理与后处理的实现

SpringMVC 拦截器(Interceptor):请求预处理与后处理的实现

各位看官,大家好!今天咱们来聊聊SpringMVC里一个既神秘又实用的家伙——拦截器(Interceptor)。别一听“拦截器”就觉得是搞破坏的,它其实是个好同志,专门负责在你的请求“进宫面圣”之前和“退朝回府”之后做一些贴心的小工作。

想象一下,你的controller就像一位皇帝,接收来自四面八方的请求(圣旨)。在古代,皇帝批阅奏折之前,总得先经过太监总管过一遍,筛掉一些无关紧要的,标注一些重点,这就是预处理;皇帝批完奏折之后,还得让记录员记录下皇帝的旨意,这就是后处理。咱们的拦截器,就扮演了太监总管和记录员的角色。

一、 拦截器是啥?能吃吗?

当然不能吃!拦截器是SpringMVC框架提供的一种强大的机制,允许你在请求到达controller之前和响应返回给客户端之后,对请求进行预处理和后处理。它可以理解为AOP(面向切面编程)的一种具体实现,但比AOP更加轻量级,专门针对Web请求进行拦截。

拦截器的主要作用:

  • 请求预处理: 检查用户是否登录、权限验证、参数校验、防止CSRF攻击等等。
  • 请求后处理: 记录请求日志、修改响应内容、清理资源等等。
  • 其他: 统一设置字符编码、国际化处理等等。

二、 拦截器三剑客:HandlerInterceptor接口

SpringMVC的拦截器是通过实现 HandlerInterceptor 接口来实现的。这个接口里有三个重要的方法,就像三位武功盖世的剑客,各有所长:

  • preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 这个方法在请求到达controller之前执行,也就是“进宫面圣”之前。它返回一个布尔值:
    • true: 允许请求继续执行,顺利到达controller。
    • false: 阻止请求继续执行,相当于“打道回府”,通常会重定向到错误页面或者返回一个特定的响应。
  • postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 这个方法在controller执行之后,但在视图渲染之前执行,也就是“退朝回府”之后,但皇帝的旨意还没正式发布。它可以访问controller返回的ModelAndView对象,修改视图或数据。
  • afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) 这个方法在整个请求完成之后执行,包括视图渲染完成之后,也就是皇帝的旨意已经发布了。它主要用于清理资源,记录异常信息等等,类似于善后处理。

三、 代码示例:一个简单的登录检查拦截器

咱们来创建一个简单的登录检查拦截器,看看这三剑客是如何配合工作的。

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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        Object user = session.getAttribute("user");

        if (user == null) {
            // 用户未登录,重定向到登录页面
            response.sendRedirect(request.getContextPath() + "/login");
            return false; // 阻止请求继续执行
        }

        return true; // 允许请求继续执行
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 可选:在这里可以对ModelAndView进行一些修改
        // 例如,添加一些公共数据到视图中
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 可选:在这里可以进行资源清理,记录日志等
    }
}

代码解释:

  • preHandle 方法:首先获取session中的user属性,如果为null,表示用户未登录,就重定向到登录页面/login,并返回false,阻止请求继续执行。如果用户已登录,则返回true,允许请求继续执行。
  • postHandle 方法:这里暂时什么也没做,但可以在这里对ModelAndView进行一些修改,例如添加一些公共数据到视图中,方便页面显示。
  • afterCompletion 方法:这里也暂时什么也没做,但可以在这里进行资源清理,记录日志等。

四、 如何让拦截器生效?配置是关键!

光有拦截器还不行,还需要告诉SpringMVC框架,让它知道什么时候该调用哪个拦截器。这就要通过配置来实现。

配置方式一:XML配置(传统方式)

如果你还在使用XML配置,可以在springmvc.xml文件中配置拦截器:

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/> <!-- 拦截所有请求 -->
        <bean class="com.example.interceptor.LoginInterceptor"/>
    </mvc:interceptor>

    <!-- 可以配置多个拦截器 -->
    <mvc:interceptor>
        <mvc:mapping path="/admin/**"/> <!-- 只拦截/admin/下的请求 -->
        <bean class="com.example.interceptor.AdminInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

配置解释:

  • <mvc:interceptors>: 声明拦截器列表。
  • <mvc:interceptor>: 配置单个拦截器。
  • <mvc:mapping path="/**"/>: 指定拦截的路径,/** 表示拦截所有请求。
  • <bean class="com.example.interceptor.LoginInterceptor"/>: 指定拦截器类的全限定名。

配置方式二:Java配置(推荐方式)

如果你使用的是Java配置,可以在配置类中实现WebMvcConfigurer接口,并重写addInterceptors方法:

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 WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**") // 拦截所有请求
                .excludePathPatterns("/login", "/register"); // 排除/login和/register请求

        // 可以添加多个拦截器
        registry.addInterceptor(new AdminInterceptor())
                .addPathPatterns("/admin/**"); // 只拦截/admin/下的请求
    }
}

配置解释:

  • addInterceptors(InterceptorRegistry registry): 重写此方法来添加拦截器。
  • registry.addInterceptor(new LoginInterceptor()): 添加一个拦截器实例。
  • addPathPatterns("/**"): 指定拦截的路径,/** 表示拦截所有请求。
  • excludePathPatterns("/login", "/register"): 排除不需要拦截的路径,例如登录和注册页面。

五、 拦截器的执行顺序:谁先来,谁后到?

如果配置了多个拦截器,它们的执行顺序是按照配置的顺序来执行的。

  • preHandle方法: 按照配置的顺序依次执行。
  • postHandle方法: 按照配置的逆序依次执行。
  • afterCompletion方法: 按照配置的逆序依次执行。

举个例子:

假设我们配置了两个拦截器,分别是InterceptorAInterceptorB,配置顺序是先InterceptorA,后InterceptorB。那么它们的执行顺序如下:

  1. InterceptorA.preHandle
  2. InterceptorB.preHandle
  3. Controller的处理
  4. InterceptorB.postHandle
  5. InterceptorA.postHandle
  6. View的渲染
  7. InterceptorB.afterCompletion
  8. InterceptorA.afterCompletion

六、 拦截器与Filter的区别:哥俩不是亲兄弟

拦截器和Filter都是用于拦截请求的,但它们之间还是有一些区别的:

特性 拦截器 (Interceptor) 过滤器 (Filter)
级别 SpringMVC框架级别 Servlet规范级别
依赖 依赖于SpringMVC框架 不依赖于SpringMVC框架
作用范围 只能拦截controller的请求 可以拦截所有请求,包括静态资源等
执行时机 在DispatcherServlet内部执行 在DispatcherServlet之前执行
访问对象 可以访问SpringMVC的HandlerModelAndView等对象 只能访问Servlet API的对象,如HttpServletRequestHttpServletResponse
配置方式 通过SpringMVC的配置进行配置 通过web.xml@WebFilter注解进行配置

简单来说:

  • Filter 是Servlet规范的一部分,它是一个更底层的概念,可以拦截所有的Web请求,包括静态资源等。
  • Interceptor 是SpringMVC框架的一部分,它只能拦截controller的请求,但可以访问SpringMVC的上下文,例如HandlerModelAndView等对象。

七、 拦截器的适用场景:哪里需要它?

拦截器在实际开发中有很多应用场景,常见的有:

  • 身份验证和授权: 检查用户是否登录,是否有权限访问特定的资源。
  • 日志记录: 记录请求的URL、参数、执行时间等信息,用于性能分析和故障排查。
  • 国际化处理: 根据用户的语言偏好设置Locale,实现国际化支持。
  • 防止CSRF攻击: 生成和验证CSRF Token,防止跨站请求伪造攻击。
  • 参数校验: 对请求参数进行校验,防止非法数据进入系统。
  • 性能监控: 统计controller的执行时间,用于性能监控和优化。
  • 数据加密和解密: 对请求和响应数据进行加密和解密,保证数据安全。

八、 注意事项:用好拦截器,避免踩坑

  • 不要过度使用拦截器: 拦截器会增加请求的处理时间,过度使用会影响系统性能。
  • 注意拦截器的执行顺序: 确保拦截器的执行顺序符合预期,避免出现错误。
  • 处理好异常: 在拦截器中处理好异常,避免影响后续的处理流程。
  • 考虑静态资源: 如果需要拦截静态资源,应该使用Filter而不是Interceptor。
  • 避免循环依赖: 拦截器之间不要相互依赖,否则会导致循环依赖问题。
  • 配置要清晰: 拦截器的配置要清晰明了,方便维护和管理。

九、 总结:拦截器,请求处理的守护神

拦截器是SpringMVC框架中一个非常强大的工具,它可以让你在请求到达controller之前和响应返回给客户端之后,对请求进行预处理和后处理。通过合理地使用拦截器,可以提高代码的复用性,减少代码冗余,增强系统的安全性和可维护性。

希望通过这篇文章,大家能够对SpringMVC的拦截器有一个更深入的了解,并在实际开发中灵活运用,让拦截器成为你请求处理的守护神!

最后,记住,拦截器虽好,可不要贪杯哦!合理使用,才能发挥它最大的价值。祝大家编码愉快!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注