✔ Java 11
✔ Gradle 7
✔ Spring boot 2.6.3
Controller 예외 처리
1. Error Response
@Getter
@AllArgsConstructor
public class ErrorResponse {
private int status;
private String message;
}
밑의 json 형태로 반환하기 위해 response entity를 생성한다.
{
"status" : 200,
"message" : "ok"
}
2. Enum - ErrorCode
@Getter
@AllArgsConstructor
public enum ErrorCodeEnum {
USER_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "User Not Found"),
USER_ALREADY_EXIST(HttpStatus.CONFLICT.value(), "User Already Exist");
private final int status;
private final String message;
}
json으로 반환할 값을 enum으로 생성한다.
enum명(int status, String message) 형태로 필요한 에러를 선언하면 된다.
3. Custom Error
@Getter
public class ApiException extends RuntimeException {
private final ErrorCodeEnum errorCodeEnum;
public ApiException(ErrorCodeEnum e){
super(e.getMessage());
this.errorCodeEnum = e;
}
}
예외 처리를 사용하기 위해 공통 Exception을 구현한다.
예외를 보낼 곳에 이런 형태로 사용할 수 있다.
throw new ApiException(ErrorCodeEnum.USER_NOT_FOUND);
4. RestControllerAdvice
@Slf4j
- loging API 제공하는 메소드로 log를 사용할 수 있다.
@RestControllerAdvice
- 전역에서 발생되는 예외를 처리하기 위한 어노테이션
- 예외 발생 시 json 형태로 반환한다.
@ExceptionHandler
- 예외 발생 시 직접 정의한 핸들링을 통해 json 형태로 에러 메시지를 전달한다.
@Slf4j
@RestControllerAdvice
public class ApiExceptionAdvice {
@ExceptionHandler({ApiException.class})
protected ResponseEntity<ErrorResponse> exceptionHandler(final ApiException e) {
return new ResponseEntity<>(
new ErrorResponse( // json 형태
e.getErrorCodeEnum().getStatus(),
e.getErrorCodeEnum().getMessage()
),
HttpStatus.valueOf( // http 상태 코드
e.getErrorCodeEnum().getStatus()
));
}
@ExceptionHandler({MethodArgumentNotValidException.class}) //400
protected ResponseEntity<ErrorResponse> MethodArgumentNotValidExceptionHandler(final MethodArgumentNotValidException e) {
log.error(e.getCause().getMessage()); // 에러 로그로 해당 메시지를 찍을 수 있음
return new ResponseEntity<>(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), e.getLocalizedMessage()), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler({Exception.class}) //500
protected ResponseEntity<ErrorResponse> ExceptionHandler(final Exception e) {
log.error(e.getCause().getMessage());
return new ResponseEntity<>(new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getLocalizedMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler({DataIntegrityViolationException.class}) //409
protected ResponseEntity<ErrorResponse> DataIntegrityViolationExceptionHandler(final DataIntegrityViolationException e) {
log.error(e.getCause().getMessage());
return new ResponseEntity<>(new ErrorResponse(HttpStatus.CONFLICT.value(), e.getLocalizedMessage()), HttpStatus.CONFLICT);
}
@ExceptionHandler({MethodArgumentTypeMismatchException.class}) //400
protected ResponseEntity<ErrorResponse> MethodArgumentTypeMismatchExceptionHandler(final MethodArgumentTypeMismatchException e) {
log.error(e.getCause().getMessage());
return new ResponseEntity<>(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), e.getLocalizedMessage()), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler({HttpRequestMethodNotSupportedException.class}) //405
protected ResponseEntity<ErrorResponse> HttpRequestMethodNotSupportedExceptionHandler(final HttpRequestMethodNotSupportedException e) {
log.error(e.getCause().getMessage());
return new ResponseEntity<>(new ErrorResponse(HttpStatus.METHOD_NOT_ALLOWED.value(), e.getLocalizedMessage()), HttpStatus.METHOD_NOT_ALLOWED);
}
}
ApiException
- 위에서 직접 정의한 예외로 커스텀한 메시지를 전달할 수 있다.
MethodArgumentNotValidException
- @Valid 어노테이션으로 인한 에러를 잡을 수 있다.
Exception
- 500 상태 코드 예외 처리
- NullPointException 등이 잡힌다.
DataIntegrityViolationException
- lower level persistence exception과 관련된 예외를 잡아준다.
- sql문이나 data가 잘못된 경우 잡힌다.
MethodArgumentTypeMismatchException
- enum type이 일치하지 않아 바인딩을 못할 경우 발생한다.
HttpRequestMethodNotSupportedException
- 지원하지 않는 http 메소드를 호출할 때 발생한다.
sql문이 잘못된 경우
2. userService - 예외 처리
1. 회원 생성
@Transactional
public void createUser(UserRequestDto userRequestDto) {
// 예외 처리
if(userRepository.existsByUserId(userRequestDto.getUserId())){
throw new ApiException(ErrorCodeEnum.USER_ALREADY_EXIST);
}
UserMinj user = UserMinj.createUser(userRequestDto.getUserId(), userRequestDto.getUserName(), userRequestDto.getUserPassword());
userRepository.save(user);
}
회원을 생성할 때 이미 존재하는 회원 아이디인지 체크를 해주어야 한다.
직접 예외를 생성하지 않는다면 500이 반환되어, 409와 함께 이미 존재하는 회원이라는 예외를 던져준다.
entity > user > repository > userRespository.java
Boolean existsByUserId(String userId);
해당 메소드는 userId가 존재할 경우 true를 반환한다.
exception > ErrorCodeEnum.java
USER_ALREADY_EXIST(HttpStatus.CONFLICT.value(), "User Already Exist");
409를 반환하는 에러 코드를 추가해준다.
중복된 회원일 경우
2. 회원 상세 조회 / 회원 삭제 / 회원 수정
@Transactional
public UserResponseDto detailsUser(long id) {
// 예외 처리
UserMinj userMinj = userRepository.findById(id).orElseThrow(() ->{
throw new ApiException(ErrorCodeEnum.USER_NOT_FOUND);
});
return UserResponseDto.of(userMinj);
}
id가 존재하지 않을 경우 404와 함께 존재하지 않는 회원이란 예외를 던져준다.
exception > ErrorCodeEnum.java
USER_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "User Not Found");
404를 반환하는 에러 코드를 추가해준다.
존재하지 않는 아이디일 경우
참고 글
예외 처리 방법 참조 - https://leeys.tistory.com/30
예외 처리 핸들러 참조 - https://cheese10yun.github.io/spring-guide-exception/
handler 설명 참고 - https://sun-22.tistory.com/12
restAdvice 참고 - https://shinsunyoung.tistory.com/54
'Study > Spring' 카테고리의 다른 글
[Spring | test | H2] test에서 H2 DB 연결하기 (0) | 2022.02.12 |
---|---|
[Spring boot | MySQL] Intellij에 MySQL 연결하기 | 모든 프로젝트에서 연결된 디비 연결하기 (0) | 2022.02.11 |
[Spring | Gradle 7] QueryDSL 적용 (0) | 2022.02.10 |
회원 수정 기능 구현 | Spring Spring boot JPA Study (1) | 2022.02.10 |
회원 조회 기능 | Spring Spring boot JPA Study (0) | 2022.02.08 |
댓글