【图书管理系统】全栈开发图书管理系统获取图书列表接口(后端:计算图书页数、查询当前页展示的书籍)



图书列表
实现服务器代码(计算图书总数量+查询当前页需要展示的书籍)
后端响应时,需要响应给前端的数据
records:第 pageNum 页要展示的图书有哪些(存储到List集合中)total:计算一共有多少本书(用于告诉前端显示多少页)

我们创建一个类 ResponseResult ,用于存放后端计算的 records,total,并且返回前端;
围绕着这两个功能,来完善我们的服务端代码;
控制层 BookController

为了可复用性,我们引入泛型(修改一个类名):

写好框架之后,我们在 Controller 层先调用这个接口:

对于接口参数,如果参数个数比较多,还是建议直接以对象作为参数:

我们给这两个属性先加上一个默认值:

数据层:BookInfoMapper
查询第1页的SQL语句
select * from book_info where `status` != 0 limit 0,10;

查询第2页的SQL语句
select * from book_info where `status` != 0 limit 10,10;

查询第3页的SQL语句
select * from book_info where `status` != 0 limit 20,10;

观察以上SQL语句,发现:开始索引(offset)一直在改变,每页显示条数(limit)是固定的。
select * from book_info where status != 0 limit `offset`, `limit`;
开始索引的计算公式:开始索引 = (当前页码 - 1) * 每页显示条数
接下来,我们实现**对列表翻页时,查询第 PageNum 页的图书列表** 的功能:

我们还需要计算出 offset 的值,不妨在 PageRequest 类中再增加一个属性:

并且,我们可以直接在这个类中重写 offset 的 getter() 方法,也就是在 PageRequest 类中,直接计算出 offset 的值,并且可以在其他类获取到这个值:



在 PageRequest 中并没有 limt 属性,所以我们修改一下 SQL 参数,避免出现 MyBatis 反射异常

通过以上操作,我们就实现了第一个功能:第 pageNum 页要展示的图书有哪些
接下来,我们实现第二个功能:计算一共有多少本书
插入数据后,我们使用聚合函数 count 计算一下数据库中有多少条记录:

接下来,我们回忆 BookInfo 中 status 属性的定义(0 - 无效,1 - 可借阅,2 - 不可借阅),因此,我们要先查询有效的书籍(status != 0):

我们这里有26条数据,如果一页展示十条记录,那么26条记录,就需要三页;

业务层 BookService

计算出书的数量和当前页要展示的书后,接下来,识别展示图书的 status,转换为中文说明 statusCN:

处理好 statusCN 后,我们根据方法返回类型 ResponseResult<BookInfo> ,设置好返回的书籍数量和当前页展示的书籍列表:


引入@AllArgsConstructor、 @NoArgsConstructor简化代码
这篇博客的5(2)有详细的 lombok 及相关注解的使用说明,包含 @AllArgsConstructor、 @NoArgsConstructor 的使用说明


引入枚举类 Enums 简化代码
这样的写法其实是有点啰嗦的,status 的状态只有(0,1,2)三种,因此,我们可以使用枚举类简化一下上面的代码:



通过上面的封装和注解的巧用,我们的 BookService 代码变得更加精简了:

总结:
| 需求/问题描述 | 解决方案 | 技术实现说明 |
|---|---|---|
翻页信息需要返回数据总数和列表 | 需要执行两次SQL查询 | 1. 第一次查询总数(SELECT COUNT(*))2. 第二次 查询分页数据(LIMIT语句) |
图书状态与数据库status 字段映射 | 使用枚举类处理状态码映射关系 | 定义枚举类将状态码(如0,1,2)与文字描述(如"可借阅",“已借出”)绑定 |
状态码变动导致多处代码修改 | 通过枚举类集中管理状态码 | 修改时只需调整枚举类,无需全局搜索替换代码 |

测试接口
启动服务,访问后端程序:
http://127.0.0.1:9090/book/getListByPage 返回1-10条记录(按id降序)

http://127.0.0.1:9090/book/getListByPage?currentPage=2 返回11-20条记录

后端思维导图梳理

实现客户端代码

在 ResponseResult 类中添加 private PageRequest pageRequest 属性的主要目的是实现分页信息的完整闭环传递,具体作用包括:

- 前端状态保持:
- 让前端知道当前返回的数据是依据哪些分页参数查询的
- 避免前端在接收数据后丢失原始的分页请求参数
- 分页上下文传递:
- 当前页码(currentPage)
- 每页条数(pageSize)
- 从第几本书开始展示(offset)

- 扩展性考虑:
- 方便后续添加排序字段等扩展参数
为前端提供生成分页控件所需的完整信息


onPageChange:回调函数,当换页时触发(包括初始化第一页的时候),会传入两个参数:
- 1、"目标页"的页码,Number类型
- 2、触发类型,可能的值:“init”(初始化),“change”(点击分页)

测试接口
ctrl+s 保存前端代码,重新允许程序,访问登录页面 http://127.0.0.1:9090/login.html

登录后,跳转到图书列表第一页:

点击页码,页面信息得到正确的处理

按 F12 打开控制台,查看报错信息:


保存代码,重新运行程序,打开页面:

翻页试试效果:

完整服务器代码
PageRequest
package com.bit.book.model;import lombok.Data;@Data
public class PageRequest {private Integer currentPage = 1;private Integer pageSize = 10;private Integer offset;public Integer getOffset() {return (currentPage-1)*pageSize;}
}
ResponseResult
package com.bit.book.model;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.List;@AllArgsConstructor
@NoArgsConstructor
@Data
public class ResponseResult<T> {private Integer total; // 所查询到的数据列表(存储到List集合中)private List<T> records; // 总记录数(用于告诉前端显示多少页)private PageRequest pageRequest;}
BookController
package com.bit.book.Controller;import com.bit.book.model.BookInfo;
import com.bit.book.model.PageRequest;
import com.bit.book.model.ResponseResult;
import com.bit.book.service.BookService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/book")
@Slf4j
public class BookController {@Autowiredprivate BookService bookService;// 返回页数接口@RequestMapping("/getListByPage")public ResponseResult<BookInfo> getListByPage(PageRequest pageRequest){// 参数校验, 此处涉及复杂的校验逻辑,由公司负责安全的团队负责,这里就省略了// 接收前端发送的请求,调用底层处理请求ResponseResult<BookInfo> listByPage = bookService.getListByPage(pageRequest);// 接收 service 处理好的响应,并返回给前端return listByPage;}
}
BookService
package com.bit.book.service;import com.bit.book.enums.BookStatusEnum;
import com.bit.book.mapper.BookMapper;
import com.bit.book.model.BookInfo;
import com.bit.book.model.PageRequest;
import com.bit.book.model.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class BookService {@Autowiredprivate BookMapper bookMapper;public ResponseResult<BookInfo> getListByPage(PageRequest pageRequest){// 1. 获取总的图书数Integer count = bookMapper.count();// 2. 获取当前页需要展示的图书有哪些List<BookInfo> bookInfos = bookMapper.selectBooksByPage(pageRequest);// 3. 识别展示图书的 status, 转换为中文说明 statusCNfor (BookInfo bookInfo : bookInfos) {bookInfo.setStatusCN(BookStatusEnum.getStatusByCode(bookInfo.getStatus()).getDesc());}return new ResponseResult<>(count,bookInfos,pageRequest);}
}
BookStatusEnum
package com.bit.book.enums;public enum BookStatusEnum {DELETED(0, "该图书不存在"),NORMAL(1,"允许借阅"),FORBIDDEN(2,"不允许借阅");private Integer code;private String desc;public static BookStatusEnum getStatusByCode(Integer code){switch (code){case 0: return BookStatusEnum.DELETED;case 1: return BookStatusEnum.NORMAL;case 2: return BookStatusEnum.FORBIDDEN;default:return null;}}BookStatusEnum(Integer code, String desc) {this.code = code;this.desc = desc;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;}
}
BookMapper
package com.bit.book.mapper;import com.bit.book.model.BookInfo;
import com.bit.book.model.PageRequest;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;import java.util.List;@Mapper
public interface BookMapper {@Insert("insert into book_info " +"(book_name, author, count, price, publish, `status`) " +"values (#{bookName}, #{author}, #{count}, #{price}, #{publish}, #{status})")Integer addBook(BookInfo bookInfo);@Select("select * from book_info " +"where `status` !=0 " +"limit #{offset}, #{pageSize}")List<BookInfo> selectBooksByPage(PageRequest pageRequest);@Select("select count(1) " +"from book_info " +"where `status` != 0")Integer count();
}


相关文章:
【图书管理系统】全栈开发图书管理系统获取图书列表接口(后端:计算图书页数、查询当前页展示的书籍)
图书列表 实现服务器代码(计算图书总数量查询当前页需要展示的书籍) 后端响应时,需要响应给前端的数据 records:第 pageNum 页要展示的图书有哪些(存储到List集合中)total:计算一共有多少本书(用于告诉前…...
正则表达式补充——python
简介 本章是对前面正则表达式的补充。 一、复杂的查找替换等任务 content 张三是脑卒中病 李四,是高血脂 苏齐,是肺结核病 六六,是血血血血import re p re.compile(r...病) for one in p.findall(content):print(one) 运行结果…...
Kotlin日常使用函数记录
文章目录 前言字符串集合1.两个集合的差集2.集合转数组2.1.集合转基本数据类型数组2.2.集合转对象数组 Map1.合并Map1.1.使用 操作符1.2.使用 操作符1.3.使用 putAll 方法1.4.使用 merge 函数 前言 记录一些kotlin开发中,日常使用的函数和方式之类的,…...
Android 回答视频边播放边下载的问题
分层次的回答突出 技术深度、架构思维 和 实战优化,从基础实现到高阶优化: 一、核心技术方案(基础回答) 如何实现视频边下边播? 1. **网络请求**:使用 HTTP Range 请求(Header: Range: bytes0…...
RHCSA Linux系统 数据流和重定向 tee 命令
一.数据流和重定向 1. 数据流 (1) 标准输入(stdin,代码 0):默认从键盘获取输入,只读。 (2) 标准输出(stdout,代码 1):命令执行正确信息默认输出到屏幕,只写…...
[ctfshow web入门] web7
信息收集 题目提示:版本控制很重要,但不要部署到生产环境更重要。 那么很有可能,版本控制相关的信息被部署到环境了,比如比如version.txt记录了一些相关配件的版本,git版本管理工具中的.git文件夹未删除 信息收集就是…...
DeepSeek-V3 API:开启下一代AI应用开发的新篇章
引言 在人工智能技术日新月异的今天,大型语言模型(LLM)正以前所未有的速度改变着我们与技术互动的方式。DeepSeek-V3作为国内领先的大语言模型之一,其API的开放为开发者提供了强大的AI能力集成方案。 DeepSeek-V3 API的核心优势 1.强大的语言理解与生…...
华为数字芯片机考2025合集3已校正
1. 题目内容 下列说法正确的是()。 1. 解题步骤 1.1 选项分析 选项描述正误依据A异步 FIFO 采用格雷码是为了省功耗✗格雷码用于消除多比特信号跨时钟域的位跳变风险,与功耗无关B单比特信号打两拍可以完全避免亚稳态✗双触发器同步仅降低…...
控制 ElementUI el-table 树形表格多选框的显示层级
1、你可以通过 selectable 属性来控制哪些行可以选择(显示多选框) <el-table:data"tableData"row-key"id"default-expand-all:tree-props"{children: children, hasChildren: hasChildren}"select"handleSelect&…...
go语言应该如何学习
以下是学习Go语言的高效路径及关键技巧,结合多个优质来源整理而成,适合不同基础的学习者: 一、基础语法快速入门(1-2周) 1、环境搭建 下载安装Go SDK,配置GOPATH和GOROOT环境变量,推荐使用Go…...
NO.84十六届蓝桥杯备战|动态规划-路径类DP|矩阵的最小路径和|迷雾森林|过河卒|方格取数(C++)
路径类dp是线性dp的⼀种,它是在⼀个nm的矩阵中设置⼀个⾏⾛规则,研究从起点⾛到终点的⽅案数、最⼩路径和或者最⼤路径和等等的问题 矩阵的最小路径和_牛客题霸_牛客网 状态表⽰: dp[i][j]表⽰:到达[i, j]位置处,最⼩…...
React + TipTap 富文本编辑器 实现消息列表展示,类似Slack,Deepseek等对话框功能
经过几天折腾再折腾,弄出来了,弄出来了!!! 消息展示 在位编辑功能。 两个tiptap实例1个用来展示 消息列表,一个用来在位编辑消息。 tiptap灵活富文本编辑器,拓展性太好了!!! !!! 关键点&#x…...
博途 TIA Portal之1200做主站与汇川EASY的TCP通讯
前言,虽然已经做了几篇关于TCP通讯的文章,但是不同的PLC之间的配合可能不同,下面将演示这种差异。 关于汇川EASY做从站的配置请参见下方链接文章:汇川EASY系列之以太网通讯(套接字socket做从站)_汇川以太网tcp套接字fb块-CSDN博客 1、硬件准备: 1200PLC,汇川EASY320…...
蓝桥杯速成刷题清单(上)
一、1.排序 - 蓝桥云课 (快速排序)算法代码: #include <bits/stdc.h> using namespace std; const int N 5e5 10; int a[N];int main() {int n;cin >> n;for (int i 0; i < n; i) {cin >> a[i];}sort(a, a n);for …...
力扣第444场周赛
这次力扣周赛对我来说难度确实大, 只做出两题, 但还是想分享一下的做题经验和感受 1. 移除最小数对使数组有序 I 题目链接:力扣 给你一个数组 nums,你可以执行以下操作任意次数: 选择 相邻 元素对中 和最小 的一对。如果存在多个这样的对&a…...
Redis 持久化机制详解:RDB/AOF 过程、优缺点及配置。Redis持久化中的Fork与Copy-on-Write技术解析。
Redis 持久化机制详解:RDB/AOF 过程、优缺点及配置 一、RDB 持久化过程及特性 核心机制 生成快照:通过 fork 子进程生成内存数据的二进制快照文件(.rdb),父进程继续处理请求。写时复制(Copy-On-Write&…...
Go并发背后的双引擎:CSP通信模型与GMP调度|Go语言进阶(4)
为什么需要理解CSP与GMP? 当我们启动一个Go程序时,可能会创建成千上万个goroutine,它们是如何被调度到有限的CPU核心上的?为什么Go能够如此轻松地处理高并发场景?为什么有时候我们的并发程序会出现奇怪的性能瓶颈&…...
docker内安装达梦8数据库
1. 其他机器上实现挂载ISO # 1. 确保挂载点目录存在(你已经创建了dm8目录) ls -ld dm8# 2. 使用正确的mount命令挂载ISO sudo mount -o loop dm8_20250117_HWarm920_kylin10_sp1_64.iso dm8# 3. 验证是否挂载成功 mount | grep dm8 ls dm82. docker内运…...
UDP怎么样实现可靠传输?
如果需要在基于UDP的应用中实现可靠传输(例如确保数据不丢失、按顺序到达等),通常需要在应用层实现相应的机制。 1. 确认应答机制 应用层可以使用确认应答机制来确保数据的可靠传输。当发送方发送一个数据包时,接收方收到数据包…...
代码随想录算法训练营Day25
一、力扣93.复原IP地址【medium】 题目链接:力扣93.复原IP地址 left x300 视频链接:代码随想录 1、思路 时间复杂度: O ( n ) O(n) O(n) 2、代码 class Solution:def restoreIpAddresses(self, s: str) -> List[str]:n len(s)ans []…...
Linux服务器——Samba服务器
简介 Samba 是一个开源的跨平台文件共享服务,允许 Linux/Unix 系统与 Windows 系统实现文件和打印机的共享与互操作。其核心协议为 SMB/CIFS(Server Message Block / Common Internet File System),是 Windows 网络中…...
华为网路设备学习-17
目录 一、加密算法 二、验证算法 三、IPsec协议 1.IKE协议(密钥交换协议) ①ISAKMP(Internet Security Association and Key Management Protocol)互联网安全关联和密钥管理协议 ②安全关联(SA) ③…...
各开源协议一览
在 GitHub 上,开源项目通常会使用一些常见的开源协议来定义项目的使用、修改和分发规则。以下是目前 GitHub 上最常见的几种开源协议及其差异和示例说明: TL;DR 协议宽松程度是否强制开源专利保护适用场景MIT最宽松否无希望代码被广泛使用Apache 2.0宽松…...
解决python manage.py shell ModuleNotFoundError: No module named xxx
报错如下: python manage.py shellTraceback (most recent call last):File "/Users/z/Documents/project/c/manage.py", line 10, in <module>execute_from_command_line(sys.argv)File "/Users/z/.virtualenvs/c/lib/python3.12/site-packa…...
机器学习12-集成学习-案例
参考 【数据挖掘】基于XGBoost的垃圾短信分类与预测 【分类】使用XGBoost算法对信用卡交易进行诈骗预测 银行卡电信诈骗危险预测(LightGBM版本) 【数据挖掘】基于XGBoost的垃圾短信分类与预测 基于XGBoost的垃圾短信分类与预测 我分享了一个项目给你《【数据挖掘】基于XG…...
使用Ubuntu18恢复群晖nas硬盘数据外接usb
使用Ubuntu18恢复群晖nas硬盘数据外接usb 1. 接入硬盘2.使用Ubuntu183.查看nas硬盘信息3. 挂载nas3.1 挂载损坏nas硬盘(USB)3.2 挂载当前运行的nas 4. 拷贝数据分批传输 5. 新旧数据对比 Synology NAS 出现故障,DS DiskStation损坏,则可以使用计算机和 U…...
微服务系统记录
记录下曾经工作涉及到微服务的相关知识。 1. 架构设计与服务划分 关键内容 领域驱动设计(DDD): 利用领域模型和限界上下文(Bounded Context)拆分业务,明确服务边界。通过事件风暴(Event Storm…...
【数据库原理及安全实验】实验二 数据库的语句操作
目录 指导书原文 实操备注 指导书原文 【实验目的】 1) 掌握使用SQL语言进行数据操纵的方法。 【实验原理】 1) 面对三个关系表student,course,sc。利用SQL语句向表中插入数据(insert),然后对数据进行delete&…...
python 微信小程序支付、查询、退款使用wechatpy库
首先使用 wechatpy 库,执行以下命令进行安装 pip install wechatpy 1、 直连商户支付 import logging from django.http import JsonResponse from django.views.decorators.http import require_http_methods from wechatpy.pay import WeChatPay from wechatpy.…...
蓝桥杯备赛学习笔记:高频考点与真题预测(C++/Java/python版)
2025蓝桥杯备赛学习笔记 ——高频考点与真题预测 一、考察趋势分析 通过对第13-15届蓝桥杯真题的分析,可以发现题目主要围绕基础算法、数据结构、数学问题、字符串处理、编程语言基础展开,且近年逐渐增加动态规划、图论、贪心算法等较难题目。 1. 基…...
