사실 Exception 처리는 웹 어플리케이션의 입장에서 바라 보았을 때, 에러가 났을 때 처리할 수 있는 방법은 많지 않다.
기본적으로 Exception이 터질시, 클라이언트에게 전달되는 정보들이다. 이 많은 정보들을 클라이언트에게 최소한의 양질의 정보만 전달해줄려면은 Coustomizing한 Excpetion처리(ExcpetionHandler)
을 만들어주어야 한다.
@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
패스트캠퍼스 스프링 예성환 강의