Files
FlashSaleSystem/src/main/java/com/org/flashsalesystem/config/GlobalExceptionHandler.java
YoVinchen 989c2741a2 后端功能增强:全局异常处理、API控制器、JSP视图和单元测试
- 添加 GlobalExceptionHandler 全局异常处理
- 添加 ApiController REST API 控制器
- 更新 WebConfig 跨域配置和 ProductRepository 查询方法
- 新增 monitor/product-detail/profile JSP 视图页面
- 添加 FlashSaleServiceTest 秒杀服务单元测试
- 更新 application.yml 配置
2026-03-05 20:30:48 +08:00

414 lines
15 KiB
Java

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<ErrorResponse> 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<ErrorResponse> 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<ErrorResponse> 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<ErrorResponse> 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<ErrorResponse> 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<ErrorResponse> handleConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
log.warn("约束违规异常: {}", e.getMessage());
StringBuilder errorMessages = new StringBuilder();
Set<ConstraintViolation<?>> 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<ErrorResponse> 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<ErrorResponse> 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<ErrorResponse> 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<ErrorResponse> 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<ErrorResponse> 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<String, Object> 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<String, Object> getDetails() { return details; }
public void setDetails(Map<String, Object> 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);
}
}
}