Interceptor拦截器

我们知道Servlet中有Filter的概念,SpringMVC中一样有类似的组件,Interceptor(拦截器)。拦截器常用于实现登录验证、日志记录等功能。使用拦截器使得功能代码解耦的更加清晰,拦截器实现了AOP的编程思想,在功能较复杂的项目中合理使用拦截器实现通用功能能保持代码结构清晰、利于维护。

使用SpringMVC拦截器

下面给出一个拦截器例子,实现Session登录验证功能。

LoginInterceptor.java

package com.gacfox.demo.interceptor;

import com.gacfox.demo.model.User;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("user");
        if (user == null) {
            response.sendRedirect("/index");
            System.out.println("未登录");
            return false;
        } else {
            System.out.println("已登录");
            return true;
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}

编写拦截器,首先实现HandlerInterceptor接口,然后在XML配置文件中进行拦截器类的声明。

代码中,我们实现了HandlerInterceptor接口的3个方法:

  • preHandle():在控制器方法执行前执行,返回值为true表示继续处理链,返回false表示终止处理链
  • postHandle():在控制器方法执行后执行
  • afterCompletion():在所有拦截器的postHandle()执行完成后执行

下面的JavaConfig配置类用于注册拦截器,并设置一些排除路径。

package com.gacfox.demo.config;

import com.gacfox.demo.interceptor.LoginInterceptor;
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 LoginInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns(
                        "/login",
                        "/register",
                        "/error"
                );
    }
}

多个拦截器的执行流程

如果存在多个拦截器,拦截器中的方法会按照一定顺序调用,下面是一个例子。

flowchart TD
    I1pre["Interceptor1<br/>(preHandle)"] -- "return true;" --> I2pre["Interceptor2<br/>(preHandle)"]
    I2pre -- "return true;" --> HA["HandlerAdapter<br/>(Handle)"]
    HA --> I2post["Interceptor2<br/>(postHandle)"]
    I2post --> I1post["Interceptor1<br/>(postHandle)"]
    I1post --> DS["DispatcherServlet<br/>(render)"]
    DS --> I2after["Interceptor2<br/>(afterCompletion)"]
    I2after --> I1after["Interceptor1<br/>(afterCompletion)"]

    style I1pre fill:#fff,stroke:#333
    style I2pre fill:#fff,stroke:#333
    style HA fill:#fff,stroke:#333
    style I2post fill:#fff,stroke:#333
    style I1post fill:#fff,stroke:#333
    style DS fill:#fff,stroke:#333
    style I2after fill:#fff,stroke:#333
    style I1after fill:#fff,stroke:#333
作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。