Mastering Spring Boot Filters and Interceptors: A Complete Guide with Code Samples
This article explains the differences between servlet filters and Spring MVC interceptors, demonstrates how to wrap requests with HttpServletRequestWrapper, use OncePerRequestFilter, configure filters and interceptors in Spring Boot, handle login interception with AJAX redirects, set up listeners, manage static resources, and provides step‑by‑step testing procedures with code examples.
1. Relationship Diagram
2. Differences
Filter
Initialized once when the web application starts and destroyed when it stops.
Can filter request URLs, e.g., for sensitive‑word filtering.
Operates outside the interceptor layer.
Implements javax.servlet.Filter, part of the Servlet specification.
Pre‑processes the request after it enters the container but before the servlet; post‑processes after the servlet finishes.
Depends on the web container.
May be executed multiple times during a request lifecycle.
HttpServletRequestWrapper
Modifies the request before it reaches the servlet.
package com.dingwen.lir.filter;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.Arrays;
/**
* 在请求到达之前对 request 进行修改
*
* @author dingwen
*/
@Slf4j
public class RequestWrapper extends HttpServletRequestWrapper {
public RequestWrapper(HttpServletRequest request) {
super(request);
log.info("RequestWrapper");
}
@Override
public String getParameter(String name) {
// 可以对请求参数进行过滤
return super.getParameter(name);
}
@Override
public String[] getParameterValues(String name) {
// 对请求参数值进行过滤
// String[] values = super.getRequest().getParameterValues(name);
// return super.getParameterValues(name);
return "t e s t".split(" ");
}
}OncePerRequestFilter
Ensures the filter runs only once per request, which helps maintain compatibility across different servlet containers.
package com.dingwen.lir.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
/**
* 请求过滤器
* OncePerRequestFilter,顾名思义,它能够确保在一次请求中只通过一次filter.
*
* @author dingwen
*/
@Slf4j
public class RequestFilter extends OncePerRequestFilter {
@Override
public void destroy() {
super.destroy();
log.info("RequestFilter destroy");
}
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
FilterChain filterChain) throws ServletException, IOException {
try {
RequestWrapper requestWrapper = new RequestWrapper(httpServletRequest);
filterChain.doFilter(requestWrapper, httpServletResponse);
log.info("RequestFilter");
log.info(Arrays.toString(requestWrapper.getParameterValues("name")));
} catch (Exception exception) {
httpServletResponse.setCharacterEncoding("utf-8");
httpServletResponse.setContentType("application/json; charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
writer.write(exception.toString());
}
}
}Configuration
Registers the filter bean, sets its order and URL pattern.
package com.dingwen.lir.configuration;
import com.dingwen.lir.filter.RequestFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 过滤器配置类
*
* @author dingwen
*/
@Configuration
public class FilterConfig {
@Bean
public RequestFilter requestFilter() {
return new RequestFilter();
}
@Bean
public FilterRegistrationBean<RequestFilter> registrationBean() {
FilterRegistrationBean<RequestFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(requestFilter());
registrationBean.addUrlPatterns("/filter/*");
registrationBean.setName("RequestFilter");
// 过滤器的级别,值越小级别越高越先执行
registrationBean.setOrder(1);
return registrationBean;
}
}3. Interceptor
Implements org.springframework.web.servlet.HandlerInterceptor.
Typical use cases: performance analysis, permission checks, logging.
It is a Spring component managed by the Spring container and does not depend on Tomcat.
Pre‑processes the request before the controller; post‑processes after the view is rendered.
Login Interceptor
package com.dingwen.lir.interceptor;
import com.dingwen.lir.entity.User;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 登录拦截
*
* @author dingwen
*/
@Component
public class PageInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
User user = (User) request.getSession().getAttribute("user");
if (!ObjectUtils.isEmpty(user)) {
return true;
} else {
// 不管是转发还是重定向,必须返回 false,否则出现多次提交响应的错误
redirect(request, response);
return false;
}
}
/**
* 处理 AJAX 与普通 HTTP 请求的重定向逻辑
*/
public void redirect(HttpServletRequest request, HttpServletResponse response) throws IOException {
if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) { // AJAX
response.setHeader("Access-Control-Expose-Headers", "REDIRECT,CONTENT_PATH");
response.setHeader("REDIRECT", "REDIRECT");
StringBuffer url = request.getRequestURL();
String contextPath = request.getContextPath();
response.setHeader("CONTENT_PATH", url.replace(url.indexOf(contextPath) + contextPath.length(), url.length(), "/").toString());
} else { // 普通 HTTP
response.sendRedirect("/page/login");
}
response.getWriter().write(403);
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
}
}Interceptor Configuration
package com.dingwen.lir.configuration;
import com.dingwen.lir.interceptor.PageInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* MVC 控制器配置(Spring Boot 2.x 以后使用)
*
* @author dingwen
*/
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 拦截器的执行顺序与注册顺序相同,order 越小越先执行
registry.addInterceptor(new PageInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/page/login", "/user/login", "/page/ajax", "/static/**");
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/page/ajax").setViewName("ajax");
}
// 示例:自定义静态资源映射(可选)
// registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
// registry.addResourceHandler("/static/**").addResourceLocations("file:E:/static/");
}4. Listener
Implements interfaces such as javax.servlet.ServletRequestListener, javax.servlet.http.HttpSessionListener, and javax.servlet.ServletContextListener to monitor creation and destruction of requests, sessions, and the servlet context.
5. Important Notes
Static Resource Handling
In Spring Boot 2.x, interceptors also intercept static resources; therefore, static paths must be excluded in the interceptor configuration.
registry.addInterceptor(new PageInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/page/login", "/user/login", "/page/ajax", "/static/**");Default static resource locations (priority order):
classpath:/META-INF/resources
classpath:/resources
classpath:/static
classpath:/public
Priority: META‑INF/resources > resources > static > public.
6. Testing
Filter and interceptor tests include:
Accessing the home page without logging in redirects to the login page.
After successful login, the user can access protected pages.
Logging out revokes access and redirects to login.
When an unauthenticated AJAX request is made, the server sets custom response headers ( REDIRECT and CONTENT_PATH) and the client‑side script performs a redirect based on those headers.
Images in the original article illustrate each test step.
Code repository: https://gitee.com/dingwen-gitee/filter-interceptor-study.git
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java High-Performance Architecture
Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
