【图书管理系统】深入解析基于 MyBatis 数据持久化操作:全栈开发图书管理系统获取图书列表接口(后端:计算图书页数、查询当前页展示的书籍)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


图书列表


实现服务器代码(计算图书总数量+查询当前页需要展示的书籍)


后端响应时,需要响应给前端的数据

  • records:第 pageNum 页要展示的图书有哪些(存储到List集合中)
  • total:计算一共有多少本书(用于告诉前端显示多少页)

image-20250408224403942

我们创建一个类 ResponseResult ,用于存放后端计算的 records,total,并且返回前端;

围绕着这两个功能,来完善我们的服务端代码;


控制层 BookController


image-20250408212938351


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

image-20250408213834468


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

image-20250408213906136


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

image-20250408214134584


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

image-20250408214355246


数据层:BookInfoMapper


查询第1页的SQL语句

select * from book_info where `status` != 0 limit 0,10;

image-20250408211303566


查询第2页的SQL语句

select * from book_info where `status` != 0 limit 10,10;

image-20250408211433468


查询第3页的SQL语句

select * from book_info where `status` != 0 limit 20,10;

image-20250408211510253

观察以上SQL语句,发现:开始索引(offset)一直在改变,每页显示条数(limit)是固定的

select * from book_info where status != 0 limit `offset`, `limit`;

开始索引的计算公式:开始索引 = (当前页码 - 1) * 每页显示条数


接下来,我们实现**对列表翻页时,查询第 PageNum 页的图书列表** 的功能:

image-20250408215519228


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

image-20250408215859573


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

image-20250408220230778


image-20250408220535082


image-20250408220639529


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

image-20250409093749258

通过以上操作,我们就实现了第一个功能:第 pageNum 页要展示的图书有哪些


接下来,我们实现第二个功能:计算一共有多少本书

插入数据后,我们使用聚合函数 count 计算一下数据库中有多少条记录:

image-20250408210657988


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

image-20250408211117125

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


image-20250408222912122


业务层 BookService


image-20250408223726591


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

image-20250408224152991


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

image-20250408224540754


image-20250408224914348


引入@AllArgsConstructor、 @NoArgsConstructor简化代码


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

image-20250408225249103


image-20250408225410291


引入枚举类 Enums 简化代码


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

image-20250409085625718


image-20250409090330756


image-20250409090753624


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

image-20250409091308254


总结:

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

image-20250409092430335


测试接口


启动服务,访问后端程序:


http://127.0.0.1:9090/book/getListByPage 返回1-10条记录(按id降序)

image-20250409093945645


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

image-20250409094045394


后端思维导图梳理


在这里插入图片描述


实现客户端代码


在这里插入图片描述


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

在这里插入图片描述

  1. 前端状态保持
    • 让前端知道当前返回的数据是依据哪些分页参数查询的
    • 避免前端在接收数据后丢失原始的分页请求参数

  1. 分页上下文传递
    • 当前页码(currentPage)
    • 每页条数(pageSize)
    • 从第几本书开始展示(offset)

在这里插入图片描述


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

在这里插入图片描述


在这里插入图片描述

onPageChange:回调函数,当换页时触发(包括初始化第一页的时候),会传入两个参数:

  • 1、"目标页"的页码,Number类型
  • 2、触发类型,可能的值:“init”(初始化),“change”(点击分页)

在这里插入图片描述


测试接口


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

在这里插入图片描述


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

在这里插入图片描述


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

image-20250408124057586


按 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();
}

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/76442.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在idea中快速搭建一个Spring Boot项目?

文章目录 前言1、创建项目名称2、勾选需要的依赖3、在setting中检查maven4、编写数据源5、开启热启动&#xff08;热部署&#xff09;结语 前言 Spring Boot 凭借其便捷的开发特性&#xff0c;极大提升了开发效率&#xff0c;为 Java 开发工作带来诸多便利。许多大伙伴希望快速…

制作前的关键筹备:考试考核系统之核心要点

明确系统使用目的​ 制作考试考核系统前&#xff0c;企业需明确系统使用目的&#xff0c;这是开发基石&#xff0c;不同目的决定系统功能特性。用于员工培训考核时&#xff0c;系统要与培训内容结合&#xff0c;能生成相应考题&#xff0c;检验员工知识掌握程度&#xff0c;具备…

Springboot把外部jar包打包进最终的jar包,并实现上传服务器

1、创建lib目录&#xff0c;把jar包放进这个目录下&#xff0c;然后标记lib目录为“资源根路径”&#xff08;鼠标右键lib目录->将目录标记为->资源根路径。之后lib文件夹会有如下的图标变化&#xff09; 文件结构如下&#xff1a; 2、pom文件添加依赖 <dependency…

内容中台的核心架构是什么?

数据中枢与服务API架构 在内容中台的核心架构中&#xff0c;数据中枢作为基础层&#xff0c;通过统一的数据模型与标准化接口&#xff0c;实现多源内容的集中存储与治理。其核心能力体现在对结构化与非结构化数据的清洗、分类及跨系统同步&#xff0c;例如整合企业内部的CRM、…

Light RPC:一款轻量高效的Java RPC框架实践指南

Light RPC&#xff1a;一款轻量高效的Java RPC框架实践指南 一、框架简介二、快速入门1. 环境准备2. 服务端配置2.1 添加依赖2.2 YAML配置2.3 接口与实现 3. 客户端配置3.1 添加依赖3.2 YAML配置3.3 客户端调用 三、核心设计解析四、适用场景与优势对比五、总结 一、框架简介 …

Hologres实时数仓在B站游戏的建设与实践

一、背景 实时数据仓库是近年来数据技术领域内的一大发展潮流。构建一个能够实现高吞吐量写入与更新、端到端全链路实时处理以及低延迟、高并发的实时数据仓库&#xff0c;一直是众多企业面临的重大挑战。随着B站游戏业务的快速发展&#xff0c;对数据的实时应用需求也日益增加…

Android WiFi协议之P2P介绍与实践

Android WiFi P2P WiFi P2P (Peer-to-Peer) 是 Android 提供的一种允许设备之间直接通过 WiFi 进行通信的技术&#xff0c;无需接入传统的 WiFi 网络或互联网。这种技术也被称为 WiFi Direct。 一、WiFi P2P 基本概念 1. 核心组件 P2P 设备&#xff1a;支持 WiFi P2P 的 And…

浅谈在HTTP中GET与POST的区别

从 HTTP 报文来看&#xff1a; GET请求方式将请求信息放在 URL 后面&#xff0c;请求信息和 URL 之间以 &#xff1f;隔开&#xff0c;请求信息的格式为键值对&#xff0c;这种请求方式将请求信息直接暴露在 URL 中&#xff0c;安全性比较低。另外从报文结构上来看&#xff0c…

若依微服务集成Flowable仿钉钉工作流

项目简介 本项目工作流模块集成在若依项目单独一个模块&#xff0c;可实现单独运行部署&#xff0c; 前端采用微前端&#xff0c;嵌入在若依的前端项目中。因博主是后端开发&#xff0c;对前端不是太属性&#xff0c;没将工作流模块前端代码移到若依前端。下面贴上代码工程结构…

WPS JS宏编程教程(从基础到进阶)-- 第六部分:JS集合与映射在 WPS 的应用

目录 第6章 JS集合与映射在 WPS 的应用6-1 集合的创建(实例:唯一值提取)示例代码详细解析Excel 环境模拟说明6-2 集合的不重复特性应用(案例:提取唯一值记录)示例代码详细解析案例说明6-3 集合成员添加与删除示例代码代码解析直观示意(Excel 模拟表格)6-4 集合成员添加…

MySQL 约束(入门版)

目录 一、约束的基本概念 二、约束演示 三、外键约束 &#xff08;一&#xff09;介绍 &#xff08;二&#xff09;外键约束语法 &#xff08;三&#xff09;删除/更新行为 一、约束的基本概念 1、概念&#xff1a;约束是作用于表中字段上的规则&#xff0c;用于限制存储…

【ISP】ISP pipeline(AI)

ISP Pipeline 全流程概览 ISP&#xff08;Image Signal Processing&#xff0c;图像信号处理&#xff09;流程通常从原始 Bayer 数据出发&#xff0c;经过一系列模块处理&#xff0c;逐步完成图像校正和增强&#xff0c;最终生成用于显示或编码的标准图像。常见处理模块包括&a…

【Rust开发】Rust快速入门,开发出Rust的第一个Hello World

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Google Chrome下载受限制的解决方案【方法指南】

在国内使用网络时&#xff0c;部分用户在尝试访问Google Chrome官网下载谷歌浏览器时&#xff0c;常常遇到网页无法打开或文件下载失败的情况。这种下载受限制的问题多由网络访问政策或DNS解析异常导致。为了正常获取Google Chrome的最新版安装程序&#xff0c;用户需要通过一些…

使用 new EventSource 实现前端实时通信

示例&#xff1a; eventSource单向通信 1. 什么是 EventSource&#xff1f; EventSource 是浏览器提供的一种实现服务器推送&#xff08;Server-Sent Events&#xff0c;简称 SSE&#xff09;功能的 API。它是基于 HTTP 协议的单向通信机制&#xff0c;可以通过服务器将实时数…

Android Input——查找并添加目标窗口(七)

在 Android 输入系统中,InputDispatcher 的核心职责之一是将输入事件正确地传递到目标窗口。上一篇文章我们介绍到 InputDispatcher 事件分发调用到 findFocusedWindowTargetsLocked() 函数查找焦点窗口,并将焦点窗口添加到目标窗口,这里我们继续往下看。 一、获取焦点窗口…

Spring Boot中Spring MVC相关配置的详细描述及表格总结

以下是Spring Boot中Spring MVC相关配置的详细描述及表格总结&#xff1a; Spring MVC 配置项详解 1. 异步请求配置 spring.mvc.async.request-timeout 描述&#xff1a;设置异步请求的超时时间&#xff08;单位&#xff1a;毫秒&#xff09;。默认值&#xff1a;未设置&…

HTTP GET 和 POST 请求有什么区别

HTTP 的 GET 和 POST 请求是两种常见的 HTTP 请求方法&#xff0c;它们有不同的特点和应用场景。以下是它们的主要区别&#xff1a; 1. 用途 GET&#xff1a;用于从服务器获取数据或资源。GET 请求会附带查询参数在 URL 中&#xff0c;通常用于请求数据&#xff0c;如加载网页…

从入门到精通【MySQL】 联合查询

文章目录 &#x1f4d5;摘要&#x1f4d5;1. 多表联合查询时MySQL内部原理✏️1.1 实例&#xff1a;一个完整的联合查询过程 &#x1f4d5;2. 内连接&#x1f4d5;3. 外连接&#x1f4d5;4. 自连接&#x1f4d5;5. 子查询✏️5.1 单行子查询✏️5.2 多行子查询✏️5.3 多列子查…

高可用之战:Redis Sentinal(哨兵模式)

参考&#xff1a;Redis系列24&#xff1a;Redis使用规范 - Hello-Brand - 博客园 1 背景 在我们的《Redis高可用之战&#xff1a;主从架构》篇章中&#xff0c;介绍了Redis的主从架构模式&#xff0c;可以有效的提升Redis服务的可用性&#xff0c;减少甚至避免Redis服务发生完…