如何扩展PagedResourceAssembler

时间:2016-05-13 16:50:21

标签: java spring rest spring-hateoas

Spring-Web RestController 中,我们使用PagedResources来创建ResponseEntities。 我们有一个RequestMethod会触发5公里半径范围内的元素的背景搜索,如果没有结果是10公里,20公里,直到找到任何元素。

由于我们现在从客户端更改给定的选项(使用给定距离调用资源),我们希望将更改后的searchDistance返回给客户端。 那么实际的响应将是这样的:

{
  "_links": {
    "self": {
      "href": "http://...
      "templated": true
    }
  },
  "_embedded": {
    "parcelShopResourceList": [
      {
        "_id": "2760183530"
        ...
      },
      {
        "_id": "2760128505"
        ...
      },
      {
        "_id": "2760162267"
        ...
      },
      {
        "_id": "2760196914"
        ...
      },
      {
        "_id": "2760147255"
        ...
      }
    ]
  },
  "page": {
    "size": 200,
    "totalElements": 5,
    "totalPages": 1,
    "number": 0
    "searchDistance": 10
  }
}

现在问题:

  • 我如何延长PagedResourcesAssembler,以便它会返回任何其他页面信息?

我认为创建一个扩展的Page就足够了,所以PagedResourcesAssembler会将额外的信息添加到页面信息中,但事实并非如此。

ResponseEntity.ok(pagedResourcesAssembler.toResource(page, resourceAssembler));

然后我试图覆盖PagedResourcesAssembler本身,但由于它使用了很多私有方法,因此覆盖PagedResourcesAssembler.createResource并不是真的有用。

我想我完全错过了一些东西。可以请任何人向我解释如何在我的回复中添加其他信息?我相信有一个更简单的方法。

由于我想添加一个关于整个List的信息,我不想为了方便而将这些信息插入到单个资源中。

2 个答案:

答案 0 :(得分:0)

确实,一种方法是创建自己的页面资源并根据需要自定义您的实体。这包括要呈现的内容和元数据,如搜索距离,大小等。

这是一个例子:

 /**
 * 
 * Pagination for a resource content
 *
 * @param <T> content to render 
 */
public class PagedResource<T> {
  private List<T> content;
  private final Map metadata;
  public PagedResource(Page<T> page, String pageParam, String sizeParam, String sortParam, String sortField) {
    super();
    this.setContent(page.getContent());
    this.metadata = new HashMap();
    List<Link> links = new ArrayList<Link>();
    if (page.hasPrevious()) {
      String path = createBuilder().queryParam(pageParam, page.getNumber() - 1).queryParam(sizeParam, page.getSize()).queryParam(sortParam, sortField).build().toUriString();
      Link previousPageLink = new Link(path, Link.REL_PREVIOUS);
      links.add(previousPageLink);
    }
    if (page.hasNext()) {
      String path = createBuilder().queryParam(pageParam, page.getNumber() + 1).queryParam(sizeParam, page.getSize()).queryParam(sortParam, sortField).build().toUriString();
      Link nextPageLink = new Link(path, Link.REL_NEXT);
      links.add(nextPageLink);
    }
    if (!page.isFirst()) {
      Link firstPageLink = buildPageLink(pageParam, 0, sizeParam, page.getSize(), sortParam, sortField, Link.REL_FIRST);
      links.add(firstPageLink);
    }
    if (!page.isLast()) {
      int lastPage = page.getTotalPages() - 1;
      Link lastPageLink = buildPageLink(pageParam, lastPage, sizeParam, page.getSize(), sortParam, sortField, Link.REL_LAST);
      links.add(lastPageLink);
    }
    Link currentPagelink = buildPageLink(pageParam, page.getNumber(), sizeParam, page.getSize(), sortParam, sortField, Link.REL_SELF);
    links.add(currentPagelink);
    populateMetadata(page, links);
  }
  private void populateMetadata(Page<T> page, List<Link> links) {
    int per_page = page.getSize();
    int totalPages = page.getTotalPages();
    int numberOfPageElements = page.getNumberOfElements();
    metadata.put("numberOfPageElements", numberOfPageElements);
    metadata.put("perPage", per_page);
    metadata.put("totalPages", totalPages);
    metadata.put("links", links);
  }
  private Link buildPageLink(String pageParam, int page, String sizeParam, int size, String sortParam, String sortAttribute, String rel) {
    String path = createBuilder().queryParam(pageParam, page).queryParam(sizeParam, size).queryParam(sortParam, sortAttribute).toUriString();
    Link link = new Link(path, rel);
    return link;
  }
  private ServletUriComponentsBuilder createBuilder() {
    return ServletUriComponentsBuilder.fromCurrentRequestUri();
  }
  public List<T> getContent() {
    return content;
  }
  public void setContent(List<T> content) {
    this.content = content;
  }
  public Map getMetadata() {
    return metadata;
  }
}

您可以在下面找到有关如何使用自定义分页资源的完整example

答案 1 :(得分:0)

感谢Hassam示例,但我或多或少地受到hateoas提供的现有响应结构的约束!

我实际上通过在RestController中创建一个包装器来解决问题,该包装器创建一个新的Response并在PagedResourcesAssembler创建的响应周围添加所需的信息。