基于my Batis优化图书管理系统(二)

2024-08-29 16:28

本文主要是介绍基于my Batis优化图书管理系统(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 4.  图书列表

        添加图书之后, 跳转到图书列表⻚⾯, 并没有显⽰刚才添加的图书信息, 接下来我们来实现图 书列表

4.1 需求分析

        当查询到我们的图书数据很多的时候,一个页可能存放不了,所以我们进行分页处理数据,并且分页进行查询;如果想看非当前页的数据,我们可以进行点击其他页码进行查询;

        分⻚时, 数据是如何展⽰的呢:

        第1⻚: 显⽰1-10 条的数据

        第2⻚: 显⽰11-20 条的数据 

        以此类推... 要想实现这个功能, 从数据库中进⾏分⻚查询,我们要使⽤ LIMIT 关键字,        

        格式为:limit 开始索引 每⻚显⽰的条数(开始索引从0开始

        查询第1⻚的SQL语句

         SELECT * FROM book_info LIMIT 0,10;

        查询第2⻚的SQL语句

        SELECT * FROM book_info LIMIT 10,10;

        观察以上SQL语句,发现: 开始索引⼀直在改变, 每⻚显⽰条数是固定的 开始索引的计算公式: 开始索引 = (当前⻚码 - 1) * 每⻚显⽰条数

        我们继续基于前端⻚⾯, 继续分析, 得出以下结论:

        1. 前端在发起查询请求时,需要向服务端传递的参数 :

         currentPage 当前⻚码 //默认值为1 ,

         pageSize 每⻚显⽰条数 //默认值为10

        2、后端响应时, 需要响应给前端的数据 ◦:

        records 所查询到的数据列表(存储到List 集合中)

        total 总记录数 (⽤于告诉前端显⽰多少⻚, 显⽰⻚数为: (total + pageSize -1)/pageSize 显⽰⻚数;totalPage 计算公式为 : total % pagesize == 0 ? total / pagesize : (total / pagesize)+1 ;

        翻⻚请求和响应部分, 我们通常封装在两个对象中 ;

1、翻⻚请求对象

@Data
public class PageRequest {//当前页private Integer currentPage =1;//每页显示个数private Integer pageSize =10;/*** 从多少条记录开始查询*/private Integer offset;public Integer getOffset() {return (currentPage-1) * pageSize;}
}

2、翻⻚列表结果类:

@AllArgsConstructor//全参构造
@NoArgsConstructor//无参构造
@Data
public class PageResult<T> {private List<T> records;//当前的t是bookinfo类型private Integer count;//所有的记录数private PageRequest pageRequest;//当前页的记录数据
}

4.2 约定前后端交互接⼝

[请求]
/book/getListByPage?currentPage=1&pageSize=10
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
[参数]
[响应]
Content-Type: application/json
{"total": 25,"records": [{"id": 25,"bookName": "图书21","author": "作者2","count": 29,"price": 22.00,"publish": "出版社1","status": 1,"statusCN": "可借阅"}, {......} ]
}

4.3 实现服务器代码

        控制层: 完善 BookController

 @RequestMapping("/getListByPage")public PageResult<BookInfo> getListByPage(PageRequest pageRequest) {log.info("获取图书列表, pageRequest:{}", pageRequest);PageResult<BookInfo> pageResult =bookService.getListByPage(pageRequest);return pageResult;}

        业务层: BookService 

public PageResult<BookInfo> getBookListByPage(PageRequest pageRequest) {Integer count = bookInfoMapper.count();List<BookInfo> books = bookInfoMapper.queryBookListByPage(pageRequest);for (BookInfo book:books){if (book.getStatus()==0){book.setStatusCN("⽆效");}else if (book.getStatus()==1){book.setStatusCN("可借阅");}else {book.setStatusCN("不可借阅");}}return new PageResult<>(count,books);
}

存在的问题:

        1. 翻⻚信息需要返回数据的总数和列表信息, 需要查两次SQL

        2. 图书状态: 图书状态和数据库存储的status有⼀定的对应关系 如果后续状态码有变动, 我们需要修改项⽬中所有涉及的代码, 这种情况, 通常采⽤枚举类来处理映射关系

         创建enmus⽬录, 创建BookStatus类:

package com.example.book_manage_240827.enums;public enum BookStatusEnums {DELETE(0,"无效"),NORMAL(1,"可借阅"),FORBIDDEN(2,"不可借阅"),;private int code;private String desc;BookStatusEnums(int code, String desc) {this.code = code;this.desc = desc;}//根据code, 获取描述public static BookStatusEnums getDescByCode(int code){switch (code){case 0: return BookStatusEnums.DELETE;case 1: return BookStatusEnums.NORMAL;case 2: return BookStatusEnums.FORBIDDEN;}return BookStatusEnums.DELETE;}public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;}
}

        getNameByCode: 通过code来获取对应的枚举, 以获取该枚举对应的中⽂名称 后续如果有状态变更, 只需要修改该枚举类即可

        BookService的代码, 可以修改如下: 

 public PageResult<BookInfo> getListByPage(PageRequest pageRequest) {//1. 查询记录的总数Integer count = bookInfoMapper.count();//2. 查询当前页的数据List<BookInfo> bookInfos = bookInfoMapper.queryListBypage(pageRequest);for (BookInfo bookInfo:bookInfos){//根据状态, 设置描述bookInfo.setStateCN(BookStatusEnums.getDescByCode(bookInfo.getStatus()).getDesc());}return new PageResult<>(bookInfos,count,pageRequest);}

        BookInfoMapper :

        图书列表按id降序排列:

 /*** 查询总数*/@Select("select count(1) from book_info where `status` <>0")Integer count();/*** 查询当前页的数据*/@Select("select * from book_info where `status` <>0 order by id desc limit #{offset}, #{pageSize}")List<BookInfo> queryListBypage(PageRequest pageRequest);

        访问http://127.0.0.1:8082/book/getListByPage ,查询第一页的数据;

        访问第二页的数据,http://127.0.0.1:8082/book/getListByPage?currentPage=2 ,

 4.4 实现客户端代码

        浏览器访问 book_list.html ⻚⾯时, 就去请求后端, 把后端返回数据显⽰在⻚⾯上 调⽤后端请求: /book/getListByPage?currentPage=1

 getBookList();getBookList();function getBookList() {$.ajax({type: "get",url: "/book/getListByPage",success: function (result) {if (result != null) {var finalHtml = "";for (var book of result) {finalHtml += '<tr>';finalHtml += '<td><input type="checkbox" name="selectBook" ' +'value="'+book.id+'" id="selectBook" class="book-select"></td>';finalHtml += '<td>'+book.id+'</td>';finalHtml += '<td>'+book.bookName+'</td>';finalHtml += '<td>'+book.author+'</td>';finalHtml += '<td>'+book.count+'</td>';finalHtml += '<td>'+book.price+'</td>';finalHtml += '<td>'+book.publish+'</td>';finalHtml += '<td>'+book.statusCN+'</td>';finalHtml += '<td><div class="op">';finalHtml += '<a href="book_update.html?bookId='+book.id+'">修改</a>';finalHtml += '<a href="javascript:void(0)"onclick="deleteBook('+book.id+')">删除</a>';finalHtml += '</div></td>';finalHtml += "</tr>";}$("tbody").html(finalHtml);}}});}

         此时, url还未设置 currentPage 参数 ,我们直接使⽤ location.search 从url中获取参数信息即可 ;

        location.search : 获取url的查询字符串 (包含问号) 如: url:         http://127.0.0.1:8082/book_list.html?currentPage=1

        location.search : ?currentPage=1

 $.ajax({type: "get",url: "/book/getListByPage"+ location.search,

         接下来处理分页信息

        分页插件 --->本案例中, 分⻚代码采⽤了⼀个分⻚组件 ;

        分⻚组件⽂档介绍: jqPaginator分⻚组件 ,使⽤时, 只需要按照 [使⽤说明]部分的⽂档, 把代码复制粘贴进来就可以了(提供的前端代码中, 已经包含该部分内容)

        onPageChange :回调函数,当换⻚时触发(包括初始化第⼀⻚的时候),会传⼊两个参数:         1、"⽬标⻚"的⻚码,Number类型

        2、触发类型,可能的值:"init"(初始化),"change"(点击分⻚)

        我们在图书列表信息加载之后, 需要分⻚信息, 同步加载:

        分⻚组件需要提供⼀些信息:

        totalCounts: 总记录数,

        pageSize: 每⻚的个数,

        visiblePages: 可视⻚数

        currentPage: 当前⻚码

        这些信息中, pageSize 和 visiblePages 前端直接设置即可. totalCounts 后端已经提供, currentPage 也可以从参数中取到, 但太复杂了, 咱们直接由后端返回即可.

        修改后端代码

        1. 为避免后续还需要其他请求处的信息, 我们直接在PageResult 添加 PageRequest 属性

         2. 处理返回结果, 填充 PageRequest 

PageResult:

package com.example.book_manage_240827.model;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.List;@AllArgsConstructor//全参构造
@NoArgsConstructor//无参构造
@Data
public class PageResult<T> {private List<T> records;//当前的t是bookinfo类型private Integer count;//所有的记录数private PageRequest pageRequest;//当前页的记录数据public PageResult(Integer count, PageRequest pageRequest, List<T> records){this.count = count;this.pageRequest = pageRequest;this.records = records;}}

BookService:

    public PageResult<BookInfo> getListByPage(PageRequest pageRequest) {//1. 查询记录的总数Integer count = bookInfoMapper.count();//2. 查询当前页的数据List<BookInfo> bookInfos = bookInfoMapper.queryListBypage(pageRequest);for (BookInfo bookInfo:bookInfos){//根据状态, 设置描述bookInfo.setStateCN(BookStatusEnums.getDescByCode(bookInfo.getStatus()).getDesc());}return new PageResult<>(count,pageRequest,bookInfos);}

        后端数据返回后, 我们加载⻚⾯信息, 把分⻚代码挪到getBookList⽅法中;

   getBookList();getBookList();function getBookList() {$.ajax({type: "get",url: "/book/getListByPage"+ location.search,success: function (result) {if (result != null) {var finalHtml = "";for (var book of result) {finalHtml += '<tr>';finalHtml += '<td><input type="checkbox" name="selectBook" ' +'value="'+book.id+'" id="selectBook" class="book-select"></td>';finalHtml += '<td>'+book.id+'</td>';finalHtml += '<td>'+book.bookName+'</td>';finalHtml += '<td>'+book.author+'</td>';finalHtml += '<td>'+book.count+'</td>';finalHtml += '<td>'+book.price+'</td>';finalHtml += '<td>'+book.publish+'</td>';finalHtml += '<td>'+book.statusCN+'</td>';finalHtml += '<td><div class="op">';finalHtml += '<a href="book_update.html?bookId='+book.id+'">修改</a>';finalHtml += '<a href="javascript:void(0)"onclick="deleteBook('+book.id+')">删除</a>';finalHtml += '</div></td>';finalHtml += "</tr>";}$("tbody").html(finalHtml);//翻页信息$("#pageContainer").jqPaginator({totalCounts: 100, //总记录数pageSize: 10,    //每页的个数visiblePages: 5, //可视页数currentPage: 1,  //当前页码first: '<li class="page-item"><a class="page-link">首页</a></li>',prev: '<li class="page-item"><a class="page-link" href="javascript:void(0);">上一页<\/a><\/li>',next: '<li class="page-item"><a class="page-link" href="javascript:void(0);">下一页<\/a><\/li>',last: '<li class="page-item"><a class="page-link" href="javascript:void(0);">最后一页<\/a><\/li>',page: '<li class="page-item"><a class="page-link" href="javascript:void(0);">{{page}}<\/a><\/li>',//页面初始化和页码点击时都会执行onPageChange: function (page, type) {console.log("第"+page+"页, 类型:"+type);}});}}});}

        完善⻚⾯点击代码: 当点击⻚码时: 跳转到⻚⾯: book_list.html?currentPage=? 修改上述代码代码:

//页面初始化和页码点击时都会执行onPageChange: function (page, type) {if (type != 'init') {location.href = "book_list.html?currentPage=" + page;}}

4.5 测试

        浏览器访问地址http://127.0.0.1:8082/book_list.html ,即是图书列表第一页,结果如下:

        点击第二页,结果如下:

 

5.修改图书

5.1 约定前后端交互接⼝

        1、进⼊修改⻚⾯, 需要显⽰当前图书的信息:

[请求]
/book/queryBookById?bookId=25
[参数]
⽆
[响应]
{"id": 25,"bookName": "图书21","author": "作者2","count": 999,"price": 222.00,"publish": "出版社1","status": 2,"statusCN": null,"createTime": "2023-09-04T04:01:27.000+00:00","updateTime": "2023-09-05T03:37:03.000+00:00"
}

        即根据图书ID, 获取当前图书的信息;

2、点击修改按钮, 修改图书信息

[请求]
/book/updateBook
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
[参数]
id=1&bookName=图书1&author=作者1&count=23&price=36&publish=出版社1&status=1
[响应]
"" //失败信息, 成功时返回空字符串

        我们约定, 浏览器给服务器发送⼀个 /book/updateBook 这样的 HTTP 请求, form表单的形式来 提交数据 ,服务器返回处理结果, 返回""表⽰修改图书成功,;否则, 返回失败信息;

5.2 实现服务器代码

        BookController:

   @RequestMapping("/queryBookById")public BookInfo queryBookById(Integer bookId){if (bookId==null || bookId<=0){return new BookInfo();}BookInfo bookInfo = bookService.queryBookById(bookId);return bookInfo;}@RequestMapping("/updateBook")public String updateBook(BookInfo bookInfo) {log.info("修改图书:{}", bookInfo);try {bookService.updateBook(bookInfo);return "";} catch (Exception e) {log.error("修改图书失败", e);return e.getMessage();}}

        业务层: BookService:

  public BookInfo queryBookById(Integer bookId) {return bookInfoMapper.queryBookById(bookId);}public Integer updateBook(BookInfo bookInfo) {return bookInfoMapper.updateBook(bookInfo);}

        数据层: 根据图书ID,查询图书信息

  /*** 根据ID查询图书信息*/@Select("select * from book_info where `status` <>0 and id= #{id}")BookInfo queryBookById(Integer id);/*** 根据ID, 修改图书信息*/Integer updateBook(BookInfo bookInfo);

        对于update接口,我们采⽤xml的⽅式来实现;

        定义Mapper接⼝: BookInfoMapper

 Integer updateBook(BookInfo bookInfo);

        xml实现:

        创建bookInfoMapper.xml文件:文件路径和代码如下如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.book_manage_240827.mapper.BookInfoMapper"><update id="updateBook">update book_info<set><if test="bookName!=null">book_name = #{bookName},</if><if test="author!=null">author =#{author},</if><if test="count!=null">count = #{count},</if><if test="price!=null">price =#{price},</if><if test="publish">publish = #{publish},</if><if test="status!=null">status =#{status},</if></set>where id = #{id}</update>
</mapper>

5.3 实现客户端代码

        1、在列表⻚时, 我们已经补充了[修改] 的链接:

 <div><button class="btn btn-outline-info" type="button" onclick="location.href='book_add.html'">添加图书</button></div>

        2、点击[修改] 链接时, 就会⾃动跳转到 http://127.0.0.1:8082/book_update.html?bookId=2 (2为对应的图书ID)

        进⼊[修改图书]⻚⾯时, 需要先从后端拿到当前图书的信息, 显⽰在⻚⾯上:

$.ajax({type: "get",url: "/book/queryBookById"+location.search,success: function (result) {//前端根据后端返回结果, 针对不同的情况进行处理if (result != null) {console.log(result)$("#bookId").val(result.id);$("#bookName").val(result.bookName);$("#bookAuthor").val(result.author);$("#bookStock").val(result.count);$("#bookPrice").val(result.price);$("#bookPublisher").val(result.publish);$("#bookStatus").val(result.status);}}});

        补全修改图书的⽅法:

function update() {$.ajax({type:"post",url: "/book/updateBook",data: $("#updateBook").serialize(),success:function(result){if(result == "") {location.href = "book_list.html"}else{console.log(result);alert("更新失败"+result);}},error: function (error) {console.log(error);}});}

        我们修改图书信息, 是根据图书ID来修改的, 所以需要前端传递的参数中, 包含图书ID. 有两种⽅式:

        1. 获取url中参数的值(⽐较复杂, 需要拆分url)

        2. 在form表单中, 再增加⼀个隐藏输⼊框, 存储图书ID, 随 $("#updateBook").serialize() ⼀起提交到后端

        下面我们采⽤第⼆种⽅式 在form表单中,添加隐藏输⼊框

<form id="updateBook"><input type="hidden" class="form-control" id="bookId" name="id"><div class="form-group"><label for="bookName">图书名称:</label><input type="text" class="form-control" id="bookName" name="bookName"></div>

        hidden 类型的 <input>元素 :隐藏表单, 用户不可⻅、不可改的数据,在用户提交表单时,这些数据会⼀并发送出

        使⽤场景: 正被请求或编辑的内容的 ID. 这些隐藏的 input 元素在渲染完成的⻚⾯中完全不可⻅,⽽ 且没有⽅法可以使它重新变为可⻅.

        ⻚⾯加载时, 给该hidden框赋值

 $("#bookId").val(result.id);$("#bookName").val(result.bookName);$("#bookAuthor").val(result.author);$("#bookStock").val(result.count);$("#bookPrice").val(result.price);$("#bookPublisher").val(result.publish);$("#bookStatus").val(result.status);

5.4 测试 

        点击修改,

        出现修改页面:

        在修改正确的数据之后点击确定,返回到图书列表页;

        查看修改前与修改后的数据变化:

ps:本项目未完待续,如果对你有所帮助的话,就请一键三连哦!!! 

这篇关于基于my Batis优化图书管理系统(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1118362

相关文章

从原理到实战解析Java Stream 的并行流性能优化

《从原理到实战解析JavaStream的并行流性能优化》本文给大家介绍JavaStream的并行流性能优化:从原理到实战的全攻略,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的... 目录一、并行流的核心原理与适用场景二、性能优化的核心策略1. 合理设置并行度:打破默认阈值2. 避免装箱

Python实战之SEO优化自动化工具开发指南

《Python实战之SEO优化自动化工具开发指南》在数字化营销时代,搜索引擎优化(SEO)已成为网站获取流量的重要手段,本文将带您使用Python开发一套完整的SEO自动化工具,需要的可以了解下... 目录前言项目概述技术栈选择核心模块实现1. 关键词研究模块2. 网站技术seo检测模块3. 内容优化分析模

Java实现复杂查询优化的7个技巧小结

《Java实现复杂查询优化的7个技巧小结》在Java项目中,复杂查询是开发者面临的“硬骨头”,本文将通过7个实战技巧,结合代码示例和性能对比,手把手教你如何让复杂查询变得优雅,大家可以根据需求进行选择... 目录一、复杂查询的痛点:为何你的代码“又臭又长”1.1冗余变量与中间状态1.2重复查询与性能陷阱1.

Python内存优化的实战技巧分享

《Python内存优化的实战技巧分享》Python作为一门解释型语言,虽然在开发效率上有着显著优势,但在执行效率方面往往被诟病,然而,通过合理的内存优化策略,我们可以让Python程序的运行速度提升3... 目录前言python内存管理机制引用计数机制垃圾回收机制内存泄漏的常见原因1. 循环引用2. 全局变

Python多线程应用中的卡死问题优化方案指南

《Python多线程应用中的卡死问题优化方案指南》在利用Python语言开发某查询软件时,遇到了点击搜索按钮后软件卡死的问题,本文将简单分析一下出现的原因以及对应的优化方案,希望对大家有所帮助... 目录问题描述优化方案1. 网络请求优化2. 多线程架构优化3. 全局异常处理4. 配置管理优化优化效果1.

MySQL中优化CPU使用的详细指南

《MySQL中优化CPU使用的详细指南》优化MySQL的CPU使用可以显著提高数据库的性能和响应时间,本文为大家整理了一些优化CPU使用的方法,大家可以根据需要进行选择... 目录一、优化查询和索引1.1 优化查询语句1.2 创建和优化索引1.3 避免全表扫描二、调整mysql配置参数2.1 调整线程数2.

基于Spring Boot 的小区人脸识别与出入记录管理系统功能

《基于SpringBoot的小区人脸识别与出入记录管理系统功能》文章介绍基于SpringBoot框架与百度AI人脸识别API的小区出入管理系统,实现自动识别、记录及查询功能,涵盖技术选型、数据模型... 目录系统功能概述技术栈选择核心依赖配置数据模型设计出入记录实体类出入记录查询表单出入记录 VO 类(用于

深入解析Java NIO在高并发场景下的性能优化实践指南

《深入解析JavaNIO在高并发场景下的性能优化实践指南》随着互联网业务不断演进,对高并发、低延时网络服务的需求日益增长,本文将深入解析JavaNIO在高并发场景下的性能优化方法,希望对大家有所帮助... 目录简介一、技术背景与应用场景二、核心原理深入分析2.1 Selector多路复用2.2 Buffer

SpringBoot利用树形结构优化查询速度

《SpringBoot利用树形结构优化查询速度》这篇文章主要为大家详细介绍了SpringBoot利用树形结构优化查询速度,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一个真实的性能灾难传统方案为什么这么慢N+1查询灾难性能测试数据对比核心解决方案:一次查询 + O(n)算法解决

小白也能轻松上手! 路由器设置优化指南

《小白也能轻松上手!路由器设置优化指南》在日常生活中,我们常常会遇到WiFi网速慢的问题,这主要受到三个方面的影响,首要原因是WiFi产品的配置优化不合理,其次是硬件性能的不足,以及宽带线路本身的质... 在数字化时代,网络已成为生活必需品,追剧、游戏、办公、学习都离不开稳定高速的网络。但很多人面对新路由器