본문 바로가기

개인적으로 공부한 것을 정리해 놓은 블로그입니다 틀린 것이 있으면 댓글 부탁 드립니다!


SPRING BOOT

Spring boot 공부 3 - 예외 처리 ControllerAdvice와 @ExceptionHandler

반응형

Web Application의 입장에서 에러가 났을 때 에러를 내려줄 수 있는 방법은 아래와 같다

 

1. 에러 페이지 

 

2. 4xx Error or 5xx Error

 

3. Client 가 200 외에 처리를 하지 못 할 때는 200을 내려주고 별도의 에러 Message를 전달

 

 

d

두 가지 요청이 있다 

Get 요청 컨트롤러의 경우 이름과 age를 파라미터로 받는고 age 는 Integer 타입이기 때문에 값이 없다면 null로 들어오게 된다 . setAge 부분에서 NullPointerExcetion(NPE라고 하겠다)이 발생할 것이다 . 

 

요청과 응답 결과는 아래 그림과 같다

 

 

서버쪽에서 NPE 가 발생했기 때문에 500 에러가 발생했다 기본적인 정보는 들어가 있지만 어떤에러가 발생했는지는 알 수 없다.

 

 

 

Post 요청에서는 annotation을 통해 검증하고 user를 검증하고 있다.  

 

 

User 클래스에선 위와 같이

name 에 대해서는 빈 값이면 안되고 사이즈는 최소 1 최대 10이도록 

age에 대해서는 최소값이 1이도록 검증하게 했다 .

 

요청 결과는 아래 그림과 같다 .

 

클라이언트에서 잘못된 값을 넘겨주었기 떄문에 400 에러가 발생한다 위의 Get 요청과 같이 기본적인 정보만 들어가게 된다  클라이언트가 알 수 있는 정보가 많지 않다 . 

 

예외 처리를 통해 조금 더 친절하게 해보자

 

@RestControllerAdvice  //RestAPI 컨트롤러용 advice
//@ViewResolverAdvice MVC 형식일때의 advice
public class GlobalControllerAdvice {

    @ExceptionHandler(value = Exception.class)
    public ResponseEntity exception(Exception e){

        System.out.println(e.getMessage());
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("");

    }
}

 

2가지 방법이 있다

 

1.@ControllerAdvice을 붙힌 advice 클래스를 만들어서 @ExceptionHandler를 지정하면   애플리케이션 전역(Global)에서 일어나는 예외를 잡을때  사용된다. 

 

2.특정 컨트롤러에 @ExceptionHandler를 붙힌 메서드를 만든다.

@ControllerAdvice가 지정되어 있더라도 우선순위는 컨트롤러내의  @ExceptionHandler이 위에 있기때문에 해당 클래스안에서만 @ExceptionHandler가 적용된다

 

 

1번 방법을 먼저 알아보자

 

Advice 클래스를 만들어야한다 . 

 

@RestControllerAdvice는 Rest 형식의 컨트롤러에서 사용되는 advice이다 애플리케이션 전역(Global)에서 일어나는 예

외를 잡을때  사용된다. 

 

@ExceptionHandler는 예외를 핸들링하는 annotation이다 

 

핸들링할 메서드를 만들고 @ExceptionHandler을 붙힌 후에 해당 메서드에 핸들링 로직을 구현한다. 

 

RestAPI 이기 때문에 ResponseEntity를 리턴한다. 

 

위의 경우 value로 Exception 타입을 받기 떄문에 모든 예외상황이 잡힌다.  

 

파라미터로 @ExceptionHandler에 지정한 예외를 받아서 사용할 수도 있다 . 

 

@RestControllerAdvice  //RestAPI 컨트롤러용 advice
//@ViewResolverAdvice MVC 형식일때의 advice
public class GlobalControllerAdvice {

	//모든 Exception 에 대해서 잡아낸다.
    @ExceptionHandler(value = Exception.class)
    public ResponseEntity exception(Exception e){
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("");

    }
    
    //특정 Exception 을 지정해서 잡아낸다.
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResponseEntity MethodArgumentNotValidException(MethodArgumentNotValidException e){
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
    }
}

 

 

ControllerAdvice를 지정해서  예외를 잡아내고 ResponseEntity를 생성해서 리턴해주었다 응답코드는 400번이며 

응답바디에는 해당 예외에 대한 메시지가 담겨있다 . 

 

요청을 보내보면 아래 그림과 같다. 

 

 

 

메시지가 잘 정리되어 있지는 않지만 더 많은 정보가 담겨있다 . 

 

@RestControllerAdvice의 옵션으로 basePackages 를 지정해주면 예외를 잡아낼 범위를 지정해 줄 수도 있다 .

 

예시)

@RestControllerAdvice(basePackages = "com.example.hello.exception.*")

 

 

 

 

2번 방법으로 특정 컨트롤러에 @ExceptionHandler를 지정해 보잡 

 

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

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

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResponseEntity MethodArgumentNotValidException(MethodArgumentNotValidException e){
        System.out.println("controller handler");
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("controller handler");
    }
}

 

컨트롤러에   @ExceptionHandler를 만들었다 현재 위의 @ControllerAdvice로 glabal 로도  똑같은 핸들러가 지정되

 

있는 상태이다 우선순위는 Controller 안에 Handler가 위이기 때문에 응답 바디에 controller handler가 찍힐 것이다. 

 

반응형