{"id":113,"date":"2020-03-12T22:40:07","date_gmt":"2020-03-12T13:40:07","guid":{"rendered":"http:\/\/www.skyer9.pe.kr\/wordpress\/?p=113"},"modified":"2020-03-28T16:08:51","modified_gmt":"2020-03-28T07:08:51","slug":"from-hello-to-querydsl-add-paging-3-12","status":"publish","type":"post","link":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=113","title":{"rendered":"[From Hello To QueryDSL] Add Paging (3\/12)"},"content":{"rendered":"<h1>Add Paging<\/h1>\n<p>\uac8c\uc2dc\ud310\uc5d0 \ud398\uc774\uc9d5 \uae30\ub2a5\uc744 \ucd94\uac00\ud569\ub2c8\ub2e4.<\/p>\n<h2>\uac1c\ubc1c\ud658\uacbd<\/h2>\n<ul>\n<li>Spring Boot 2.1.x<\/li>\n<li>Gradle 4.10.2<\/li>\n<\/ul>\n<p>\ud504\ub85c\uc81d\ud2b8\ub294 \uc774\uc804 \uae00\uc5d0\uc11c \uc791\uc131\ub41c \ud504\ub85c\uc81d\ud2b8\uc5d0 \ud30c\uc77c\uc744 \ucd94\uac00 \ub610\ub294 \uc218\uc815\ud558\ub294 \ubc29\uc2dd\uc73c\ub85c \uc9c4\ud589\ub429\ub2c8\ub2e4. \uc774\uc804 \uae00\uc744 \ub530\ub77c \ud558\uc9c0 \uc54a\uc740 \uacbd\uc6b0, \uba3c\uc800 \uc774\uc804 \uae00\ub300\ub85c \ud504\ub85c\uc81d\ud2b8\ub97c \uad6c\uc131\ud558\uc2dc\uae30 \ubc14\ub78d\ub2c8\ub2e4.<\/p>\n<h2>\ud30c\uc77c\ucd94\uac00<\/h2>\n<p><code>JpaRepository<\/code> \ub294 <code>PagingAndSortingRepository<\/code> \ub97c \ud655\uc7a5\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<p>\ud074\ub798\uc2a4\uba85\uc5d0 \uc788\ub4ef\uc774 \ud398\uc774\uc9d5\uacfc \uc815\ub82c\ub3c4 \ucc98\ub9ac\ud558\ub294\ub370 \uc815\ub82c\uae30\ub2a5\uc740 \uc0ac\uc6a9\ud558\uc9c0 \uc54a\uaca0\uc2b5\ub2c8\ub2e4.<\/p>\n<p>src\/main\/java\/kr\/co\/episode\/example\/domain\/posts\/PostsPagingRepository.java<\/p>\n<pre><code class=\"language-java\">package kr.co.episode.example.domain.posts;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.data.repository.JpaRepository;\n\npublic interface PostsPagingRepository extends JpaRepository&lt;Posts, Long&gt; {\n\n    @Query(value = &quot;SELECT p FROM Posts p ORDER BY p.id DESC&quot;)\n    Page&lt;Posts&gt; findAllDesc(Pageable pageable);\n}<\/code><\/pre>\n<p>src\/main\/java\/kr\/co\/episode\/example\/service\/posts\/PostsPagingService.java<\/p>\n<pre><code class=\"language-java\">package kr.co.episode.example.service.posts;\n\nimport kr.co.episode.example.domain.posts.Posts;\nimport kr.co.episode.example.domain.posts.PostsPagingRepository;\nimport kr.co.episode.example.web.dto.PostsListResponseDto;\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageImpl;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n@RequiredArgsConstructor\n@Service\npublic class PostsPagingService {\n\n    private final PostsPagingRepository postsPagingRepository;\n\n    @Transactional(readOnly = true)\n    public Page&lt;PostsListResponseDto&gt; findAllDesc(Pageable pageable) {\n        Page&lt;Posts&gt; posts = postsPagingRepository.findAllDesc(pageable);\n        List&lt;PostsListResponseDto&gt; results = posts.getContent().stream()\n                .map(PostsListResponseDto::new)\n                .collect(Collectors.toList());\n        long totalCount = posts.getTotalElements();\n\n        return new PageImpl&lt;&gt;(results, pageable, totalCount);\n    }\n}<\/code><\/pre>\n<h2>\ud30c\uc77c\uc218\uc815<\/h2>\n<p>src\/main\/java\/kr\/co\/episode\/example\/web\/IndexController.java<\/p>\n<pre><code class=\"language-java\">    \/\/ ......\n    private final PostsPagingService postsPagingService;\n\n    @GetMapping(&quot;\/&quot;)\n    public String index(Model model, @PageableDefault Pageable pageable) {\n        \/\/model.addAttribute(&quot;posts&quot;, postsService.findAllDesc());\n\n        \/\/ \ud398\uc774\uc9c0\ub2f9 \ud45c\uc2dc \uac8c\uc2dc\uae00 \uc218\ub97c 3\uac1c\ub85c \uc81c\ud55c\n        pageable = PageRequest.of(pageable.getPageNumber(), 3);\n        model.addAttribute(&quot;posts&quot;, postsPagingService.findAllDesc(pageable));\n\n        return &quot;index&quot;;\n    }\n    \/\/ ......<\/code><\/pre>\n<p>src\/main\/resources\/templates\/index.html<\/p>\n<pre><code class=\"language-html\">&lt;!DOCTYPE html&gt;\n&lt;html xmlns:th=&quot;http:\/\/www.thymeleaf.org&quot;&gt;\n&lt;head&gt;\n    &lt;meta charset=&quot;UTF-8&quot;&gt;\n    &lt;title&gt;\uac8c\uc2dc\ud310&lt;\/title&gt;\n    &lt;link rel=&quot;stylesheet&quot; href=&quot;https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/3.3.2\/css\/bootstrap.min.css&quot;&gt;\n    &lt;style&gt;\n        .container p { display: inline }\n    &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body class=&quot;container&quot;&gt;\n\n&lt;h1&gt;\uc2a4\ud504\ub9c1 \ubd80\ud2b8 \uac8c\uc2dc\ud310&lt;\/h1&gt;\n\n&lt;div class=&quot;col-md-12&quot;&gt;\n    &lt;div class=&quot;row&quot;&gt;\n        &lt;div class=&quot;col-md-6&quot;&gt;\n            &lt;a href=&quot;\/posts\/save&quot; role=&quot;button&quot; class=&quot;btn&quot; btn-primary&gt;\uae00 \ub4f1\ub85d&lt;\/a&gt;\n        &lt;\/div&gt;\n    &lt;\/div&gt;\n&lt;\/div&gt;\n\n&lt;div style=&quot;height: 80px;&quot;&gt;\n\n&lt;\/div&gt;\n\n&lt;table class=&quot;table&quot;&gt;\n    &lt;tr&gt;\n        &lt;th&gt;\uae00 \ubc88\ud638&lt;\/th&gt;\n        &lt;th&gt;\uae00\uc4f4\uc774&lt;\/th&gt;\n        &lt;th&gt;\uae00 \uc81c\ubaa9&lt;\/th&gt;\n        &lt;th&gt;\ucd5c\uc885\uc218\uc815&lt;\/th&gt;\n    &lt;\/tr&gt;\n    &lt;tr th:each=&quot;posts: ${posts}&quot;&gt;\n        &lt;td th:text=&quot;${posts.id}&quot;&gt;&lt;\/td&gt;\n        &lt;td&gt;\n            &lt;a th:href=&quot;${posts.link}&quot; th:text=&quot;${posts.author}&quot; \/&gt;\n        &lt;\/td&gt;\n        &lt;td&gt;\n            &lt;a th:href=&quot;${posts.link}&quot; th:text=&quot;${posts.title}&quot; \/&gt;\n        &lt;\/td&gt;\n        &lt;td th:text=&quot;${posts.modifiedDate}&quot;&gt;&lt;\/td&gt;\n    &lt;\/tr&gt;\n&lt;\/table&gt;\n\n&lt;nav style=&quot;text-align: center;&quot;&gt;\n    &lt;ul class=&quot;pagination&quot;\n        th:with=&quot;start=${T(Math).floor(posts.number\/10)*10},\n                    last=(${start + 9 &lt; posts.totalPages-1 ? start + 9 : posts.totalPages-1})&quot;&gt;\n        &lt;li&gt;\n            &lt;a th:href=&quot;@{\/(page=0)}&quot; aria-label=&quot;First&quot;&gt;\n                &lt;span aria-hidden=&quot;true&quot;&gt;First&lt;\/span&gt;\n            &lt;\/a&gt;\n        &lt;\/li&gt;\n\n        &lt;li th:class=&quot;${posts.first} ? &#039;disabled&#039;&quot;&gt;\n            &lt;a th:href=&quot;${posts.first} ? &#039;#&#039; :@{\/(page=${posts.number-1})}&quot; aria-label=&quot;Previous&quot;&gt;\n                &lt;span aria-hidden=&quot;true&quot;&gt;&lt;&lt;\/span&gt;\n            &lt;\/a&gt;\n        &lt;\/li&gt;\n\n        &lt;li th:each=&quot;page: ${#numbers.sequence(start, last)}&quot; th:class=&quot;${page == posts.number} ? &#039;active&#039;&quot;&gt;\n            &lt;a th:text=&quot;${page+1}&quot; th:href=&quot;@{\/(page=${page})}&quot;&gt;&lt;\/a&gt;\n        &lt;\/li&gt;\n\n        &lt;li th:class=&quot;${posts.last} ? &#039;disabled&#039;&quot;&gt;\n            &lt;a th:href=&quot;${posts.last} ? &#039;#&#039; : @{\/(page=${posts.number+1})}&quot; aria-label=&quot;Next&quot;&gt;\n                &lt;span aria-hidden=&quot;true&quot;&gt;&gt;&lt;\/span&gt;\n            &lt;\/a&gt;\n        &lt;\/li&gt;\n\n        &lt;li&gt;\n            &lt;a th:href=&quot;@{\/(page=${posts.totalPages-1})}&quot; aria-label=&quot;Last&quot;&gt;\n                &lt;span aria-hidden=&quot;true&quot;&gt;Last&lt;\/span&gt;\n            &lt;\/a&gt;\n        &lt;\/li&gt;\n    &lt;\/ul&gt;\n&lt;\/nav&gt;\n\n&lt;script src=&quot;https:\/\/code.jquery.com\/jquery-3.3.1.min.js&quot;&gt;&lt;\/script&gt;\n&lt;script src=&quot;https:\/\/stackpath.bootstrapcdn.com\/bootstrap\/4.3.1\/js\/bootstrap.min.js&quot;&gt;&lt;\/script&gt;\n\n&lt;script src=&quot;\/js\/app\/index.js&quot;&gt;&lt;\/script&gt;\n\n&lt;\/body&gt;\n&lt;\/html&gt;<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\uac8c\uc2dc\ud310\uc5d0 \ud398\uc774\uc9d5 \uae30\ub2a5\uc744 \ucd94\uac00\ud569\ub2c8\ub2e4.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-113","post","type-post","status-publish","format-standard","hentry","category-spring-boot-2-1"],"_links":{"self":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/113","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=113"}],"version-history":[{"count":5,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/113\/revisions"}],"predecessor-version":[{"id":325,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/113\/revisions\/325"}],"wp:attachment":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=113"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=113"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=113"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}