圖書列表
實現服務器代碼(計算圖書總數量+查詢當前頁需要展示的書籍)
后端響應時,需要響應給前端的數據
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();
}