들어가기 전

RestControllerAdvice가 무엇인지에 대해 먼저 알아보고 RestControllerAdvice을 활용한 Validation처리 방법에 대해 알아보겠습니다.

 

validation을 하기 위한 설정

 

build.gradle

implementation 'org.springframework.boot:spring-boot-starter-validation'
  • 의존성을 추가하면 @Valid를 이용하여 Validation처리를 할 수 있습니다.

 

@RestControllerAdvice이란?

@ExceptionHandler, @ModelAttribute, @InitBinder가 적용된 메서드들에 AOP를 적용해 Controller단에 적용하기 위하 고안된 어노테이션입니다.

클래스에 선언하면 되고 @RestController에 대한 전역적으로 발생하는 예외를 처리할 수 있습니다.

그리고 RestControllerAdvice를 보면 ControllerAdvice + ResponseBody가 있습니다.

ControllerAdvice는 RestControllerAdvice와 동일한 역할을 수행합니다.

하지만 ControllerAdvice는 단순히 예외만 처리하고 싶을 때 사용하고 RestControllerAdvice는 예외를 응답할 때 객체로 리턴해야 할 때 사용합니다.

 

 

@RestControllerAdvice 사용 전 Validation처리

필자는 Validation을 처리할 때 아래와 같이 하면 처리된다고 생각을 했습니다.

 

@AllArgsConstructor
@Getter
@NoArgsConstructor
public class PersonRequestDto {
    @NotBlank
    private String name;
    @NotNull
    private String address;
}

 

@RestController
public class RestControllerAdviceExampleController {


    @PostMapping
    public void exampleValidation(@Valid @RequestBody PersonRequestDto personRequestDto) {
        
    }
}

 

 

 

필자가 생각한 결과

 

 

 

실제 결과

 

 

필자가  작성한 코드처럼 했는데 위의 사진처럼 validation처리가 안되었을 경우 MethodArgumentNotValidException이 발생을 했는지 Console에서 확인을 합니다.

이거에 대한 해결방법은 바로 아래에서 설명하겠습니다.

 

해결방법

@RestController
public class RestControllerAdviceExampleController {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, String>> exampleResponseValidation(MethodArgumentNotValidException e) {
        Map<String, String> error = new HashMap<>();
        e.getAllErrors().forEach(
                c -> error.put(((FieldError) c).getField(), c.getDefaultMessage())
        );
        return ResponseEntity.badRequest().body(error);
    }

    @PostMapping
    public void exampleValidation(@Valid @RequestBody PersonRequestDto personRequestDto) {
        
    }
}

 

  • 해당 컨트롤러에서  MethodArgumentNotValidException가 발생하면 @ExceptionHanlder로 처리합니다.

 

 

이렇게 해서 문제는 해결할 수 있습니다. 하지만 치명적인 단점이 있습니다.  컨트롤러에 @ExceptionHanlder를 사용하여 validation처리할 때 컨트롤러를 생성할 때마다 @ExceptionHanlder를 사용하여 validation을 처리하는 코드를 작성을 해줘야 됩니다.

그럼 불필요하게 중복적인 코드가 발생하게 됩니다.

 

중복적인 코드가 발생하는 것을 방지하기 위해 @RestControllerAdvice 또는 @ControllerAdvice를 사용하여 전역적으로 처리해 주면 됩니다.

 

@RestControllerAdvice를 사용하여 전역적으로 Validation을 처리하는 방법

 

import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class ExampleRestControllerAdvice {
}

 

  • @RestControllerAdvice를 클래스에 붙여줍니다. ControllerAdvice를 사용해야 되는 경우라면 @ControllerAdvice를 붙여주면 됩니다.

 

import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class ExampleRestControllerAdvice {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, String>> exampleResponseValidation(MethodArgumentNotValidException e) {
        Map<String, String> error = new HashMap<>();
        e.getAllErrors().forEach(
                c -> error.put(((FieldError) c).getField(), c.getDefaultMessage())
        );
        return ResponseEntity.badRequest().body(error);
    }
}

 

위와 같이 코드를 작성하고 결과를 확인하면  원했던 결과가 확인할 수 있습니다.