From b564774a816ef5b4a570622a7f09e6e033817ae3 Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Tue, 22 Oct 2024 00:57:48 +0900 Subject: [PATCH 1/2] =?UTF-8?q?#81=20[refactor]=20:=20CustomException?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=ED=86=B5=EC=9D=BC=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../onetime/exception/CustomException.java | 25 +++++++++++ .../onetime/exception/EventException.java | 15 ------- .../EventParticipationException.java | 15 ------- .../onetime/exception/MemberException.java | 15 ------- .../onetime/exception/ScheduleException.java | 15 ------- .../onetime/exception/SelectionException.java | 15 ------- .../onetime/exception/TokenErrorResult.java | 40 ----------------- .../onetime/exception/TokenException.java | 15 ------- .../side/onetime/exception/UserException.java | 15 ------- .../EventErrorStatus.java} | 10 ++--- .../EventParticipationErrorStatus.java} | 8 ++-- .../MemberErrorStatus.java} | 11 ++--- .../ScheduleErrorStatus.java} | 11 +++-- .../SelectionErrorStatus.java} | 6 +-- .../exception/status/TokenErrorStatus.java | 40 +++++++++++++++++ .../UserErrorStatus.java} | 9 ++-- .../onetime/global/common/ApiResponse.java | 5 +++ .../global/common/status/ErrorStatus.java | 8 +++- .../side/onetime/service/EventService.java | 27 ++++++----- .../side/onetime/service/MemberService.java | 19 ++++---- .../side/onetime/service/ScheduleService.java | 45 ++++++++++--------- .../side/onetime/service/TokenService.java | 8 ++-- .../java/side/onetime/service/UrlService.java | 8 ++-- .../side/onetime/service/UserService.java | 10 ++--- src/main/java/side/onetime/util/JwtUtil.java | 21 +++++---- 25 files changed, 176 insertions(+), 240 deletions(-) create mode 100644 src/main/java/side/onetime/exception/CustomException.java delete mode 100644 src/main/java/side/onetime/exception/EventException.java delete mode 100644 src/main/java/side/onetime/exception/EventParticipationException.java delete mode 100644 src/main/java/side/onetime/exception/MemberException.java delete mode 100644 src/main/java/side/onetime/exception/ScheduleException.java delete mode 100644 src/main/java/side/onetime/exception/SelectionException.java delete mode 100644 src/main/java/side/onetime/exception/TokenErrorResult.java delete mode 100644 src/main/java/side/onetime/exception/TokenException.java delete mode 100644 src/main/java/side/onetime/exception/UserException.java rename src/main/java/side/onetime/exception/{EventErrorResult.java => status/EventErrorStatus.java} (66%) rename src/main/java/side/onetime/exception/{EventParticipationErrorResult.java => status/EventParticipationErrorStatus.java} (73%) rename src/main/java/side/onetime/exception/{ScheduleErrorResult.java => status/MemberErrorStatus.java} (62%) rename src/main/java/side/onetime/exception/{MemberErrorResult.java => status/ScheduleErrorStatus.java} (63%) rename src/main/java/side/onetime/exception/{SelectionErrorResult.java => status/SelectionErrorStatus.java} (78%) create mode 100644 src/main/java/side/onetime/exception/status/TokenErrorStatus.java rename src/main/java/side/onetime/exception/{UserErrorResult.java => status/UserErrorStatus.java} (68%) diff --git a/src/main/java/side/onetime/exception/CustomException.java b/src/main/java/side/onetime/exception/CustomException.java new file mode 100644 index 0000000..9a03e27 --- /dev/null +++ b/src/main/java/side/onetime/exception/CustomException.java @@ -0,0 +1,25 @@ +package side.onetime.exception; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import side.onetime.global.common.code.BaseErrorCode; + +@Getter +@RequiredArgsConstructor +public class CustomException extends RuntimeException { + private final BaseErrorCode errorCode; + + @Override + public String getMessage() { + return errorCode.getReasonHttpStatus().getMessage(); + } + + public String getCode() { + return errorCode.getReasonHttpStatus().getCode(); + } + + public HttpStatus getHttpStatus() { + return errorCode.getReasonHttpStatus().getHttpStatus(); + } +} \ No newline at end of file diff --git a/src/main/java/side/onetime/exception/EventException.java b/src/main/java/side/onetime/exception/EventException.java deleted file mode 100644 index 72457fa..0000000 --- a/src/main/java/side/onetime/exception/EventException.java +++ /dev/null @@ -1,15 +0,0 @@ -package side.onetime.exception; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor -public class EventException extends RuntimeException { - private final EventErrorResult eventErrorResult; - - @Override - public String getMessage() { - return eventErrorResult.getMessage(); - } -} \ No newline at end of file diff --git a/src/main/java/side/onetime/exception/EventParticipationException.java b/src/main/java/side/onetime/exception/EventParticipationException.java deleted file mode 100644 index c635365..0000000 --- a/src/main/java/side/onetime/exception/EventParticipationException.java +++ /dev/null @@ -1,15 +0,0 @@ -package side.onetime.exception; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor -public class EventParticipationException extends RuntimeException { - private final EventParticipationErrorResult eventParticipationErrorResult; - - @Override - public String getMessage() { - return eventParticipationErrorResult.getMessage(); - } -} \ No newline at end of file diff --git a/src/main/java/side/onetime/exception/MemberException.java b/src/main/java/side/onetime/exception/MemberException.java deleted file mode 100644 index a6547e9..0000000 --- a/src/main/java/side/onetime/exception/MemberException.java +++ /dev/null @@ -1,15 +0,0 @@ -package side.onetime.exception; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor -public class MemberException extends RuntimeException { - private final MemberErrorResult memberErrorResult; - - @Override - public String getMessage() { - return memberErrorResult.getMessage(); - } -} \ No newline at end of file diff --git a/src/main/java/side/onetime/exception/ScheduleException.java b/src/main/java/side/onetime/exception/ScheduleException.java deleted file mode 100644 index e370c4d..0000000 --- a/src/main/java/side/onetime/exception/ScheduleException.java +++ /dev/null @@ -1,15 +0,0 @@ -package side.onetime.exception; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor -public class ScheduleException extends RuntimeException { - private final ScheduleErrorResult scheduleErrorResult; - - @Override - public String getMessage() { - return scheduleErrorResult.getMessage(); - } -} \ No newline at end of file diff --git a/src/main/java/side/onetime/exception/SelectionException.java b/src/main/java/side/onetime/exception/SelectionException.java deleted file mode 100644 index 7c02fb3..0000000 --- a/src/main/java/side/onetime/exception/SelectionException.java +++ /dev/null @@ -1,15 +0,0 @@ -package side.onetime.exception; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor -public class SelectionException extends RuntimeException { - private final SelectionErrorResult selectionErrorResult; - - @Override - public String getMessage() { - return selectionErrorResult.getMessage(); - } -} \ No newline at end of file diff --git a/src/main/java/side/onetime/exception/TokenErrorResult.java b/src/main/java/side/onetime/exception/TokenErrorResult.java deleted file mode 100644 index 89e1b53..0000000 --- a/src/main/java/side/onetime/exception/TokenErrorResult.java +++ /dev/null @@ -1,40 +0,0 @@ -package side.onetime.exception; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; -import side.onetime.global.common.code.BaseErrorCode; -import side.onetime.global.common.dto.ErrorReasonDto; - -@Getter -@RequiredArgsConstructor -public enum TokenErrorResult implements BaseErrorCode { - _INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "401", "유효하지 않은 토큰입니다."), - _INVALID_REFRESH_TOKEN(HttpStatus.UNAUTHORIZED, "401", "유효하지 않은 리프레쉬 토큰입니다."), - _EXPIRED_TOKEN(HttpStatus.UNAUTHORIZED, "401", "만료된 토큰입니다."), - _NOT_FOUND_REFRESH_TOKEN(HttpStatus.UNAUTHORIZED, "401", "리프레쉬 토큰을 찾을 수 없습니다.") - ; - - private final HttpStatus httpStatus; - private final String code; - private final String message; - - @Override - public ErrorReasonDto getReason() { - return ErrorReasonDto.builder() - .isSuccess(false) - .code(code) - .message(message) - .build(); - } - - @Override - public ErrorReasonDto getReasonHttpStatus() { - return ErrorReasonDto.builder() - .isSuccess(false) - .httpStatus(httpStatus) - .code(code) - .message(message) - .build(); - } -} \ No newline at end of file diff --git a/src/main/java/side/onetime/exception/TokenException.java b/src/main/java/side/onetime/exception/TokenException.java deleted file mode 100644 index e82e9ff..0000000 --- a/src/main/java/side/onetime/exception/TokenException.java +++ /dev/null @@ -1,15 +0,0 @@ -package side.onetime.exception; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor -public class TokenException extends RuntimeException { - private final TokenErrorResult tokenErrorResult; - - @Override - public String getMessage() { - return tokenErrorResult.getMessage(); - } -} \ No newline at end of file diff --git a/src/main/java/side/onetime/exception/UserException.java b/src/main/java/side/onetime/exception/UserException.java deleted file mode 100644 index a7de386..0000000 --- a/src/main/java/side/onetime/exception/UserException.java +++ /dev/null @@ -1,15 +0,0 @@ -package side.onetime.exception; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor -public class UserException extends RuntimeException { - private final UserErrorResult userErrorResult; - - @Override - public String getMessage() { - return userErrorResult.getMessage(); - } -} \ No newline at end of file diff --git a/src/main/java/side/onetime/exception/EventErrorResult.java b/src/main/java/side/onetime/exception/status/EventErrorStatus.java similarity index 66% rename from src/main/java/side/onetime/exception/EventErrorResult.java rename to src/main/java/side/onetime/exception/status/EventErrorStatus.java index fe01044..11aaf50 100644 --- a/src/main/java/side/onetime/exception/EventErrorResult.java +++ b/src/main/java/side/onetime/exception/status/EventErrorStatus.java @@ -1,4 +1,4 @@ -package side.onetime.exception; +package side.onetime.exception.status; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -8,10 +8,10 @@ @Getter @RequiredArgsConstructor -public enum EventErrorResult implements BaseErrorCode { - _NOT_FOUND_EVENT(HttpStatus.NOT_FOUND, "404", "이벤트를 찾을 수 없습니다."), - _IS_NOT_DATE_FORMAT(HttpStatus.NOT_FOUND, "404", "날짜 이벤트에 요일을 입력할 수 없습니다."), - _IS_NOT_DAY_FORMAT(HttpStatus.NOT_FOUND, "404", "요일 이벤트에 날짜를 입력할 수 없습니다.") +public enum EventErrorStatus implements BaseErrorCode { + _NOT_FOUND_EVENT(HttpStatus.NOT_FOUND, "EVENT-001", "이벤트를 찾을 수 없습니다."), + _IS_NOT_DATE_FORMAT(HttpStatus.BAD_REQUEST, "EVENT-002", "날짜 이벤트에 요일을 입력할 수 없습니다."), + _IS_NOT_DAY_FORMAT(HttpStatus.BAD_REQUEST, "EVENT-003", "요일 이벤트에 날짜를 입력할 수 없습니다.") ; private final HttpStatus httpStatus; diff --git a/src/main/java/side/onetime/exception/EventParticipationErrorResult.java b/src/main/java/side/onetime/exception/status/EventParticipationErrorStatus.java similarity index 73% rename from src/main/java/side/onetime/exception/EventParticipationErrorResult.java rename to src/main/java/side/onetime/exception/status/EventParticipationErrorStatus.java index 5356ee5..447a4d1 100644 --- a/src/main/java/side/onetime/exception/EventParticipationErrorResult.java +++ b/src/main/java/side/onetime/exception/status/EventParticipationErrorStatus.java @@ -1,4 +1,4 @@ -package side.onetime.exception; +package side.onetime.exception.status; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -8,9 +8,9 @@ @Getter @RequiredArgsConstructor -public enum EventParticipationErrorResult implements BaseErrorCode { - _NOT_FOUND_EVENT_PARTICIPATION(HttpStatus.NOT_FOUND, "404", "이벤트 참여 여부를 찾을 수 없습니다."), - _IS_NOT_USERS_CREATED_EVENT_PARTICIPATION(HttpStatus.BAD_REQUEST, "400", "해당 이벤트의 생성자가 아닙니다."), +public enum EventParticipationErrorStatus implements BaseErrorCode { + _NOT_FOUND_EVENT_PARTICIPATION(HttpStatus.NOT_FOUND, "EVENT-PARTICIPATION-001", "이벤트 참여 여부를 찾을 수 없습니다."), + _IS_NOT_USERS_CREATED_EVENT_PARTICIPATION(HttpStatus.BAD_REQUEST, "EVENT-PARTICIPATION-002", "해당 이벤트의 생성자가 아닙니다."), ; private final HttpStatus httpStatus; diff --git a/src/main/java/side/onetime/exception/ScheduleErrorResult.java b/src/main/java/side/onetime/exception/status/MemberErrorStatus.java similarity index 62% rename from src/main/java/side/onetime/exception/ScheduleErrorResult.java rename to src/main/java/side/onetime/exception/status/MemberErrorStatus.java index 8858a26..0d4c788 100644 --- a/src/main/java/side/onetime/exception/ScheduleErrorResult.java +++ b/src/main/java/side/onetime/exception/status/MemberErrorStatus.java @@ -1,4 +1,4 @@ -package side.onetime.exception; +package side.onetime.exception.status; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -8,10 +8,11 @@ @Getter @RequiredArgsConstructor -public enum ScheduleErrorResult implements BaseErrorCode { - _NOT_FOUND_ALL_SCHEDULES(HttpStatus.NOT_FOUND, "404", "전체 스케줄을 가져오는 데 실패했습니다."), - _NOT_FOUND_DAY_SCHEDULES(HttpStatus.NOT_FOUND, "404", "요일 스케줄을 가져오는 데 실패했습니다."), - _NOT_FOUND_DATE_SCHEDULES(HttpStatus.NOT_FOUND, "404", "날짜 스케줄을 가져오는 데 실패했습니다."), +public enum MemberErrorStatus implements BaseErrorCode { + _NOT_FOUND_MEMBER(HttpStatus.NOT_FOUND, "MEMBER-001", "멤버를 찾을 수 없습니다."), + _IS_EXISTED_NAME(HttpStatus.CONFLICT, "MEMBER-002", "이미 존재하는 이름입니다."), + _IS_ALREADY_REGISTERED(HttpStatus.CONFLICT, "MEMBER-003", "이미 등록된 멤버입니다."), + _NOT_FOUND_MEMBERS(HttpStatus.NOT_FOUND, "MEMBER-004", "멤버 전체 목록을 가져오는 데 실패했습니다.") ; private final HttpStatus httpStatus; diff --git a/src/main/java/side/onetime/exception/MemberErrorResult.java b/src/main/java/side/onetime/exception/status/ScheduleErrorStatus.java similarity index 63% rename from src/main/java/side/onetime/exception/MemberErrorResult.java rename to src/main/java/side/onetime/exception/status/ScheduleErrorStatus.java index 711c226..8bb98f4 100644 --- a/src/main/java/side/onetime/exception/MemberErrorResult.java +++ b/src/main/java/side/onetime/exception/status/ScheduleErrorStatus.java @@ -1,4 +1,4 @@ -package side.onetime.exception; +package side.onetime.exception.status; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -8,11 +8,10 @@ @Getter @RequiredArgsConstructor -public enum MemberErrorResult implements BaseErrorCode { - _NOT_FOUND_MEMBER(HttpStatus.NOT_FOUND, "404", "멤버를 찾을 수 없습니다."), - _IS_EXISTED_NAME(HttpStatus.CONFLICT, "409", "이미 존재하는 이름입니다."), - _IS_ALREADY_REGISTERED(HttpStatus.CONFLICT, "409", "이미 등록된 멤버입니다."), - _NOT_FOUND_MEMBERS(HttpStatus.NOT_FOUND, "404", "멤버 전체 목록을 가져오는 데 실패했습니다.") +public enum ScheduleErrorStatus implements BaseErrorCode { + _NOT_FOUND_ALL_SCHEDULES(HttpStatus.NOT_FOUND, "SCHEDULE-001", "전체 스케줄을 가져오는 데 실패했습니다."), + _NOT_FOUND_DAY_SCHEDULES(HttpStatus.NOT_FOUND, "SCHEDULE-002", "요일 스케줄을 가져오는 데 실패했습니다."), + _NOT_FOUND_DATE_SCHEDULES(HttpStatus.NOT_FOUND, "SCHEDULE-003", "날짜 스케줄을 가져오는 데 실패했습니다."), ; private final HttpStatus httpStatus; diff --git a/src/main/java/side/onetime/exception/SelectionErrorResult.java b/src/main/java/side/onetime/exception/status/SelectionErrorStatus.java similarity index 78% rename from src/main/java/side/onetime/exception/SelectionErrorResult.java rename to src/main/java/side/onetime/exception/status/SelectionErrorStatus.java index 78698bc..87483d2 100644 --- a/src/main/java/side/onetime/exception/SelectionErrorResult.java +++ b/src/main/java/side/onetime/exception/status/SelectionErrorStatus.java @@ -1,4 +1,4 @@ -package side.onetime.exception; +package side.onetime.exception.status; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -8,8 +8,8 @@ @Getter @RequiredArgsConstructor -public enum SelectionErrorResult implements BaseErrorCode { - _NOT_FOUND_ALL_SELECTIONS(HttpStatus.NOT_FOUND, "404", "전체 선택 목록을 가져오는 데 실패했습니다."), +public enum SelectionErrorStatus implements BaseErrorCode { + _NOT_FOUND_ALL_SELECTIONS(HttpStatus.NOT_FOUND, "SELECTION-001", "전체 선택 목록을 가져오는 데 실패했습니다."), ; private final HttpStatus httpStatus; diff --git a/src/main/java/side/onetime/exception/status/TokenErrorStatus.java b/src/main/java/side/onetime/exception/status/TokenErrorStatus.java new file mode 100644 index 0000000..4edff09 --- /dev/null +++ b/src/main/java/side/onetime/exception/status/TokenErrorStatus.java @@ -0,0 +1,40 @@ +package side.onetime.exception.status; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import side.onetime.global.common.code.BaseErrorCode; +import side.onetime.global.common.dto.ErrorReasonDto; + +@Getter +@RequiredArgsConstructor +public enum TokenErrorStatus implements BaseErrorCode { + _INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "TOKEN-001", "유효하지 않은 토큰입니다."), + _INVALID_REFRESH_TOKEN(HttpStatus.UNAUTHORIZED, "TOKEN-002", "유효하지 않은 리프레쉬 토큰입니다."), + _EXPIRED_TOKEN(HttpStatus.UNAUTHORIZED, "TOKEN-003", "만료된 토큰입니다."), + _NOT_FOUND_REFRESH_TOKEN(HttpStatus.UNAUTHORIZED, "TOKEN-004", "리프레쉬 토큰을 찾을 수 없습니다.") + ; + + private final HttpStatus httpStatus; + private final String code; + private final String message; + + @Override + public ErrorReasonDto getReason() { + return ErrorReasonDto.builder() + .isSuccess(false) + .code(code) + .message(message) + .build(); + } + + @Override + public ErrorReasonDto getReasonHttpStatus() { + return ErrorReasonDto.builder() + .isSuccess(false) + .httpStatus(httpStatus) + .code(code) + .message(message) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/side/onetime/exception/UserErrorResult.java b/src/main/java/side/onetime/exception/status/UserErrorStatus.java similarity index 68% rename from src/main/java/side/onetime/exception/UserErrorResult.java rename to src/main/java/side/onetime/exception/status/UserErrorStatus.java index c29dc0f..42f0a37 100644 --- a/src/main/java/side/onetime/exception/UserErrorResult.java +++ b/src/main/java/side/onetime/exception/status/UserErrorStatus.java @@ -1,4 +1,4 @@ -package side.onetime.exception; +package side.onetime.exception.status; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -8,10 +8,9 @@ @Getter @RequiredArgsConstructor -public enum UserErrorResult implements BaseErrorCode { - _NOT_FOUND_USER(HttpStatus.NOT_FOUND, "404", "유저를 찾을 수 없습니다."), - _NICKNAME_TOO_LONG(HttpStatus.BAD_REQUEST, "400", "닉네임 길이 제한을 초과했습니다."), - _NOT_FOUND_REQUEST_NICKNAME(HttpStatus.BAD_REQUEST, "400", "닉네임 요청 값을 찾을 수 없습니다.") +public enum UserErrorStatus implements BaseErrorCode { + _NOT_FOUND_USER(HttpStatus.NOT_FOUND, "USER-001", "유저를 찾을 수 없습니다."), + _NICKNAME_TOO_LONG(HttpStatus.BAD_REQUEST, "USER-002", "닉네임 길이 제한을 초과했습니다."), ; private final HttpStatus httpStatus; diff --git a/src/main/java/side/onetime/global/common/ApiResponse.java b/src/main/java/side/onetime/global/common/ApiResponse.java index 5f95338..f1744d9 100644 --- a/src/main/java/side/onetime/global/common/ApiResponse.java +++ b/src/main/java/side/onetime/global/common/ApiResponse.java @@ -32,4 +32,9 @@ public static ResponseEntity> onFailure(BaseErrorCode code) { ApiResponse response = new ApiResponse<>(false, code.getReasonHttpStatus().getCode(), code.getReasonHttpStatus().getMessage(), null); return ResponseEntity.status(code.getReasonHttpStatus().getHttpStatus()).body(response); } + + public static ResponseEntity onFailure(BaseErrorCode code, String message) { + ApiResponse response = new ApiResponse<>(false, code.getReasonHttpStatus().getCode(), message, null); + return ResponseEntity.status(code.getReasonHttpStatus().getHttpStatus()).body(response); + } } \ No newline at end of file diff --git a/src/main/java/side/onetime/global/common/status/ErrorStatus.java b/src/main/java/side/onetime/global/common/status/ErrorStatus.java index 3aefbf3..5f0b9f8 100644 --- a/src/main/java/side/onetime/global/common/status/ErrorStatus.java +++ b/src/main/java/side/onetime/global/common/status/ErrorStatus.java @@ -10,10 +10,14 @@ @AllArgsConstructor public enum ErrorStatus implements BaseErrorCode { // 전역 에러 - _INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR,"500", "서버에서 요청을 처리 하는 동안 오류가 발생했습니다."), + _INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR,"500", "서버 내부 오류가 발생했습니다. 자세한 사항은 백엔드 팀에 문의하세요."), _BAD_REQUEST(HttpStatus.BAD_REQUEST,"400", "입력 값이 잘못된 요청 입니다."), _UNAUTHORIZED(HttpStatus.UNAUTHORIZED,"401", "인증이 필요 합니다."), - _FORBIDDEN(HttpStatus.FORBIDDEN, "403", "금지된 요청 입니다."); + _FORBIDDEN(HttpStatus.FORBIDDEN, "403", "금지된 요청 입니다."), + _METHOD_NOT_ALLOWED(HttpStatus.METHOD_NOT_ALLOWED, "405", "허용되지 않은 요청 메소드입니다."), + _UNSUPPORTED_MEDIA_TYPE(HttpStatus.UNSUPPORTED_MEDIA_TYPE, "415", "지원되지 않는 미디어 타입입니다."), + _NOT_FOUND_HANDLER(HttpStatus.NOT_FOUND, "404", "해당 경로에 대한 핸들러를 찾을 수 없습니다."), + ; private final HttpStatus httpStatus; private final String code; diff --git a/src/main/java/side/onetime/service/EventService.java b/src/main/java/side/onetime/service/EventService.java index 01dbf03..2b23aa1 100644 --- a/src/main/java/side/onetime/service/EventService.java +++ b/src/main/java/side/onetime/service/EventService.java @@ -8,7 +8,10 @@ import side.onetime.domain.enums.EventStatus; import side.onetime.dto.event.request.CreateEventRequest; import side.onetime.dto.event.response.*; -import side.onetime.exception.*; +import side.onetime.exception.CustomException; +import side.onetime.exception.status.EventErrorStatus; +import side.onetime.exception.status.EventParticipationErrorStatus; +import side.onetime.exception.status.ScheduleErrorStatus; import side.onetime.repository.EventParticipationRepository; import side.onetime.repository.EventRepository; import side.onetime.repository.ScheduleRepository; @@ -39,12 +42,12 @@ public CreateEventResponse createEventForAnonymousUser(CreateEventRequest create if (createEventRequest.category().equals(Category.DATE)) { if (!isDateFormat(createEventRequest.ranges().get(0))) { - throw new EventException(EventErrorResult._IS_NOT_DATE_FORMAT); + throw new CustomException(EventErrorStatus._IS_NOT_DATE_FORMAT); } createAndSaveDateSchedules(event, createEventRequest.ranges(), createEventRequest.startTime(), createEventRequest.endTime()); } else { if (isDateFormat(createEventRequest.ranges().get(0))) { - throw new EventException(EventErrorResult._IS_NOT_DAY_FORMAT); + throw new CustomException(EventErrorStatus._IS_NOT_DAY_FORMAT); } createAndSaveDaySchedules(event, createEventRequest.ranges(), createEventRequest.startTime(), createEventRequest.endTime()); } @@ -67,12 +70,12 @@ public CreateEventResponse createEventForAuthenticatedUser(CreateEventRequest cr if (createEventRequest.category().equals(Category.DATE)) { if (!isDateFormat(createEventRequest.ranges().get(0))) { - throw new EventException(EventErrorResult._IS_NOT_DATE_FORMAT); + throw new CustomException(EventErrorStatus._IS_NOT_DATE_FORMAT); } createAndSaveDateSchedules(event, createEventRequest.ranges(), createEventRequest.startTime(), createEventRequest.endTime()); } else { if (isDateFormat(createEventRequest.ranges().get(0))) { - throw new EventException(EventErrorResult._IS_NOT_DAY_FORMAT); + throw new CustomException(EventErrorStatus._IS_NOT_DAY_FORMAT); } createAndSaveDaySchedules(event, createEventRequest.ranges(), createEventRequest.startTime(), createEventRequest.endTime()); } @@ -114,10 +117,10 @@ protected void createAndSaveDaySchedules(Event event, List ranges, Strin @Transactional(readOnly = true) public GetEventResponse getEvent(String eventId) { Event event = eventRepository.findByEventId(UUID.fromString(eventId)) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); List schedules = scheduleRepository.findAllByEvent(event) - .orElseThrow(() -> new ScheduleException(ScheduleErrorResult._NOT_FOUND_ALL_SCHEDULES)); + .orElseThrow(() -> new CustomException(ScheduleErrorStatus._NOT_FOUND_ALL_SCHEDULES)); List ranges = event.getCategory().equals(Category.DATE) ? DateUtil.getSortedDateRanges(schedules.stream().map(Schedule::getDate).toList(), "yyyy.MM.dd") @@ -130,7 +133,7 @@ public GetEventResponse getEvent(String eventId) { @Transactional(readOnly = true) public GetParticipantsResponse getParticipants(String eventId) { Event event = eventRepository.findByEventId(UUID.fromString(eventId)) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); // 이벤트에 참여하는 모든 멤버 List members = event.getMembers(); @@ -154,7 +157,7 @@ public GetParticipantsResponse getParticipants(String eventId) { @Transactional(readOnly = true) public List getMostPossibleTime(String eventId) { Event event = eventRepository.findByEventId(UUID.fromString(eventId)) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); // 이벤트에 참여하는 모든 멤버 List members = event.getMembers(); @@ -291,13 +294,13 @@ public List getUserParticipatedEvents(String public void removeUserCreatedEvent(String authorizationHeader, String eventId) { User user = jwtUtil.getUserFromHeader(authorizationHeader); Event event = eventRepository.findByEventId(UUID.fromString(eventId)) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); EventParticipation eventParticipation = eventParticipationRepository.findByUserAndEvent(user, event) - .orElseThrow(() -> new EventParticipationException(EventParticipationErrorResult._NOT_FOUND_EVENT_PARTICIPATION)); + .orElseThrow(() -> new CustomException(EventParticipationErrorStatus._NOT_FOUND_EVENT_PARTICIPATION)); if (!EventStatus.CREATOR.equals(eventParticipation.getEventStatus())) { // 해당 이벤트의 생성자가 아닌 경우 - throw new EventParticipationException(EventParticipationErrorResult._IS_NOT_USERS_CREATED_EVENT_PARTICIPATION); + throw new CustomException(EventParticipationErrorStatus._IS_NOT_USERS_CREATED_EVENT_PARTICIPATION); } eventRepository.deleteEvent(event); diff --git a/src/main/java/side/onetime/service/MemberService.java b/src/main/java/side/onetime/service/MemberService.java index a52a94c..5a31c29 100644 --- a/src/main/java/side/onetime/service/MemberService.java +++ b/src/main/java/side/onetime/service/MemberService.java @@ -15,7 +15,10 @@ import side.onetime.dto.member.response.LoginMemberResponse; import side.onetime.dto.member.response.RegisterMemberResponse; import side.onetime.dto.member.response.ScheduleResponse; -import side.onetime.exception.*; +import side.onetime.exception.CustomException; +import side.onetime.exception.status.EventErrorStatus; +import side.onetime.exception.status.MemberErrorStatus; +import side.onetime.exception.status.ScheduleErrorStatus; import side.onetime.repository.EventRepository; import side.onetime.repository.MemberRepository; import side.onetime.repository.ScheduleRepository; @@ -38,10 +41,10 @@ public class MemberService { public RegisterMemberResponse registerMember(RegisterMemberRequest registerMemberRequest) { UUID eventId = UUID.fromString(registerMemberRequest.eventId()); Event event = eventRepository.findByEventId(eventId) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); if (memberRepository.existsByEventAndName(event, registerMemberRequest.name())) { - throw new MemberException(MemberErrorResult._IS_ALREADY_REGISTERED); + throw new CustomException(MemberErrorStatus._IS_ALREADY_REGISTERED); } Member member = registerMemberRequest.toEntity(event); @@ -66,7 +69,7 @@ private List createMembersDaySelections(Event event, Member member, R String day = schedule.timePoint(); List times = schedule.times(); List selectedSchedules = scheduleRepository.findAllByEventAndDay(event, day) - .orElseThrow(() -> new ScheduleException(ScheduleErrorResult._NOT_FOUND_DAY_SCHEDULES)); + .orElseThrow(() -> new CustomException(ScheduleErrorStatus._NOT_FOUND_DAY_SCHEDULES)); for (Schedule selectedSchedule : selectedSchedules) { if (times.contains(selectedSchedule.getTime())) { @@ -88,7 +91,7 @@ private List createMembersDateSelections(Event event, Member member, String date = schedule.timePoint(); List times = schedule.times(); List selectedSchedules = scheduleRepository.findAllByEventAndDate(event, date) - .orElseThrow(() -> new ScheduleException(ScheduleErrorResult._NOT_FOUND_DATE_SCHEDULES)); + .orElseThrow(() -> new CustomException(ScheduleErrorStatus._NOT_FOUND_DATE_SCHEDULES)); for (Schedule selectedSchedule : selectedSchedules) { if (times.contains(selectedSchedule.getTime())) { @@ -107,10 +110,10 @@ private List createMembersDateSelections(Event event, Member member, public LoginMemberResponse loginMember(LoginMemberRequest loginMemberRequest) { UUID eventId = UUID.fromString(loginMemberRequest.eventId()); Event event = eventRepository.findByEventId(eventId) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); Member member = memberRepository.findByEventAndNameAndPin(event, loginMemberRequest.name(), loginMemberRequest.pin()) - .orElseThrow(() -> new MemberException(MemberErrorResult._NOT_FOUND_MEMBER)); + .orElseThrow(() -> new CustomException(MemberErrorStatus._NOT_FOUND_MEMBER)); return LoginMemberResponse.of(member, event); } @@ -120,7 +123,7 @@ public LoginMemberResponse loginMember(LoginMemberRequest loginMemberRequest) { public IsDuplicateResponse isDuplicate(IsDuplicateRequest isDuplicateRequest) { UUID eventId = UUID.fromString(isDuplicateRequest.eventId()); Event event = eventRepository.findByEventId(eventId) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); return IsDuplicateResponse.of(!memberRepository.existsByEventAndName(event, isDuplicateRequest.name())); } } \ No newline at end of file diff --git a/src/main/java/side/onetime/service/ScheduleService.java b/src/main/java/side/onetime/service/ScheduleService.java index 8fae3d9..cf6c89b 100644 --- a/src/main/java/side/onetime/service/ScheduleService.java +++ b/src/main/java/side/onetime/service/ScheduleService.java @@ -13,7 +13,10 @@ import side.onetime.dto.schedule.response.DaySchedule; import side.onetime.dto.schedule.response.PerDateSchedulesResponse; import side.onetime.dto.schedule.response.PerDaySchedulesResponse; -import side.onetime.exception.*; +import side.onetime.exception.CustomException; +import side.onetime.exception.status.EventErrorStatus; +import side.onetime.exception.status.MemberErrorStatus; +import side.onetime.exception.status.ScheduleErrorStatus; import side.onetime.repository.*; import side.onetime.util.JwtUtil; @@ -35,9 +38,9 @@ public class ScheduleService { @Transactional public void createDaySchedulesForAnonymousUser(CreateDayScheduleRequest createDayScheduleRequest) { Event event = eventRepository.findByEventId(UUID.fromString(createDayScheduleRequest.eventId())) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); Member member = memberRepository.findByMemberId(UUID.fromString(createDayScheduleRequest.memberId())) - .orElseThrow(() -> new MemberException(MemberErrorResult._NOT_FOUND_MEMBER)); + .orElseThrow(() -> new CustomException(MemberErrorStatus._NOT_FOUND_MEMBER)); List daySchedules = createDayScheduleRequest.daySchedules(); List selections = new ArrayList<>(); @@ -45,7 +48,7 @@ public void createDaySchedulesForAnonymousUser(CreateDayScheduleRequest createDa String day = daySchedule.day(); List times = daySchedule.times(); List schedules = scheduleRepository.findAllByEventAndDay(event, day) - .orElseThrow(() -> new ScheduleException(ScheduleErrorResult._NOT_FOUND_DAY_SCHEDULES)); + .orElseThrow(() -> new CustomException(ScheduleErrorStatus._NOT_FOUND_DAY_SCHEDULES)); for (Schedule schedule : schedules) { if (times.contains(schedule.getTime())) { @@ -65,7 +68,7 @@ public void createDaySchedulesForAnonymousUser(CreateDayScheduleRequest createDa @Transactional public void createDaySchedulesForAuthenticatedUser(CreateDayScheduleRequest createDayScheduleRequest, String authorizationHeader) { Event event = eventRepository.findByEventId(UUID.fromString(createDayScheduleRequest.eventId())) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); User user = jwtUtil.getUserFromHeader(authorizationHeader); // 참여 정보가 없는 경우 참여자로 저장 eventParticipationRepository.findByUserAndEvent(user, event) @@ -85,7 +88,7 @@ public void createDaySchedulesForAuthenticatedUser(CreateDayScheduleRequest crea String day = daySchedule.day(); List times = daySchedule.times(); List schedules = scheduleRepository.findAllByEventAndDay(event, day) - .orElseThrow(() -> new ScheduleException(ScheduleErrorResult._NOT_FOUND_DAY_SCHEDULES)); + .orElseThrow(() -> new CustomException(ScheduleErrorStatus._NOT_FOUND_DAY_SCHEDULES)); for (Schedule schedule : schedules) { if (times.contains(schedule.getTime())) { @@ -105,9 +108,9 @@ public void createDaySchedulesForAuthenticatedUser(CreateDayScheduleRequest crea @Transactional public void createDateSchedulesForAnonymousUser(CreateDateScheduleRequest createDateScheduleRequest) { Event event = eventRepository.findByEventId(UUID.fromString(createDateScheduleRequest.eventId())) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); Member member = memberRepository.findByMemberId(UUID.fromString(createDateScheduleRequest.memberId())) - .orElseThrow(() -> new MemberException(MemberErrorResult._NOT_FOUND_MEMBER)); + .orElseThrow(() -> new CustomException(MemberErrorStatus._NOT_FOUND_MEMBER)); List dateSchedules = createDateScheduleRequest.dateSchedules(); List selections = new ArrayList<>(); @@ -115,7 +118,7 @@ public void createDateSchedulesForAnonymousUser(CreateDateScheduleRequest create String date = dateSchedule.date(); List times = dateSchedule.times(); List schedules = scheduleRepository.findAllByEventAndDate(event, date) - .orElseThrow(() -> new ScheduleException(ScheduleErrorResult._NOT_FOUND_DATE_SCHEDULES)); + .orElseThrow(() -> new CustomException(ScheduleErrorStatus._NOT_FOUND_DATE_SCHEDULES)); for (Schedule schedule : schedules) { if (times.contains(schedule.getTime())) { @@ -135,7 +138,7 @@ public void createDateSchedulesForAnonymousUser(CreateDateScheduleRequest create @Transactional public void createDateSchedulesForAuthenticatedUser(CreateDateScheduleRequest createDateScheduleRequest, String authorizationHeader) { Event event = eventRepository.findByEventId(UUID.fromString(createDateScheduleRequest.eventId())) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); User user = jwtUtil.getUserFromHeader(authorizationHeader); // 참여 정보가 없는 경우 참여자로 저장 eventParticipationRepository.findByUserAndEvent(user, event) @@ -156,7 +159,7 @@ public void createDateSchedulesForAuthenticatedUser(CreateDateScheduleRequest cr List times = dateSchedule.times(); List schedules = scheduleRepository.findAllByEventAndDate(event, date) - .orElseThrow(() -> new ScheduleException(ScheduleErrorResult._NOT_FOUND_DATE_SCHEDULES)); + .orElseThrow(() -> new CustomException(ScheduleErrorStatus._NOT_FOUND_DATE_SCHEDULES)); for (Schedule schedule : schedules) { if (times.contains(schedule.getTime())) { @@ -178,7 +181,7 @@ public void createDateSchedulesForAuthenticatedUser(CreateDateScheduleRequest cr @Transactional(readOnly = true) public List getAllDaySchedules(String eventId) { Event event = eventRepository.findByEventId(UUID.fromString(eventId)) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); // 이벤트에 참여하는 모든 멤버 List members = memberRepository.findAllWithSelectionsAndSchedulesByEvent(event); @@ -234,10 +237,10 @@ public List getAllDaySchedules(String eventId) { @Transactional(readOnly = true) public PerDaySchedulesResponse getMemberDaySchedules(String eventId, String memberId) { Event event = eventRepository.findByEventId(UUID.fromString(eventId)) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); Member member = memberRepository.findByMemberIdWithSelections(UUID.fromString(memberId)) - .orElseThrow(() -> new MemberException(MemberErrorResult._NOT_FOUND_MEMBER)); + .orElseThrow(() -> new CustomException(MemberErrorStatus._NOT_FOUND_MEMBER)); Map> groupedSelectionsByDay = member.getSelections().stream() .collect(Collectors.groupingBy( @@ -257,7 +260,7 @@ public PerDaySchedulesResponse getMemberDaySchedules(String eventId, String memb @Transactional(readOnly = true) public PerDaySchedulesResponse getUserDaySchedules(String eventId, String authorizationHeader) { Event event = eventRepository.findByEventId(UUID.fromString(eventId)) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); User user = jwtUtil.getUserFromHeader(authorizationHeader); @@ -280,7 +283,7 @@ public PerDaySchedulesResponse getUserDaySchedules(String eventId, String author @Transactional(readOnly = true) public List getAllDateSchedules(String eventId) { Event event = eventRepository.findByEventId(UUID.fromString(eventId)) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); // 이벤트에 참여하는 모든 멤버 List members = memberRepository.findAllWithSelectionsAndSchedulesByEvent(event); @@ -336,10 +339,10 @@ public List getAllDateSchedules(String eventId) { @Transactional(readOnly = true) public PerDateSchedulesResponse getMemberDateSchedules(String eventId, String memberId) { Event event = eventRepository.findByEventId(UUID.fromString(eventId)) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); Member member = memberRepository.findByMemberIdWithSelections(UUID.fromString(memberId)) - .orElseThrow(() -> new MemberException(MemberErrorResult._NOT_FOUND_MEMBER)); + .orElseThrow(() -> new CustomException(MemberErrorStatus._NOT_FOUND_MEMBER)); Map> groupedSelectionsByDate = member.getSelections().stream() .collect(Collectors.groupingBy( @@ -359,7 +362,7 @@ public PerDateSchedulesResponse getMemberDateSchedules(String eventId, String me @Transactional(readOnly = true) public PerDateSchedulesResponse getUserDateSchedules(String eventId, String authorizationHeader) { Event event = eventRepository.findByEventId(UUID.fromString(eventId)) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); User user = jwtUtil.getUserFromHeader(authorizationHeader); @@ -382,7 +385,7 @@ public PerDateSchedulesResponse getUserDateSchedules(String eventId, String auth @Transactional(readOnly = true) public List getFilteredDaySchedules(GetFilteredSchedulesRequest getFilteredSchedulesRequest) { Event event = eventRepository.findByEventId(UUID.fromString(getFilteredSchedulesRequest.eventId())) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); List members = memberRepository.findAllWithSelectionsAndSchedulesByEventAndNames(event, getFilteredSchedulesRequest.names()); @@ -408,7 +411,7 @@ public List getFilteredDaySchedules(GetFilteredSchedule @Transactional(readOnly = true) public List getFilteredDateSchedules(GetFilteredSchedulesRequest getFilteredSchedulesRequest) { Event event = eventRepository.findByEventId(UUID.fromString(getFilteredSchedulesRequest.eventId())) - .orElseThrow(() -> new EventException(EventErrorResult._NOT_FOUND_EVENT)); + .orElseThrow(() -> new CustomException(EventErrorStatus._NOT_FOUND_EVENT)); List members = memberRepository.findAllWithSelectionsAndSchedulesByEventAndNames(event, getFilteredSchedulesRequest.names()); diff --git a/src/main/java/side/onetime/service/TokenService.java b/src/main/java/side/onetime/service/TokenService.java index 8e58fee..78c9941 100644 --- a/src/main/java/side/onetime/service/TokenService.java +++ b/src/main/java/side/onetime/service/TokenService.java @@ -7,8 +7,8 @@ import side.onetime.domain.RefreshToken; import side.onetime.dto.token.request.ReissueTokenRequest; import side.onetime.dto.token.response.ReissueTokenResponse; -import side.onetime.exception.TokenErrorResult; -import side.onetime.exception.TokenException; +import side.onetime.exception.CustomException; +import side.onetime.exception.status.TokenErrorStatus; import side.onetime.repository.RefreshTokenRepository; import side.onetime.util.JwtUtil; @@ -34,11 +34,11 @@ public ReissueTokenResponse reissueToken(ReissueTokenRequest reissueTokenRequest Long userId = jwtUtil.getUserIdFromToken(refreshToken); List existRefreshTokens = refreshTokenRepository.findByUserId(userId) - .orElseThrow(() -> new TokenException(TokenErrorResult._NOT_FOUND_REFRESH_TOKEN)); + .orElseThrow(() -> new CustomException(TokenErrorStatus._NOT_FOUND_REFRESH_TOKEN)); if (!existRefreshTokens.contains(refreshToken)) { // RefreshToken이 존재하지 않으면 예외 발생 - throw new TokenException(TokenErrorResult._NOT_FOUND_REFRESH_TOKEN); + throw new CustomException(TokenErrorStatus._NOT_FOUND_REFRESH_TOKEN); } // 새로운 AccessToken 생성 diff --git a/src/main/java/side/onetime/service/UrlService.java b/src/main/java/side/onetime/service/UrlService.java index 435a5ba..3bc0019 100644 --- a/src/main/java/side/onetime/service/UrlService.java +++ b/src/main/java/side/onetime/service/UrlService.java @@ -6,8 +6,8 @@ import side.onetime.dto.url.request.ConvertToShortenUrlRequest; import side.onetime.dto.url.response.ConvertToOriginalUrlResponse; import side.onetime.dto.url.response.ConvertToShortenUrlResponse; -import side.onetime.exception.EventErrorResult; -import side.onetime.exception.EventException; +import side.onetime.exception.CustomException; +import side.onetime.exception.status.EventErrorStatus; import side.onetime.repository.EventRepository; import side.onetime.util.Base62Util; @@ -24,7 +24,7 @@ public ConvertToShortenUrlResponse convertToShortenUrl(ConvertToShortenUrlReques UUID eventId = extractEventIdFromUrl(originalUrl); if (!eventRepository.existsByEventId(eventId)) { - throw new EventException(EventErrorResult._NOT_FOUND_EVENT); + throw new CustomException(EventErrorStatus._NOT_FOUND_EVENT); } return ConvertToShortenUrlResponse.of(Base62Util.convertToShortenUrl(originalUrl)); @@ -37,7 +37,7 @@ public ConvertToOriginalUrlResponse convertToOriginalUrl(ConvertToOriginalUrlReq UUID eventId = extractEventIdFromUrl(originalUrl); if (!eventRepository.existsByEventId(eventId)) { - throw new EventException(EventErrorResult._NOT_FOUND_EVENT); + throw new CustomException(EventErrorStatus._NOT_FOUND_EVENT); } return ConvertToOriginalUrlResponse.of(originalUrl); diff --git a/src/main/java/side/onetime/service/UserService.java b/src/main/java/side/onetime/service/UserService.java index 747da1b..2e17219 100644 --- a/src/main/java/side/onetime/service/UserService.java +++ b/src/main/java/side/onetime/service/UserService.java @@ -1,17 +1,17 @@ package side.onetime.service; -import org.springframework.transaction.annotation.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import side.onetime.domain.RefreshToken; import side.onetime.domain.User; import side.onetime.dto.user.request.OnboardUserRequest; import side.onetime.dto.user.request.UpdateUserProfileRequest; import side.onetime.dto.user.response.GetUserProfileResponse; import side.onetime.dto.user.response.OnboardUserResponse; -import side.onetime.exception.UserErrorResult; -import side.onetime.exception.UserException; +import side.onetime.exception.CustomException; +import side.onetime.exception.status.UserErrorStatus; import side.onetime.repository.RefreshTokenRepository; import side.onetime.repository.UserRepository; import side.onetime.util.JwtUtil; @@ -44,7 +44,7 @@ public OnboardUserResponse onboardUser(OnboardUserRequest onboardUserRequest) { String email = jwtUtil.getEmailFromToken(registerToken); if (onboardUserRequest.nickname().length() > NICKNAME_LENGTH_LIMIT) { - throw new UserException(UserErrorResult._NICKNAME_TOO_LONG); + throw new CustomException(UserErrorStatus._NICKNAME_TOO_LONG); } User user = User.builder() @@ -84,7 +84,7 @@ public void updateUserProfile(String authorizationHeader, UpdateUserProfileReque String nickname = updateUserProfileRequest.nickname(); if (nickname.length() > NICKNAME_LENGTH_LIMIT) { - throw new UserException(UserErrorResult._NICKNAME_TOO_LONG); + throw new CustomException(UserErrorStatus._NICKNAME_TOO_LONG); } user.updateNickName(nickname); userRepository.save(user); diff --git a/src/main/java/side/onetime/util/JwtUtil.java b/src/main/java/side/onetime/util/JwtUtil.java index a302a26..96290df 100644 --- a/src/main/java/side/onetime/util/JwtUtil.java +++ b/src/main/java/side/onetime/util/JwtUtil.java @@ -9,10 +9,9 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import side.onetime.domain.User; -import side.onetime.exception.TokenErrorResult; -import side.onetime.exception.TokenException; -import side.onetime.exception.UserErrorResult; -import side.onetime.exception.UserException; +import side.onetime.exception.CustomException; +import side.onetime.exception.status.TokenErrorStatus; +import side.onetime.exception.status.UserErrorStatus; import side.onetime.repository.UserRepository; import javax.crypto.SecretKey; @@ -90,7 +89,7 @@ public Long getUserIdFromToken(String token) { } catch (JwtException | IllegalArgumentException e) { // 토큰이 유효하지 않은 경우 log.error("토큰에서 userId를 반환하던 도중 에러가 발생했습니다."); - throw new TokenException(TokenErrorResult._INVALID_TOKEN); + throw new CustomException(TokenErrorStatus._INVALID_TOKEN); } } @@ -100,7 +99,7 @@ public User getUserFromHeader(String authorizationHeader) { validateTokenExpiration(token); return userRepository.findById(getUserIdFromToken(token)) - .orElseThrow(() -> new UserException(UserErrorResult._NOT_FOUND_USER)); + .orElseThrow(() -> new CustomException(UserErrorStatus._NOT_FOUND_USER)); } // 토큰에서 provider를 반환하는 메서드 @@ -118,7 +117,7 @@ public String getProviderFromToken(String token) { } catch (JwtException | IllegalArgumentException e) { // 토큰이 유효하지 않은 경우 log.error("토큰에서 provider를 반환하는 도중 에러가 발생했습니다."); - throw new TokenException(TokenErrorResult._INVALID_TOKEN); + throw new CustomException(TokenErrorStatus._INVALID_TOKEN); } } @@ -137,7 +136,7 @@ public String getProviderIdFromToken(String token) { } catch (JwtException | IllegalArgumentException e) { // 토큰이 유효하지 않은 경우 log.error("토큰에서 providerId를 반환하는 도중 에러가 발생했습니다."); - throw new TokenException(TokenErrorResult._INVALID_TOKEN); + throw new CustomException(TokenErrorStatus._INVALID_TOKEN); } } @@ -156,7 +155,7 @@ public String getNameFromToken(String token) { } catch (JwtException | IllegalArgumentException e) { // 토큰이 유효하지 않은 경우 log.error("토큰에서 이름을 반환하는 도중 에러가 발생했습니다."); - throw new TokenException(TokenErrorResult._INVALID_TOKEN); + throw new CustomException(TokenErrorStatus._INVALID_TOKEN); } } @@ -175,7 +174,7 @@ public String getEmailFromToken(String token) { } catch (JwtException | IllegalArgumentException e) { // 토큰이 유효하지 않은 경우 log.error("토큰에서 이메일을 반환하는 도중 에러가 발생했습니다."); - throw new TokenException(TokenErrorResult._INVALID_TOKEN); + throw new CustomException(TokenErrorStatus._INVALID_TOKEN); } } @@ -192,7 +191,7 @@ public void validateTokenExpiration(String token) { } catch (JwtException | IllegalArgumentException e) { // 토큰이 유효하지 않은 경우 log.error("만료된 토큰입니다."); - throw new TokenException(TokenErrorResult._EXPIRED_TOKEN); + throw new CustomException(TokenErrorStatus._EXPIRED_TOKEN); } } } \ No newline at end of file From 0aecfd87696180f7dd368a5858fb9e2aa98efdb4 Mon Sep 17 00:00:00 2001 From: bbbang105 <2018111366@dgu.ac.kr> Date: Tue, 22 Oct 2024 01:02:00 +0900 Subject: [PATCH 2/2] =?UTF-8?q?#81=20[feat]=20:=20=EC=9C=A0=ED=9A=A8?= =?UTF-8?q?=EC=84=B1=20=EA=B2=80=EC=A6=9D=20=EB=B0=8F=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=20=EC=B2=98=EB=A6=AC=EB=A5=BC=20=EC=B6=94=EA=B0=80=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../onetime/controller/EventController.java | 3 +- .../onetime/controller/MemberController.java | 7 +- .../controller/ScheduleController.java | 9 +- .../onetime/controller/TokenController.java | 3 +- .../onetime/controller/UrlController.java | 5 +- .../onetime/controller/UserController.java | 5 +- .../exception/GlobalExceptionHandler.java | 154 ++++++++++++------ 7 files changed, 119 insertions(+), 67 deletions(-) diff --git a/src/main/java/side/onetime/controller/EventController.java b/src/main/java/side/onetime/controller/EventController.java index a452f5c..85ee4ff 100644 --- a/src/main/java/side/onetime/controller/EventController.java +++ b/src/main/java/side/onetime/controller/EventController.java @@ -1,5 +1,6 @@ package side.onetime.controller; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -20,7 +21,7 @@ public class EventController { // 이벤트 생성 API @PostMapping public ResponseEntity> createEvent( - @RequestBody CreateEventRequest createEventRequest, + @Valid @RequestBody CreateEventRequest createEventRequest, @RequestHeader(value = "Authorization", required = false) String authorizationHeader) { CreateEventResponse createEventResponse; diff --git a/src/main/java/side/onetime/controller/MemberController.java b/src/main/java/side/onetime/controller/MemberController.java index 36c5f70..6ba7f6b 100644 --- a/src/main/java/side/onetime/controller/MemberController.java +++ b/src/main/java/side/onetime/controller/MemberController.java @@ -1,5 +1,6 @@ package side.onetime.controller; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; @@ -25,7 +26,7 @@ public class MemberController { // 멤버 등록 API @PostMapping("/action-register") public ResponseEntity> registerMember( - @RequestBody RegisterMemberRequest registerMemberRequest) { + @Valid @RequestBody RegisterMemberRequest registerMemberRequest) { RegisterMemberResponse registerMemberResponse = memberService.registerMember(registerMemberRequest); return ApiResponse.onSuccess(SuccessStatus._REGISTER_MEMBER, registerMemberResponse); @@ -34,7 +35,7 @@ public ResponseEntity> registerMember( // 멤버 로그인 API @PostMapping("/action-login") public ResponseEntity> loginMember( - @RequestBody LoginMemberRequest loginMemberRequest) { + @Valid @RequestBody LoginMemberRequest loginMemberRequest) { LoginMemberResponse loginMemberResponse = memberService.loginMember(loginMemberRequest); return ApiResponse.onSuccess(SuccessStatus._LOGIN_MEMBER, loginMemberResponse); @@ -43,7 +44,7 @@ public ResponseEntity> loginMember( // 이름 중복 확인 API @PostMapping("/name/action-check") public ResponseEntity> isDuplicate( - @RequestBody IsDuplicateRequest isDuplicateRequest) { + @Valid @RequestBody IsDuplicateRequest isDuplicateRequest) { IsDuplicateResponse isDuplicateResponse = memberService.isDuplicate(isDuplicateRequest); return ApiResponse.onSuccess(SuccessStatus._IS_POSSIBLE_NAME, isDuplicateResponse); diff --git a/src/main/java/side/onetime/controller/ScheduleController.java b/src/main/java/side/onetime/controller/ScheduleController.java index eb92ca6..944aea0 100644 --- a/src/main/java/side/onetime/controller/ScheduleController.java +++ b/src/main/java/side/onetime/controller/ScheduleController.java @@ -1,5 +1,6 @@ package side.onetime.controller; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -23,7 +24,7 @@ public class ScheduleController { // 요일 스케줄 등록 API @PostMapping("/day") public ResponseEntity> createDaySchedules( - @RequestBody CreateDayScheduleRequest createDayScheduleRequest, + @Valid @RequestBody CreateDayScheduleRequest createDayScheduleRequest, @RequestHeader(value = "Authorization", required = false) String authorizationHeader) { if (authorizationHeader != null) { @@ -37,7 +38,7 @@ public ResponseEntity> createDaySchedules( // 날짜 스케줄 등록 API @PostMapping("/date") public ResponseEntity> createDateSchedules( - @RequestBody CreateDateScheduleRequest createDateScheduleRequest, + @Valid @RequestBody CreateDateScheduleRequest createDateScheduleRequest, @RequestHeader(value = "Authorization", required = false) String authorizationHeader) { if (authorizationHeader != null) { @@ -80,7 +81,7 @@ public ResponseEntity> getUserDaySchedules( // 멤버 필터링 요일 스케줄 조회 API @GetMapping("/day/action-filtering") public ResponseEntity>> getFilteredDaySchedules( - @RequestBody GetFilteredSchedulesRequest getFilteredSchedulesRequest) { + @Valid @RequestBody GetFilteredSchedulesRequest getFilteredSchedulesRequest) { List perDaySchedulesResponses = scheduleService.getFilteredDaySchedules(getFilteredSchedulesRequest); return ApiResponse.onSuccess(SuccessStatus._GET_FILTERED_DAY_SCHEDULES, perDaySchedulesResponses); @@ -118,7 +119,7 @@ public ResponseEntity> getUserDateSchedule // 멤버 필터링 날짜 스케줄 조회 API @GetMapping("/date/action-filtering") public ResponseEntity>> getFilteredDateSchedules( - @RequestBody GetFilteredSchedulesRequest getFilteredSchedulesRequest) { + @Valid @RequestBody GetFilteredSchedulesRequest getFilteredSchedulesRequest) { List perDateSchedulesResponses = scheduleService.getFilteredDateSchedules(getFilteredSchedulesRequest); return ApiResponse.onSuccess(SuccessStatus._GET_FILTERED_DATE_SCHEDULES, perDateSchedulesResponses); diff --git a/src/main/java/side/onetime/controller/TokenController.java b/src/main/java/side/onetime/controller/TokenController.java index 198765a..471d278 100644 --- a/src/main/java/side/onetime/controller/TokenController.java +++ b/src/main/java/side/onetime/controller/TokenController.java @@ -1,5 +1,6 @@ package side.onetime.controller; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; @@ -21,7 +22,7 @@ public class TokenController { // 액세스 토큰 재발행 API @PostMapping("/action-reissue") public ResponseEntity> reissueToken( - @RequestBody ReissueTokenRequest reissueAccessTokenRequest) { + @Valid @RequestBody ReissueTokenRequest reissueAccessTokenRequest) { ReissueTokenResponse reissueTokenResponse = tokenService.reissueToken(reissueAccessTokenRequest); return ApiResponse.onSuccess(SuccessStatus._REISSUE_TOKENS, reissueTokenResponse); diff --git a/src/main/java/side/onetime/controller/UrlController.java b/src/main/java/side/onetime/controller/UrlController.java index 6d2d500..2425283 100644 --- a/src/main/java/side/onetime/controller/UrlController.java +++ b/src/main/java/side/onetime/controller/UrlController.java @@ -1,5 +1,6 @@ package side.onetime.controller; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; @@ -23,7 +24,7 @@ public class UrlController { // 원본 -> 단축 URL API @PostMapping("/action-shorten") public ResponseEntity> convertToShortenUrl( - @RequestBody ConvertToShortenUrlRequest covertToShortenUrlRequest) { + @Valid @RequestBody ConvertToShortenUrlRequest covertToShortenUrlRequest) { ConvertToShortenUrlResponse convertToShortenUrlResponse = urlService.convertToShortenUrl(covertToShortenUrlRequest); return ApiResponse.onSuccess(SuccessStatus._CONVERT_TO_SHORTEN_URL, convertToShortenUrlResponse); @@ -32,7 +33,7 @@ public ResponseEntity> convertToShorten // 단축 -> 원본 URL API @PostMapping("/action-original") public ResponseEntity> convertToOriginalUrl( - @RequestBody ConvertToOriginalUrlRequest convertToOriginalUrlRequest) { + @Valid @RequestBody ConvertToOriginalUrlRequest convertToOriginalUrlRequest) { ConvertToOriginalUrlResponse convertToOriginalUrlResponse = urlService.convertToOriginalUrl(convertToOriginalUrlRequest); return ApiResponse.onSuccess(SuccessStatus._CONVERT_TO_ORIGINAL_URL, convertToOriginalUrlResponse); diff --git a/src/main/java/side/onetime/controller/UserController.java b/src/main/java/side/onetime/controller/UserController.java index b225892..2a135aa 100644 --- a/src/main/java/side/onetime/controller/UserController.java +++ b/src/main/java/side/onetime/controller/UserController.java @@ -1,5 +1,6 @@ package side.onetime.controller; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -20,7 +21,7 @@ public class UserController { // 유저 온보딩 API @PostMapping("/onboarding") public ResponseEntity> onboardUser( - @RequestBody OnboardUserRequest onboardUserRequest) { + @Valid @RequestBody OnboardUserRequest onboardUserRequest) { OnboardUserResponse onboardUserResponse = userService.onboardUser(onboardUserRequest); return ApiResponse.onSuccess(SuccessStatus._ONBOARD_USER, onboardUserResponse); @@ -39,7 +40,7 @@ public ResponseEntity> getUserProfile( @PatchMapping("/profile/action-update") public ResponseEntity> updateUserProfile( @RequestHeader("Authorization") String authorizationHeader, - @RequestBody UpdateUserProfileRequest updateUserProfileRequest) { + @Valid @RequestBody UpdateUserProfileRequest updateUserProfileRequest) { userService.updateUserProfile(authorizationHeader, updateUserProfileRequest); return ApiResponse.onSuccess(SuccessStatus._UPDATE_USER_PROFILE); diff --git a/src/main/java/side/onetime/exception/GlobalExceptionHandler.java b/src/main/java/side/onetime/exception/GlobalExceptionHandler.java index ebad34a..c7f92fb 100644 --- a/src/main/java/side/onetime/exception/GlobalExceptionHandler.java +++ b/src/main/java/side/onetime/exception/GlobalExceptionHandler.java @@ -1,88 +1,134 @@ package side.onetime.exception; +import jakarta.validation.ConstraintViolationException; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.HttpMediaTypeNotSupportedException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.NoHandlerFoundException; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import side.onetime.global.common.ApiResponse; -import side.onetime.global.common.code.BaseErrorCode; -import side.onetime.global.common.status.ErrorStatus; import side.onetime.global.common.dto.ErrorReasonDto; +import side.onetime.global.common.status.ErrorStatus; + +import java.util.List; +import java.util.stream.Collectors; -@RestControllerAdvice @Slf4j +@RestControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { - // Event - @ExceptionHandler(EventException.class) - public ResponseEntity> handleTokenException(EventException e) { - EventErrorResult errorResult = e.getEventErrorResult(); - return ApiResponse.onFailure(errorResult); + // 커스텀 예외 처리 + @ExceptionHandler(CustomException.class) + public ResponseEntity> handleCustomException(CustomException e) { + logError(e.getMessage(), e); + return ApiResponse.onFailure(e.getErrorCode()); } - // Member - @ExceptionHandler(MemberException.class) - public ResponseEntity> handleMemberException(MemberException e) { - MemberErrorResult errorResult = e.getMemberErrorResult(); - return ApiResponse.onFailure(errorResult); + // Security 인증 관련 처리 + @ExceptionHandler(SecurityException.class) + public ResponseEntity> handleSecurityException(SecurityException e) { + logError(e.getMessage(), e); + return ApiResponse.onFailure(ErrorStatus._UNAUTHORIZED); } - // Schedule - @ExceptionHandler(ScheduleException.class) - public ResponseEntity> handleScheduleException(ScheduleException e) { - ScheduleErrorResult errorResult = e.getScheduleErrorResult(); - return ApiResponse.onFailure(errorResult); + // IllegalArgumentException 처리 (잘못된 인자가 전달된 경우) + @ExceptionHandler(IllegalArgumentException.class) + public ResponseEntity handleIllegalArgumentException(IllegalArgumentException e) { + String errorMessage = "잘못된 요청입니다: " + e.getMessage(); + logError("IllegalArgumentException", errorMessage); + return ApiResponse.onFailure(ErrorStatus._BAD_REQUEST, errorMessage); } - // Selection - @ExceptionHandler(SelectionException.class) - public ResponseEntity> handleSelectionException(SelectionException e) { - SelectionErrorResult errorResult = e.getSelectionErrorResult(); - return ApiResponse.onFailure(errorResult); + // ConstraintViolationException 처리 (쿼리 파라미터에 올바른 값이 들어오지 않은 경우) + @ExceptionHandler(ConstraintViolationException.class) + public ResponseEntity handleValidationParameterError(ConstraintViolationException ex) { + String errorMessage = ex.getMessage(); + logError("ConstraintViolationException", errorMessage); + return ApiResponse.onFailure(ErrorStatus._BAD_REQUEST, errorMessage); } - // User - @ExceptionHandler(UserException.class) - public ResponseEntity> handleUserException(UserException e) { - UserErrorResult errorResult = e.getUserErrorResult(); - return ApiResponse.onFailure(errorResult); + // MissingServletRequestParameterException 처리 (필수 쿼리 파라미터가 입력되지 않은 경우) + @Override + protected ResponseEntity handleMissingServletRequestParameter(MissingServletRequestParameterException ex, + HttpHeaders headers, + HttpStatusCode status, + WebRequest request) { + String errorMessage = "필수 파라미터 '" + ex.getParameterName() + "'가 없습니다."; + logError("MissingServletRequestParameterException", errorMessage); + return ApiResponse.onFailure(ErrorStatus._BAD_REQUEST, errorMessage); } - // Token - @ExceptionHandler(TokenException.class) - public ResponseEntity> handleTokenException(TokenException e) { - TokenErrorResult errorResult = e.getTokenErrorResult(); - return ApiResponse.onFailure(errorResult); + // MethodArgumentNotValidException 처리 (RequestBody로 들어온 필드들의 유효성 검증에 실패한 경우) + @Override + protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, + HttpHeaders headers, + HttpStatusCode status, + WebRequest request) { + String combinedErrors = extractFieldErrors(ex.getBindingResult().getFieldErrors()); + logError("Validation error", combinedErrors); + return ApiResponse.onFailure(ErrorStatus._BAD_REQUEST, combinedErrors); } - // EventParticipation - @ExceptionHandler(EventParticipationException.class) - public ResponseEntity> handleEventParticipationException(EventParticipationException e) { - EventParticipationErrorResult errorResult = e.getEventParticipationErrorResult(); - return ApiResponse.onFailure(errorResult); + // NoHandlerFoundException 처리 (요청 경로에 매핑된 핸들러가 없는 경우) + @Override + protected ResponseEntity handleNoHandlerFoundException(NoHandlerFoundException ex, + HttpHeaders headers, + HttpStatusCode status, + WebRequest request) { + String errorMessage = "해당 경로에 대한 핸들러를 찾을 수 없습니다: " + ex.getRequestURL(); + logError("NoHandlerFoundException", errorMessage); + return ApiResponse.onFailure(ErrorStatus._NOT_FOUND_HANDLER, errorMessage); } - // AccessDeniedException 등 보안 관련 에러 처리 - @ExceptionHandler(SecurityException.class) - public ResponseEntity handleSecurityException(SecurityException e) { - log.error("SecurityException: {}", e.getMessage()); - return ResponseEntity.status(ErrorStatus._UNAUTHORIZED.getHttpStatus()) - .body(ErrorStatus._UNAUTHORIZED.getReasonHttpStatus()); + // HttpRequestMethodNotSupportedException 처리 (지원하지 않는 HTTP 메소드 요청이 들어온 경우) + @Override + protected ResponseEntity handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, + HttpHeaders headers, + HttpStatusCode status, + WebRequest request) { + String errorMessage = "지원하지 않는 HTTP 메소드 요청입니다: " + ex.getMethod(); + logError("HttpRequestMethodNotSupportedException", errorMessage); + return ApiResponse.onFailure(ErrorStatus._METHOD_NOT_ALLOWED, errorMessage); + } + + // HttpMediaTypeNotSupportedException 처리 (지원하지 않는 미디어 타입 요청이 들어온 경우) + @Override + protected ResponseEntity handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex, + HttpHeaders headers, + HttpStatusCode status, + WebRequest request) { + String errorMessage = "지원하지 않는 미디어 타입입니다: " + ex.getContentType(); + logError("HttpMediaTypeNotSupportedException", errorMessage); + return ApiResponse.onFailure(ErrorStatus._UNSUPPORTED_MEDIA_TYPE, errorMessage); } - // 기타 Exception 처리 + // 내부 서버 에러 처리 (500) @ExceptionHandler(Exception.class) - public ResponseEntity handleException(Exception e) { - log.error("Exception: {}", e.getMessage()); + public ResponseEntity> handleException(Exception e) { + // 서버 내부 에러 발생 시 로그에 예외 내용 기록 + logError(e.getMessage(), e); + return ApiResponse.onFailure(ErrorStatus._INTERNAL_SERVER_ERROR); + } - if (e instanceof IllegalArgumentException) { - return ResponseEntity.status(ErrorStatus._BAD_REQUEST.getHttpStatus()) - .body(ErrorStatus._BAD_REQUEST.getReasonHttpStatus()); - } + // 유효성 검증 오류 메시지 추출 메서드 (FieldErrors) + private String extractFieldErrors(List fieldErrors) { + return fieldErrors.stream() + .map(DefaultMessageSourceResolvable::getDefaultMessage) + .collect(Collectors.joining(", ")); + } - // 그 외 내부 서버 오류로 처리 - return ResponseEntity.status(ErrorStatus._INTERNAL_SERVER_ERROR.getHttpStatus()) - .body(ErrorStatus._INTERNAL_SERVER_ERROR.getReasonHttpStatus()); + // 로그 기록 메서드 + private void logError(String message, Object errorDetails) { + log.error("{}: {}", message, errorDetails); } } \ No newline at end of file