====== @ControllerAdvice ======
* [[https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html|@ControllerAdvice]]
* '' @ExceptionHandler'','' @InitBinder'', ''@ModelAttribute''를 여러 컨트롤러에 걸쳐 공통으로 설정할 수 있다.
===== @ExceptionHandler =====
* [[springframework:mvc:handlerexceptionresolver|HandlerExceptionResolver]]
* [[springframework:problem_spring_web|Problem Spring Web]]
* [[https://dzone.com/articles/global-exception-handling-with-controlleradvice|Global Exception Handling With @ControllerAdvice - DZone Java]]
* ''@ControllerAdvice''에 각종 예외 처리 핸들러(''@ExceptionHandler'')를 미리 등록해 두고 component-scan을 하면 자동 에러 처리가 된다.
* [[http://www.javabeat.net/exception-controlleradvice-spring-3-2/|Exception Handling With @ControllerAdvice in Spring 3.2]]
package javabeat.net;
import java.io.IOException;
import java.sql.SQLException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@ControllerAdvice
public class ControllerAdviceTest {
@ExceptionHandler(IOException.class)
public ModelAndView handleIOException(IOException exception){
ModelAndView andView = new ModelAndView();
andView.setViewName("error");
return andView;
}
@ExceptionHandler(SQLException.class)
public ModelAndView handleSQLException(SQLException exception){
ModelAndView andView = new ModelAndView();
andView.setViewName("error");
return andView;
}
// JSON 에러 내면서 Http Status Code 변경
@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseEntity exceptionHandler(Exception e) {
// org.springframework.http.HttpStatus 를 참조할 것.
HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
SomeErrorObject errorObject = new SomeErrorObject();
return new ResponseEntity<>(errorObject, httpStatus);
}
}
==== Parameter Validation/Binding Exception 처리 ====
=== @Valid 에 의한 파라미터 Validation 오류 핸들러 ===
* ''@Valid'' Validation 시에 오류가 발생했을 때의 처리 핸들러
* [[https://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-adding-validation-to-a-rest-api/|Spring From the Trenches: Adding Validation to a REST API]] 참조.
@ControllerAdvice
public class RestErrorHandler {
private MessageSource messageSource;
@Autowired
public RestErrorHandler(MessageSource messageSource) {
this.messageSource = messageSource;
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ValidationErrorDTO processValidationError(MethodArgumentNotValidException ex) {
BindingResult result = ex.getBindingResult();
List fieldErrors = result.getFieldErrors();
return processFieldErrors(fieldErrors);
}
private ValidationErrorDTO processFieldErrors(List fieldErrors) {
ValidationErrorDTO dto = new ValidationErrorDTO();
for (FieldError fieldError: fieldErrors) {
String localizedErrorMessage = resolveLocalizedErrorMessage(fieldError);
dto.addFieldError(fieldError.getField(), localizedErrorMessage);
}
return dto;
}
private String resolveLocalizedErrorMessage(FieldError fieldError) {
Locale currentLocale = LocaleContextHolder.getLocale();
String localizedErrorMessage = messageSource.getMessage(fieldError, currentLocale);
//If the message was not found, return the most accurate field error code instead.
//You can remove this check if you prefer to get the default error message.
if (localizedErrorMessage.equals(fieldError.getDefaultMessage())) {
String[] fieldErrorCodes = fieldError.getCodes();
localizedErrorMessage = fieldErrorCodes[0];
}
return localizedErrorMessage;
}
}
=== BindingException 처리 ===
* [[https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/BindException.html|BindException]] 은 Controller에서 쿼리 파라미터를 객체로 변환할 때 타입이 다르던가 날짜 포맷팅이 잘못됐던가 할 때 발생한다.
@ExceptionHandler(BindException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ExDto handleBindException(BindException e) {
// BindException이 BindingResult, Errors를 상속하고 있으므로 해당 데이터를 꺼내서 사용하면 된다.
}
==== 주요 Spring MVC Exception에 대해 오버라이드 하지 말 것 ====
* ''ControllerAdvice''나 ''ExceptionHandler''를 override 했을 경우 Spring이 기본으로 지정한 에러코드가 아닌 다른 에러코드로 응답 코드가 내려갈 수도 있다.
* [[https://doanduyhai.wordpress.com/2012/05/06/spring-mvc-part-v-exception-handling/|Spring MVC part V: Exception handling | DuyHai's Java Blog]]
* 주요 Exception들에 대해 올바른 응답 코드가 내려가도록 처리한다.
* [[https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.html|DefaultHandlerExceptionResolver]]를 보면 각 예외별 응답 코드 기본값을 알 수 있다.
===== ResponseBodyAdvice, RequestBodyAdvice =====
* [[https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyAdvice.html|ResponseBodyAdvice (Spring Framework 5.1.3.RELEASE API)]]
* https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/RequestBodyAdvice.html
* [[https://chung-develop.tistory.com/61|[Spring]스프링에서 공통 Response처리 하기(@ControllerAdvice 이용)]]
===== 참고 =====
* [[http://wonwoo.ml/index.php/post/2208|Spring 의 @ControllerAdvice]]