在Spring Boot项目中,设计统一的异常处理可以帮助你更好地管理和处理应用中的错误,并以一致的方式返回友好的错误响应。Spring Boot提供了多种方式来实现统一异常处理,常见的方式是通过@ControllerAdvice和@ExceptionHandler注解来集中管理所有控制器的异常。
- 基本设计思路
通过@ControllerAdvice类全局捕获异常,并使用@ExceptionHandler针对不同类型的异常做处理,然后返回自定义的响应。 - 代码实现
2.1 自定义异常类
首先定义一些自定义的异常类,根据你的业务需求来扩展异常处理。
public class CustomNotFoundException extends RuntimeException {
public CustomNotFoundException(String message) {
super(message);
}
}
public class CustomBadRequestException extends RuntimeException {
public CustomBadRequestException(String message) {
super(message);
}
}
2.2 定义错误响应类
用于统一返回错误信息。
public class ErrorResponse {
private int status;
private String message;
private long timestamp;
public ErrorResponse(int status, String message) {
this.status = status;
this.message = message;
this.timestamp = System.currentTimeMillis();
}
// Getters and setters
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
}
2.3 统一异常处理类
使用@ControllerAdvice注解定义全局异常处理类,并用@ExceptionHandler处理不同的异常类型。
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
@ControllerAdvice
public class GlobalExceptionHandler {
// 处理自定义的资源未找到异常
@ExceptionHandler(CustomNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFoundException(CustomNotFoundException ex, WebRequest request) {
ErrorResponse error = new ErrorResponse(HttpStatus.NOT_FOUND.value(), ex.getMessage());
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
// 处理自定义的非法请求异常
@ExceptionHandler(CustomBadRequestException.class)
public ResponseEntity<ErrorResponse> handleBadRequestException(CustomBadRequestException ex, WebRequest request) {
ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
// 处理所有其他未处理的异常
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGlobalException(Exception ex, WebRequest request) {
ErrorResponse error = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), "An unexpected error occurred");
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
2.4 在Controller中使用异常
在Controller中直接抛出自定义异常,以便由全局异常处理器捕获。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
public class MyController {
@GetMapping("/item/{id}")
public String getItem(@PathVariable int id) {
if (id == 1) {
return "Item 1";
} else if (id == 2) {
throw new CustomNotFoundException("Item not found");
} else {
throw new CustomBadRequestException("Invalid request");
}
}
}
- 返回格式示例
假设你请求 /api/item/2,将会返回如下JSON格式的错误响应:
{
"status": 404,
"message": "Item not found",
"timestamp": 1665891017191
}
- 扩展:日志与监控
除了捕获异常和返回响应,通常也会在异常处理过程中记录日志,以便后续分析问题。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGlobalException(Exception ex, WebRequest request) {
logger.error("Unhandled exception occurred: ", ex); // 记录异常信息
ErrorResponse error = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), "An unexpected error occurred");
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}