API는 동작중 여러 오류사항을 마주할 수 있다.
오류가 발생했을때 클라이언트쪽에서 에러를 판별하고 적절한 처리를 할 수 있도록 예외를 리턴해주어야한다.
우선 boot-starter-web가 없다면 의존성을 추가해준다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
}
1. Response 규정
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum ServerResponse {
SUCCESS(HttpStatus.OK, "OK", HttpStatus.OK.getReasonPhrase())
, INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "ER40100", "Invalid token")
, EXPIRE_TOKEN(HttpStatus.UNAUTHORIZED, "ER40101", "Token expired")
, FORBIDDEN(HttpStatus.FORBIDDEN, "ER40300", HttpStatus.FORBIDDEN.getReasonPhrase())
, INVALID_REQUEST(HttpStatus.BAD_REQUEST, "ER40000", "유효하지 않은 요청입니다")
, INVALID_ACCOUNT(HttpStatus.BAD_REQUEST, "ER40001", "Account information not available.")
, DATA_NOT_EXIST(HttpStatus.BAD_REQUEST, "ER40002", "Data does not exist")
, VALIDATION_ERROR(HttpStatus.BAD_REQUEST, "ER40003", "Request body has an invalid value format.")
, DUPLICATE_NAME_ERROR(HttpStatus.BAD_REQUEST, "ER40011", "Duplicate name")
, INVALID_LOGIN(HttpStatus.BAD_REQUEST, "ER40012", "The ID or password does not match.")
, SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "ER50000", "Contact your administrator")
;
public final int status;
public final String code;
public final String message;
ServerResponse(HttpStatus status, String code, String message) {
this.status = status.value();
this.code = code;
this.message = message;
}
}
개발중에 리턴해줄 예외 Response를 규정한다.
첫번째 인자로 HTTP status값
두번째 인자로 프로젝트내에서 처리할 코드
세번째 인자로 에러 메세지를 넣었다.
2. Exception Handler 생성
@RestControllerAdvice
@Slf4j
public class ServerExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(
@NonNull HttpRequestMethodNotSupportedException ex,
@NonNull HttpHeaders headers,
@NonNull HttpStatusCode status,
@NonNull WebRequest request) {
log.error("handleHttpRequestMethodNotSupported() : 유효하지 않은 메소드 진입", ex);
ServerResponse serverResponse = ServerResponse.INVALID_METHOD;
return ResponseEntity.status(serverResponse.status).body(serverResponse);
}
... 잠시생략 ...
}
첫번째로 handleHttpRequestMethodNotSupported 핸들러를 넣었다.
URL은 맞지만 Method가 맞지 않을때 이 메소드를 타게된다.
@RestControllerAdvice
@Slf4j
public class ServerExceptionHandler extends ResponseEntityExceptionHandler {
... 잠시생략 ...
/**
* 유효성 검사 실패는 400
*
* @param ex MethodArgumentNotValidException
* @return 400 올바르지 않은 형식의 입력값입니다
*/
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
@NonNull MethodArgumentNotValidException ex,
@NonNull HttpHeaders headers,
@NonNull HttpStatusCode status,
@NonNull WebRequest request) {
log.error("handleMethodArgumentNotValid(): 유효성 검사 실패", ex);
ex.printStackTrace();
ServerResponse serverResponse = ServerResponse.VALIDATION_ERROR;
return ResponseEntity.status(serverResponse.status).body(serverResponse);
}
... 잠시생략 ...
}
handleMethodArgumentNotValid는 Request Body로 받은 값이 유효하지 않을때 타게된다.
@RestControllerAdvice
@Slf4j
public class ServerExceptionHandler extends ResponseEntityExceptionHandler {
... 잠시생략 ...
/**
* 잘못된 요청은 400
*
* @param exception BadRequestException
* @return 400 유효하지 않은 요청입니다
*/
@ExceptionHandler(value = {BadRequestException.class})
public ResponseEntity<ServerResponse> badRequestExceptionHandler(BadRequestException exception) {
log.error("badRequestExceptionHandler() : 잘못된 요청", exception);
exception.printStackTrace();
ServerResponse serverResponse = exception.getServerResponse();
return ResponseEntity.status(serverResponse.status).body(serverResponse);
}
... 잠시생략 ...
}
badRequestExceptionHandler는 API를 요청할때 요청값이 올바르지 않을때 리턴한다.
ResponseEntityExceptionHandler에서 명시된 메소드는 아니며, 서비스로직에서 리턴시킬 용도로 만들었다.
아래 Exception과 같이 쓰여야한다.
@Getter
public class BadRequestException extends RuntimeException {
ServerResponse serverResponse;
public BadRequestException(ServerResponse serverResponse) {
super(serverResponse.message);
this.serverResponse = serverResponse;
}
}
@RestControllerAdvice
@Slf4j
public class ServerExceptionHandler extends ResponseEntityExceptionHandler {
... 잠시생략 ...
/**
* BadRequestException 외 모든 Exception은 500
*
* @param exception exception
* @return 500 관리자에게 문의하세요
*/
@ExceptionHandler(value = {ServerException.class, Exception.class})
public ResponseEntity<ServerResponse> serverExceptionHandler(Exception exception) {
log.error("serverExceptionHandler() : 서버 오류 진입", exception);
exception.printStackTrace();
ServerResponse serverResponse = ServerResponse.SERVER_ERROR;
return ResponseEntity.status(serverResponse.status).body(serverResponse);
}
}
나머지 예외처리를 못한 오류에대해서는 ServerException 오류를 리턴한다.
3. 테스트
동작중인 서비스에서 강제로 BadRequestException을 보내보았다.
리턴값이 ServerResponse의 형태대로 출력되었다.
Method를 바꾼 경우에도 오류값이 예상대로 출력되었다
'Back-End > JAVA' 카테고리의 다른 글
Spring 프로젝트 시작하기 - 보안 ) Jwt Token 쿠키 검증 (0) | 2024.11.15 |
---|---|
Spring 프로젝트 시작하기 - 보안 ) Jwt Token 쿠키 발급 (1) | 2024.11.14 |
Spring 프로젝트 시작하기 - 프로파일 설정편 (1) | 2024.11.12 |
Spring 프로젝트 시작하기 - DB 연결(JPA) (0) | 2024.11.11 |
Spring 프로젝트 시작하기 - 구조설계 및 테스트편 (1) | 2024.09.25 |