diff --git a/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java b/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java index b94c011..8ded23c 100644 --- a/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java +++ b/src/main/java/com/example/umc9th/domain/review/controller/ReviewController.java @@ -1,12 +1,13 @@ package com.example.umc9th.domain.review.controller; +import com.example.umc9th.domain.review.converter.ReviewConverter; +import com.example.umc9th.domain.review.dto.res.ReviewResDTO; import com.example.umc9th.domain.review.entity.Review; -import com.example.umc9th.domain.review.service.ReviewQueryService; +import com.example.umc9th.domain.review.service.query.ReviewQueryServiceImpl; +import com.example.umc9th.global.apiPayload.ApiResponse; +import com.example.umc9th.global.apiPayload.code.GeneralSuccessCode; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.util.List; @@ -14,18 +15,24 @@ @RequiredArgsConstructor @RequestMapping("/api/reviews") public class ReviewController { - private final ReviewQueryService reviewQueryService; + private final ReviewQueryServiceImpl reviewQueryService; + // /api/reviews/me?memberId=7 // /api/reviews/me?memberId=7&type=restaurant&query=반이학생마라탕마라반 // /api/reviews/me?memberId=7&type=rating&query=4 // /api/reviews/me?memberId=7&type=both&query=반이학생마라탕마라반&4 @GetMapping("/me") - public List myReviews( + public ApiResponse myReviews( @RequestParam Long memberId, @RequestParam(required = false) String type, @RequestParam(required = false) String query ) { - return reviewQueryService.searchMyReviews(memberId, type, query); + List list = reviewQueryService.searchMyReviews(memberId, type, query); + ReviewResDTO.MyReviews dto = ReviewConverter.toMyReviews(list); + return ApiResponse.onSuccess(GeneralSuccessCode.OK, dto); } + + + } diff --git a/src/main/java/com/example/umc9th/domain/review/converter/ReviewConverter.java b/src/main/java/com/example/umc9th/domain/review/converter/ReviewConverter.java new file mode 100644 index 0000000..c9f1839 --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/review/converter/ReviewConverter.java @@ -0,0 +1,34 @@ +package com.example.umc9th.domain.review.converter; + +import com.example.umc9th.domain.review.dto.res.ReviewResDTO; +import com.example.umc9th.domain.review.entity.Review; + +import java.util.ArrayList; +import java.util.List; + +public class ReviewConverter { + public static ReviewResDTO.MyReview toMyReview(Review review) { + return ReviewResDTO.MyReview.builder() + .reviewId(review.getId()) + .restaurantName(review.getRestaurant().getRestaurantName()) + .content(review.getReviewContent()) + .rating(review.getRating()) + .createdAt(review.getCreatedAt()) + .build(); + } + + public static ReviewResDTO.MyReviews toMyReviews(List list) { + List reviews = new ArrayList<>(); + if (list != null) { + for (Review review : list) { + if (review != null) { + reviews.add(toMyReview(review)); + } + } + } + return ReviewResDTO.MyReviews.builder() + .reviews(reviews) + .totalCount(reviews.size()) + .build(); + } +} diff --git a/src/main/java/com/example/umc9th/domain/review/dto/res/ReviewResDTO.java b/src/main/java/com/example/umc9th/domain/review/dto/res/ReviewResDTO.java new file mode 100644 index 0000000..e3daea4 --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/review/dto/res/ReviewResDTO.java @@ -0,0 +1,26 @@ +package com.example.umc9th.domain.review.dto.res; + +import lombok.Builder; +import lombok.Getter; +import java.time.LocalDateTime; +import java.util.List; + +public class ReviewResDTO { + + @Builder + @Getter + public static class MyReview { + private Long reviewId; + private String restaurantName; + private String content; + private Double rating; + private LocalDateTime createdAt; + } + + @Builder + @Getter + public static class MyReviews { + private List reviews; + private Integer totalCount; + } +} diff --git a/src/main/java/com/example/umc9th/domain/review/exception/ReviewException.java b/src/main/java/com/example/umc9th/domain/review/exception/ReviewException.java new file mode 100644 index 0000000..afde6b0 --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/review/exception/ReviewException.java @@ -0,0 +1,10 @@ +package com.example.umc9th.domain.review.exception; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import com.example.umc9th.global.apiPayload.exception.GeneralException; + +public class ReviewException extends GeneralException { + public ReviewException(BaseErrorCode code) { + super(code); + } +} diff --git a/src/main/java/com/example/umc9th/domain/review/exception/code/ReviewErrorCode.java b/src/main/java/com/example/umc9th/domain/review/exception/code/ReviewErrorCode.java new file mode 100644 index 0000000..1408d0e --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/review/exception/code/ReviewErrorCode.java @@ -0,0 +1,19 @@ +package com.example.umc9th.domain.review.exception.code; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum ReviewErrorCode implements BaseErrorCode { + INVALID_TYPE(HttpStatus.BAD_REQUEST, "REVIEW400_1", "type 값이 올바르지 않습니다. [restaurant|rating|both|all]"), + MISSING_QUERY(HttpStatus.BAD_REQUEST, "REVIEW400_2", "해당 type에 필요한 query 값이 없습니다."), + INVALID_BOTH_QUERY(HttpStatus.BAD_REQUEST, "REVIEW400_3", "both 타입의 query는 '이름&숫자' 형식이어야 합니다."), + INVALID_RATING(HttpStatus.BAD_REQUEST, "REVIEW400_4", "rating은 0.0 ~ 5.0 사이의 숫자여야 합니다."),; + + private final HttpStatus status; + private final String code; + private final String message; +} diff --git a/src/main/java/com/example/umc9th/domain/review/service/ReviewQueryService.java b/src/main/java/com/example/umc9th/domain/review/service/ReviewQueryService.java deleted file mode 100644 index 00505f8..0000000 --- a/src/main/java/com/example/umc9th/domain/review/service/ReviewQueryService.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.example.umc9th.domain.review.service; - -import com.example.umc9th.domain.review.entity.QReview; -import com.example.umc9th.domain.review.entity.Review; -import com.example.umc9th.domain.review.repository.ReviewRepository; -import com.querydsl.core.BooleanBuilder; -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -@RequiredArgsConstructor -@Transactional -public class ReviewQueryService { - private final ReviewRepository reviewRepository; - - - public List searchMyReviews(Long memberId, String type, String query){ - QReview review = QReview.review; - - // BooleanBuilder 선언 - BooleanBuilder builder = new BooleanBuilder(); - - // BooleanBuilder 사용 - - // 1) 내가 작성한 리뷰 - builder.and(review.member.id.eq(memberId)); - - // 동적 쿼리 : 조회 조건 - if (type.equals("restaurant")) { - builder.and(review.restaurant.restaurantName.contains(query)); - } - if (type.equals("rating")) { - double base = Double.parseDouble(query.trim()); - if (base >= 5.0) { - // 정확히 5.0만 - builder.and(review.rating.eq(5.0)); - } else if (base >= 0.0) { - // n점대 - double lower = base; - double upper = Math.min(5.0, base + 1.0); - builder.and(review.rating.goe(lower)); - builder.and(review.rating.lt(upper)); - } - - } - if(type.equals("both")) { - String firstQuery = query.split("&")[0]; - String secondQuery = query.split("&")[1]; - - builder.and(review.restaurant.restaurantName.contains(query)); - - double base = Double.parseDouble(query.trim()); - if (base >= 5.0) { - // 정확히 5.0만 - builder.and(review.rating.eq(5.0)); - } else if (base >= 0.0) { - // n점대 - double lower = base; - double upper = Math.min(5.0, base + 1.0); - builder.and(review.rating.goe(lower)); - builder.and(review.rating.lt(upper)); - } - - } - - - List reviewList = reviewRepository.searchReview(builder); - - return reviewList; - } - -} diff --git a/src/main/java/com/example/umc9th/domain/review/service/query/ReviewQueryService.java b/src/main/java/com/example/umc9th/domain/review/service/query/ReviewQueryService.java new file mode 100644 index 0000000..98ae711 --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/review/service/query/ReviewQueryService.java @@ -0,0 +1,9 @@ +package com.example.umc9th.domain.review.service.query; + +import com.example.umc9th.domain.review.entity.Review; + +import java.util.List; + +public interface ReviewQueryService { + List searchMyReviews(Long memberId, String type, String query); +} diff --git a/src/main/java/com/example/umc9th/domain/review/service/query/ReviewQueryServiceImpl.java b/src/main/java/com/example/umc9th/domain/review/service/query/ReviewQueryServiceImpl.java new file mode 100644 index 0000000..2fe7e9e --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/review/service/query/ReviewQueryServiceImpl.java @@ -0,0 +1,94 @@ +package com.example.umc9th.domain.review.service.query; + +import com.example.umc9th.domain.review.entity.QReview; +import com.example.umc9th.domain.review.entity.Review; +import com.example.umc9th.domain.review.exception.ReviewException; +import com.example.umc9th.domain.review.exception.code.ReviewErrorCode; +import com.example.umc9th.domain.review.repository.ReviewRepository; +import com.querydsl.core.BooleanBuilder; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +@Transactional +public class ReviewQueryServiceImpl implements ReviewQueryService { + private final ReviewRepository reviewRepository; + + + public List searchMyReviews(Long memberId, String type, String query){ + String safeType = (type == null) ? "all" : type.trim(); + String safeQuery = (query == null) ? "" : query.trim(); + + QReview review = QReview.review; + + // BooleanBuilder 선언 + BooleanBuilder builder = new BooleanBuilder(); + + // BooleanBuilder 사용 + + // 1) 내가 작성한 리뷰 + builder.and(review.member.id.eq(memberId)); + + // 동적 쿼리 : 조회 조건 + switch (type) { + case "all" -> { + // 추가 필터 없음 + } + case "restaurant" -> { + if (query.isEmpty()) throw new ReviewException(ReviewErrorCode.MISSING_QUERY); + builder.and(review.restaurant.restaurantName.contains(query)); + } + case "rating" -> { + if (query.isEmpty()) throw new ReviewException(ReviewErrorCode.MISSING_QUERY); + applyRatingFilterOrThrow(builder, review, query); + } + case "both" -> { + if (query.isEmpty() || !query.contains("&")) { + throw new ReviewException(ReviewErrorCode.INVALID_BOTH_QUERY); + } + String[] parts = query.split("&", 2); + String name = parts[0].trim(); + String ratingStr = parts[1].trim(); + if (name.isEmpty() || ratingStr.isEmpty()) { + throw new ReviewException(ReviewErrorCode.INVALID_BOTH_QUERY); + } + builder.and(review.restaurant.restaurantName.contains(name)); + applyRatingFilterOrThrow(builder, review, ratingStr); + } + default -> throw new ReviewException(ReviewErrorCode.INVALID_TYPE); + } + + + List reviewList = reviewRepository.searchReview(builder); + + return reviewList; + } + + private void applyRatingFilterOrThrow(BooleanBuilder builder, QReview review, String ratingText) { + if (ratingText == null || ratingText.isEmpty()) return; + + double base; + try { + base = Double.parseDouble(ratingText); + } catch (NumberFormatException e) { + throw new ReviewException(ReviewErrorCode.INVALID_RATING); + } + + if (base < 0.0 || base > 5.0) { + throw new ReviewException(ReviewErrorCode.INVALID_RATING); + } + + if (base >= 5.0) { + builder.and(review.rating.eq(5.0)); + } else if (base >= 0.0) { + double lower = base; + double upper = Math.min(5.0, base + 1.0); + builder.and(review.rating.goe(lower)); + builder.and(review.rating.lt(upper)); + } + } +} diff --git a/src/main/java/com/example/umc9th/domain/test/controller/TestController.java b/src/main/java/com/example/umc9th/domain/test/controller/TestController.java new file mode 100644 index 0000000..ae20a6c --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/test/controller/TestController.java @@ -0,0 +1,41 @@ +package com.example.umc9th.domain.test.controller; + +import com.example.umc9th.domain.test.converter.TestConverter; +import com.example.umc9th.domain.test.dto.res.TestResDTO; +import com.example.umc9th.domain.test.service.query.TestQueryService; +import com.example.umc9th.global.apiPayload.ApiResponse; +import com.example.umc9th.global.apiPayload.code.GeneralSuccessCode; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/temp") +public class TestController { + private final TestQueryService testQueryService; + + @GetMapping("/test") + public ApiResponse test() throws Exception { + // 응답 코드 정의 + GeneralSuccessCode code = GeneralSuccessCode.OK; + return ApiResponse.onSuccess( + code, + TestConverter.toTestingDTO("This is Test!") + ); + } + + // 예외 상황 + @GetMapping("/exception") + public ApiResponse exception( + @RequestParam Long flag + ) { + testQueryService.checkFlag(flag); + + // 응답 코드 정의 + GeneralSuccessCode code = GeneralSuccessCode.OK; + return ApiResponse.onSuccess(code, TestConverter.toExceptionDTO("This is Test!")); + } +} diff --git a/src/main/java/com/example/umc9th/domain/test/converter/TestConverter.java b/src/main/java/com/example/umc9th/domain/test/converter/TestConverter.java new file mode 100644 index 0000000..7da0c42 --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/test/converter/TestConverter.java @@ -0,0 +1,24 @@ +package com.example.umc9th.domain.test.converter; + +import com.example.umc9th.domain.test.dto.res.TestResDTO; + +public class TestConverter { + // 객체 -> DTO + public static TestResDTO.Testing toTestingDTO( + String testing + ) { + return TestResDTO.Testing.builder() + .testString(testing) + .build(); + } + + + // 객체 -> DTO + public static TestResDTO.Exception toExceptionDTO( + String testing + ){ + return TestResDTO.Exception.builder() + .testString(testing) + .build(); + } +} diff --git a/src/main/java/com/example/umc9th/domain/test/dto/req/TestReqDTO.java b/src/main/java/com/example/umc9th/domain/test/dto/req/TestReqDTO.java new file mode 100644 index 0000000..405e3b9 --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/test/dto/req/TestReqDTO.java @@ -0,0 +1,4 @@ +package com.example.umc9th.domain.test.dto.req; + +public class TestReqDTO { +} diff --git a/src/main/java/com/example/umc9th/domain/test/dto/res/TestResDTO.java b/src/main/java/com/example/umc9th/domain/test/dto/res/TestResDTO.java new file mode 100644 index 0000000..ec1cc59 --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/test/dto/res/TestResDTO.java @@ -0,0 +1,18 @@ +package com.example.umc9th.domain.test.dto.res; + +import lombok.Builder; +import lombok.Getter; + +public class TestResDTO { + @Builder + @Getter + public static class Testing { + private String testString; + } + + @Builder + @Getter + public static class Exception { + private String testString; + } +} diff --git a/src/main/java/com/example/umc9th/domain/test/exception/TestException.java b/src/main/java/com/example/umc9th/domain/test/exception/TestException.java new file mode 100644 index 0000000..1faf200 --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/test/exception/TestException.java @@ -0,0 +1,10 @@ +package com.example.umc9th.domain.test.exception; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import com.example.umc9th.global.apiPayload.exception.GeneralException; + +public class TestException extends GeneralException { + public TestException(BaseErrorCode code) { + super(code); + } +} diff --git a/src/main/java/com/example/umc9th/domain/test/exception/code/TestErrorCode.java b/src/main/java/com/example/umc9th/domain/test/exception/code/TestErrorCode.java new file mode 100644 index 0000000..9fe17e7 --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/test/exception/code/TestErrorCode.java @@ -0,0 +1,18 @@ +package com.example.umc9th.domain.test.exception.code; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum TestErrorCode implements BaseErrorCode { + // For test + TEST_EXCEPTION(HttpStatus.BAD_REQUEST, "TEST400_1", "이거는 테스트"), + ; + + private final HttpStatus status; + private final String code; + private final String message; +} diff --git a/src/main/java/com/example/umc9th/domain/test/service/command/TestCommandService.java b/src/main/java/com/example/umc9th/domain/test/service/command/TestCommandService.java new file mode 100644 index 0000000..b1102dd --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/test/service/command/TestCommandService.java @@ -0,0 +1,4 @@ +package com.example.umc9th.domain.test.service.command; + +public interface TestCommandService { +} diff --git a/src/main/java/com/example/umc9th/domain/test/service/command/TestCommandServiceImpl.java b/src/main/java/com/example/umc9th/domain/test/service/command/TestCommandServiceImpl.java new file mode 100644 index 0000000..52d2c5e --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/test/service/command/TestCommandServiceImpl.java @@ -0,0 +1,4 @@ +package com.example.umc9th.domain.test.service.command; + +public class TestCommandServiceImpl implements TestCommandService { +} diff --git a/src/main/java/com/example/umc9th/domain/test/service/query/TestQueryService.java b/src/main/java/com/example/umc9th/domain/test/service/query/TestQueryService.java new file mode 100644 index 0000000..2163565 --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/test/service/query/TestQueryService.java @@ -0,0 +1,5 @@ +package com.example.umc9th.domain.test.service.query; + +public interface TestQueryService { + void checkFlag(Long flag); +} diff --git a/src/main/java/com/example/umc9th/domain/test/service/query/TestQueryServiceImpl.java b/src/main/java/com/example/umc9th/domain/test/service/query/TestQueryServiceImpl.java new file mode 100644 index 0000000..f56190b --- /dev/null +++ b/src/main/java/com/example/umc9th/domain/test/service/query/TestQueryServiceImpl.java @@ -0,0 +1,17 @@ +package com.example.umc9th.domain.test.service.query; + +import com.example.umc9th.domain.test.exception.TestException; +import com.example.umc9th.domain.test.exception.code.TestErrorCode; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class TestQueryServiceImpl implements TestQueryService { + @Override + public void checkFlag(Long flag) { + if(flag == 1) { + throw new TestException(TestErrorCode.TEST_EXCEPTION); + } + } +} diff --git a/src/main/java/com/example/umc9th/global/apiPayload/ApiResponse.java b/src/main/java/com/example/umc9th/global/apiPayload/ApiResponse.java new file mode 100644 index 0000000..c24d7c0 --- /dev/null +++ b/src/main/java/com/example/umc9th/global/apiPayload/ApiResponse.java @@ -0,0 +1,34 @@ +package com.example.umc9th.global.apiPayload; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import com.example.umc9th.global.apiPayload.code.BaseSuccessCode; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +@JsonPropertyOrder({"isSuccess", "code", "message", "result"}) +public class ApiResponse { + @JsonProperty("isSuccess") + private final Boolean isSuccess; + + @JsonProperty("code") + private final String code; + + @JsonProperty("message") + private final String message; + + @JsonProperty("result") + private final T result; + + // 성공한 경우(result 포함) + public static ApiResponse onSuccess(BaseSuccessCode code, T result) { + return new ApiResponse<>(true, code.getCode(), code.getMessage(), result); + } + // 실패한 경우(result 포함) + public static ApiResponse onFailure(BaseErrorCode code, T result) { + return new ApiResponse<>(false, code.getCode(), code.getMessage(), result); + } +} diff --git a/src/main/java/com/example/umc9th/global/apiPayload/code/BaseErrorCode.java b/src/main/java/com/example/umc9th/global/apiPayload/code/BaseErrorCode.java new file mode 100644 index 0000000..16d3f22 --- /dev/null +++ b/src/main/java/com/example/umc9th/global/apiPayload/code/BaseErrorCode.java @@ -0,0 +1,9 @@ +package com.example.umc9th.global.apiPayload.code; + +import org.springframework.http.HttpStatus; + +public interface BaseErrorCode { + HttpStatus getStatus(); // HttpStatus를 가지고 있는 enum + String getCode(); + String getMessage(); +} diff --git a/src/main/java/com/example/umc9th/global/apiPayload/code/BaseSuccessCode.java b/src/main/java/com/example/umc9th/global/apiPayload/code/BaseSuccessCode.java new file mode 100644 index 0000000..0b31bf3 --- /dev/null +++ b/src/main/java/com/example/umc9th/global/apiPayload/code/BaseSuccessCode.java @@ -0,0 +1,9 @@ +package com.example.umc9th.global.apiPayload.code; + +import org.springframework.http.HttpStatus; + +public interface BaseSuccessCode { + HttpStatus getStatus(); // HttpStatus를 가지고 있는 enum + String getCode(); + String getMessage(); +} diff --git a/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralErrorCode.java b/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralErrorCode.java new file mode 100644 index 0000000..37f2770 --- /dev/null +++ b/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralErrorCode.java @@ -0,0 +1,19 @@ +package com.example.umc9th.global.apiPayload.code; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum GeneralErrorCode implements BaseErrorCode { + BAD_REQUEST(HttpStatus.BAD_REQUEST, "COMMON400_1", "잘못된 요청입니다."), + UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "AUTH401_1", "인증이 필요합니다."), + FORBIDDEN(HttpStatus.FORBIDDEN, "AUTH403_1", "요청이 거부되었습니다."), + NOT_FOUND(HttpStatus.NOT_FOUND, "COMMON404_1", "요청한 리소스를 찾을 수 없습니다."), + INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "COMMON500_1", "예기치 않은 서버 에러가 발생했습니다."), + ; + private final HttpStatus status; + private final String code; + private final String message; +} diff --git a/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralSuccessCode.java b/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralSuccessCode.java new file mode 100644 index 0000000..99449d9 --- /dev/null +++ b/src/main/java/com/example/umc9th/global/apiPayload/code/GeneralSuccessCode.java @@ -0,0 +1,18 @@ +package com.example.umc9th.global.apiPayload.code; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum GeneralSuccessCode implements BaseSuccessCode { + OK(HttpStatus.OK, "COMMON200_1", "요청이 성공적으로 처리되었습니다."), + CREATED(HttpStatus.CREATED, "COMMON201_1", "리소스가 성공적으로 생성되었습니다."), + ACCEPTED(HttpStatus.ACCEPTED, "COMMON202_1", "요청이 접수되었으며 비동기적으로 처리됩니다."), + NO_CONTENT(HttpStatus.NO_CONTENT, "COMMON204_1", "응답 본문 없이 성공적으로 처리되었습니다."); + ; + private final HttpStatus status; + private final String code; + private final String message; +} diff --git a/src/main/java/com/example/umc9th/global/apiPayload/exception/GeneralException.java b/src/main/java/com/example/umc9th/global/apiPayload/exception/GeneralException.java new file mode 100644 index 0000000..b512339 --- /dev/null +++ b/src/main/java/com/example/umc9th/global/apiPayload/exception/GeneralException.java @@ -0,0 +1,11 @@ +package com.example.umc9th.global.apiPayload.exception; + +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class GeneralException extends RuntimeException { + private final BaseErrorCode code; +} diff --git a/src/main/java/com/example/umc9th/global/apiPayload/handler/GeneralExceptionAdvice.java b/src/main/java/com/example/umc9th/global/apiPayload/handler/GeneralExceptionAdvice.java new file mode 100644 index 0000000..827cbef --- /dev/null +++ b/src/main/java/com/example/umc9th/global/apiPayload/handler/GeneralExceptionAdvice.java @@ -0,0 +1,40 @@ +package com.example.umc9th.global.apiPayload.handler; + +import com.example.umc9th.global.apiPayload.ApiResponse; +import com.example.umc9th.global.apiPayload.code.BaseErrorCode; +import com.example.umc9th.global.apiPayload.code.GeneralErrorCode; +import com.example.umc9th.global.apiPayload.exception.GeneralException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GeneralExceptionAdvice { + // 애플리케이션에서 발생하는 커스텀 예외를 처리 + @ExceptionHandler(GeneralException.class) + public ResponseEntity> handleException( + GeneralException ex + ) { + return ResponseEntity.status(ex.getCode().getStatus()) + .body(ApiResponse.onFailure( + ex.getCode(), + null + ) + ); + } + + // 그 외의 정의되지 않은 모든 예외 처리 + @ExceptionHandler(Exception.class) + public ResponseEntity> handleException( + Exception ex + ) { + BaseErrorCode code = GeneralErrorCode.INTERNAL_SERVER_ERROR; + return ResponseEntity.status(code.getStatus()) + .body(ApiResponse.onFailure( + code, + ex.getMessage() + ) + ); + } +}