TIL&WIL
2023-07-14 TIL (예외 처리)
blues_jun
2023. 7. 14. 21:45
문제상황
- 개인 과제의 요구 사항 중에서 validation의 유효성을 검사하고 이에 따른 예외를 처리하는 것이 있었다.
- Controller에서 try-catch 로 이에 해당하는 MethodArgumentNotValidException을 처리하려고 했는데 아직 이유는 잘 모르지만 오류가 발생했다.
- 다른 방법을 찾아보니 @ExceptionHandler로 예외를 처리할 수 있었다.
@ExceptionHandler
- @Controller, @RestController가 적용된 Bean내에서 발생하는 예외를 잡아서 하나의 메서드에서 처리해주는 기능
- Controller, Restcontroller에만 적용이 가능하다 (@Service 같은 빈에서는 안된다.)
- @ExceptionHandler에 등록한 Controller에만 적용된다. ( 다른 Controller에서 같은 exception이 발생하더라도 예외 처리를 할 수 없음
- 리턴 타입은 자유롭게 가능
- 메서드의 파라미터도 자유롭게 가능
@ControllerAdvice
- @ControllerAdvice : 전역으로 예외를 처리할 수 있도록 해줌
해결
에러를 해결하는데 크게 두 가지 방법이 있었다.
- @ControllerAdvice를 활용하여 해당 예외를 Controller 전역에서 처리
- @ExceptionHandler를 해당 Controller에 선언하여 지역에서 처리
@ControllerAdvice를 활용하여 해당 예외를 Controller 전역에서 처리
이 방법은 새로운 클래스를 만들에서 그 클래스를 @ControllerAdvice를 선언해주고 그 안에서 @ExceptionHandler로 해당 예외를 처리해주면 된다. 이렇게 되면 Controller 전역에서 해당 예외를 같은 방법으로 처리할 수 있다.
//@ControllerAdvice : 전역으로 예외를 처리할 수 있음
@ControllerAdvice
public class ExceptionController {
//@valid 유효성체크에 통과하지 못하면 MethodArgumentNotValidException 이 발생한다.
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiResponseDto> methodValidException() {
return ResponseEntity.badRequest().body(new ApiResponseDto("잘못된 형식입니다.", HttpStatus.BAD_REQUEST.value()));
}
}
@ExceptionHandler를 해당 Controller에 선언하여 지역에서 처리
이 방법은 해당 Controller에 메소드를 선언해주는 것이다. 해당 Controller에서 예외가 발생한 경우에 대신 예외를 처리해준다. 다른 클래스에서 발생한 에러는 처리하지 않는다.
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
// 회원 가입
// @valid 유효성체크에 통과하지 못하면 MethodArgumentNotValidException 이 발생한다. -> ControllerAdvice, ExceptionHandler 로 전역에서 예외 관리
@PostMapping("/user/signup")
public ResponseEntity<ApiResponseDto> signup(@Valid @RequestBody SignupRequestDto requestDto) {
try {
userService.signup(requestDto);
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(new ApiResponseDto("중복된 username 입니다", HttpStatus.BAD_REQUEST.value()));
}
return ResponseEntity.ok().body(new ApiResponseDto("회원가입에 성공했습니다.", HttpStatus.CREATED.value()));
}
// 로그인 처리
@GetMapping("/user/login/successful")
public ResponseEntity<ApiResponseDto> login() {
return ResponseEntity.ok().body(new ApiResponseDto("로그인에 성공했습니다.", HttpStatus.OK.value()));
}
@GetMapping("/user/login/fail")
public ResponseEntity<ApiResponseDto> failLogin() {
return ResponseEntity.ok().body(new ApiResponseDto("회원을 찾을 수 없습니다.", HttpStatus.BAD_REQUEST.value()));
}
// @valid 유효성체크에 통과하지 못하면 MethodArgumentNotValidException 이 발생한다.
// 다른 Controller에서 동일한 예외가 발생해도 처리하지 않는다.
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiResponseDto> methodValidException() {
return ResponseEntity.badRequest().body(new ApiResponseDto("잘못된 형식입니다.", HttpStatus.BAD_REQUEST.value()));
}
}
spring은 새로운 개념이 끊임없이 나오는 것 같다.
이 부분을 전부 자연스럽게 사용할 수 있도록 열심히 공부하자..!