Spring Boot 中的过滤器的用法及示例代码另有异常处理方案
Spring Boot 中的过滤器是一种用于处理 HTTP 请求和响应的重要组件。以下是对 Spring Boot 过滤器的简要介绍:
1. 概念:
过滤器是 Java Servlet 规范中的一部分,用于在请求到达 Servlet(在 Spring MVC 中通常是 DispatcherServlet)之前和响应发送回客户端之前执行预处理和后处理操作。
2. 我司项目中主要用途:
- 请求/响应编码转换
- 请求内容的修改或包装
- 身份验证和授权
- 日志记录和审计
- 数据压缩
- 不想让用户访问的数据我们也会放到过滤器里以防止用户能访问到
3. 实现方式:
通过实现 javax.servlet.Filter 接口来创建过滤器。
4. 关键方法:
- init(): 过滤器初始化时调用
- doFilter(): 处理请求和响应的主要方法
- destroy(): 过滤器销毁时调用
5. 配置:
可以通过 @Component 注解和 @WebFilter 注解,或者通过 FilterRegistrationBean 在 Java 配置类中注册过滤器。
6. 执行顺序:
多个过滤器组成过滤器链,按照配置的顺序依次执行。
7. 与拦截器的区别:
过滤器是 Servlet 规范的一部分,作用于所有请求;拦截器是 Spring MVC 的一部分,只作用于 Spring MVC 的请求。
以下是我司技术人员写的一个简单的示例:这个过滤器会记录所有请求的处理时间和一些基本信息。首先,让我们创建过滤器:
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class RequestLoggingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 过滤器初始化时的操作(如果需要)
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
long startTime = System.currentTimeMillis();
// 记录请求信息
System.out.println("开始处理请求: " + httpRequest.getMethod() + " " + httpRequest.getRequestURI());
// 继续处理请求
chain.doFilter(request, response);
// 记录响应信息
long endTime = System.currentTimeMillis();
System.out.println("请求处理完成: " + httpRequest.getRequestURI() +
", 状态码: " + httpResponse.getStatus() +
", 耗时: " + (endTime - startTime) + "ms");
}
@Override
public void destroy() {
// 过滤器销毁时的操作(如果需要)
}
}这个过滤器已经使用 `@Component` 注解,Spring Boot 会自动检测并注册它。但是,如果你想更精确地控制过滤器的顺序或者应用于特定的 URL 模式,你可以创建一个配置类:
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<RequestLoggingFilter> loggingFilter() {
FilterRegistrationBean<RequestLoggingFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new RequestLoggingFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(1); // 设置过滤器的优先级
return registrationBean;
}
}这个示例中的过滤器做了以下几件事:
1. 在 `doFilter` 方法开始时,记录请求的开始时间和基本信息。
2. 调用 `chain.doFilter(request, response)` 继续处理请求。
3. 在请求处理完成后,记录响应状态码和处理时间。
我司技术在使用这个过滤器后,每次处理请求时,控制台会输出类似以下的信息:
开始处理请求: GET /api/example 请求处理完成: /api/example, 状态码: 200, 耗时: 50ms
这个简单的示例展示了如何创建和配置一个基本的过滤器。你可以根据具体需求修改或扩展这个过滤器,例如添加更详细的日志记录、请求参数检查、响应内容修改等功能。以下我们再看看异常如何处理:
处理异常如下:
我司经常会处理这些问题
以下是一些在 Spring Boot 过滤器中处理异常的方法和最佳实践:
在 doFilter 方法中使用 try-catch 块。这是最直接的方法,可以捕获并处理在过滤器链中发生的异常。
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class ExceptionHandlingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (Exception e) {
// 记录异常
System.err.println("过滤器捕获到异常: " + e.getMessage());
e.printStackTrace();
// 设置响应
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
httpResponse.getWriter().write("发生了一个错误: " + e.getMessage());
}
}
}第二步,你可以创建一个专门的异常处理过滤器。你可以创建一个专门的过滤器来处理异常,并将其放置在过滤器链的最前面。
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
@Order(Integer.MIN_VALUE) // 确保这个过滤器是第一个执行的
public class GlobalExceptionFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (Exception e) {
System.err.println("全局异常过滤器捕获到异常: " + e.getMessage());
e.printStackTrace();
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
httpResponse.getWriter().write("服务器遇到了一个问题");
}
}
}第三步:使用 ErrorController 处理过滤器中的异常。如果你想让 Spring Boot 的错误处理机制来处理过滤器中的异常,你可以将异常传播到 ErrorController。
import jakarta.servlet.*;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class ExceptionPropagatingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (Exception e) {
// 记录异常
System.err.println("过滤器捕获到异常: " + e.getMessage());
// 将异常重新抛出,让 ErrorController 处理
throw new ServletException(e);
}
}
}最后,你可以创建一个自定义的 ErrorController 来处理这些异常:
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.servlet.http.HttpServletRequest;
@RestController
public class CustomErrorController implements ErrorController {
@RequestMapping("/error")
public ResponseEntity<String> handleError(HttpServletRequest request) {
Exception exception = (Exception) request.getAttribute("jakarta.servlet.error.exception");
if (exception != null) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("发生错误: " + exception.getMessage());
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("发生未知错误");
}
}第四步,最佳实践。总是记录异常,这对于调试和监控非常重要。考虑不同类型的异常,可能需要不同的处理方式。不要在响应中暴露敏感的错误信息。使用统一的错误响应格式。在处理异常时,确保正确设置响应的状态码。通过这些方法,你可以在过滤器中有效地处理异常,提高应用的稳定性和用户体验。选择哪种方法取决于你的具体需求和应用架构。
相关文章
服务热线:0632-5272123,0632-5271123
业务咨询:13969468882,18006320170
营销中心:山东省 枣庄市 市中区 中坚1878 A406室
邮箱:kf@zzint.com