SpringBoot统一功能处理实战:拦截器、响应与异常管理
- 发布时间:2025-02-21 21:34:19
- 本文热度:浏览 10 赞 0 评论 0
- 文章标签: SpringBoot 拦截器 异常处理
- 全文共1字,阅读约需1分钟
一、拦截器在SpringBoot中的实现原理
拦截器(Interceptor)是Spring MVC框架中处理请求预处理和后处理的核心机制,其执行流程与Servlet Filter有明显差异。我们通过创建HandlerInterceptor
实现类来定义拦截逻辑:
public class AuthInterceptor implements HandlerInterceptor {
// 预处理阶段(Controller方法执行前)
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String token = request.getHeader("Authorization");
if (!validateToken(token)) {
response.setStatus(401);
return false; // 中断请求链
}
return true;
}
// 后处理阶段(Controller方法执行后,视图渲染前)
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) {
log.debug("请求处理完成,准备渲染视图");
}
// 完成处理(视图渲染完成后)
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) {
log.debug("请求处理全流程结束");
}
}
注册拦截器时需要继承WebMvcConfigurer
:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/api/public/**");
}
}
拦截器执行流程示意图:
HTTP请求 -> Filter链 -> DispatcherServlet -> 拦截器preHandle
-> Controller方法 -> 拦截器postHandle -> 视图渲染
-> 拦截器afterCompletion
二、响应统一封装的深度实践
2.1 响应体结构设计
推荐采用三层结构设计:
public class Result<T> {
private int code; // 业务状态码
private String message; // 提示信息
private T data; // 业务数据
private long timestamp; // 响应时间戳
// 成功静态方法
public static <T> Result<T> success(T data) {
return new Result<>(200, "操作成功", data);
}
// 失败静态方法
public static Result<?> error(int code, String message) {
return new Result<>(code, message, null);
}
}
2.2 全局响应处理实现
通过实现ResponseBodyAdvice
接口进行自动包装:
@RestControllerAdvice
public class GlobalResponseHandler implements ResponseBodyAdvice<Object> {
// 判断是否需要包装
@Override
public boolean supports(MethodParameter returnType,
Class converterType) {
return !returnType.getGenericParameterType().equals(Result.class);
}
// 实际包装处理
@Override
public Object beforeBodyWrite(Object body,
MethodParameter returnType,
MediaType selectedContentType,
Class selectedConverterType,
ServerHttpRequest request,
ServerHttpResponse response) {
if (body instanceof Result) return body;
if (body instanceof String) {
// 特殊处理String类型返回值
return JSON.toJSONString(Result.success(body));
}
return Result.success(body);
}
}
特殊类型处理注意事项:
- 文件下载等特殊响应需要添加排除逻辑
- 使用
@ResponseNotWrap
自定义注解排除特定方法 - 处理Swagger等第三方接口的响应格式
三、异常处理的体系化方案
3.1 异常分类处理策略
建立异常处理层次结构:
// 基础异常类
public class BaseException extends RuntimeException {
private int code;
public BaseException(int code, String message) {
super(message);
this.code = code;
}
}
// 业务异常
public class BusinessException extends BaseException {
public BusinessException(String message) {
super(500100, message);
}
}
// 参数校验异常
public class ValidationException extends BaseException {
private Map<String, String> errors;
public ValidationException(Map<String, String> errors) {
super(400100, "参数校验失败");
this.errors = errors;
}
}
3.2 全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理业务异常
@ExceptionHandler(BusinessException.class)
public Result<?> handleBusinessException(BusinessException ex) {
return Result.error(ex.getCode(), ex.getMessage());
}
// 处理参数校验异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<?> handleValidationException(MethodArgumentNotValidException ex) {
Map<String, String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.collect(Collectors.toMap(
FieldError::getField,
FieldError::getDefaultMessage
));
return Result.error(400100, "参数校验失败").data(errors);
}
// 兜底异常处理
@ExceptionHandler(Exception.class)
public Result<?> handleUnknownException(Exception ex) {
log.error("系统异常:", ex);
return Result.error(500000, "系统繁忙,请稍后再试");
}
}
3.3 异常处理进阶技巧
- 异常国际化处理:
@Autowired
private MessageSource messageSource;
@ExceptionHandler(BusinessException.class)
public Result<?> handleI18nException(BusinessException ex,
HttpServletRequest request) {
String message = messageSource.getMessage(
ex.getMessageKey(),
ex.getArgs(),
LocaleContextHolder.getLocale());
return Result.error(ex.getCode(), message);
}
- 异常日志分级处理:
@ExceptionHandler(ClientException.class)
public Result<?> handleClientException(ClientException ex) {
log.warn("客户端异常:{}", ex.getMessage());
return Result.error(ex.getCode(), ex.getMessage());
}
@ExceptionHandler(ServerException.class)
public Result<?> handleServerException(ServerException ex) {
log.error("服务端异常:", ex);
return Result.error(ex.getCode(), "系统内部错误");
}
四、组件整合与性能优化
4.1 拦截器与过滤器的协同
对比项 | 拦截器 | 过滤器 |
---|---|---|
作用范围 | Spring MVC层面 | Servlet容器层面 |
依赖关系 | 依赖Spring容器 | 不依赖Spring |
执行顺序 | 在DispatcherServlet之后 | 在DispatcherServlet之前 |
功能特性 | 可获取Handler信息 | 只能处理Request/Response |
典型整合案例:
// 跨域过滤器配置
@Bean
public FilterRegistrationBean<CorsFilter> corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new FilterRegistrationBean<>(new CorsFilter(source));
}
4.2 性能优化要点
- 拦截器优化策略:
// 使用@Order控制执行顺序
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new PerformanceInterceptor())
.order(Ordered.HIGHEST_PRECEDENCE);
}
}
// 性能监控拦截器示例
public class PerformanceInterceptor implements HandlerInterceptor {
private ThreadLocal<Long> startTime = new ThreadLocal<>();
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
startTime.set(System.currentTimeMillis());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) {
long duration = System.currentTimeMillis() - startTime.get();
if (duration > 500) {
log.warn("接口响应超时:{}ms {}", duration, request.getRequestURI());
}
startTime.remove();
}
}
- 异常处理优化:
- 使用@ControllerAdvice的annotations属性限定处理范围
- 对频繁发生的异常进行缓存处理
- 异步异常处理机制
五、实战:电商系统统一处理案例
5.1 接口鉴权方案实现
// JWT解析拦截器
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String token = request.getHeader("X-Token");
try {
Claims claims = JwtUtil.parseToken(token);
request.setAttribute("userId", claims.getSubject());
return true;
} catch (JwtException e) {
response.setStatus(401);
return false;
}
}
}
// 权限注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequireRole {
String value();
}
// 权限校验拦截器
public class RoleInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod) handler;
RequireRole annotation = method.getMethodAnnotation(RequireRole.class);
if (annotation != null) {
String requiredRole = annotation.value();
String userRole = getUserRole(request);
if (!requiredRole.equals(userRole)) {
throw new BusinessException("权限不足");
}
}
}
return true;
}
}
5.2 分布式追踪集成
// 追踪ID拦截器
public class TraceInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String traceId = request.getHeader("X-Trace-ID");
if (StringUtils.isEmpty(traceId)) {
traceId = UUID.randomUUID().toString();
}
MDC.put("traceId", traceId);
response.setHeader("X-Trace-ID", traceId);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) {
MDC.remove("traceId");
}
}
// 日志配置示例(logback-spring.xml)
<pattern>[%d{HH:mm:ss}] [%X{traceId}] [%thread] %-5level %logger{36} - %msg%n</pattern>
六、调试与问题排查指南
6.1 常见问题解决方案
- 拦截器不生效检查清单:
- 检查是否添加了@Configuration注解
- 确认拦截路径配置正确
- 查看是否被更高优先级的拦截器阻断
- 检查Spring Boot版本兼容性
- 响应包装失效场景:
- 返回类型为void的方法
- 使用了@ResponseStatus注解
- 手动调用了HttpServletResponse的输出流
- 异常处理不生效原因:
- 异常被局部catch处理
- 多个@ControllerAdvice的order冲突
- 异常类型不匹配
6.2 调试技巧
- 拦截器调试命令:
# 查看注册的拦截器
curl -v http://localhost:8080/actuator/mappings | grep Interceptor
- 异常处理调试方法:
// 临时禁用全局异常处理
@Profile("debug")
@RestControllerAdvice
public class DebugExceptionHandler {
@ExceptionHandler(Exception.class)
public void handleException(Exception ex) {
ex.printStackTrace();
}
}
- 响应处理调试工具:
// 测试响应包装
@SpringBootTest
public class ResponseTest {
@Autowired
private MockMvc mockMvc;
@Test
void testResponseWrapper() throws Exception {
MvcResult result = mockMvc.perform(get("/api/test"))
.andExpect(jsonPath("$.code").value(200))
.andReturn();
System.out.println(result.getResponse().getContentAsString());
}
}
正文到此结束
相关文章
热门推荐
评论插件初始化中...