乐趣区

Spring-Boot项目中如何定制拦截器

本文首发于个人网站:Spring Boot 项目中如何定制拦截器

Servlet 过滤器属于 Servlet API,和 Spring 关系不大。除了使用过滤器包装 web 请求,Spring MVC 还提供 HandlerInterceptor(拦截器) 工具。根据文档,HandlerInterceptor 的功能跟过滤器类似,但拦截器提供更精细的控制能力:在 request 被响应之前、request 被响应之后、视图渲染之前以及 request 全部结束之后。我们不能通过拦截器修改 request 内容,但是可以通过抛出异常(或者返回 false)来暂停 request 的执行。

Spring MVC 中常用的拦截器有:LocaleChangeInterceptor(用于国际化配置)ThemeChangeInterceptor。我们也可以增加自己定义的拦截器,可以参考这篇文章中提供的 demo

实战

添加拦截器不仅是在 WebConfiguration 中定义 bean,Spring Boot 提供了基础类 WebMvcConfigurerAdapter,我们项目中的 WebConfiguration 类需要继承这个类。

  1. 继承 WebMvcConfigurerAdapter;
  2. 为 LocaleChangeInterceptor 添加 @Bean 定义,这仅仅是定义了一个 interceptor spring bean,但是 Spring boot 不会自动将它加入到调用链中。
  3. 拦截器需要手动加入调用链。

修改后完整的 WebConfiguration 代码如下:

package com.test.bookpub;

import org.apache.catalina.filters.RemoteIpFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;

@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {@Bean    public RemoteIpFilter remoteIpFilter() {return new RemoteIpFilter();
    }

    @Bean    public LocaleChangeInterceptor localeChangeInterceptor() {return new LocaleChangeInterceptor();
    }
    @Override    public void addInterceptors(InterceptorRegistry registry {registry.addInterceptor(localeChangeInterceptor());
    }
}

使用 mvn spring-boot:run 运行程序,然后通过 httpie 访问http://localhost:8080/books?locale=foo,在终端看到如下错误信息。

Servlet.service() for servlet [dispatcherServlet] in context with path [] 
threw exception [Request processing failed; nested exception is 
java.lang.UnsupportedOperationException: Cannot change HTTP accept 
header - use a different locale resolution strategy] with root cause

PS:这里发生错误并不是因为我们输入的 locale 是错误的,而是因为默认的 locale 修改策略不允许来自浏览器的请求修改。发生这样的错误说明我们之前定义的拦截器起作用了。

分析

在我们的示例项目中,覆盖并重写了 addInterceptors(InterceptorRegistory registory) 方法,这是典型的回调函数——利用该函数的参数 registry 来添加自定义的拦截器。

在 Spring Boot 的自动配置阶段,Spring Boot 会扫描所有 WebMvcConfigurer 的实例,并顺序调用其中的回调函数,这表示:如果我们想对配置信息做逻辑上的隔离,可以在 Spring Boot 项目中定义多个 WebMvcConfigurer 的实例。

Spring Boot 1.x 系列

  1. Spring Boot 的自动配置、Command-line-Runner
  2. 了解 Spring Boot 的自动配置
  3. Spring Boot 的 @PropertySource 注解在整合 Redis 中的使用
  4. Spring Boot 项目中如何定制 HTTP 消息转换器
  5. Spring Boot 整合 Mongodb 提供 Restful 接口
  6. Spring 中 bean 的 scope
  7. Spring Boot 项目中使用事件派发器模式
  8. Spring Boot 提供 RESTful 接口时的错误处理实践
  9. Spring Boot 实战之定制自己的 starter
  10. Spring Boot 项目如何同时支持 HTTP 和 HTTPS 协议
  11. 自定义的 Spring Boot starter 如何设置自动配置注解
  12. Spring Boot 项目中使用 Mockito
  13. 在 Spring Boot 项目中使用 Spock 测试框架

本号专注于后端技术、JVM 问题排查和优化、Java 面试题、个人成长和自我管理等主题,为读者提供一线开发者的工作和成长经验,期待你能在这里有所收获。

退出移动版