@Slf4j
@RestController
public class ApiExceptionController {
// 이하 예외 발생 시 처리하고 싶은 내용 작성
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public ErrorResult illegalExHandle(IllegalArgumentException e) {
log.error(e.getMessage());
return new ErrorResult(" ", e.getMessage());
}
@ExceptionHandler
public ResponseEntity<ErrorResult> userExHandle(UserException e) {
log.error(e.getMessage());
return new ResponseEntity<>(new ErrorResult, HttpStatus.BAD_REQUEST);
}
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler
public ErrorResult exHandle(Exception e) {
log.error(e.getMessage());
return new ErrorResult("~~");
}
// 이하 컨트롤러 코드 작성
@GetMapping("/members/{id}")
public MemberDto getMember(@PathVariable("id) String id) {
if("id".equals(id)) {
throw new RuntimeException("~~");
}
...
}
}
@ExceptionHandler를 선언하고 해당 컨트롤러에서 해당 예외 발생 시 처리하고 싶은 내용을 작성한다.
(1) Exception이 발생하여 컨트롤러 밖으로 던져진다.
(2) 예외가 발생했으므로 ExceptionResolver가 작동한다. 우선순위가 가장 높은 ExceptionHandlerExceptionResolver가 작동한다.
(3) ExceptionHandlerExceptionResolver는 해당 Exception을 처리할 수 있는 @ExceptionHandler가 있는지 확인한다.
(4) 있으면 해당 메소드를 처리한다.
(5) 이후 HTTP 컨버터가 사용되고 맞추어 반환한다.
- ExceptionHandlerExceptionResolver
- ResponseStatusExceptionResolver
- DefaultHandlerExceptionResolver
@ControllerAdvice는 예외 처리 코드 부분과 정상 처리 부분을 분리하여 작성할 수 있게 해준다.
@Slf4j
@RestController
public class ApiExceptionController {
// 기존 @ExceptionHandler를 통한 예외처리 부분 제거
// 이하 기존 컨트롤러 코드
@GetMapping("/members/{id}")
public MemberDto getMember(@PathVariable("id) String id) {
if("id".equals(id)) {
throw new RuntimeException("~~");
}
...
}
}
@Sl4fj
@RestControllerAdvice
public class ExControllerAdvice {
// 위 컨트롤러 상단에 있던 코드 그대로 이하 작성
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public ErrorResult illegalExHandle(IllegalArgumentException e) {
log.error(e.getMessage());
return new ErrorResult(" ", e.getMessage());
}
@ExceptionHandler
public ResponseEntity<ErrorResult> userExHandle(UserException e) {
log.error(e.getMessage());
return new ResponseEntity<>(new ErrorResult, HttpStatus.BAD_REQUEST);
}
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler
public ErrorResult exHandle(Exception e) {
log.error(e.getMessage());
return new ErrorResult("~~");
}
}
@ControllerAdvice는 컨트롤러를 적용 범위를 지정할 수 있다. 적용하지 않으면 전체 컨트롤러를 대상으로 적용한다.
@RestControllerAdvice는 @ControllerAdvice와 같고, @ResponseBody가 추가되어 있다.
이하 컨트롤러 범위 지정 예시
@ControllerAdvice(annotations = RestController.class)
public class ExampleAdvice1 {}
@ControllerAdvice("org.example.controllers")
public class ExampleAdvice2 {}
@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
public class ExampleAdvice3 {}