第一章:为什么需要统一功能处理?
想象你正在开发一个电商系统,包含用户管理、商品管理、订单管理等模块。每个模块都需要:
- 用户身份验证
- 操作日志记录
- 异常统一处理
- 数据格式标准化
如果每个模块都单独实现这些功能:
java
// 用户模块
@PostMapping("/users")
public User createUser(@RequestBody User user) {
try {
// 1. 验证token
// 2. 记录日志
// 3. 业务处理
// 4. 统一返回格式
} catch (Exception e) {
// 5. 异常处理
}
}
// 商品模块
@PostMapping("/products")
public Product createProduct(@RequestBody Product product) {
try {
// 重复步骤1-5...
} catch (Exception e) {
// ...
}
}
问题暴露:
- 代码重复率高(DRY原则被破坏)
- 维护困难(修改需多处调整)
- 系统一致性差(不同开发者实现方式不同)
第二章:Spring Boot统一处理四大核心组件
2.1 拦截器(Interceptor) - 请求的"安检门"
作用:在请求到达Controller前/后执行通用逻辑
java
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
// 1. 从请求头获取Token(就像门卫检查你的门禁卡)
String token = request.getHeader("Authorization");
// 2. 验证Token是否有效(门卫刷卡机验证)
if (!validateToken(token)) {
// 3. 无效则拒绝进入(设置401状态码)
response.setStatus(401);
return false; // 中断请求
}
return true; // 允许进入
}
// 验证Token的方法(门卫的验证设备)
private boolean validateToken(String token) {
// 实际验证逻辑(这里简化为非空检查)
return token != null && !token.isEmpty();
}
}
通俗解释:
- 这个类就像小区的门卫,检查每个进入的人(请求)
preHandle
方法:在业主回家前检查门禁卡(Token)- 如果门禁卡无效(
validateToken
返回false),门卫会拒绝进入(返回401状态码) - 如果有效,就放行(return true)
配置方式:
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 给门卫分配工作区域
registry.addInterceptor(new AuthInterceptor())
.addPathPatterns("/api/**") // 保护所有/api路径
.excludePathPatterns("/api/login"); // 但登录入口不需要检查
}
}
通俗解释:
- 这相当于给门卫划定工作范围:
/api/**
:需要检查的所有区域/api/login
:特殊通道(登录入口),不需要检查
2.2 过滤器(Filter) - 请求的"净化器"
作用:处理HTTP请求/响应的原始数据
java
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// 1. 记录请求开始时间(水电表开始计数)
long startTime = System.currentTimeMillis();
// 2. 继续处理请求(让水流/电流继续)
chain.doFilter(request, response);
// 3. 计算耗时(计算水电用量)
long duration = System.currentTimeMillis() - startTime;
// 4. 记录日志(生成水电账单)
System.out.println("请求耗时: " + duration + "ms");
}
}
- 这个过滤器就像水电表:
- 请求开始时记录时间(开水龙头)
chain.doFilter
让请求继续处理(水流)- 请求结束后计算耗时(关水龙头,计算用水量)
- 记录日志(生成水电账单)
与拦截器区别:
特性 | 过滤器(Filter) | 拦截器(Interceptor) |
---|---|---|
作用范围 | Servlet规范 | Spring MVC特有 |
依赖 | 不依赖Spring容器 | 依赖Spring容器 |
获取信息 | 原始HTTP请求/响应 | HandlerMethod信息 |
执行顺序 | 最先执行 | 在DispatcherServlet后执行 |
2.3 切面(AOP) - 功能的"手术刀"
作用:在方法执行前后插入通用逻辑
java
@Aspect
@Component
public class ServiceMonitorAspect {
// 监控Service层方法
@Around("execution(* com.example..service.*.*(..))")
public Object monitorService(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
try {
return pjp.proceed(); // 执行目标方法
} finally {
long duration = System.currentTimeMillis() - start;
// 记录慢查询
if (duration > 500) {
log.warn("慢方法: {} 耗时: {}ms",
pjp.getSignature(), duration);
}
}
}
}
2.4 控制器增强(@ControllerAdvice) - 全局的"管理员"
作用:统一处理控制器异常和返回格式
java
@ControllerAdvice
public class GlobalExceptionHandler {
// 处理业务异常
@ExceptionHandler(BusinessException.class)
@ResponseBody
public ResponseResult<Void> handleBusinessEx(BusinessException e) {
return ResponseResult.error(e.getCode(), e.getMessage());
}
// 处理所有未捕获异常
@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseResult<Void> handleException(Exception e) {
log.error("系统异常", e);
return ResponseResult.error(500, "系统繁忙");
}
}
第三章:统一功能处理实战案例
3.1 统一响应格式
java
// 标准响应体
public class ResponseResult<T> {
private int code;
private String msg;
private T data;
// 成功响应
public static <T> ResponseResult<T> success(T data) {
return new ResponseResult<>(200, "成功", data);
}
// 错误响应
public static <T> ResponseResult<T> error(int code, String msg) {
return new ResponseResult<>(code, msg, null);
}
}
// 控制器统一返回
@RestController
public class UserController {
@GetMapping("/users/{id}")
public ResponseResult<User> getUser(@PathVariable Long id) {
User user = userService.findById(id);
return ResponseResult.success(user);
}
}
3.2 统一异常处理
java
@ControllerAdvice // 1. 声明这是全局异常处理器
public class GlobalExceptionHandler {
// 2. 处理业务异常(如订单处理失败)
@ExceptionHandler(BusinessException.class)
@ResponseBody
public ResponseResult<Void> handleBusinessEx(BusinessException e) {
// 返回标准错误格式
return ResponseResult.error(e.getCode(), e.getMessage());
}
// 3. 处理所有未预料异常(系统崩溃)
@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseResult<Void> handleException(Exception e) {
// 记录错误日志(就像应急系统记录事故)
e.printStackTrace();
// 返回友好提示
return ResponseResult.error(500, "系统繁忙,请稍后再试");
}
}
@ControllerAdvice
:这是整个小区的应急中心@ExceptionHandler
:不同类型的应急处理小组BusinessException
:处理业务问题(如订单错误)Exception
:处理所有未预料的问题(系统崩溃)
- 当发生问题时,系统会自动调用对应的方法处理
3.3 统一日志记录
java
@Aspect
@Component
public class ControllerLogAspect {
@Around("@within(org.springframework.web.bind.annotation.RestController)")
public Object logController(ProceedingJoinPoint pjp) throws Throwable {
// 获取请求信息
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
.getRequest();
// 记录请求日志
log.info("请求开始 => URI: {}, 参数: {}",
request.getRequestURI(),
Arrays.toString(pjp.getArgs()));
long start = System.currentTimeMillis();
try {
Object result = pjp.proceed();
// 记录响应日志
log.info("请求完成 <= URI: {}, 耗时: {}ms",
request.getRequestURI(),
System.currentTimeMillis() - start);
return result;
} catch (Exception e) {
// 记录异常日志
log.error("请求异常 <= URI: {}, 错误: {}",
request.getRequestURI(), e.getMessage());
throw e;
}
}
}
3.4 统一身份认证
java
public class JwtAuthInterceptor implements HandlerInterceptor {
@Autowired
private JwtTokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
// 1. 获取Token
String token = request.getHeader("Authorization");
if (StringUtils.isEmpty(token)) {
sendError(response, 401, "未提供认证信息");
return false;
}
// 2. 验证Token
Claims claims = tokenService.parseToken(token);
if (claims == null) {
sendError(response, 401, "无效的Token");
return false;
}
// 3. 存储用户信息
UserContext.setCurrentUser(claims.getSubject());
return true;
}
private void sendError(HttpServletResponse response, int status, String msg) {
response.setStatus(status);
response.setContentType("application/json");
try {
response.getWriter().write(
new ResponseResult<>(status, msg).toString()
);
} catch (IOException e) {
log.error("响应写入失败", e);
}
}
}
第四章:高级应用场景
4.1 接口限流(Rate Limiting)
java
@Aspect
@Component
public class RateLimitAspect {
private final Map<String, RateLimiter> limiters = new ConcurrentHashMap<>();
@Around("@annotation(rateLimit)")
public Object rateLimit(ProceedingJoinPoint pjp, RateLimit rateLimit) throws Throwable {
String key = getRateLimitKey(pjp);
RateLimiter limiter = limiters.computeIfAbsent(key,
k -> RateLimiter.create(rateLimit.value()));
if (limiter.tryAcquire()) {
return pjp.proceed();
} else {
throw new BusinessException(429, "请求过于频繁");
}
}
private String getRateLimitKey(ProceedingJoinPoint pjp) {
// 根据方法+IP生成唯一key
MethodSignature signature = (MethodSignature) pjp.getSignature();
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
return signature.getMethod().getName() + ":" + request.getRemoteAddr();
}
}
// 使用注解
@GetMapping("/api/data")
@RateLimit(value = 10) // 每秒10次
public ResponseResult<Data> getData() {
// ...
}
4.2 多租户数据隔离
java
public class TenantInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
// 从请求头获取租户ID
String tenantId = request.getHeader("X-Tenant-ID");
if (StringUtils.isNotBlank(tenantId)) {
TenantContext.setCurrentTenant(tenantId);
}
return true;
}
}
// 在MyBatis拦截器中应用
@Intercepts({@Signature(type = Executor.class, method = "query", ...)})
public class TenantInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 自动添加租户过滤条件
String tenantId = TenantContext.getCurrentTenant();
if (tenantId != null) {
MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
Object parameter = invocation.getArgs()[1];
// 修改SQL添加 tenant_id = #{tenantId}
}
return invocation.proceed();
}
}
4.3 API版本控制
java
public class ApiVersionInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
// 从URL路径获取版本号
String path = request.getRequestURI();
Matcher matcher = Pattern.compile("/v(\\d+)/").matcher(path);
if (matcher.find()) {
int version = Integer.parseInt(matcher.group(1));
ApiVersionContext.setVersion(version);
}
return true;
}
}
// 控制器根据版本路由
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping
@ApiVersion(1) // v1版本
public ResponseResult<List<User>> getUsersV1() {
// 旧版逻辑
}
@GetMapping
@ApiVersion(2) // v2版本
public ResponseResult<List<UserDto>> getUsersV2() {
// 新版逻辑
}
}
第五章:性能优化与最佳实践
5.1 组件执行顺序优化
请求进入
Filter-Interceptor-preHandle-Controller-Interceptor-postHandle-Filter-after-Response
优化策略:
- 过滤器优先处理原始数据(如请求体缓存)
- 拦截器处理业务相关逻辑(如认证、日志)
- 切面处理具体方法逻辑(如性能监控)
- @ControllerAdvice最后处理异常和响应
5.2 避免的陷阱
-
循环依赖问题:
java
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Autowired
private AuthService authService; // 可能导致循环依赖
}
解决方案 :使用@Lazy
延迟注入
3.
java
@Lazy
@Autowired
private AuthService authService;
线程安全问题:
4.
java
public class UserContext {
private static final ThreadLocal<User> currentUser = new ThreadLocal<>();
}
性能热点:
5.
java
// 避免在拦截器/过滤器中执行耗时操作
public boolean preHandle(...) {
// 错误:执行数据库查询
User user = userRepository.findById(userId);
}
5.3 最佳实践总结
-
职责分离原则:
- 过滤器:处理原始HTTP请求/响应
- 拦截器:处理业务相关前置/后置逻辑
- 切面:处理具体方法逻辑
- 控制器增强:统一异常和响应处理
-
配置顺序原则:
java
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 1. 认证拦截器(最先执行)
registry.addInterceptor(authInterceptor);
// 2. 日志拦截器
registry.addInterceptor(logInterceptor);
// 3. 其他业务拦截器
}
性能监控指标:
9.
java
// 使用Micrometer监控
@Autowired
private MeterRegistry meterRegistry;
public void afterCompletion(...) {
meterRegistry.counter("api.requests",
"uri", request.getRequestURI(),
"status", String.valueOf(response.getStatus())
).increment();
}
第六章:综合实战 - 电商系统统一处理
6.1 系统架构图

6.2 核心配置代码
java
// 网关统一配置
@Configuration
public class GatewayConfig {
@Bean
public GlobalFilter customFilter() {
return (exchange, chain) -> {
// 1. 统一添加请求ID
ServerHttpRequest request = exchange.getRequest().mutate()
.header("X-Request-ID", UUID.randomUUID().toString())
.build();
return chain.filter(exchange.mutate().request(request).build());
};
}
}
// 微服务统一配置
@Configuration
public class ServiceConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TenantInterceptor());
registry.addInterceptor(new AuthInterceptor());
}
@Bean
public FilterRegistrationBean<LoggingFilter> loggingFilter() {
FilterRegistrationBean<LoggingFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(new LoggingFilter());
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
}
6.3 业务服务示例
java
@RestController
@RequestMapping("/orders")
public class OrderController {
@PostMapping
public ResponseResult<Order> createOrder(@Valid @RequestBody OrderCreateDTO dto) {
// 无需处理认证、日志、异常等
Order order = orderService.createOrder(dto);
return