Spring中的REST分页的实现代码

 更新时间:2019年01月30日 11:48:51   作者:banq  
本文将介绍在REST API中实现分页的基础知识。我们将专注于使用Spring Boot和Spring Data 在Spring MVC中构建REST分页,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

本文将介绍在REST API中实现分页的基础知识。我们将专注于使用Spring Boot和Spring Data 在Spring MVC中构建REST分页。

分页是一种处理大结果数据集的机制。在REST API中实现分页并没有什么不同,但需要一些额外的思考过程。为REST API提供流畅有效的分页可以增加用户体验并有助于构建高效,快速的REST API。我们使用Spring Boot作为示例。

1.资源与表示

在我们开始设计分页API之前,我们需要清楚地了解页面作为资源或资源的表示。我们需要记住许多基本要素

一个页面Page不是REST中的一个资源,而是其请求的属性。

以资源名称Product为构建分页的例子,在高层次上我们确实有以下三个选项来构建分页。

  • 将产品Product作为资源并使用查询字符串来处理分页以及其他参数,例如排序等(例如http://domainname/products?page=1)。
  • 第二个选项是将页面Page用作资源和查询字符串进行排序。(例如http://domainname/products/page/1?sort_by=date)。
  • 使用页面Page作为资源和URL部分进行排序。(例如http://domainname/products/date/page/1)

考虑到上述问题,让我们尝试回答一些在设计REST API分页时有用的问题。

  • 您是否将页面Page视为页面中产品的资源?

请记住,REST API不是围绕任何预定义的规则或规范构建的,所有上述三个选项都是有效的,并且基于上述问题的答案。如果我们将页面视为资源,则选项3是有效选择;但如果我们说页面上的产品是资源,那么选项3不再有效(在第1,2页上的产品可能会在将来更改),就个人而言,我会选择选项1,因为对我来说,页面 Page 不是  资源Resouce,它是请求的属性。

2.可发现性

可发现性  有助于使  RESTful API  更加实用和优雅。使REST API  可被发现经常被忽视。以下是REST API可发现性的高级摘要 。

  • 有了这个功能,REST API在对客户端的响应中提供完整的URI意味着没有客户端需要“组合”URI。
  • 客户端API独立于URI结构。
  • 通过以上2点,API更加灵活,允许开发人员在不破坏API的情况下更改URI架构。(请记住,API提供所有URI,它们不是由客户端API动态创建的)。

可发现性与REST API中的HATEOAS密切相关。REST API分页可发现将通过"next","previous","first"和"last"链路作为响应数据的一部分。我们正在考虑如何在分页期间将此功能添加到您的API。

3.分页设计考虑因素

在构建REST API分页界面时,让我们快速介绍一些要点。

3.1 限制limit

限制允许API和客户端控制结果集中请求的结果数。通过传递  limit 参数,您可以指定每个页面要返回的项目数.API可以配置默认限制,但应允许客户端指定限制。

http://hostname/products?page=1&limit=50

在上面的请求中,客户端将限制设置为50.小心,同时允许客户将limit 参数设置 , 设置为极高数量的限制会降低API性能。建议在API设计期间具有最大允许限制。

3.2 排序

排序总是与搜索和分页并排。在设计REST API时,提供灵活性,让客户指定排序选项,同时从API返回结果。建议在设计API时使用  sort_by = [attribute  name] - [asc / desc]模式.API设计器应将允许的属性名称指定为sort参数。例如,您可以使用?name-asc按产品名称排序或?name-desc反向排序。

4. Maven依赖

我们在Spring中处理REST分页时介绍了所有基本内容。我们在这篇文章中使用了以下技术堆栈,但它可以在任何其他技术上实现,前提是您在设计时遵循所有基本原则。

  • Spring Boot
  • JPA.
  • Spring Data REST

在本文中使用Spring Data REST的原因之一是Data REST API支持的开箱即用功能。

我们将在pom.xml中添加以下依赖项

  1. Spring Boot JPA
  2. Spring Boot Data REST
  3. HATEOS和Web
<dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-rest</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-hateoas</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
   <groupId>org.hsqldb</groupId>
   <artifactId>hsqldb</artifactId>
   <scope>runtime</scope>
  </dependency>
</dependencies>

4.1 REST控制器:

@RestController
public class ProductRESTController {

 @Autowired
 private ProductService productService;

 @Autowired private EntityLinks links;

 @GetMapping(value = "/products", produces = MediaType.APPLICATION_JSON_VALUE)
 public ResponseEntity < PagedResources < ProductEntity >> AllProducts(Pageable pageable, PagedResourcesAssembler assembler) {
 Page < ProductEntity > products = productService.findAllProducts(pageable);
 PagedResources < ProductEntity > pr = assembler.toResource(products, linkTo(ProductRESTController.class).slash("/products").withSelfRel());
 HttpHeaders responseHeaders = new HttpHeaders();
 responseHeaders.add("Link", createLinkHeader(pr));
 return new ResponseEntity < > (assembler.toResource(products, linkTo(ProductRESTController.class).slash("/products").withSelfRel()), responseHeaders, HttpStatus.OK);
 }

 private String createLinkHeader(PagedResources < ProductEntity > pr) {
 final StringBuilder linkHeader = new StringBuilder();
 linkHeader.append(buildLinkHeader(pr.getLinks("first").get(0).getHref(), "first"));
 linkHeader.append(", ");
 linkHeader.append(buildLinkHeader(pr.getLinks("next").get(0).getHref(), "next"));
 return linkHeader.toString();
 }

 public static String buildLinkHeader(final String uri, final String rel) {
 return "<" + uri + ">; rel=\"" + rel + "\"";
 }
}

让我们快速介绍上面代码中的几个要点。

  1. 我们使用  Pageable作为控制器的参数之一。这将有助于返回页面而不是列表。
  2. Pageable具有所有必需的分页信息。
  3. Pageable在Spring JPA中运行得非常好,并且透明地处理分页。

4.2 Previous 和Next 链接

每个页面响应将返回链接到当前页面前面和后面的页,这是基于使用IANA定义链接关系 prev 和  next。但是,如果您当前位于结果的第一页,则不会呈现任何 prev链接。

我们来看下面的例子:

curl http://localhost:8080/products

{
  "_embedded": {
    "productEntities": [
      ...data...
    ]
  },
  "_links": {
    "first": {
      "href": "http://localhost:8080/products?page=0&size=20"
    },
    "self": {
      "href": "http://localhost:8080/products"
    },
    "next": {
      "href": "http://localhost:8080/products?page=1&size=20"
    },
    "last": {
      "href": "http://localhost:8080/products?page=4&size=20"
    }
  },
  "page": {
    "size": 20,
    "totalElements": 100,
    "totalPages": 5,
    "number": 0
  }
}

让我们深入了解响应数据中的一些有趣事实

  • next 链接指向下一页。last 链接指向的最后一个结果集。
  • self 链接提供整个系列。
  • 底部  page 提供有关分页的信息,包括页面大小,总结果,总页数和当前页码。

4.2使用链接头

HTTP标头是REST API的关键方面.HTTP链接标头还可用于将分页信息传递给客户端。通过上述测试,系统将返回以下附加信息作为Link HTTP标头的一部分。

Link →<http://localhost:8080/products?page=0&size=20>; rel="first", <http://localhost:8080/products?page=1&size=20>; rel="next"

rel="next" 意思是下一页是  page=2;rel="first" 意思是第一页总是依赖page=2.于提供给你的这些链接关系。不要试图猜测或构建自己的URL。Spring PagedResource提供所有这些信息作为结果的一部分,我们只需要确保从这些信息中构建正确的HTTP头。在我们的控制器示例中,我们在createLinkHeader方法中构建标头。

private String createLinkHeader(PagedResources < ProductEntity > pr) {
 final StringBuilder linkHeader = new StringBuilder();
 linkHeader.append(buildLinkHeader(pr.getLinks("first").get(0).getHref(), "first"));
 linkHeader.append(", ");
 linkHeader.append(buildLinkHeader(pr.getLinks("next").get(0).getHref(), "next"));
 return linkHeader.toString();
}

public static String buildLinkHeader(final String uri, final String rel) {
 return "<" + uri + ">; rel=\"" + rel + "\"";
}

总结

在这篇文章中,我们学习了如何在Spring和Spring Boot中实现  REST分页。我们讨论了如何构建响应以及在REST API响应中使用链接HTTP标头的重要性。

所有这些示例和代码片段的实现都可以在GitHub项目中找到

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 浅谈MyBatis循环Map(高级用法)

    浅谈MyBatis循环Map(高级用法)

    这篇文章主要介绍了浅谈MyBatis循环Map(高级用法),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • SpringBoot配置多数据源的四种方式分享

    SpringBoot配置多数据源的四种方式分享

    在日常开发中我们都是以单个数据库进行开发,在小型项目中是完全能够满足需求的,但是,当我们牵扯到大型项目的时候,单个数据库就难以承受用户的CRUD操作,那么此时,我们就需要使用多个数据源进行读写分离的操作,本文就给大家介绍SpringBoot配置多数据源的方式
    2023-07-07
  • SWT(JFace) 简易浏览器 制作实现代码

    SWT(JFace) 简易浏览器 制作实现代码

    SWT(JFace) 简易浏览器 制作实现代码
    2009-06-06
  • Java中接收键盘输入的三种方法

    Java中接收键盘输入的三种方法

    这篇文章主要介绍了Java中接收键盘输入的三种方法,本文给出3个方法实现通过读取控制台的输入与用户实现交互,需要的朋友可以参考下
    2015-06-06
  • 深入理解Spring Boot中的Flyway

    深入理解Spring Boot中的Flyway

    Flyway将数据库结构的变更定义为一系列迁移脚本,通常是SQL脚本文件,当应用程序启动时,Flyway会自动检测并执行未应用的迁移脚本,将数据库升级到最新版本,这篇文章主要介绍了深入理解Spring Boot中的Flyway,需要的朋友可以参考下
    2024-01-01
  • Java圆柱体表面积和体积计算代码实例

    Java圆柱体表面积和体积计算代码实例

    这篇文章主要介绍了Java圆柱体表面积和体积计算代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • java正则替换sql中的参数实例代码

    java正则替换sql中的参数实例代码

    这篇文章主要给大家介绍了关于java正则替换sql中参数的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-10-10
  • spring boot 下对JSON返回值去除null和空字段操作

    spring boot 下对JSON返回值去除null和空字段操作

    这篇文章主要介绍了spring boot 下对JSON返回值去除null和空字段操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • Java代码实现矩形覆盖实例

    Java代码实现矩形覆盖实例

    这篇文章主要介绍了Java代码实现矩形覆盖实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,,需要的朋友可以参考下
    2019-06-06
  • Spring AOP 创建代理对象详情

    Spring AOP 创建代理对象详情

    这篇文章介绍了Spring AOP 创建代理对象详情,主要介绍AOP 创建代理对象和上下文相关的内容,下文分享具有一定的参考价值,需要的小伙伴可以参考一下
    2022-05-05

最新评论