From 2334a393486cafee5365edfb4745cb5968e4ed7e Mon Sep 17 00:00:00 2001 From: can019 Date: Sun, 14 Sep 2025 20:52:22 +0900 Subject: [PATCH 1/4] chore: Paging request, reponse dto --- .../site/icebang/common/dto/PageParams.java | 25 +++++++++++++++++++ .../site/icebang/common/dto/PageResult.java | 16 ++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 apps/user-service/src/main/java/site/icebang/common/dto/PageParams.java create mode 100644 apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java diff --git a/apps/user-service/src/main/java/site/icebang/common/dto/PageParams.java b/apps/user-service/src/main/java/site/icebang/common/dto/PageParams.java new file mode 100644 index 00000000..5f2f0d30 --- /dev/null +++ b/apps/user-service/src/main/java/site/icebang/common/dto/PageParams.java @@ -0,0 +1,25 @@ +package site.icebang.common.dto; + +import lombok.Data; + +@Data +public class PageParams { + private int current = 1; + private int pageSize = 10; + private String search; + private String[] sorters; + private String[] filters; + + // 계산된 offset + public int getOffset() { + return (current - 1) * pageSize; + } + + public boolean hasSearch() { + return search != null && !search.trim().isEmpty(); + } + + public boolean hasSorters() { + return sorters != null && sorters.length > 0; + } +} diff --git a/apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java b/apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java new file mode 100644 index 00000000..5ed56f5f --- /dev/null +++ b/apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java @@ -0,0 +1,16 @@ +package site.icebang.common.dto; + +import java.util.List; + +import lombok.Data; + +@Data +public class PageResult { + private List data; + private int total; + private int current; + private int pageSize; + private int totalPages; + private boolean hasNext; + private boolean hasPrevious; +} From 85c0b9e089c1a18b02a866ea67cb758692d7602c Mon Sep 17 00:00:00 2001 From: can019 Date: Sun, 14 Sep 2025 21:01:42 +0900 Subject: [PATCH 2/4] chore: Pagination controller, service example --- .../site/icebang/common/dto/PageResult.java | 14 +++++++++ .../icebang/common/service/PageService.java | 27 +++++++++++++++++ .../controller/WorkflowController.java | 30 +++++++++++++++++++ .../domain/workflow/dto/WorkflowCardDto.java | 6 ++++ .../workflow/service/WorkflowService.java | 19 ++++++++++++ 5 files changed, 96 insertions(+) create mode 100644 apps/user-service/src/main/java/site/icebang/common/service/PageService.java create mode 100644 apps/user-service/src/main/java/site/icebang/domain/workflow/controller/WorkflowController.java create mode 100644 apps/user-service/src/main/java/site/icebang/domain/workflow/dto/WorkflowCardDto.java create mode 100644 apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowService.java diff --git a/apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java b/apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java index 5ed56f5f..1e2a832a 100644 --- a/apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java +++ b/apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java @@ -13,4 +13,18 @@ public class PageResult { private int totalPages; private boolean hasNext; private boolean hasPrevious; + + public PageResult(List data, int total, int current, int pageSize) { + this.data = data; + this.total = total; + this.current = current; + this.pageSize = pageSize; + this.totalPages = (int) Math.ceil((double) total / pageSize); + this.hasNext = current < totalPages; + this.hasPrevious = current > 1; + } + + public static PageResult of(List data, int total, int current, int pageSize) { + return new PageResult<>(data, total, current, pageSize); + } } diff --git a/apps/user-service/src/main/java/site/icebang/common/service/PageService.java b/apps/user-service/src/main/java/site/icebang/common/service/PageService.java new file mode 100644 index 00000000..58025ef5 --- /dev/null +++ b/apps/user-service/src/main/java/site/icebang/common/service/PageService.java @@ -0,0 +1,27 @@ +package site.icebang.common.service; + +import java.util.List; +import java.util.function.Function; + +import org.springframework.stereotype.Service; + +import site.icebang.common.dto.ApiResponse; +import site.icebang.common.dto.PageParams; +import site.icebang.common.dto.PageResult; + +@Service +public class PageService { + + public ApiResponse> createPagedResponse( + PageParams pageParams, + Function> dataProvider, + Function countProvider) { + List data = dataProvider.apply(pageParams); + int total = countProvider.apply(pageParams); + + PageResult pageResult = + PageResult.of(data, total, pageParams.getCurrent(), pageParams.getPageSize()); + + return ApiResponse.success(pageResult); + } +} diff --git a/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/WorkflowController.java b/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/WorkflowController.java new file mode 100644 index 00000000..c0fe6549 --- /dev/null +++ b/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/WorkflowController.java @@ -0,0 +1,30 @@ +package site.icebang.domain.workflow.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import lombok.RequiredArgsConstructor; + +import site.icebang.common.dto.ApiResponse; +import site.icebang.common.dto.PageParams; +import site.icebang.common.dto.PageResult; +import site.icebang.common.service.PageService; +import site.icebang.domain.workflow.dto.WorkflowCardDto; +import site.icebang.domain.workflow.service.WorkflowService; + +@RestController +@RequestMapping("/workflows") +@RequiredArgsConstructor +public class WorkflowController { + private final PageService pageService; + private final WorkflowService workflowService; + + @GetMapping("") + public ApiResponse> getWorkflowList( + @ModelAttribute PageParams pageParams) { + return pageService.createPagedResponse( + pageParams, workflowService::getWorkflowList, workflowService::getWorkflowCount); + } +} diff --git a/apps/user-service/src/main/java/site/icebang/domain/workflow/dto/WorkflowCardDto.java b/apps/user-service/src/main/java/site/icebang/domain/workflow/dto/WorkflowCardDto.java new file mode 100644 index 00000000..b54a29c0 --- /dev/null +++ b/apps/user-service/src/main/java/site/icebang/domain/workflow/dto/WorkflowCardDto.java @@ -0,0 +1,6 @@ +package site.icebang.domain.workflow.dto; + +import lombok.Data; + +@Data +public class WorkflowCardDto {} diff --git a/apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowService.java b/apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowService.java new file mode 100644 index 00000000..cff9bc21 --- /dev/null +++ b/apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowService.java @@ -0,0 +1,19 @@ +package site.icebang.domain.workflow.service; + +import java.util.List; + +import org.springframework.stereotype.Service; + +import site.icebang.common.dto.PageParams; +import site.icebang.domain.workflow.dto.WorkflowCardDto; + +@Service +public class WorkflowService { + public List getWorkflowList(PageParams pageParams) { + throw new RuntimeException("Not implemented"); + } + + public Integer getWorkflowCount(PageParams pageParams) { + throw new RuntimeException("Not implemented"); + } +} From 375fc7a99fec849a72bf2ab094a7f14119695aed Mon Sep 17 00:00:00 2001 From: can019 Date: Sun, 14 Sep 2025 21:03:10 +0900 Subject: [PATCH 3/4] =?UTF-8?q?chore:=20workflows=20api=20=EC=95=9E?= =?UTF-8?q?=EC=97=90=20v0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../icebang/domain/workflow/controller/WorkflowController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/WorkflowController.java b/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/WorkflowController.java index c0fe6549..fe29b078 100644 --- a/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/WorkflowController.java +++ b/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/WorkflowController.java @@ -15,7 +15,7 @@ import site.icebang.domain.workflow.service.WorkflowService; @RestController -@RequestMapping("/workflows") +@RequestMapping("/v0/workflows") @RequiredArgsConstructor public class WorkflowController { private final PageService pageService; From 61126dfb3149d53b30c09499b9bca675d48b9ef5 Mon Sep 17 00:00:00 2001 From: can019 Date: Sun, 14 Sep 2025 21:24:53 +0900 Subject: [PATCH 4/4] =?UTF-8?q?refactor:=20=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EC=85=98=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PageService를 PageableService 인터페이스로 변경하여 트랜잭션 처리 개선 --- .../site/icebang/common/dto/PageResult.java | 49 ++++++++++++++++++- .../icebang/common/service/PageService.java | 27 ---------- .../common/service/PageableService.java | 8 +++ .../controller/WorkflowController.java | 6 +-- .../workflow/service/WorkflowService.java | 22 ++++++--- 5 files changed, 73 insertions(+), 39 deletions(-) delete mode 100644 apps/user-service/src/main/java/site/icebang/common/service/PageService.java create mode 100644 apps/user-service/src/main/java/site/icebang/common/service/PageableService.java diff --git a/apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java b/apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java index 1e2a832a..4a2a8bfa 100644 --- a/apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java +++ b/apps/user-service/src/main/java/site/icebang/common/dto/PageResult.java @@ -1,10 +1,13 @@ package site.icebang.common.dto; import java.util.List; +import java.util.function.Supplier; import lombok.Data; +import lombok.NoArgsConstructor; @Data +@NoArgsConstructor public class PageResult { private List data; private int total; @@ -19,12 +22,56 @@ public PageResult(List data, int total, int current, int pageSize) { this.total = total; this.current = current; this.pageSize = pageSize; - this.totalPages = (int) Math.ceil((double) total / pageSize); + calculatePagination(); + } + + // 페이징 계산 로직 분리 + private void calculatePagination() { + this.totalPages = total > 0 ? (int) Math.ceil((double) total / pageSize) : 0; this.hasNext = current < totalPages; this.hasPrevious = current > 1; } + // 기존 of 메서드 public static PageResult of(List data, int total, int current, int pageSize) { return new PageResult<>(data, total, current, pageSize); } + + // PageParams를 받는 of 메서드 + public static PageResult of(List data, int total, PageParams pageParams) { + return new PageResult<>(data, total, pageParams.getCurrent(), pageParams.getPageSize()); + } + + // 함수형 인터페이스를 활용한 from 메서드 (트랜잭션 내에서 실행) + public static PageResult from( + PageParams pageParams, Supplier> dataSupplier, Supplier countSupplier) { + List data = dataSupplier.get(); + int total = countSupplier.get(); + return new PageResult<>(data, total, pageParams.getCurrent(), pageParams.getPageSize()); + } + + // 빈 페이지 결과 생성 + public static PageResult empty(PageParams pageParams) { + return new PageResult<>(List.of(), 0, pageParams.getCurrent(), pageParams.getPageSize()); + } + + // 빈 페이지 결과 생성 (기본값) + public static PageResult empty() { + return new PageResult<>(List.of(), 0, 1, 10); + } + + // 데이터가 있는지 확인 + public boolean hasData() { + return data != null && !data.isEmpty(); + } + + // 첫 번째 페이지인지 확인 + public boolean isFirstPage() { + return current == 1; + } + + // 마지막 페이지인지 확인 + public boolean isLastPage() { + return current == totalPages; + } } diff --git a/apps/user-service/src/main/java/site/icebang/common/service/PageService.java b/apps/user-service/src/main/java/site/icebang/common/service/PageService.java deleted file mode 100644 index 58025ef5..00000000 --- a/apps/user-service/src/main/java/site/icebang/common/service/PageService.java +++ /dev/null @@ -1,27 +0,0 @@ -package site.icebang.common.service; - -import java.util.List; -import java.util.function.Function; - -import org.springframework.stereotype.Service; - -import site.icebang.common.dto.ApiResponse; -import site.icebang.common.dto.PageParams; -import site.icebang.common.dto.PageResult; - -@Service -public class PageService { - - public ApiResponse> createPagedResponse( - PageParams pageParams, - Function> dataProvider, - Function countProvider) { - List data = dataProvider.apply(pageParams); - int total = countProvider.apply(pageParams); - - PageResult pageResult = - PageResult.of(data, total, pageParams.getCurrent(), pageParams.getPageSize()); - - return ApiResponse.success(pageResult); - } -} diff --git a/apps/user-service/src/main/java/site/icebang/common/service/PageableService.java b/apps/user-service/src/main/java/site/icebang/common/service/PageableService.java new file mode 100644 index 00000000..25d41d29 --- /dev/null +++ b/apps/user-service/src/main/java/site/icebang/common/service/PageableService.java @@ -0,0 +1,8 @@ +package site.icebang.common.service; + +import site.icebang.common.dto.PageParams; +import site.icebang.common.dto.PageResult; + +public interface PageableService { + PageResult getPagedResult(PageParams pageParams); +} diff --git a/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/WorkflowController.java b/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/WorkflowController.java index fe29b078..39077eca 100644 --- a/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/WorkflowController.java +++ b/apps/user-service/src/main/java/site/icebang/domain/workflow/controller/WorkflowController.java @@ -10,7 +10,6 @@ import site.icebang.common.dto.ApiResponse; import site.icebang.common.dto.PageParams; import site.icebang.common.dto.PageResult; -import site.icebang.common.service.PageService; import site.icebang.domain.workflow.dto.WorkflowCardDto; import site.icebang.domain.workflow.service.WorkflowService; @@ -18,13 +17,12 @@ @RequestMapping("/v0/workflows") @RequiredArgsConstructor public class WorkflowController { - private final PageService pageService; private final WorkflowService workflowService; @GetMapping("") public ApiResponse> getWorkflowList( @ModelAttribute PageParams pageParams) { - return pageService.createPagedResponse( - pageParams, workflowService::getWorkflowList, workflowService::getWorkflowCount); + PageResult result = workflowService.getPagedResult(pageParams); + return ApiResponse.success(result); } } diff --git a/apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowService.java b/apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowService.java index cff9bc21..1a358924 100644 --- a/apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowService.java +++ b/apps/user-service/src/main/java/site/icebang/domain/workflow/service/WorkflowService.java @@ -1,19 +1,27 @@ package site.icebang.domain.workflow.service; -import java.util.List; - import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import lombok.RequiredArgsConstructor; import site.icebang.common.dto.PageParams; +import site.icebang.common.dto.PageResult; +import site.icebang.common.service.PageableService; import site.icebang.domain.workflow.dto.WorkflowCardDto; @Service -public class WorkflowService { - public List getWorkflowList(PageParams pageParams) { - throw new RuntimeException("Not implemented"); - } +@RequiredArgsConstructor +public class WorkflowService implements PageableService { - public Integer getWorkflowCount(PageParams pageParams) { + @Override + @Transactional(readOnly = true) + public PageResult getPagedResult(PageParams pageParams) { throw new RuntimeException("Not implemented"); + // return PageResult.from( + // pageParams, + // () -> workflowMapper.selectWorkflowList(pageParams), + // () -> workflowMapper.selectWorkflowCount(pageParams) + // ); } }