✅ ErrorCode ENUM 처리
@Getter
public enum ErrorCode {
// 400 Bad Request
BAD_REQUEST(HttpStatus.BAD_REQUEST, "BAD_REQUEST", "클라이언트 요청의 형식이나 내용이 잘못된 경우"),
INVALID_PARAMETER(HttpStatus.BAD_REQUEST, "INVALID_PARAMETER", "요청한 파라미터의 형식이나 내용에 오류가 있는 경우"),
INVALID_RESOURCE(HttpStatus.BAD_REQUEST, "INVALID_RESOURCE", "요청한 리소스의 내용에 오류가 있는 경우"),
MISSING_PARAMETER(HttpStatus.BAD_REQUEST, "MISSING_PARAMETER", "필수 파라미터를 지정하지 않은 경우"),
LIMIT_EXCEEDED_400(HttpStatus.BAD_REQUEST, "LIMIT_EXCEEDED", "제한 설정을 초과한 경우"),
OUT_OF_RANGE_400(HttpStatus.BAD_REQUEST, "OUT_OF_RANGE", "요청 값이 범위를 벗어나는 경우"),
// 401 Unauthorized
UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "UNAUTHORIZED", "요구되는 인증 정보가 누락되었거나 잘못됨"),
INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "INVALID_TOKEN", "Access Token이 잘못된 경우"),
// 403 Forbidden
FORBIDDEN(HttpStatus.FORBIDDEN, "FORBIDDEN", "요청은 이해했지만 권한이 없어 거부됨"),
ACCESS_DENIED(HttpStatus.FORBIDDEN, "ACCESS_DENIED", "요청한 리소스에 대한 접근이 제한됨"),
LIMIT_EXCEEDED_403(HttpStatus.FORBIDDEN, "LIMIT_EXCEEDED", "리소스 제한을 초과한 경우"),
OUT_OF_RANGE_403(HttpStatus.FORBIDDEN, "OUT_OF_RANGE", "요청 범위를 벗어난 경우"),
INSUFFICIENT_SCOPE(HttpStatus.FORBIDDEN, "INSUFFICIENT_SCOPE", "Access Token에 필요한 Scope 권한이 없음"),
// 404 Not Found
NOT_FOUND(HttpStatus.NOT_FOUND, "NOT_FOUND", "요청한 리소스를 찾을 수 없음"),
RESOURCE_NOT_EXIST(HttpStatus.NOT_FOUND, "RESOURCE_NOT_EXIST", "특정 리소스를 찾을 수 없음"),
// 409 Conflict
CONFLICT(HttpStatus.CONFLICT, "CONFLICT", "요청한 리소스와 충돌 발생"),
ALREADY_EXIST(HttpStatus.CONFLICT, "ALREADY_EXIST", "요청한 리소스가 이미 존재함"),
RESOURCE_ALREADY_EXIST(HttpStatus.CONFLICT, "RESOURCE_ALREADY_EXIST", "특정 리소스가 이미 존재함"),
// 410 Gone
DELETED(HttpStatus.GONE, "DELETED", "요청한 리소스가 삭제되어 존재하지 않음"),
// 500 Internal Server Error
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "INTERNAL_SERVER_ERROR", "서버 내부 오류 발생"),
// 503 Service Unavailable
SERVICE_UNAVAILABLE(HttpStatus.SERVICE_UNAVAILABLE, "SERVICE_UNAVAILABLE", "일시적인 서버 오류");
ErrorCode(HttpStatus httpStatus, String errorCode, String message) {
this.httpStatus = httpStatus;
this.errorCode = errorCode;
this.message = message;
}
private final HttpStatus httpStatus;
private final String errorCode;
private final String message;
}
✏️ 공부내용
일단 httpStatus와 errorCode로 세분화를 해서 enum을 구성했고 단순히 httpStatus와 message보다는 구체적으로 어떤 오류인지 errorCode를 정의해서 사용함으로써 오류를 직관적으로 알수있다.
@Getter
@Builder
@RequiredArgsConstructor
public class ErrorResponse{
private String errorCode;
private String errorMessage;
public static ErrorResponse of(String errorCode, String errorMessage){
return ErrorResponse.builder()
.errorCode(errorCode)
.errorMessage(errorMessage)
.build();
}
//BindingResult에 Error정보들이 들어간다.
public static ErrorResponse of(String errorCode, BindingResult bindingResult){
return ErrorResponse.builder()
.errorCode(errorCode)
.errorMessage(createErrorMessage(bindingResult))
.build();
}
private static String createErrorMessage(BindingResult bindingResult) {
StringBuilder sb = new StringBuilder();
boolean isFirst = true;
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
//첫번째 에러 메세지가 아니면 ", " 단위로 연결을 해준다
if(!isFirst){
sb.append(", ");
}else{
isFirst = false;
}
sb.append("[");
//에러의 필드명
sb.append(fieldError.getField());
sb.append("]");
//에러의 기본 메세지
sb.append(fieldError.getDefaultMessage());
}
return sb.toString();
}
}
✏️ ErrorCode 공부내용
of 메서드는 오버로딩을 사용해서 erroMessage와 bindingResult에서의 메세지를 사용할수있게 하였다.
bindingResult는 BindingResult로 매개변수를 바인딩 할 시 오류가 발생해도 에러를 발생시키지 않고 에러코드를 BindingResult 객체가 저장해서 그걸로 인해 에러를 전달할수 있다. ( 즉 controller에서 오류발생시 사용 )
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* javax.validation.Valid 또는 @Validated binding error가 발생할 경우
*/
@ExceptionHandler(BindException.class)
protected ResponseEntity<ErrorResponse> handleBindException(BindException e) {
log.error("handleBindException", e);
ErrorResponse errorResponse = ErrorResponse.of(HttpStatus.BAD_REQUEST.toString(), e.getBindingResult());
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(errorResponse);
}
/**
* 주로 @RequestParam enum으로 binding 못했을 경우 발생
*/
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
protected ResponseEntity<ErrorResponse> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
log.error("handleMethodArgumentTypeMismatchException", e);
ErrorResponse errorResponse = ErrorResponse.of(HttpStatus.BAD_REQUEST.toString(), e.getMessage());
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(errorResponse);
}
/**
* 지원하지 않은 HTTP method 호출 할 경우 발생
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
protected ResponseEntity<ErrorResponse> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
log.error("handleHttpRequestMethodNotSupportedException", e);
ErrorResponse errorResponse = ErrorResponse.of(HttpStatus.METHOD_NOT_ALLOWED.toString(), e.getMessage());
return ResponseEntity.status(HttpStatus.METHOD_NOT_ALLOWED).body(errorResponse);
}
/**
* 비즈니스 로직 실행 중 오류 발생
*/
@ExceptionHandler(value = { BusinessException.class })
protected ResponseEntity<ErrorResponse> handleConflict(BusinessException e) {
log.error("BusinessException", e);
ErrorResponse errorResponse = ErrorResponse.of(e.getErrorCode().getErrorCode(), e.getMessage());
return ResponseEntity.status(e.getErrorCode().getHttpStatus())
.body(errorResponse);
}
/**
* 나머지 예외 발생
*/
@ExceptionHandler(Exception.class)
protected ResponseEntity<ErrorResponse> handleException(Exception e) {
log.error("Exception", e);
ErrorResponse errorResponse = ErrorResponse.of(HttpStatus.INTERNAL_SERVER_ERROR.toString(), e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
}
}
✏️ GlobalExceptionHandler 공부내용
Exception의 종류에 따라서 method를 만들어서 사용하면될거같다.
ErrorCode는 httpStatus코드를 넣어놨다 저 세분해서 넣어도될꺼같다
'Project' 카테고리의 다른 글
| [Side Project] application.yml설정 & default_batch_fetch_size & OSIV (0) | 2025.05.18 |
|---|---|
| [Side Project] CORS 설정 & Preflight (0) | 2025.05.18 |
| [Side Project] Health Check API - 서버 상태 체크 (1) | 2025.05.17 |