package com.org.flashsalesystem.config; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.BindException; import org.springframework.validation.ObjectError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import javax.servlet.http.HttpServletRequest; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeoutException; /** * 全局异常处理器 * 统一处理应用中的各种异常,提供一致的错误响应格式 */ @RestControllerAdvice @Slf4j public class GlobalExceptionHandler { /** * 业务异常处理 */ @ExceptionHandler(BusinessException.class) public ResponseEntity handleBusinessException(BusinessException e, HttpServletRequest request) { log.warn("业务异常: {} - {}", e.getErrorCode(), e.getMessage(), e); ErrorResponse errorResponse = ErrorResponse.builder() .timestamp(LocalDateTime.now()) .status(HttpStatus.BAD_REQUEST.value()) .error("Business Error") .message(e.getMessage()) .errorCode(e.getErrorCode()) .path(request.getRequestURI()) .build(); return ResponseEntity.badRequest().body(errorResponse); } /** * 秒杀相关异常处理 */ @ExceptionHandler(FlashSaleException.class) public ResponseEntity handleFlashSaleException(FlashSaleException e, HttpServletRequest request) { log.warn("秒杀异常: {} - {}", e.getErrorCode(), e.getMessage(), e); ErrorResponse errorResponse = ErrorResponse.builder() .timestamp(LocalDateTime.now()) .status(HttpStatus.BAD_REQUEST.value()) .error("Flash Sale Error") .message(e.getMessage()) .errorCode(e.getErrorCode()) .path(request.getRequestURI()) .build(); return ResponseEntity.badRequest().body(errorResponse); } /** * 限流异常处理 */ @ExceptionHandler(RateLimitException.class) public ResponseEntity handleRateLimitException(RateLimitException e, HttpServletRequest request) { log.warn("限流异常: {}", e.getMessage(), e); ErrorResponse errorResponse = ErrorResponse.builder() .timestamp(LocalDateTime.now()) .status(HttpStatus.TOO_MANY_REQUESTS.value()) .error("Rate Limit Exceeded") .message(e.getMessage()) .errorCode("RATE_LIMIT_EXCEEDED") .path(request.getRequestURI()) .build(); return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(errorResponse); } /** * 数据验证异常处理 */ @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity handleValidationException(MethodArgumentNotValidException e, HttpServletRequest request) { log.warn("数据验证异常: {}", e.getMessage()); StringBuilder errorMessages = new StringBuilder(); for (ObjectError error : e.getBindingResult().getAllErrors()) { if (errorMessages.length() > 0) { errorMessages.append("; "); } errorMessages.append(error.getDefaultMessage()); } ErrorResponse errorResponse = ErrorResponse.builder() .timestamp(LocalDateTime.now()) .status(HttpStatus.BAD_REQUEST.value()) .error("Validation Error") .message(errorMessages.toString()) .errorCode("VALIDATION_ERROR") .path(request.getRequestURI()) .build(); return ResponseEntity.badRequest().body(errorResponse); } /** * 参数绑定异常处理 */ @ExceptionHandler(BindException.class) public ResponseEntity handleBindException(BindException e, HttpServletRequest request) { log.warn("参数绑定异常: {}", e.getMessage()); StringBuilder errorMessages = new StringBuilder(); for (ObjectError error : e.getBindingResult().getAllErrors()) { if (errorMessages.length() > 0) { errorMessages.append("; "); } errorMessages.append(error.getDefaultMessage()); } ErrorResponse errorResponse = ErrorResponse.builder() .timestamp(LocalDateTime.now()) .status(HttpStatus.BAD_REQUEST.value()) .error("Parameter Binding Error") .message(errorMessages.toString()) .errorCode("BINDING_ERROR") .path(request.getRequestURI()) .build(); return ResponseEntity.badRequest().body(errorResponse); } /** * 约束违规异常处理 */ @ExceptionHandler(ConstraintViolationException.class) public ResponseEntity handleConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) { log.warn("约束违规异常: {}", e.getMessage()); StringBuilder errorMessages = new StringBuilder(); Set> violations = e.getConstraintViolations(); for (ConstraintViolation violation : violations) { if (errorMessages.length() > 0) { errorMessages.append("; "); } errorMessages.append(violation.getMessage()); } ErrorResponse errorResponse = ErrorResponse.builder() .timestamp(LocalDateTime.now()) .status(HttpStatus.BAD_REQUEST.value()) .error("Constraint Violation") .message(errorMessages.toString()) .errorCode("CONSTRAINT_VIOLATION") .path(request.getRequestURI()) .build(); return ResponseEntity.badRequest().body(errorResponse); } /** * 超时异常处理 */ @ExceptionHandler(TimeoutException.class) public ResponseEntity handleTimeoutException(TimeoutException e, HttpServletRequest request) { log.error("超时异常: {}", e.getMessage(), e); ErrorResponse errorResponse = ErrorResponse.builder() .timestamp(LocalDateTime.now()) .status(HttpStatus.REQUEST_TIMEOUT.value()) .error("Timeout Error") .message("请求超时,请稍后重试") .errorCode("TIMEOUT_ERROR") .path(request.getRequestURI()) .build(); return ResponseEntity.status(HttpStatus.REQUEST_TIMEOUT).body(errorResponse); } /** * 非法参数异常处理 */ @ExceptionHandler(IllegalArgumentException.class) public ResponseEntity handleIllegalArgumentException(IllegalArgumentException e, HttpServletRequest request) { log.warn("非法参数异常: {}", e.getMessage(), e); ErrorResponse errorResponse = ErrorResponse.builder() .timestamp(LocalDateTime.now()) .status(HttpStatus.BAD_REQUEST.value()) .error("Illegal Argument") .message(e.getMessage()) .errorCode("ILLEGAL_ARGUMENT") .path(request.getRequestURI()) .build(); return ResponseEntity.badRequest().body(errorResponse); } /** * 空指针异常处理 */ @ExceptionHandler(NullPointerException.class) public ResponseEntity handleNullPointerException(NullPointerException e, HttpServletRequest request) { log.error("空指针异常: {}", e.getMessage(), e); ErrorResponse errorResponse = ErrorResponse.builder() .timestamp(LocalDateTime.now()) .status(HttpStatus.INTERNAL_SERVER_ERROR.value()) .error("Null Pointer Error") .message("系统内部错误,请联系管理员") .errorCode("NULL_POINTER_ERROR") .path(request.getRequestURI()) .build(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); } /** * 运行时异常处理 */ @ExceptionHandler(RuntimeException.class) public ResponseEntity handleRuntimeException(RuntimeException e, HttpServletRequest request) { log.error("运行时异常: {}", e.getMessage(), e); // 对于已知的业务异常,使用友好的错误信息 String message = e.getMessage(); if (message == null || message.trim().isEmpty()) { message = "系统繁忙,请稍后重试"; } ErrorResponse errorResponse = ErrorResponse.builder() .timestamp(LocalDateTime.now()) .status(HttpStatus.INTERNAL_SERVER_ERROR.value()) .error("Runtime Error") .message(message) .errorCode("RUNTIME_ERROR") .path(request.getRequestURI()) .build(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); } /** * 通用异常处理 */ @ExceptionHandler(Exception.class) public ResponseEntity handleGenericException(Exception e, HttpServletRequest request) { log.error("系统异常: {}", e.getMessage(), e); ErrorResponse errorResponse = ErrorResponse.builder() .timestamp(LocalDateTime.now()) .status(HttpStatus.INTERNAL_SERVER_ERROR.value()) .error("System Error") .message("系统异常,请联系管理员") .errorCode("SYSTEM_ERROR") .path(request.getRequestURI()) .build(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); } /** * 统一错误响应格式 */ public static class ErrorResponse { private LocalDateTime timestamp; private int status; private String error; private String message; private String errorCode; private String path; private Map details; public ErrorResponse() { this.details = new HashMap<>(); } public static ErrorResponseBuilder builder() { return new ErrorResponseBuilder(); } // Getters and Setters public LocalDateTime getTimestamp() { return timestamp; } public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; } public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public String getError() { return error; } public void setError(String error) { this.error = error; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getErrorCode() { return errorCode; } public void setErrorCode(String errorCode) { this.errorCode = errorCode; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public Map getDetails() { return details; } public void setDetails(Map details) { this.details = details; } public static class ErrorResponseBuilder { private ErrorResponse errorResponse = new ErrorResponse(); public ErrorResponseBuilder timestamp(LocalDateTime timestamp) { errorResponse.setTimestamp(timestamp); return this; } public ErrorResponseBuilder status(int status) { errorResponse.setStatus(status); return this; } public ErrorResponseBuilder error(String error) { errorResponse.setError(error); return this; } public ErrorResponseBuilder message(String message) { errorResponse.setMessage(message); return this; } public ErrorResponseBuilder errorCode(String errorCode) { errorResponse.setErrorCode(errorCode); return this; } public ErrorResponseBuilder path(String path) { errorResponse.setPath(path); return this; } public ErrorResponseBuilder detail(String key, Object value) { errorResponse.getDetails().put(key, value); return this; } public ErrorResponse build() { return errorResponse; } } } /** * 业务异常类 */ public static class BusinessException extends RuntimeException { private final String errorCode; public BusinessException(String message) { super(message); this.errorCode = "BUSINESS_ERROR"; } public BusinessException(String errorCode, String message) { super(message); this.errorCode = errorCode; } public BusinessException(String message, Throwable cause) { super(message, cause); this.errorCode = "BUSINESS_ERROR"; } public String getErrorCode() { return errorCode; } } /** * 秒杀异常类 */ public static class FlashSaleException extends RuntimeException { private final String errorCode; public FlashSaleException(String message) { super(message); this.errorCode = "FLASH_SALE_ERROR"; } public FlashSaleException(String errorCode, String message) { super(message); this.errorCode = errorCode; } public String getErrorCode() { return errorCode; } } /** * 限流异常类 */ public static class RateLimitException extends RuntimeException { public RateLimitException(String message) { super(message); } public RateLimitException(String message, Throwable cause) { super(message, cause); } } }