目录
背景
去面试的时候被问到SpringBoot项目中,如何处理全局异常的,也就是如何捕获全局异常的
前言
在Spring Boot中捕获全局异常是一种有效的方式,可以将应用程序中的所有异常集中处理,提供统一的错误响应,并且可以避免重复编写异常处理逻辑。实现全局异常处理通常使用@ControllerAdvice注解来定义一个全局的异常处理类。在类中编写异常处理方法,并使用@ExceptionHandler注解指定要处理的异常类型。以下是具体的步骤和示例
设计步骤
1.定义异常信息类:
通常情况下,我们会定义一个通用的错误信息类,用来包装异常信息返回给客户端。
public class ErrorDetails {
private int statusCode;
private String message;
private String details;
public ErrorDetails(int statusCode, String message, String details) {
super();
this.statusCode = statusCode;
this.message = message;
this.details = details;
}
// Getters and Setters
public int getStatusCode() {
return statusCode;
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getDetails() {
return details;
}
public void setDetails(String details) {
this.details = details;
}
}
2.自定义异常:
在实际项目中,我们通常会自定义一些异常,比如资源未找到异常。
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
3.创建全局异常处理类
首先,我们需要创建一个带有
@ControllerAdvice
注解的类,这个类可以捕获应用程序中所有控制器(controller)抛出的异常。并使用@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(ResourceNotFoundException.class)
public ResponseEntity<?> resourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(HttpStatus.NOT_FOUND.value(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
}
// 捕获全局异常
@ExceptionHandler(Exception.class)
public ResponseEntity<?> globalExceptionHandler(Exception ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
4.在控制器中抛出异常
在控制器中可以抛出自定义的异常,然后由全局异常处理类来捕获并处理。
@RestController
@RequestMapping("/api")
public class ExportController {
@Resource
private UserDao userDao;
@GetMapping("/resource/{id}")
public ResponseEntity<User> getResourceById(@PathVariable(value = "id") Integer id) {
User user = userDao.selectById(id);
//模拟找不到情况,然后会抛出异常,被全局异常处理器捕捉到
if(user == null){
throw new ResourceNotFoundException("Resource not found for this id :: " + id);
}
return ResponseEntity.ok(user);
}
}
5.输出
捕获 @Valid
校验异常
如果你在控制器中使用
@Valid
进行数据校验,可以捕获校验失败时抛出的MethodArgumentNotValidException。
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<?> handleValidationException(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
}
总结
通过
@ControllerAdvice
和@ExceptionHandler
,我们可以在 Spring Boot 中集中管理和处理异常。全局异常处理不仅提高了代码的可维护性,还为用户提供了统一且友好的错误信息。同时,还可以结合日志记录、监控等功能,为应用提供全面的异常管理机制。