SpringBoot统一功能处理实战:拦截器、响应与异常管理

一、拦截器在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);
    }
}

特殊类型处理注意事项:

  1. 文件下载等特殊响应需要添加排除逻辑
  2. 使用@ResponseNotWrap自定义注解排除特定方法
  3. 处理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 异常处理进阶技巧

  1. 异常国际化处理:
@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);
}
  1. 异常日志分级处理:
@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 性能优化要点

  1. 拦截器优化策略:
// 使用@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();
    }
}
  1. 异常处理优化:
  • 使用@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 常见问题解决方案

  1. 拦截器不生效检查清单:
  • 检查是否添加了@Configuration注解
  • 确认拦截路径配置正确
  • 查看是否被更高优先级的拦截器阻断
  • 检查Spring Boot版本兼容性
  1. 响应包装失效场景:
  • 返回类型为void的方法
  • 使用了@ResponseStatus注解
  • 手动调用了HttpServletResponse的输出流
  1. 异常处理不生效原因:
  • 异常被局部catch处理
  • 多个@ControllerAdvice的order冲突
  • 异常类型不匹配

6.2 调试技巧

  1. 拦截器调试命令:
# 查看注册的拦截器
curl -v http://localhost:8080/actuator/mappings | grep Interceptor
  1. 异常处理调试方法:
// 临时禁用全局异常处理
@Profile("debug")
@RestControllerAdvice
public class DebugExceptionHandler {
    @ExceptionHandler(Exception.class)
    public void handleException(Exception ex) {
        ex.printStackTrace();
    }
}
  1. 响应处理调试工具:
// 测试响应包装
@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());
    }
}
正文到此结束
评论插件初始化中...
Loading...