From ddcaedbdf48b7c8cef1e815435be95a9fd341112 Mon Sep 17 00:00:00 2001 From: LeeShinHeang Date: Tue, 21 Jan 2025 11:44:19 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=ED=8E=98=EC=9D=B4=EC=A7=95=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?(=ED=8E=98=EC=9D=B4=EC=A7=95=20=EC=98=A4=EB=A5=98=EB=A1=9C=20?= =?UTF-8?q?=EA=B3=A0=EC=B9=A0=20=EB=B6=80=EB=B6=84=20=EC=A1=B4=EC=9E=AC)?= =?UTF-8?q?=20#12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AppearanceController.java | 31 ++++++++++ .../dto/response/AppearancePageResponse.java | 20 ++++++ .../dto/response/AppearanceResponse.java | 23 +++++++ .../actor/dto/response/PageableResponse.java | 62 +++++++++++++++++++ .../actor/service/AppearanceService.java | 46 ++++++++++++++ 5 files changed, 182 insertions(+) create mode 100644 customer-service/src/main/java/com/example/customerservice/actor/controller/AppearanceController.java create mode 100644 customer-service/src/main/java/com/example/customerservice/actor/dto/response/AppearancePageResponse.java create mode 100644 customer-service/src/main/java/com/example/customerservice/actor/dto/response/AppearanceResponse.java create mode 100644 customer-service/src/main/java/com/example/customerservice/actor/dto/response/PageableResponse.java create mode 100644 customer-service/src/main/java/com/example/customerservice/actor/service/AppearanceService.java diff --git a/customer-service/src/main/java/com/example/customerservice/actor/controller/AppearanceController.java b/customer-service/src/main/java/com/example/customerservice/actor/controller/AppearanceController.java new file mode 100644 index 0000000..191391c --- /dev/null +++ b/customer-service/src/main/java/com/example/customerservice/actor/controller/AppearanceController.java @@ -0,0 +1,31 @@ +package com.example.customerservice.actor.controller; + +import com.example.customerservice.actor.dto.response.AppearancePageResponse; +import com.example.customerservice.actor.service.AppearanceService; +import jakarta.validation.constraints.PositiveOrZero; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.http.ResponseEntity; +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("/api/appearance") +public class AppearanceController { + private final AppearanceService appearanceService; + + @GetMapping + public ResponseEntity getAppearance( + @PositiveOrZero @RequestParam(defaultValue = "0") int page, + @PositiveOrZero @RequestParam(defaultValue = "10") int size, + @RequestParam(value = "actor") String actor + + ){ + AppearancePageResponse response = appearanceService.getAppearanceByName(actor, PageRequest.of(page, size)); + return ResponseEntity.ok(response); + } + +} diff --git a/customer-service/src/main/java/com/example/customerservice/actor/dto/response/AppearancePageResponse.java b/customer-service/src/main/java/com/example/customerservice/actor/dto/response/AppearancePageResponse.java new file mode 100644 index 0000000..707b6ba --- /dev/null +++ b/customer-service/src/main/java/com/example/customerservice/actor/dto/response/AppearancePageResponse.java @@ -0,0 +1,20 @@ +package com.example.customerservice.actor.dto.response; + +import lombok.Builder; +import lombok.Getter; + +import java.util.List; + +@Builder +@Getter +public class AppearancePageResponse { + List content; + PageableResponse pageable; + + public static AppearancePageResponse of(List content, PageableResponse pageable) { + return AppearancePageResponse.builder() + .content(content) + .pageable(pageable) + .build(); + } +} diff --git a/customer-service/src/main/java/com/example/customerservice/actor/dto/response/AppearanceResponse.java b/customer-service/src/main/java/com/example/customerservice/actor/dto/response/AppearanceResponse.java new file mode 100644 index 0000000..79f9be8 --- /dev/null +++ b/customer-service/src/main/java/com/example/customerservice/actor/dto/response/AppearanceResponse.java @@ -0,0 +1,23 @@ +package com.example.customerservice.actor.dto.response; + +import com.example.customerservice.contents.entity.Contents; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class AppearanceResponse { + private Long contentId; + private String category; + private String title; + private String writer; + + public static AppearanceResponse fromContent(Contents contents) { + return AppearanceResponse.builder() + .contentId(contents.getContentId()) + .category(contents.getCategory()) + .title(contents.getTitle()) + .writer(contents.getWriter()) + .build(); + } +} diff --git a/customer-service/src/main/java/com/example/customerservice/actor/dto/response/PageableResponse.java b/customer-service/src/main/java/com/example/customerservice/actor/dto/response/PageableResponse.java new file mode 100644 index 0000000..a8b6875 --- /dev/null +++ b/customer-service/src/main/java/com/example/customerservice/actor/dto/response/PageableResponse.java @@ -0,0 +1,62 @@ +package com.example.customerservice.actor.dto.response; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +import java.util.List; + +import lombok.Getter; +import org.springframework.data.domain.Pageable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; + +@Builder +@Getter +public class PageableResponse{ + @Schema( + defaultValue = "0", + description = "페이지 인덱스로, 0부터 시작합니다. 별도의 값 없이 요청 시, 0으로 설정됩니다.", + requiredMode = REQUIRED + ) + private int page; + + @Schema( + defaultValue = "10", + description = "페이지 내 최대 응답 개수입니다. 별도의 값 없이 요청 시, 10으로 설정됩니다.", + requiredMode = REQUIRED + ) + private int size; + + @Schema( + defaultValue = "3", + description = "전체 페이지 수 입니다.", + requiredMode = REQUIRED + ) + private int totalPages; + + @Schema( + defaultValue = "30", + description = "전체 요소 개수 입니다.", + requiredMode = REQUIRED + ) + private int totalElements; + + @Schema( + defaultValue = "false", + description = "현재 응답하는 페이지가 마지막 일 시, true로 설정됩니다.", + requiredMode = REQUIRED + ) + private boolean isEnd; + + public static PageableResponse of(Pageable pageable, List totalElements) { + int totalPageSize = (int)Math.ceil((double)totalElements.size() / pageable.getPageSize()); + boolean isEnd = pageable.getPageNumber() + 1 >= totalPageSize; + return PageableResponse.builder() + .page(pageable.getPageNumber()) + .size(pageable.getPageSize()) + .totalPages(totalPageSize) + .totalElements(totalElements.size()) + .isEnd(isEnd) + .build(); + } +} diff --git a/customer-service/src/main/java/com/example/customerservice/actor/service/AppearanceService.java b/customer-service/src/main/java/com/example/customerservice/actor/service/AppearanceService.java new file mode 100644 index 0000000..6c82840 --- /dev/null +++ b/customer-service/src/main/java/com/example/customerservice/actor/service/AppearanceService.java @@ -0,0 +1,46 @@ +package com.example.customerservice.actor.service; + +import com.example.customerservice.actor.dto.response.AppearancePageResponse; +import com.example.customerservice.actor.dto.response.AppearanceResponse; +import com.example.customerservice.actor.dto.response.PageableResponse; +import com.example.customerservice.actor.entity.Actor; +import com.example.customerservice.actor.entity.ActorAppearances; +import com.example.customerservice.actor.repository.ActorRepository; +import com.example.customerservice.contents.entity.Contents; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class AppearanceService { + private final ActorRepository actorRepository; + + @Transactional(readOnly = true) + public AppearancePageResponse getAppearanceByName(String actorName, Pageable pageable) { + // 배우 이름으로 배우 조회 + Actor actor = actorRepository.findByActorName(actorName) + .orElseThrow(() -> new RuntimeException("Actor not found")); + + // 배우 출연작으로 작품 조회 + List contents = new ArrayList<>(); + for (ActorAppearances appearance : actor.getActorAppearances()) { + contents.add(appearance.getContents()); + } + + // 작품을 페이징 형식에 맞게 교체 + List appearanceResponses = new ArrayList<>(); + for (Contents content : contents) { + appearanceResponses.add(AppearanceResponse.fromContent(content)); + } + + PageableResponse pageableResponse = PageableResponse.of(pageable, appearanceResponses); + + // 리턴할 객체 빌드 + return AppearancePageResponse.of(appearanceResponses, pageableResponse); + } +} From fb054ec1266640100fe8ff900a315b95181dc8c5 Mon Sep 17 00:00:00 2001 From: LeeShinHeang Date: Tue, 21 Jan 2025 13:11:03 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=ED=8E=98=EC=9D=B4=EC=A7=95=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EB=84=A4=EC=9D=B4=ED=8B=B0=EB=B8=8C=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=EC=82=AC=EC=9A=A9=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20#12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/AppearancePageResponse.java | 6 ++--- .../actor/dto/response/PageableResponse.java | 6 ++--- .../actor/service/AppearanceService.java | 20 +++++++++-------- .../repository/ContentsRepository.java | 22 +++++++++++++++++++ 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/customer-service/src/main/java/com/example/customerservice/actor/dto/response/AppearancePageResponse.java b/customer-service/src/main/java/com/example/customerservice/actor/dto/response/AppearancePageResponse.java index 707b6ba..dbc114c 100644 --- a/customer-service/src/main/java/com/example/customerservice/actor/dto/response/AppearancePageResponse.java +++ b/customer-service/src/main/java/com/example/customerservice/actor/dto/response/AppearancePageResponse.java @@ -8,13 +8,13 @@ @Builder @Getter public class AppearancePageResponse { - List content; PageableResponse pageable; + List content; - public static AppearancePageResponse of(List content, PageableResponse pageable) { + public static AppearancePageResponse of(PageableResponse pageable, List content) { return AppearancePageResponse.builder() - .content(content) .pageable(pageable) + .content(content) .build(); } } diff --git a/customer-service/src/main/java/com/example/customerservice/actor/dto/response/PageableResponse.java b/customer-service/src/main/java/com/example/customerservice/actor/dto/response/PageableResponse.java index a8b6875..2b847ac 100644 --- a/customer-service/src/main/java/com/example/customerservice/actor/dto/response/PageableResponse.java +++ b/customer-service/src/main/java/com/example/customerservice/actor/dto/response/PageableResponse.java @@ -48,14 +48,14 @@ public class PageableResponse{ ) private boolean isEnd; - public static PageableResponse of(Pageable pageable, List totalElements) { - int totalPageSize = (int)Math.ceil((double)totalElements.size() / pageable.getPageSize()); + public static PageableResponse of(Pageable pageable, int totalElementsSize) { + int totalPageSize = (int)Math.ceil((double)totalElementsSize / pageable.getPageSize()); boolean isEnd = pageable.getPageNumber() + 1 >= totalPageSize; return PageableResponse.builder() .page(pageable.getPageNumber()) .size(pageable.getPageSize()) .totalPages(totalPageSize) - .totalElements(totalElements.size()) + .totalElements(totalElementsSize) .isEnd(isEnd) .build(); } diff --git a/customer-service/src/main/java/com/example/customerservice/actor/service/AppearanceService.java b/customer-service/src/main/java/com/example/customerservice/actor/service/AppearanceService.java index 6c82840..e508c14 100644 --- a/customer-service/src/main/java/com/example/customerservice/actor/service/AppearanceService.java +++ b/customer-service/src/main/java/com/example/customerservice/actor/service/AppearanceService.java @@ -7,6 +7,7 @@ import com.example.customerservice.actor.entity.ActorAppearances; import com.example.customerservice.actor.repository.ActorRepository; import com.example.customerservice.contents.entity.Contents; +import com.example.customerservice.contents.repository.ContentsRepository; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -19,6 +20,7 @@ @RequiredArgsConstructor public class AppearanceService { private final ActorRepository actorRepository; + private final ContentsRepository contentsRepository; @Transactional(readOnly = true) public AppearancePageResponse getAppearanceByName(String actorName, Pageable pageable) { @@ -26,21 +28,21 @@ public AppearancePageResponse getAppearanceByName(String actorName, Pageable pag Actor actor = actorRepository.findByActorName(actorName) .orElseThrow(() -> new RuntimeException("Actor not found")); - // 배우 출연작으로 작품 조회 - List contents = new ArrayList<>(); - for (ActorAppearances appearance : actor.getActorAppearances()) { - contents.add(appearance.getContents()); - } + // 배우 출연작으로 총 작품 수 작품 조회 + int totalSize = actor.getActorAppearances().size(); + + // 페이징을 위해 limit와 offset을 적용해서 조회 + List contentsByActorName = contentsRepository.findContentsByActorName( + actorName, pageable.getPageSize(), pageable.getOffset()); // 작품을 페이징 형식에 맞게 교체 List appearanceResponses = new ArrayList<>(); - for (Contents content : contents) { + for (Contents content : contentsByActorName) { appearanceResponses.add(AppearanceResponse.fromContent(content)); } - - PageableResponse pageableResponse = PageableResponse.of(pageable, appearanceResponses); + PageableResponse pageableResponse = PageableResponse.of(pageable, totalSize); // 리턴할 객체 빌드 - return AppearancePageResponse.of(appearanceResponses, pageableResponse); + return AppearancePageResponse.of(pageableResponse, appearanceResponses); } } diff --git a/customer-service/src/main/java/com/example/customerservice/contents/repository/ContentsRepository.java b/customer-service/src/main/java/com/example/customerservice/contents/repository/ContentsRepository.java index b2b805f..3f6b637 100644 --- a/customer-service/src/main/java/com/example/customerservice/contents/repository/ContentsRepository.java +++ b/customer-service/src/main/java/com/example/customerservice/contents/repository/ContentsRepository.java @@ -1,8 +1,10 @@ package com.example.customerservice.contents.repository; +import com.example.customerservice.actor.dto.response.AppearanceResponse; import com.example.customerservice.contents.entity.Contents; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import java.util.List; @@ -11,4 +13,24 @@ public interface ContentsRepository extends JpaRepository { List findAllTitlesAndWriters(); boolean existsByTitle(String title); + + @Query(value = """ + SELECT + * + FROM + actor a + JOIN + actor_appearances aa ON a.actor_id = aa.actor_id + JOIN + contents c ON aa.contents_id = c.content_id + WHERE + a.actor_name = :actorName + ORDER BY + c.content_id ASC + LIMIT :limit OFFSET :offset + """, nativeQuery = true) + List findContentsByActorName( + @Param("actorName") String actorName, + @Param("limit") int limit, + @Param("offset") long offset); } From 009c021a1b87da8da1d37f06cb7f2a3de61abe1a Mon Sep 17 00:00:00 2001 From: LeeShinHeang Date: Tue, 21 Jan 2025 13:11:39 +0900 Subject: [PATCH 3/3] =?UTF-8?q?refactor:=20import=20=ED=98=95=EC=8B=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20#12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../actor/dto/response/PageableResponse.java | 13 +++--- .../actor/service/AppearanceService.java | 1 - .../repository/ContentsRepository.java | 45 +++++++++---------- 3 files changed, 27 insertions(+), 32 deletions(-) diff --git a/customer-service/src/main/java/com/example/customerservice/actor/dto/response/PageableResponse.java b/customer-service/src/main/java/com/example/customerservice/actor/dto/response/PageableResponse.java index 2b847ac..b4a65c5 100644 --- a/customer-service/src/main/java/com/example/customerservice/actor/dto/response/PageableResponse.java +++ b/customer-service/src/main/java/com/example/customerservice/actor/dto/response/PageableResponse.java @@ -1,18 +1,15 @@ package com.example.customerservice.actor.dto.response; -import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; - -import java.util.List; - +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; import lombok.Getter; import org.springframework.data.domain.Pageable; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; @Builder @Getter -public class PageableResponse{ +public class PageableResponse { @Schema( defaultValue = "0", description = "페이지 인덱스로, 0부터 시작합니다. 별도의 값 없이 요청 시, 0으로 설정됩니다.", @@ -49,7 +46,7 @@ public class PageableResponse{ private boolean isEnd; public static PageableResponse of(Pageable pageable, int totalElementsSize) { - int totalPageSize = (int)Math.ceil((double)totalElementsSize / pageable.getPageSize()); + int totalPageSize = (int) Math.ceil((double) totalElementsSize / pageable.getPageSize()); boolean isEnd = pageable.getPageNumber() + 1 >= totalPageSize; return PageableResponse.builder() .page(pageable.getPageNumber()) diff --git a/customer-service/src/main/java/com/example/customerservice/actor/service/AppearanceService.java b/customer-service/src/main/java/com/example/customerservice/actor/service/AppearanceService.java index e508c14..1c2ac2d 100644 --- a/customer-service/src/main/java/com/example/customerservice/actor/service/AppearanceService.java +++ b/customer-service/src/main/java/com/example/customerservice/actor/service/AppearanceService.java @@ -4,7 +4,6 @@ import com.example.customerservice.actor.dto.response.AppearanceResponse; import com.example.customerservice.actor.dto.response.PageableResponse; import com.example.customerservice.actor.entity.Actor; -import com.example.customerservice.actor.entity.ActorAppearances; import com.example.customerservice.actor.repository.ActorRepository; import com.example.customerservice.contents.entity.Contents; import com.example.customerservice.contents.repository.ContentsRepository; diff --git a/customer-service/src/main/java/com/example/customerservice/contents/repository/ContentsRepository.java b/customer-service/src/main/java/com/example/customerservice/contents/repository/ContentsRepository.java index 3f6b637..644bc28 100644 --- a/customer-service/src/main/java/com/example/customerservice/contents/repository/ContentsRepository.java +++ b/customer-service/src/main/java/com/example/customerservice/contents/repository/ContentsRepository.java @@ -1,6 +1,5 @@ package com.example.customerservice.contents.repository; -import com.example.customerservice.actor.dto.response.AppearanceResponse; import com.example.customerservice.contents.entity.Contents; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -9,28 +8,28 @@ import java.util.List; public interface ContentsRepository extends JpaRepository { - @Query("SELECT CONCAT(c.title, '|', c.writer) FROM Contents c") - List findAllTitlesAndWriters(); + @Query("SELECT CONCAT(c.title, '|', c.writer) FROM Contents c") + List findAllTitlesAndWriters(); - boolean existsByTitle(String title); + boolean existsByTitle(String title); - @Query(value = """ - SELECT - * - FROM - actor a - JOIN - actor_appearances aa ON a.actor_id = aa.actor_id - JOIN - contents c ON aa.contents_id = c.content_id - WHERE - a.actor_name = :actorName - ORDER BY - c.content_id ASC - LIMIT :limit OFFSET :offset - """, nativeQuery = true) - List findContentsByActorName( - @Param("actorName") String actorName, - @Param("limit") int limit, - @Param("offset") long offset); + @Query(value = """ + SELECT + * + FROM + actor a + JOIN + actor_appearances aa ON a.actor_id = aa.actor_id + JOIN + contents c ON aa.contents_id = c.content_id + WHERE + a.actor_name = :actorName + ORDER BY + c.content_id ASC + LIMIT :limit OFFSET :offset + """, nativeQuery = true) + List findContentsByActorName( + @Param("actorName") String actorName, + @Param("limit") int limit, + @Param("offset") long offset); }