이전 글에서 ControllerAdvice와 RequestBodyAdvice를 사용해 복호화를 진행했었다. 이전 글에서 ControllerAdvice까지 작성하기엔 너무 길어질 것 같아 따로 글을 작성한다.
@ControllerAdvice는 짧게 말해서 Spring이 제공하는 AOP의 기능 중에 하나이며, 전역에 있는 컨트롤러에 공통적으로 사용되는 것이 있을때 사용한다.
대부분 찾아보면 에러 처리를 위한 @ExceptionHandler를 위해 사용한다. 이외에도 어떻게 사용되는지 알아보자.
@ModelAttribute는 컨트롤러 메서드의 모든 요청 처리 전에 공통 데이터를 모델에 추가하거나, 요청 파라미터를 특정 객체로 매핑할 때 사용된다.
공통 데이터 추가
객체 초기화
작동 위치
여러 컨트롤러에서 공통적으로 사용하는 데이터(예: 사용자 정보)를 자동으로 모델에 추가할 수 있다.
한번 예제를 보면 쉬울 것 같다.
@ControllerAdvice
public class GlobalModelAttribute {
@ModelAttribute
public void addCommonAttributes(Model model) {
model.addAttribute("appName", "MyAPP");
}
}
위에 예제는 공통적으로 사용되는 데이터 "appName" : "MyAPP"을 추가하여 모든 Controller에서 사용 가능하게 한다.
Controller 메서드 실행중 또는 ControllerAdvice에서 특정 예외를 처리하기 위해 사용된다.
아마 대부분 ControllerAdvice를 위의 방식으로 사용하고 있을 것이다. 나도 역시 그렇다.
아래는 현재 프로젝트에 적용된 @ExceptionHandler이다
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* @Valid를 이용한 유효성 검증 커스텀
* - key: errorMessage, value: DTO에서 지정한 메세지
* - 클라이언트에게 에러 응답
* @param ex
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
for (FieldError error : ex.getBindingResult().getFieldErrors()) {
errors.put("errorMessage", error.getDefaultMessage());
}
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
}
나는 @Valid에서 유효성 검증 오류가 발생했을때 사용자게에 보낼 응답을 커스텀하기 위해서 사용하였다.
요청 데이터를 바인딩하거나 특정 형식 데이터를 변환할때 사용한다.
데이터 바인딩 전처리
커스텀 에디터
특정 데이터 형식을 변환하기 위한 커스텀 로직 추가.
예를 들어, 날짜 형식이 문자열로 오면 이를 LocalDate 형식으로 변환하는 작업 등을 할 수 있다
작동 위치
아래는 문자열의 앞뒤 공백을 제거해주는 @InitBinder이다.
@ControllerAdvice
public class GlobalInitBinder {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) {
setValue(text.trim()); // 문자열 앞뒤 공백 제거
}
});
}
}
이전 글에서 설명했던 RequestBodyAdvice와 ResponseBodyAdvice이다.
위 두 인터페이스는 요청 본문과 응답 본문 데이터를 가로채거나 변환하기 위해 사용한다.
인터페이스이기 때문에 메서드 4개를 구현해야한다.
우선 RequestBodyAdvice부터 설명하자면,
역할
작동 위치
ResponseBodyAdvice는 RequestBodyAdvice와 거의 같지만 HTTP 변환 전(Controller 리턴 시)에 응답을 처리한다.
역할
응답 데이터를 공통 포맷으로 변환 (예: JSON 래핑).
특정 응답에 메타데이터 추가.
작동 위치
구현해야 하는 메서드들은 이전 글에 작성했으니 생략하도록 하겠다.
이들을 정리해보자면 아래와 같다.
| 기능 | 역할 | 실행 시점 |
|---|---|---|
| @ModelAttribute | 공통 데이터 추가, 요청 데이터 초기화 | 컨트롤러 메서드 실행 전 |
| @ExceptionHandler | 컨트롤러에서 발생한 예외를 처리 | 예외 발생 시 |
| @InitBinder | 요청 데이터를 바인딩하거나 변환 | 요청 데이터 바인딩 전 |
| RequestBodyAdvice | 요청 본문 데이터 전처리 | 요청 데이터 변환 전/후 |
| ResponseBodyAdvice | 응답 본문 데이터 후처리 | 응답 데이터를 변환하기 전 |