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