pagination work
This commit is contained in:
parent
1af3eb4b1f
commit
33fee76a32
@ -9,6 +9,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
import org.baeldung.persistence.model.Foo;
|
import org.baeldung.persistence.model.Foo;
|
||||||
import org.baeldung.persistence.service.IFooService;
|
import org.baeldung.persistence.service.IFooService;
|
||||||
import org.baeldung.web.exception.MyResourceNotFoundException;
|
import org.baeldung.web.exception.MyResourceNotFoundException;
|
||||||
|
import org.baeldung.web.hateoas.PaginatedResultsRetrievedEvent;
|
||||||
import org.baeldung.web.util.LinkUtil;
|
import org.baeldung.web.util.LinkUtil;
|
||||||
import org.baeldung.web.util.ResourceCreated;
|
import org.baeldung.web.util.ResourceCreated;
|
||||||
import org.baeldung.web.util.RestPreconditions;
|
import org.baeldung.web.util.RestPreconditions;
|
||||||
@ -72,7 +73,7 @@ public class FooController {
|
|||||||
if (page > resultPage.getTotalPages()) {
|
if (page > resultPage.getTotalPages()) {
|
||||||
throw new MyResourceNotFoundException();
|
throw new MyResourceNotFoundException();
|
||||||
}
|
}
|
||||||
// eventPublisher.publishEvent(new PaginatedResultsRetrievedEvent<Foo>(Foo.class, uriBuilder, response, page, resultPage.getTotalPages(), size));
|
eventPublisher.publishEvent(new PaginatedResultsRetrievedEvent<Foo>(Foo.class, uriBuilder, response, page, resultPage.getTotalPages(), size));
|
||||||
|
|
||||||
return resultPage.getContent();
|
return resultPage.getContent();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,107 @@
|
|||||||
|
package org.baeldung.web.hateoas;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.baeldung.web.util.LinkUtil;
|
||||||
|
import org.springframework.context.ApplicationListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.net.HttpHeaders;
|
||||||
|
|
||||||
|
@SuppressWarnings({ "rawtypes" })
|
||||||
|
@Component
|
||||||
|
class PaginatedResultsRetrievedDiscoverabilityListener implements ApplicationListener<PaginatedResultsRetrievedEvent> {
|
||||||
|
|
||||||
|
private static final String PAGE = "page";
|
||||||
|
|
||||||
|
public PaginatedResultsRetrievedDiscoverabilityListener() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void onApplicationEvent(final PaginatedResultsRetrievedEvent ev) {
|
||||||
|
Preconditions.checkNotNull(ev);
|
||||||
|
|
||||||
|
addLinkHeaderOnPagedResourceRetrieval(ev.getUriBuilder(), ev.getResponse(), ev.getClazz(), ev.getPage(), ev.getTotalPages(), ev.getPageSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
// - note: at this point, the URI is transformed into plural (added `s`) in a hardcoded way - this will change in the future
|
||||||
|
final void addLinkHeaderOnPagedResourceRetrieval(final UriComponentsBuilder uriBuilder, final HttpServletResponse response, final Class clazz, final int page, final int totalPages, final int pageSize) {
|
||||||
|
plural(uriBuilder, clazz);
|
||||||
|
|
||||||
|
final StringBuilder linkHeader = new StringBuilder();
|
||||||
|
if (hasNextPage(page, totalPages)) {
|
||||||
|
final String uriForNextPage = constructNextPageUri(uriBuilder, page, pageSize);
|
||||||
|
linkHeader.append(LinkUtil.createLinkHeader(uriForNextPage, LinkUtil.REL_NEXT));
|
||||||
|
}
|
||||||
|
if (hasPreviousPage(page)) {
|
||||||
|
final String uriForPrevPage = constructPrevPageUri(uriBuilder, page, pageSize);
|
||||||
|
appendCommaIfNecessary(linkHeader);
|
||||||
|
linkHeader.append(LinkUtil.createLinkHeader(uriForPrevPage, LinkUtil.REL_PREV));
|
||||||
|
}
|
||||||
|
if (hasFirstPage(page)) {
|
||||||
|
final String uriForFirstPage = constructFirstPageUri(uriBuilder, pageSize);
|
||||||
|
appendCommaIfNecessary(linkHeader);
|
||||||
|
linkHeader.append(LinkUtil.createLinkHeader(uriForFirstPage, LinkUtil.REL_FIRST));
|
||||||
|
}
|
||||||
|
if (hasLastPage(page, totalPages)) {
|
||||||
|
final String uriForLastPage = constructLastPageUri(uriBuilder, totalPages, pageSize);
|
||||||
|
appendCommaIfNecessary(linkHeader);
|
||||||
|
linkHeader.append(LinkUtil.createLinkHeader(uriForLastPage, LinkUtil.REL_LAST));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (linkHeader.length() > 0) {
|
||||||
|
response.addHeader(HttpHeaders.LINK, linkHeader.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final String constructNextPageUri(final UriComponentsBuilder uriBuilder, final int page, final int size) {
|
||||||
|
return uriBuilder.replaceQueryParam(PAGE, page + 1).replaceQueryParam("size", size).build().encode().toUriString();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String constructPrevPageUri(final UriComponentsBuilder uriBuilder, final int page, final int size) {
|
||||||
|
return uriBuilder.replaceQueryParam(PAGE, page - 1).replaceQueryParam("size", size).build().encode().toUriString();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String constructFirstPageUri(final UriComponentsBuilder uriBuilder, final int size) {
|
||||||
|
return uriBuilder.replaceQueryParam(PAGE, 0).replaceQueryParam("size", size).build().encode().toUriString();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String constructLastPageUri(final UriComponentsBuilder uriBuilder, final int totalPages, final int size) {
|
||||||
|
return uriBuilder.replaceQueryParam(PAGE, totalPages).replaceQueryParam("size", size).build().encode().toUriString();
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean hasNextPage(final int page, final int totalPages) {
|
||||||
|
return page < totalPages - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean hasPreviousPage(final int page) {
|
||||||
|
return page > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean hasFirstPage(final int page) {
|
||||||
|
return hasPreviousPage(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean hasLastPage(final int page, final int totalPages) {
|
||||||
|
return totalPages > 1 && hasNextPage(page, totalPages);
|
||||||
|
}
|
||||||
|
|
||||||
|
final void appendCommaIfNecessary(final StringBuilder linkHeader) {
|
||||||
|
if (linkHeader.length() > 0) {
|
||||||
|
linkHeader.append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// template
|
||||||
|
|
||||||
|
protected void plural(final UriComponentsBuilder uriBuilder, final Class clazz) {
|
||||||
|
final String resourceName = clazz.getSimpleName() + "s";
|
||||||
|
uriBuilder.path("/" + resourceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
package org.baeldung.web.hateoas;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event that is fired when a paginated search is performed.
|
||||||
|
* <p/>
|
||||||
|
* This event object contains all the information needed to create the URL for the paginated results
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* Type of the result that is being handled (commonly Entities).
|
||||||
|
*/
|
||||||
|
public final class PaginatedResultsRetrievedEvent<T extends Serializable> extends ApplicationEvent {
|
||||||
|
private final UriComponentsBuilder uriBuilder;
|
||||||
|
private final HttpServletResponse response;
|
||||||
|
private final int page;
|
||||||
|
private final int totalPages;
|
||||||
|
private final int pageSize;
|
||||||
|
|
||||||
|
public PaginatedResultsRetrievedEvent(final Class<T> clazz, final UriComponentsBuilder uriBuilderToSet, final HttpServletResponse responseToSet, final int pageToSet, final int totalPagesToSet, final int pageSizeToSet) {
|
||||||
|
super(clazz);
|
||||||
|
|
||||||
|
uriBuilder = uriBuilderToSet;
|
||||||
|
response = responseToSet;
|
||||||
|
page = pageToSet;
|
||||||
|
totalPages = totalPagesToSet;
|
||||||
|
pageSize = pageSizeToSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
// API
|
||||||
|
|
||||||
|
public final UriComponentsBuilder getUriBuilder() {
|
||||||
|
return uriBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final HttpServletResponse getResponse() {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getPage() {
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getTotalPages() {
|
||||||
|
return totalPages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getPageSize() {
|
||||||
|
return pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object on which the Event initially occurred.
|
||||||
|
*
|
||||||
|
* @return The object on which the Event initially occurred.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public final Class<T> getClazz() {
|
||||||
|
return (Class<T>) getSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -7,6 +7,12 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
*/
|
*/
|
||||||
public final class LinkUtil {
|
public final class LinkUtil {
|
||||||
|
|
||||||
|
public static final String REL_COLLECTION = "collection";
|
||||||
|
public static final String REL_NEXT = "next";
|
||||||
|
public static final String REL_PREV = "prev";
|
||||||
|
public static final String REL_FIRST = "first";
|
||||||
|
public static final String REL_LAST = "last";
|
||||||
|
|
||||||
private LinkUtil() {
|
private LinkUtil() {
|
||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user