[SpringBoot] @ControllerAdvice, @RestControllerAdvice - Exception 처리

devdo·2021년 12월 30일
0

SpringBoot

목록 보기
10/35
post-thumbnail

Exception 처리

사실 Exception 처리는 웹 어플리케이션의 입장에서 바라 보았을 때, 에러가 났을 때 처리할 수 있는 방법은 많지 않다.

  1. 에러 페이지
  2. 4xx Error or 5xx Error
  3. Client가 200 외에 처리를 하지 못 할 때는 200을 내려주고 별도의 에러 Message 전달

기본적으로 Exception이 터질시, 클라이언트에게 전달되는 정보들이다. 이 많은 정보들을 클라이언트에게 최소한의 양질의 정보만 전달해줄려면은 Coustomizing한 Excpetion처리(ExcpetionHandler)을 만들어주어야 한다.


Exception 처리 어노테이션

@ControllerAdvice
글로벌 예외 처리 및 특정 package / Controller 예외처리

@ExceptionHandler
특정 Controller의 예외처리

Exception 처리는 바로 구현 예시를 보고 이해하는 게 빠르다.

구현 예시

ApiController

@RestController
@RequestMapping("/api/user")
@Validated
public class ApiController {

    @GetMapping("")
    public UserDto get(
            @Size(min = 2)
            @RequestParam String name,

            @NotNull
            @Min(1) // 최소값
            @RequestParam Integer age) {        // MissingServletRequestParameterException
        System.out.println("getget");
        UserDto user = new UserDto();
        user.setName(name);
        user.setAge(age);

        int a = 10 + age;   // exception 테스트용 코드 NPE
        return user;
    }

    @PostMapping("")
    public UserDto post(@Valid @RequestBody UserDto user) {
        System.out.println(user);
        return user;
    }

    // 특정 예외를 잡는 메서드 -> 특정 컨트롤러안에 있으면 우선순위 가장 높음
/*    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResponseEntity MethodArgumentNotValidException(Exception e) {

        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
    }*/
}

UserDto

@AllArgsConstructor
@NoArgsConstructor
@Data
public class UserDto {

    @NotEmpty
    @Size(min = 1, max = 10)
    private String name;

    @Min(1)
    @NotNull
    private Integer age;
}

GlobalControllerAdvice

@Slf4j
@RestControllerAdvice(basePackages = "com.example.exception.controller")
//@ControllerAdvice // view기반
public class GlobalControllerAdvice {

    // 모든 Exception에 대한 예외처리
    @ExceptionHandler(value = Exception.class)
    public ResponseEntity exception(Exception e) {

        System.out.println(e.getClass().getName());
        System.out.println("#####################");
        System.out.println(e.getLocalizedMessage());
        System.out.println("#####################");

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("");
    }
 }

여기서보면,
@RestControllerAdvice@ControllerAdvice@ResponseBody를 합쳐놓은 어노테이션이다

단순히 예외만 처리하고 싶다면 @ControllerAdvice를 적용하면 되고, 응답으로 객체를 리턴해야 한다면 @RestControllerAdvice를 적용하면 된다.

@ExceptionHandler

이 어노테이션을 메서드에 선언하고 특정 예외 클래스를 지정해주면 해당 예외가 발생했을 때 메서드에 정의한 로직으로 처리할 수 있다. @ControllerAdvice 또는 @RestControllerAdvice에 정의된 메서드가 아닌 일반 컨트롤러 단에 존재하는 메서드에 선언할 경우, 해당 Controller에만 적용된다.

위의 예시는 모든 Exception 처리에 대해서 적용시킨 것이다.

그럼 특정 Exception 처리 예시를 보자.

// 특정 예외를 잡는 메서드 methodArgumentNotValidException
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public ResponseEntity MethodArgumentNotValidException(Exception e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
    }

@ExceptionHandler(value =) 안에 Exception 종류만 넣어주면 특정 예외처리가 가능하다는 걸 알 수 있다.


주의사항

ApiController

@RestController
@RequestMapping("/api/user")
@Validated
public class ApiController {

    @GetMapping("")
    public UserDto get(
            @Size(min = 2)
            @RequestParam String name,

            @NotNull
            @Min(1) // 최소값
            @RequestParam Integer age) {        // MissingServletRequestParameterException
        System.out.println("getget");
        UserDto user = new UserDto();
        user.setName(name);
        user.setAge(age);

        int a = 10 + age;   // exception 테스트용 코드 NPE
        return user;
    }

    @PostMapping("")
    public UserDto post(@Valid @RequestBody UserDto user) {
        System.out.println(user);
        return user;
    }

    // 특정 예외를 잡는 메서드 -> 특정 컨트롤러안에 있으면 우선순위 가장 높음
/*    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResponseEntity MethodArgumentNotValidException(Exception e) {

        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
    }*/
}

@ExceptionHandler의 우선순위는 만들어진 GlobalControllerAdvice안에 순서대로 작성하면 알아서 우선순위가 매겨지지만 바로 Controller안에 작성한 @ExceptionHandler의 우선순위가장 높다는 것을 인지해야 한다.


참고

소스출처 : https://github.com/mooh2jj/exception.git
패스트캠퍼스 스프링 예성환 강의

profile
배운 것을 기록합니다.

0개의 댓글