Spring中的REST分页的实现代码
作者:banq 发布时间:2023-03-16 01:06:46
本文将介绍在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中添加以下依赖项
Spring Boot JPA
Spring Boot Data REST
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 + "\"";
}
}
让我们快速介绍上面代码中的几个要点。
我们使用 Pageable作为控制器的参数之一。这将有助于返回页面而不是列表。
Pageable具有所有必需的分页信息。
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项目中找到
来源:https://www.jdon.com/51623
猜你喜欢
- 通常C#使用基于XML的配置文件,不过如果有需要的话,比如要兼顾较老的系统,可能还是要用到INI文件。但C#本身并不具备读写INI文件的AP
- 目录简介:根据sun的官方文档描述:示例:@SuppressWarnings注解的作用一.@SuppressWarings注解示例1——抑制
- 背景1> 大家都知道SpringBoot是通过main函数启动的,这里面跟踪代码到处都没有找到while(true),为什么启动后可以
- 主要功能设计:用户、区域、物质类型、物质详情、物质申请和审核以及我的申请和通知公告以及灵活控制菜单权限主要技术实现:spring、 spri
- 对称加密算法是应用较早的加密算法,技术成熟。在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yue)一起经过特殊加密算法处理
- 一、引言使用原生的zookeeper时候会遇到watcher一次注册生效一次等情况,因此使用curatorcurator是Netflix公司
- 前言这里用swing ,awt写的。我们大概要做成一个电脑的记事本那样的一个编辑器。可以调整字体,字号,颜色。能够打开、保存文件,新建窗口,
- 一、队列简介队列是一个有序列表,遵循“先入先出”的原则,即先存入队列的数据要先取出,后存入的数据后取出。队列有两种存储表示,顺序表示和链式表
- jdk * 和cglib * 实现及区别代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不
- 本文实例讲述了Java编程实现向文本文件中读取数据之Scanner用法。分享给大家供大家参考,具体如下:使用Scanner类来读取文件我们使
- 如下所示:package com.lcn.day05;import java.util.Scanner;public class Array
- 本文实例为大家分享了flutter实现appbar下选项卡切换的具体代码,供大家参考,具体内容如下TabBar 、Tab、TabBarVie
- 本文实例为大家分享了Java使用单链表实现约瑟夫环的具体代码,供大家参考,具体内容如下构建一个单向的环形链表思路1.先创建第一个节点, 让f
- RestTemplate 请求接收自定义400+ 或500+错误场景当服务端自定义400错误返回体时,使用restTemplate 请求接收
- 概述对List进行分组是日常开发中,经常遇到的,在JDK 8中对List按照某个属性分组的代码,超级简单。package test;impo
- 一、前言序列化:将对象转换为二进制序列在网络中传输或保存到磁盘反序列化:从网络或磁盘中将二进制序列转换为对象注意:对象必须实现Seriali
- 1. Spring Boot 入门 Spring Boot是Spring社区较新的一个项目。该项目的目的是帮助开发者更容易的创建基于Spri
- 1.配置自定义共享线程池(Spring线程池)@Configuration@EnableAsyncpublic class ThreadPo
- Singleton是众多设计模式中最容易理解的一种,也是众多设计模式中较为重要的一种设计模式。接下来我们看看具体介绍。Singleton模式
- Excel表格中的迷你图表能够直观地向我们展示出数据的变化趋势。本文将介绍C#如何实现为表格数据生成迷你图表,以及修改和删除迷你图表的方法。