Spring MVC拦截器

Spring WebMvc框架中的Interceptor,与Servlet API中的Filter十分类似,用于对Web请求进行预处理/后处理。通常情况下这些预处理/后处理逻辑是通用的,可以被应用于所有或多个Web请求,例如:

  • 记录Web请求相关日志,可以用于做一些信息监控、统计、分析
  • 检查Web请求访问权限,例如发现用户没有登录后,重定向到登录页面
  • 打开/关闭数据库连接——预处理时打开,后处理关闭,可以避免在所有业务方法中都编写类似代码,也不会忘记关闭数据库连接

Spring MVC请求处理流程

alter-text

上图是Spring MVC框架处理Web请求的基本流程,请求会经过DispatcherServlet的分发后,会按顺序经过一系列的Interceptor并执行其中的预处理方法,在请求返回时同样会执行其中的后处理方法。

HandlerInterceptor接口

Spring MVC中拦截器是实现了HandlerInterceptor接口的Bean:

public interface HandlerInterceptor {
    boolean preHandle(HttpServletRequest request, 
                      HttpServletResponse response, 
                      Object handler) throws Exception;

    void postHandle(HttpServletRequest request, 
                    HttpServletResponse response, 
                    Object handler, ModelAndView modelAndView) throws Exception;

    void afterCompletion(HttpServletRequest request, 
                         HttpServletResponse response, 
                         Object handler, Exception ex) throws Exception;
}
  • preHandle():预处理回调方法,若方法返回值为true,请求继续(调用下一个拦截器或处理器方法);若方法返回值为false,请求处理流程中断,不会继续调用其他的拦截器或处理器方法,此时需要通过response产生响应;
  • postHandle():后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时可以通过modelAndView对模型数据进行处理或对视图进行处理
  • afterCompletion():整个请求处理完毕回调方法,即在视图渲染完毕时调用

HandlerInterceptor有三个方法需要实现,但大部分时候可能只需要实现其中的一个方法,HandlerInterceptorAdapter是一个实现了HandlerInterceptor的抽象类,它的三个实现方法都为空实现(或者返回true),继承该抽象类后可以仅仅实现其中的一个方法:

public class Interceptor extends HandlerInterceptorAdapter {

    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        System.out.println("This is interceptor.");
        return true;
    }
}

配置Interceptor

定义HandlerInterceptor后,需要在MVC配置中将它们应用于特定的URL中,下面是一个配置的例子:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LocaleInterceptor());
        registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
        registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
    }

}

对应的XML配置是:

<mvc:interceptors>
    <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <mvc:exclude-mapping path="/admin/**"/>
        <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor" />
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/secure/*"/>
        <bean class="org.example.SecurityInterceptor" />
    </mvc:interceptor>
</mvc:interceptors>

实例:用户登录检查

根据前面几个小节的学习,现在需要实现用户登录检查——如果发现用户没有登录,跳转到登录页面,登录成功后跳转回之前访问的页面。

Interceptor实现检查逻辑

public class LoginInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        if (request.getSession().getAttribute(Constants.USER_SESSION_ATTR) != null) {
            return true;
        }

        response.sendRedirect("/login?next=".concat(request.getRequestURI()));
        return false;
    }
}

为了实现跳转登录页面登录成功后能够返回当前页面,在Interceptor中将当前URL作为/login的参数next

LoginController

@Controller
@RequestMapping("/login")
public class LoginController {

    public static final Logger logger = LoggerFactory.getLogger(LoginController.class);

    @RequestMapping(method = RequestMethod.GET)
    public String loginPage(@RequestParam("next") Optional<String> next) {
        logger.info("next = {}", next);
        return "login";
    }

    @RequestMapping(method = RequestMethod.POST)
    public String login(@RequestParam("next") Optional<String> next, HttpSession session) {
        logger.info("next = {}", next);
        session.setAttribute(Constants.USER_SESSION_ATTR, "username");
        return "redirect:".concat(next.orElse("/"));
    }

}

在登录的POST方法中,除了将Session中放入user对象外,跳转到next以便回到登录前的页面。

配置Interceptor

需要注意的是,登录页面本身(包括POST请求)不能应用Interceptor来拦截,否则会陷入无限循环中:

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/login");
    }
}

 

https://www.tianmaying.com/tutorial/spring-mvc-interceptor

 

Spring MVC 拦截器是一种机制,允许开发人员在请求到达控制器之前或之后执行预定的操作。它们实现了 HandlerInterceptor 接口,并可以注册到 Spring MVC 框架中,以拦截匹配特定 URL 模式的请求。拦截器通常用于执行各种任务,如身份验证、日志记录、性能监控、异常处理等[^1]。 ### 使用方法 - **请求预处理**:在请求到达控制器之前执行预处理操作,包括参数验证、用户身份验证、日志记录等。通过在 preHandle 方法中实现逻辑,可以在请求处理之前执行任何必要的操作[^1]。 - **后处理和修改响应**:在请求处理之后、视图渲染之前进行后处理。开发人员可以修改处理器的执行结果或添加额外的处理逻辑[^1]。 - **资源清理和异常处理**:拦截器的 afterCompletion 方法允许在请求处理完成后进行资源清理操作,对于释放资源、关闭连接等工作非常有用。同时,还可以在这里处理请求过程中发生的异常,以确保资源的正确释放[^1]。 - **统一处理逻辑**:可以用于实现一些统一的处理逻辑,如权限控制、日志记录、国际化等。通过将这些逻辑抽象到拦截器中,可以提高代码的重用性和可维护性,同时确保这些逻辑在整个应用程序中得到一致的应用[^1]。 ### 原理 Spring MVC 拦截器类似于 Servlet 当中的 Filter 过滤器,用于拦截用户的请求并作出相应的处理,比如通过拦截器来进行用户权限验证或者用来判断用户是否登录。它是可插拔式的设计,基于 Java 反射机制实现的请求处理增强技术,本质是 AOP 面向切面编程思想的具体实现。其实现完美体现了责任链模式的设计思想,在 HandlerExecutionChain 中定义了拦截器链的执行逻辑,包括 preHandle、postHandle 等方法的调用顺序和处理逻辑[^2][^5]。 ### 配置 在 SpringMVC 核心配置文件中配置拦截器的示例如下: ```xml <!-- 配置拦截器 --> <mvc:interceptors> <mvc:interceptor> <!-- 配置拦截器的作用路径 --> <mvc:mapping path="/**"/> <!-- 拦截器对象 --> <bean class="com.itbaizhan.interceptor.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors> ``` 上述代码中,`<mvc:mapping path="/**"/>` 表示拦截所有请求,`<bean class="com.itbaizhan.interceptor.MyInterceptor"/>` 表示使用 `com.itbaizhan.interceptor.MyInterceptor` 作为拦截器对象[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值