🌴前言
在前面我们实现了用户登录的接口。现在我们来实现图书列表展示页面。
🎋数据准备
创建图书表,并初始化数据
-- 图书表
DROP TABLE IF EXISTS book_info;
CREATE TABLE `book_info` (
`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
`book_name` VARCHAR ( 127 ) NOT NULL,
`author` VARCHAR ( 127 ) NOT NULL,
`count` INT ( 11 ) NOT NULL,
`price` DECIMAL (7,2 ) NOT NULL,
`publish` VARCHAR ( 256 ) NOT NULL,
`status` TINYINT ( 4 ) DEFAULT 1 COMMENT '0-⽆效, 1-正常, 2-不允许借阅',
`create_time` DATETIME DEFAULT now(),
`update_time` DATETIME DEFAULT now() ON UPDATE now(),
PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
-- 初始化图书数据
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('活
着', '余华', 29, 22.00, '北京⽂艺出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('平凡的
世界', '路遥', 5, 98.56, '北京⼗⽉⽂艺出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('三
体', '刘慈欣', 9, 102.67, '重庆出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('⾦字塔
原理', '⻨肯锡', 16, 178.00, '⺠主与建设出版社');
MyBatis和MySQL驱动依赖已经在用户登录时已经配置过了,直接用即可
🎄需求分析
首先我们先来看一下页面展示的效果
在分页时,第一页就展示10条数据,第二页我们也只显示10条数据
要想实现这个功能,从数据库中进⾏分⻚查询,我们要使⽤ LIMIT 关键字,格式为:limit 开始索引每⻚显⽰的条数(开始索引从0开始)
通过观察与思考,我们可以发现
开始索引的计算公式:开始索引=(当前⻚码-1)*每⻚显⽰条数
基于前端⻚⾯的分析,得出以下结论:
- 前端在发起查询请求时,需要向服务端传递的参数
- currentPage当前⻚码 //默认值为1
- pageSize每⻚显⽰条数 //默认值为10
- 后端响应时,需要响应给前端的数据
- records所查询到的数据列表(存储到List集合中)
- total总记录数(⽤于告诉前端显⽰多少⻚,显⽰⻚数为: (total + pageSize-1)/pageSize
翻⻚请求和响应部分,我们通常封装在两个对象中,并放在model文件路径下
🚩翻⻚请求对象类
除了需要currentPage当前⻚码和pageSize每⻚显⽰条数
我们还需要根据currentPage和pageSize,计算出来开始索引
代码如下:
@Data
public class PageRequest {
private int currentPage = 1; // 当前⻚
private int pageSize = 10; // 每⻚中的记录数
private int offset;
public int getOffset() {
return (currentPage-1) * pageSize;
}
}
🚩翻页响应对象类
该类博主设计的是返回一个对象。
该对象应该含有以下属性。
- records所查询到的数据列表
- total总记录数
- PageRequest属性
添加PageRequest属性是为了避免后续还需要其他请求处的信息
同时给出相应的构造方法。
代码实现如下:
@Data
public class PageResult<T> {
private int total;//所有记录数
private List<T> records; // 当前⻚数据
private PageRequest pageRequest;
public PageResult(Integer total, PageRequest pageRequest, List<T> records)
{
this.total = total;
this.pageRequest = pageRequest;
this.records = records;
}
}
🍃约定前后端交互接⼝
基于以上分析,我们来约定前后端交互接⼝
[请求]
/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”: “可借阅”
}, {
…
} ]
}
我们约定,浏览器给服务器发送⼀个 /book/getListByPage 这样的HTTP请求,通过currentPage参数告诉服务器,当前请求为第⼏⻚的数据,后端根据请求参数,返回对应⻚的数据
第一页可以不传递参数,默认为1
🌲后端服务器代码实现
依旧利用分层思想进行代码实现
🚩控制层
在该层我们只需要调用业务层的代码返回就好
@Slf4j
@RequestMapping("/book")
@RestController
public class BookController {
@Autowired
private BookService bookService;
@RequestMapping("/getListByPage")
public PageResult<BookInfo> getListByPage(PageRequest pageRequest) {
log.info("获取图书列表, pageRequest:{}", pageRequest);
PageResult<BookInfo> pageResults = bookService.getBookListByPage(pageRequest);
return pageResults;
}
}
🚩业务层
在书写业务层代码时我们需要考虑以下几点
-
翻⻚信息需要返回数据的总数和列表信息,需要查两次SQL
-
图书状态:图书状态和数据库存储的status有⼀定的对应关系
如果后续状态码有变动,我们需要修改项⽬中所有涉及的代码,这种情况,我们通常采⽤枚举类来处理映射关系
枚举类代码如下:
public enum BookStatus {
DELETED(0,"⽆效"),
NORMAL(1,"可借阅"),
FORBIDDEN(2,"不可借阅");
private Integer code;
private String name;
BookStatus(int code, String name) {
this.code = code;
this.name = name;
}
public static BookStatus getNameByCode(Integer code){
switch (code){
case 0: return DELETED;
case 1: return NORMAL;
case 2: return FORBIDDEN;
}
return null;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
此时我们只需要调用相应的数据层代码,查询相应的数据,并对查询到的数据进行状态码的更新。
最后构造新的响应对象,返回即可
代码实现如下:
@Service
public class BookService {
@Autowired
private BookInfoMapper bookInfoMapper;
public PageResult<BookInfo> getBookListByPage(PageRequest pageRequest) {
Integer count = bookInfoMapper.count();
List<BookInfo> books = bookInfoMapper.queryBookListByPage(pageRequest);
for (BookInfo book:books){
book.setStatusCN(BookStatus.getNameByCode(book.getStatus()).getName());
}
return new PageResult<>(count,pageRequest, books);
}
}
🚩数据层
数据层我们只需要进行两个查询即可
一个是返回最大数据长度,一个是查询当前页码的所有数据。
代码实现如下:
@Mapper
public interface BookInfoMapper {
@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> queryBookListByPage(PageRequest pageRequest);
}
🚩测试后端代码
到这里后端代码就写完了,我们可以进行简单的测试,只需要在浏览器中输入
- http://127.0.0.1:8080/book/getListByPage返回1-10条记录(按id降序)
- http://127.0.0.1:8080/book/getListByPage?currentPage=2返回11-20条记录
此时说明后端代码已经书写成功
🌳客户端代码的完善
这里博主直接给出改变的相应代码。
实现如下:
getBookList();
function getBookList() {
$.ajax({
type: "get",
url: "/book/getListByPage"+location.search,
success: function (result) {
console.log(result);
if (result != null) {
var finalHtml = "";
for (var book of result.records) {
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="deleteBoook(' + book.id + ')">删除</a>'
finalHtml += '</div></td>';
finalHtml += "</tr>";
}
$("tbody").html(finalHtml);
//翻页信息
$("#pageContainer").jqPaginator({
totalCounts: result.total, //总记录数
pageSize: 10, //每页的个数
visiblePages: 5, //可视页数
currentPage: result.pageRequest.currentPage, //当前页码
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);
if (type != 'init') {
location.href = "book_list.html?currentPage=" + page;
}
}
});
}
}
});
}
⭕总结
关于《【JavaEE进阶】 图书管理系统开发日记——叁》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!