{"id":7560,"date":"2023-02-07T19:52:02","date_gmt":"2023-02-07T10:52:02","guid":{"rendered":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=7560"},"modified":"2023-02-08T14:02:06","modified_gmt":"2023-02-08T05:02:06","slug":"spring-boot-jpa-paging","status":"publish","type":"post","link":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=7560","title":{"rendered":"Spring Boot &#8211; JPA Paging"},"content":{"rendered":"<h1>Spring Boot &#8211; JPA Paging<\/h1>\n<p>Spring Boot \uc758 JPA Paging \uc744 \uc704\ud55c \ubc29\ubc95\uc744 \uc124\uba85\ud569\ub2c8\ub2e4.<\/p>\n<p>\uc791\ub3d9\uac00\ub2a5\ud55c \ucf54\ub4dc\ub97c \ubaa9\uc801\uc73c\ub85c \ud558\uc9c0 \uc54a\uace0,<br \/>\n\uae30\ubcf8 \uc6d0\ub9ac\ub97c \uc815\ub9ac\ud558\ub294 \uac83\uc744 \ubaa9\uc801\uc73c\ub85c \ud569\ub2c8\ub2e4.<\/p>\n<p>\uc544\ub798 \ucf54\ub4dc\ub294 DB \uc811\uc18d API \uc11c\ubc84\uc640 \uc0ac\uc6a9\uc790 \uc694\uccad\uc744 \ubc1b\ub294 \uc11c\ubc84\uac00 \ubd84\ub9ac\ub41c \uac83\uc744 \uac00\uc815\ud569\ub2c8\ub2e4.<\/p>\n<h2>Repository<\/h2>\n<p><code>Page&lt;Entity&gt;<\/code> \ub97c \ub9ac\ud134\ubc1b\uc2b5\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-java\">public interface CompanyRepositoryCustom {\n    Page&lt;Company&gt; search(SearchCompanyRequestDto dto);\n}<\/code><\/pre>\n<h2>Service<\/h2>\n<p>MapStruct \ub4f1\uc744 \uc774\uc6a9\ud574 DTO \ub85c \ubcc0\ud658\ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-java\">@Service\n@RequiredArgsConstructor\npublic class CompanyService {\n    public ResponseEntity&lt;?&gt; search(SearchCompanyRequestDto dto) {\n        Page&lt;CompanyDto&gt; dtos = repository.search(dto).map(converter::toDto);\n        return ResponseEntity.ok(new ApiResponseWithData(ResponseCode.OK, dtos));\n    }\n}<\/code><\/pre>\n<h2>Controller<\/h2>\n<p><code>Page&lt;DTO&gt;<\/code> \ub97c \ub9ac\ud134\ud574 \uc90d\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-java\">@RestController\n@RequiredArgsConstructor\n@RequestMapping(&quot;\/v1\/account&quot;)\npublic class CompanyController {\n    @PostMapping(&quot;\/search&quot;)\n    public ResponseEntity&lt;?&gt; search(@RequestBody SearchCompanyRequestDto dto) {\n        return service.search(dto);\n    }\n}<\/code><\/pre>\n<h2>\uc758\uc874\uc131 \ucd94\uac00<\/h2>\n<p>DB \uc811\uc18d API \uc11c\ubc84\uc640 \uc0ac\uc6a9\uc790 \uc694\uccad\uc744 \ubc1b\ub294 \uc11c\ubc84\uac00 \ubd84\ub9ac\ub41c \uc0c1\ud0dc\ub77c,<br \/>\n\uc758\uc874\uc131\uc744 \ucd94\uac00\ub85c \ub123\uc5b4 \uc918\uc57c \ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-groovy\">dependencies {\n    implementation &#039;org.springframework.boot:spring-boot-starter-data-jpa&#039;\n}<\/code><\/pre>\n<pre><code class=\"language-java\">@SpringBootApplication(exclude = {\n        DataSourceAutoConfiguration.class,\n        DataSourceTransactionManagerAutoConfiguration.class,\n        HibernateJpaAutoConfiguration.class\n})\npublic class WarehousewebApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(WarehousewebApplication.class, args);\n    }\n}<\/code><\/pre>\n<h2>\ucee4\uc2a4\ud140 \ub9e4\ud37c \uc0dd\uc131<\/h2>\n<pre><code class=\"language-java\">import org.springframework.data.domain.Page;\n\npublic class PageModule extends SimpleModule {\n    public PageModule() {\n        addDeserializer(Page.class, new PageDeserializer());\n    }\n}<\/code><\/pre>\n<pre><code class=\"language-java\">public class PageDeserializer extends JsonDeserializer&lt;Page&lt;?&gt;&gt; implements ContextualDeserializer {\n    private static final String CONTENT = &quot;content&quot;;\n    private static final String NUMBER = &quot;number&quot;;\n    private static final String SIZE = &quot;size&quot;;\n    private static final String TOTAL_ELEMENTS = &quot;totalElements&quot;;\n    private JavaType valueType;\n\n    @Override\n    public Page&lt;?&gt; deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {\n        final CollectionType valuesListType = ctxt.getTypeFactory().constructCollectionType(List.class, valueType);\n\n        List&lt;?&gt; list = new ArrayList&lt;&gt;();\n        int pageNumber = 0;\n        int pageSize = 0;\n        long total = 0;\n        if (p.isExpectedStartObjectToken()) {\n            p.nextToken();\n            if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)) {\n                String propName = p.getCurrentName();\n                do {\n                    p.nextToken();\n                    switch (propName) {\n                        case CONTENT:\n                            list = ctxt.readValue(p, valuesListType);\n                            break;\n                        case NUMBER:\n                            pageNumber = ctxt.readValue(p, Integer.class);\n                            break;\n                        case SIZE:\n                            pageSize = ctxt.readValue(p, Integer.class);\n                            break;\n                        case TOTAL_ELEMENTS:\n                            total = ctxt.readValue(p, Long.class);\n                            break;\n                        default:\n                            p.skipChildren();\n                            break;\n                    }\n                } while (((propName = p.nextFieldName())) != null);\n            } else {\n                ctxt.handleUnexpectedToken(handledType(), p);\n            }\n        } else {\n            ctxt.handleUnexpectedToken(handledType(), p);\n        }\n\n        return new PageImpl&lt;&gt;(list, PageRequest.of(pageNumber, pageSize), total);\n    }\n\n    @Override\n    public JsonDeserializer&lt;?&gt; createContextual(DeserializationContext ctxt, BeanProperty property) {\n        final JavaType wrapperType = ctxt.getContextualType();\n        final PageDeserializer deserializer = new PageDeserializer();\n        deserializer.valueType = wrapperType.containedType(0);\n        return deserializer;\n    }\n}<\/code><\/pre>\n<h2>Feign Service<\/h2>\n<pre><code class=\"language-java\">@FeignClient(name = &quot;COMPANY-SERVICE&quot;,configuration = {FeignClientConfig.class, FeignRetryConfig.class}, url = &quot;${api-server.url}:${api-server.port}&quot;)\npublic interface ApiCompanyService {\n    @PostMapping(&quot;\/v1\/account\/search&quot;)\n    ApiResponseWithData search(\n            @RequestBody SearchCompanyRequestDto req\n    );\n}<\/code><\/pre>\n<h2>Service<\/h2>\n<pre><code class=\"language-java\">@Service\n@RequiredArgsConstructor\npublic class CompanyService {\n\n    private final ApiCompanyService apiCompanyService;\n\n    public Page&lt;SearchCompanyResponseDto&gt; search(SearchCompanyRequestDto req) {\n        ApiResponseWithData apiResponseWithData = apiCompanyService.search(req);\n\n        ObjectMapper mapper = new ObjectMapper();\n        mapper.registerModule(new PageModule());\n        mapper.registerModule(new JavaTimeModule());\n\n        return mapper.convertValue(apiResponseWithData.getData(), new TypeReference&lt;&gt;() {});\n    }\n}<\/code><\/pre>\n<h2>Controller<\/h2>\n<p><code>Page&lt;DTO&gt;<\/code> \ub97c \ubcc0\ud658\ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-java\">@Controller\npublic class CompanyIndexController {\n    @GetMapping(&quot;\/admin\/company\/&quot;)\n    public String search(HttpServletRequest request, ModelMap model, @ModelAttribute SearchCompanyRequestDto req) {\n        Page&lt;SearchCompanyResponseDto&gt; searchCompanyResponseDtoPage = service.search(req);\n\n        model.addAttribute(&quot;list&quot;, searchCompanyResponseDtoPage.toList());\n        model.addAttribute(&quot;req&quot;, req);\n        model.addAttribute(&quot;currentPage&quot;, req.getPageNo());\n        model.addAttribute(&quot;maxPage&quot;, searchCompanyResponseDtoPage.getTotalPages());\n\n        return &quot;\/admin\/company&quot;;\n    }\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Spring Boot &#8211; JPA Paging Spring Boot \uc758 JPA Paging \uc744 \uc704\ud55c \ubc29\ubc95\uc744 \uc124\uba85\ud569\ub2c8\ub2e4. \uc791\ub3d9\uac00\ub2a5\ud55c \ucf54\ub4dc\ub97c \ubaa9\uc801\uc73c\ub85c \ud558\uc9c0 \uc54a\uace0, \uae30\ubcf8 \uc6d0\ub9ac\ub97c \uc815\ub9ac\ud558\ub294 \uac83\uc744 \ubaa9\uc801\uc73c\ub85c \ud569\ub2c8\ub2e4. \uc544\ub798 \ucf54\ub4dc\ub294 DB \uc811\uc18d API \uc11c\ubc84\uc640 \uc0ac\uc6a9\uc790 \uc694\uccad\uc744 \ubc1b\ub294 \uc11c\ubc84\uac00 \ubd84\ub9ac\ub41c \uac83\uc744 \uac00\uc815\ud569\ub2c8\ub2e4. Repository Page&lt;Entity&gt; \ub97c \ub9ac\ud134\ubc1b\uc2b5\ub2c8\ub2e4. public interface CompanyRepositoryCustom { Page&lt;Company&gt; search(SearchCompanyRequestDto dto); } Service MapStruct \ub4f1\uc744 \uc774\uc6a9\ud574 DTO\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=7560\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[29],"tags":[],"class_list":["post-7560","post","type-post","status-publish","format-standard","hentry","category-spring-boot-2-5"],"_links":{"self":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/7560","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7560"}],"version-history":[{"count":4,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/7560\/revisions"}],"predecessor-version":[{"id":7567,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/7560\/revisions\/7567"}],"wp:attachment":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7560"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7560"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7560"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}