[Spring boot + Rest API] Handle Exception
This post has been more than 2 years since it was last updated.
1. Overview
Exception trong spring có thể được xử lý bằng nhiều cách. Trong phạm vi bài này m sẽ giới thiệu đến các bạn một vài cách xử lý tương đối cơ bản
- Sử dụng annotation @ExceptionHandler
- Sử dung HandlerExceptionResolver
- Sử dụng annotation @ControllerAdvice
2. ExceptionHandler
Có thể sử dụng annotation này nhằm mục đích đánh dấu method nào sẽ xử lý exception cụ thể nào trong controller VD:
@GetMapping(path = "/car/{id}")
public String getCar(@PathVariable("id") int id) {
switch (id) {
case 1:
throw new CarNotFoundException();
default:
return "Day la car n";
}
}
@ExceptionHandler({CarNotFoundException.class})
public void handleCarException(CarNotFoundException e) {
System.out.println(e.getMessage());
}
Như các bạn đã thấy, method handleCarException được sử dụng để xử lý các exception xảy ra trong restapi getCar
. Cách sử dụng này có một khuyết điểm là chỉ sử dụng trong ngữ cảnh controller cụ thể, không mang tính global được.
3. HandlerExceptionResolver
Bản thân spring đã có một vài cài đặt của handlerExceptionResolver. Cụ thể:
ExceptionHandlerExceptionResolver
được setup thông qua annotation@ExceptionHandler
ResponseStatusExceptionResolver
được setup thông qua annotation@ResponseStatus
Ngoài ra spring còn cung cấp một lớpAbstractHandlerExceptionResolver
cho phép chung ta tự custom một handlerExceptionResolver của ứng dụng mình
@Component
public class MyHandlerExceptionResolve extends AbstractHandlerExceptionResolver {
@Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
try {
if (ex instanceof HomeNotFoundException) {
// do something with error
}
} catch (Exception handlerException) {
}
return new ModelAndView("error");
}
}
4. ControllerAdvice
Giải pháp này đến từ spring AOP. M sẽ có một topic nói về project này. Bạn cứ hiểu nôm na đó là lập trình hướng khía cạnh. Thay vì quan tâm đến việc cụ thẻ hóa các sự vật sự việc trong đời sống như OOP thì AOP quan tâm đến một khía cạnh của vấn đề, Ví dụ: Logging, Handler Exception..... Với các làm này, bạn có thể bốc nguyên logic xử lý exception ra một class riêng.
@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(CarNotFoundException.class)
protected ResponseEntity<ApiError> handleEntityNotFound(
CarNotFoundException ex) {
ApiError apiError = new ApiError(NOT_FOUND);
apiError.setMessage(ex.getMessage());
return buildResponseEntity(apiError);
}
private ResponseEntity<ApiError> buildResponseEntity(ApiError apiError) {
return new ResponseEntity<>(apiError, apiError.getStatus());
}
@Override
protected ResponseEntity<Object> handleAsyncRequestTimeoutException(AsyncRequestTimeoutException ex, HttpHeaders headers, HttpStatus status, WebRequest webRequest) {
return super.handleAsyncRequestTimeoutException(ex, headers, status, webRequest); //To change body of generated methods, choose Tools | Templates.
}
@Override
protected ResponseEntity<Object> handleHttpMediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
return super.handleHttpMediaTypeNotAcceptable(ex, headers, status, request); //To change body of generated methods, choose Tools | Templates.
}
}
Ở đây m có sử dụng đến một class ResponseEntityExceptionHandler
. về cơ bản thằng này giống thằng AbstractHandlerExceptionResolver
. Đều cung cấp các method cho phép ta xử lý exception. nhưng anh chàng này thay vì trả về ModelAndView
thì trả về ResponseEntity
.
Ngoài những method đã được định nghĩa sẵn, bạn có thể kết hợp với @ExceptionHandler
như đã giới thiệu ở phần 1 để xây dựng cho mình cơ chế xử lý exception tiện lợi nhất.
All Rights Reserved