Τρίτη 31 Μαρτίου 2020

Pagination with PagedResourcesAssembler









Our goal is a REST api response (paginated data with pagination information, next/previous links etc), like:


    {
         ....
         ....// your DTO object list //
         ....,
        "attr": "XXXXXXX",
        "amount": -6010,
        "transactionCode": 107,
        "transactionId": "T3ce4ea05fabf2dd8a664011e9f79de120da18da0.1",
        "typeOfTransaction": "",
        "dateOfTransaction": "2020-03-20T00:00:00.000Z"
      },
      {
        "attr": "ZZZZz",
        "amount": -18200,
        "transactionCode": 105,
        "transactionId": "T1645f70098774fd23e42867f914348bdbdd047a3.1"
        "typeOfTransaction": "",
        "dateOfTransaction": "2020-03-17T00:00:00.000Z"
      }
    ]
  },
  "_links": {
    "first": {
      "href": "http://localhost:8080/api/store/account/transactions?accId=A&page=0&size=5"
    },
    "self": {
      "href": "http://localhost:8080/api/store/account/transactions?accId=A"
    },
    "next": {
      "href": "http://localhost:8080/api/store/account/transactions?accId=A&page=1&size=5"
    },
    "last": {
      "href": "http://localhost:8080/api/store/account/transactions?accnId=A&page=13&size=5"
    }
  },
  "page": {
    "size": 5,
    "totalElements": 68,
    "totalPages": 14,
    "number": 0
  }
}


1. Pom.xml


<dependency> <groupId>org.springframework.hateoas</groupId> <artifactId>spring-hateoas</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-hateoas</artifactId> </dependency>
2. Controller/Resource method

    @GetMapping("/your/path") public ResponseEntity<PagedResources<yourDTO>> getPagedDTOs(
@RequestParam(name = "page", defaultValue = "0") int page, @RequestParam(name = "size", defaultValue = "5") int size, UriComponentsBuilder uriBuilder, HttpServletResponse response, PagedResourcesAssembler assembler) {
Pageable pageable = PageRequest.of(page, size); Page<yourDTO> retrievedData = yourService.getTransactions(pageable); PagedResources<yourDTO> pr = assembler.toResource(retrievedData , linkTo(YourResource.class).slash("/your" + "/path").withSelfRel()); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.add("Link", createLinkHeader(pr)); return new ResponseEntity<>(assembler.toResource(retrievedData, linkTo(YourResource.class).slash("/your" + "/path").withSelfRel()), responseHeaders, HttpStatus.OK); }

3. Controller/Resource helper methods
private String createLinkHeader(PagedResources<yourDTO> pr){ List<String> linksList = new ArrayList<>(); List<Link> links = pr.getLinks(); for(Link link : links) { linksList.add(buildLinkHeader(link.getHref(), link.getRel())); } return String.join(",", linksList); } public static String buildLinkHeader(final String uri, final String rel) { return "<" + uri + ">; rel=\"" + rel + "\""; }
4. Service layer method

Page<yourDTO> getTransactions(Pageable pageable);


5. Service Impl method

@Override public Page<yourDTO> getTransactions(Pageable pageable) { List<yourDTO> allTransactions = getAllTransactions(); return getPage(pageable, allTransactions); }

6. Helper method

private <T> Page<T> getPage(Pageable pageable, List<T> list) { int start = (int) pageable.getOffset(); int end = ((start + pageable.getPageSize()) > list.size() ? list.size() : (start + pageable.getPageSize())); return new PageImpl<>(list.subList(start, end), pageable, list.size()); }