[hodolog] 데이터 검증2 - @ControllerAdvice, @ExceptionHandler[3]

Euiyeon Park·2025년 2월 4일
post-thumbnail

🫧 @Vaild와 BindingResult를 통한 데이터 검증

  • Spring 자체적으로 400 오류를 발생하는 방법 대신
    BindingResult를 통해 직접 error를 컨트롤해서 클라이언트에게 에러 메세지 전달
@PostMapping("/posts")
public Map<String, String> post(@RequestBody @Valid PostCreate params, 
								BindingResult result){
	if(result.hasErrors()){
    	List<FieldError> fieldErrors = result.getFieldErrors();
        FieldError firstFieldError = fieldErrors.get(0);
        String fieldName = firstFieldError.getField();
        String errorMessage = firstFieldError.getDefaultMessage();
        
        Map<String, String> error = new HashMap<>();
        error.put(fieldName, errorMessage);
        return error;
    }
    
    return Map.of();
}

🩵 위와 같은 방식의 문제점

1. 메서드마다 검증 코드가 필요하다

  • 컨트롤러의 메서드가 수십개가 된다면 ..?
  • 반복적인 작업이 발생
  • 개발자가 까먹을 수 있다.
  • 검증 부분에서 버그가 발생할 여지가 높다.

2. 적절하지 않은 반환타입

  • 응답 값에 HashMap 타입을 사용했는데,
    응답 값은 Map이 아니라 응답에 맞는 형태의 클래스를 만들어 사용하는게 좋음

3. 여러 개의 에러 처리가 힘듦

  • 위에 코드는 첫 번째 에러만 처리(fieldErrors.get(0))
  • 만약 여러 개의 에러가 발생해서 여러 개의 응답을 줘야 한다면?

🫧 @ControllerAdvice와 @ExceptionHandler

🩵 @ControllerAdvice

  • 전역 예외 처리를 위한 어노테이션
  • 개별 컨트롤러 클래스에서 예외를 처리할 필요없이,
    모든 컨트롤러에서 발생하는 예외를 한 곳에서 공통적으로 처리

💡 [참고] @ControllerAdvice vs @RestControllerAdvice

어노테이션@ControllerAdvice@RestControllerAdvice
기본 동작HTML 뷰 또는 JSON 데이터 반환 가능기본적으로 JSON데이터(응답 본문)을 반환
@ResponseBody 필요여부JSON 응답 시 @ResponseBody를 메서드에 추가자동으로 @ResponseBody 적용
주요 사용 사례HTML 뷰와 API응답을 혼용하는 프로젝트REST API 전용 프로젝트
내부 구현@ControllerAdvice@ControllerAdvice + @ResponseBody

🩵 @ExceptionHandler

  • 특정 예외를 처리하는 메서드에 적용하는 어노테이션,
    예외를 처리하여 적절한 HTTP 응답을 반환할 수 있음
  • 여러 컨트롤러에서 중복된 예외 처리 코드 제거 가능
  • 예외 유형별로 다른 응답을 설정할 수 있음
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    // 특정 예외 타입에 대한 예외 처리
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(error ->
                errors.put(error.getField(), error.getDefaultMessage())
        );
        return errors;
    }
}

🫧 정리

  • 컨트롤러에서 @RequestBody를 통해 요청 데이터를 PostCreate 객체에 매핑

    • JSON 데이터를(Request DTO)를 자바 객체로 변환
    • 변환 과정에서 Jackson 라이브러리를 사용해 자동으로 매핑(객체 생성)
    • Jackson이 객체를 생성할 때 기본 생성자가 필요
    • 필드 접근을 위해 getter(), setter()가 필요
    • JSON 데이터의 키 이름과 객체 필드명이 일치해야 함
  • PostCreate에는 검증 어노테이션(@NotBlank 등)을 추가하고,
    컨트롤러에는 @Vaild를 추가해 입력 데이터를 검증

  • 요청 데이터 검증 과정에서 에러가 발생하면,
    @ControllerAdvice@ExceptionHandler를 통해 에러를 처리

  • 에러에 대한 정보를 반환하기 위해 ErrorResponse를 작성

ref

인프런 호돌맨의 요절복통 개발쇼 (SpringBoot, Vue.JS, AWS)

profile
"개발자는 해결사이자 발견자이다✨" - Michael C. Feathers

0개의 댓글