Let's imagine we have an Account entity:
@Entity public class Account implements Identifiable<Integer>, Serializable { private static final long serialVersionUID = -3187480027431265380L; @Id private Integer id; private String name; public Account(Integer id, String name) { this.id = id; this.name = name; } public void setId(Integer id) { this.id = id; } @Override public Integer getId() { return id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
With an AccountRepository exposing its CRUD endpoints on /accounts:
@RepositoryRestResource(collectionResourceRel = "accounts", path = "accounts") public interface AccountRepository extends CrudRepository<Account, Integer> { }
And an AccountController that overrides the default GET endpoint form AccountRepository.:
@RepositoryRestController public class AccountController { private PagedResourcesAssembler<Account> pagedAssembler; @Autowired public AccountController(PagedResourcesAssembler<Account> pagedAssembler) { this.pagedAssembler = pagedAssembler; } private Page<Account> getAccounts(Pageable pageRequest){ int totalAccounts= 50; List<Account> accountList = IntStream.rangeClosed(1, totalAccounts) .boxed() .map( value -> new Account(value, value.toString())) .skip(pageRequest.getOffset()) .limit(pageRequest.getPageSize()) .collect(Collectors.toList()); return new PageImpl(accountList, pageRequest, totalAccounts); } @RequestMapping(method= RequestMethod.GET, path="/accounts", produces = "application/hal+json") public ResponseEntity<Page<Account>> getAccountsHal(Pageable pageRequest, PersistentEntityResourceAssembler assembler){ return new ResponseEntity(pagedAssembler.toResource(getAccounts(pageRequest), (ResourceAssembler) assembler), HttpStatus.OK); }
If you invoke the GET /accounts?size=5&page=0 you will get the following output which is using the mock implementation:
{ "_embedded": { "accounts": [ { "name": "1", "_links": { "self": { "href": "http://localhost:8080/accounts/1" }, "account": { "href": "http://localhost:8080/accounts/1" } } }, { "name": "2", "_links": { "self": { "href": "http://localhost:8080/accounts/2" }, "account": { "href": "http://localhost:8080/accounts/2" } } }, { "name": "3", "_links": { "self": { "href": "http://localhost:8080/accounts/3" }, "account": { "href": "http://localhost:8080/accounts/3" } } }, { "name": "4", "_links": { "self": { "href": "http://localhost:8080/accounts/4" }, "account": { "href": "http://localhost:8080/accounts/4" } } }, { "name": "5", "_links": { "self": { "href": "http://localhost:8080/accounts/5" }, "account": { "href": "http://localhost:8080/accounts/5" } } } ] }, "_links": { "first": { "href": "http://localhost:8080/accounts?page=0&size=5" }, "self": { "href": "http://localhost:8080/accounts?page=0&size=5" }, "next": { "href": "http://localhost:8080/accounts?page=1&size=5" }, "last": { "href": "http://localhost:8080/accounts?page=9&size=5" } }, "page": { "size": 5, "totalElements": 50, "totalPages": 10, "number": 0 } }
Just for the sake of completeness, the POM could be configured with the following parent and dependencies:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-rest-webmvc</artifactId> <version>2.6.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> </dependencies>