案例演示需要用到的相关技术:
- SpringBoot2.3.x
- Thymleaf模板引擎
自定义全局Page工具类:
提示:类似于PageHelper的PageInfo:
/**
* @Auther: csp1999
* @Date: 2020/12/24/9:26
* @Description: 分页辅助类
*/
public class Page<T> implements Serializable {
/**
* 页数(第几页)
*/
private long currentpage;
/**
* 查询数据库里面对应的数据有多少条
* 从数据库查的总记录数
*/
private long total;
/**
* 每页查5条
*/
private int size;
/**
* 下页
*/
private int next;
/**
* 每页的数据list集合
*/
private List<T> list;
/**
* 最后一页
*/
private int last;
/**
* 前一页
*/
private int lpage;
/**
* 后一页
*/
private int rpage;
/**
* 从哪条记录开始查
*/
private long start;
/**
* 全局偏移量
*/
public int offsize = 2;
public Page() {
super();
}
/**
* 设置当前页
*
* @param currentpage
* @param total
* @param pagesize
*/
public void setCurrentpage(long currentpage, long total, long pagesize) {
// 可以整除的情况下
long pagecount = total / pagesize;
// 如果整除表示正好分N页,如果不能整除在N页的基础上+1页
int totalPages = (int) (total % pagesize == 0 ? total / pagesize : (total / pagesize) + 1);
// 总页数
this.last = totalPages;
// 判断当前页是否越界,如果越界,我们就查最后一页
if (currentpage > totalPages) {
this.currentpage = totalPages;
} else {
this.currentpage = currentpage;
}
// 计算start
this.start = (this.currentpage - 1) * pagesize;
}
// 上一页
public long getUpper() {
return currentpage > 1 ? currentpage - 1 : currentpage;
}
// 总共有多少页,即末页
public void setLast(int last) {
this.last = (int) (total % size == 0 ? total / size : (total / size) + 1);
}
/**
* 带有偏移量设置的分页
*
* @param total
* @param currentpage
* @param pagesize
* @param offsize
*/
public Page(long total, int currentpage, int pagesize, int offsize) {
this.offsize = offsize;
initPage(total, currentpage, pagesize);
}
/**
* @param total 总记录数
* @param currentpage 当前页
* @param pagesize 每页显示多少条
*/
public Page(long total, int currentpage, int pagesize) {
initPage(total, currentpage, pagesize);
}
/**
* 初始化分页
*
* @param total
* @param currentpage
* @param pagesize
*/
public void initPage(long total, int currentpage, int pagesize) {
// 总记录数
this.total = total;
// 每页显示多少条
this.size = pagesize;
// 计算当前页和数据库查询起始值以及总页数
setCurrentpage(currentpage, total, pagesize);
// 分页计算
int leftcount = this.offsize, // 需要向上一页执行多少次
rightcount = this.offsize;
// 起点页
this.lpage = currentpage;
// 结束页
this.rpage = currentpage;
// 2点判断
this.lpage = currentpage - leftcount; //正常情况下的起点
this.rpage = currentpage + rightcount; //正常情况下的终点
// 页差=总页数和结束页的差
int topdiv = this.last - rpage; //判断是否大于最大页数
/**
* 起点页
* 1、页差<0 起点页=起点页+页差值
* 2、页差>=0 起点和终点判断
*/
this.lpage = topdiv < 0 ? this.lpage + topdiv : this.lpage;
/**
* 结束页
* 1、起点页<=0 结束页=|起点页|+1
* 2、起点页>0 结束页
*/
this.rpage = this.lpage <= 0 ? this.rpage + (this.lpage * -1) + 1 : this.rpage;
/**
* 当起点页<=0 让起点页为第一页
* 否则不管
*/
this.lpage = this.lpage <= 0 ? 1 : this.lpage;
/**
* 如果结束页>总页数 结束页=总页数
* 否则不管
*/
this.rpage = this.rpage > last ? this.last : this.rpage;
}
public long getNext() {
return currentpage < last ? currentpage + 1 : last;
}
public void setNext(int next) {
this.next = next;
}
public long getCurrentpage() {
return currentpage;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public long getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public long getLast() {
return last;
}
public long getLpage() {
return lpage;
}
public void setLpage(int lpage) {
this.lpage = lpage;
}
public long getRpage() {
return rpage;
}
public void setRpage(int rpage) {
this.rpage = rpage;
}
public long getStart() {
return start;
}
public void setStart(long start) {
this.start = start;
}
public void setCurrentpage(long currentpage) {
this.currentpage = currentpage;
}
/**
* @return the list
*/
public List<T> getList() {
return list;
}
/**
* @param list the list to set
*/
public void setList(List<T> list) {
this.list = list;
}
public static void main(String[] args) {
// 当前页
int currentPage = 10;
// Page page = new Page(1001, currentPage, 50);
// 总记录数 当前页 每页显示多少条 偏移量
Page page = new Page(1001, currentPage, 50, 2);// 开始页:8__当前页:10__结束页12____总页数:21
System.out.println("开始页:" + page.getLpage() + "__当前页:" + page.getCurrentpage() + "__结束页" + page.getRpage() + "____总页数:" + page.getLast());
}
}
后端controller:
提示:这里结合SpringBoot使用:
/**
* @Auther: csp1999
* @Date: 2021/01/22/15:57
* @Description: SkuController 用于将搜索微服务搜索得到的数据渲染到search.html页面
*/
@Controller
@RequestMapping(value = "/search")
public class SkuController {
@Autowired
private SkuFeign skuFeign;
/**
* 调用搜索微服务搜索数据,然后渲染到search.html页面
*
* @param searchParamMap
* @return
*/
@GetMapping(value = "/list")
public String search(@RequestParam(required = false) Map<String, String> searchParamMap, Model model) {
// 调用搜索微服务中的搜索方法
Map resultMap = skuFeign.search(searchParamMap);
// 计算分页
Page<SkuInfo> page = new Page<>(
Long.parseLong(resultMap.get("TotalElements").toString()),// 总记录数
Integer.parseInt(resultMap.get("pageNum").toString()),// 当前页
Integer.parseInt(resultMap.get("pageSize").toString())// 每页记录数
);
model.addAttribute("page", page);
model.addAttribute("resultMap", resultMap);
// 搜索的条件也存入model,便于前台搜索之后 搜索框保留搜索的条件
model.addAttribute("searchParamMap", searchParamMap);
// 页面请求url地址
String url = this.url(searchParamMap);
model.addAttribute("url", url);
// 跳转到searchy
return "search";
}
/**
* 请求url
**/
private String url(Map<String, String> searchMap) {// { spec_网络:"移动4G","keywords":"华为"}
String url = "/search/list"; // a/b?id=1&
if (searchMap != null) {
url += "?";
for (Map.Entry<String, String> stringStringEntry : searchMap.entrySet()) {
// 如果已经有排序条件 则 跳过 拼接排序的地址 不重复拼接
if (stringStringEntry.getKey().equals("sortField") || stringStringEntry.getKey().equals("sortRule")) {
continue;
}
// 如果已经有分页条件 则 跳过 不重复拼接
// eg: http://localhost:8087/search/list?pageNum=2 点击下页的时候更新为:
// http://localhost:8087/search/list?pageNum=3 而不是重复拼接多个pageNum
if (stringStringEntry.getKey().equalsIgnoreCase("pageNum")) {
continue;
}
// 如果已经有分类条件 则 跳过 不重复拼接
if (stringStringEntry.getKey().equalsIgnoreCase("category")) {
continue;
}
// 如果已经有品牌条件 则 跳过 不重复拼接
if (stringStringEntry.getKey().equalsIgnoreCase("brand")) {
continue;
}
url += stringStringEntry.getKey() + "=" + stringStringEntry.getValue() + "&";
}
if (url.lastIndexOf("&") != -1)
url = url.substring(0, url.lastIndexOf("&"));
}
return url;
}
}
前端页面展示分页:
提示:数据渲染这里就不再展示,直接看上一页下一页:
<div class="fr page">
<div class="sui-pagination pagination-large">
<ul>
<li th:class="${page.currentpage}<=1?'prev disabled':''">
<a th:href="@{${url}(pageNum=${page.upper})}">«上一页</a>
</li>
<li th:each="i:${#numbers.sequence(page.lpage,page.rpage)}"
th:class="${page.currentpage}==${i}?'active':''">
<a th:href="@{${url}(pageNum=${i})}" th:text="${i}">1</a>
</li>
<li th:class="${page.currentpage}>=${page.last}?'next disabled':''">
<a th:href="@{${url}(pageNum=${page.next})}">下一页»</a>
</li>
</ul>
<div>
<span>共<span style="color: red" th:text="${page.last}"></span>页 </span><span>
到第 <input type="text" id="gotoPageNum" name="pageNum" class="page-num"> 页
<button class="page-confirm" type="button"
th:onclick="|goto(${page.currentpage},${page.last})|">确定</button>
</span>
</div>
</div>
</div>
JS中的方法:
<script>
// 跳转到指定页面
function goto(currentPage, totalPage) {
// 获取旧url地址
var oldUrl = location.href;
// 获取输入框输入的目标页数
var targetPage = document.getElementById("gotoPageNum").value
if (!/^\d+$/.test(targetPage)) {
alert("您输入的目标页码不是整数");
} else if (targetPage <= totalPage && targetPage >= 1) {
// 如果该判断成立,说明url中已经存在pageNum参数,这时候需要做替换
if (oldUrl.indexOf("pageNum=") != -1) {
// 更换原来url地址中的当前页码参数为目标页码
var newUrl = oldUrl.replace("pageNum=" + currentPage, "pageNum=" + targetPage)
} else {
// 如果上面的判断条件不成立,说明url中还没有pageNum参数,默认当前为第一页,这时候只需要拼接上pageNum参数即可
var newUrl = oldUrl + "&pageNum=" + targetPage;
}
// 跳转
location.href = newUrl;
} else {
alert("您输入的目标页码越界!")
}
}
</script>
效果展示:
测试goto指定页的方法:
大功告成!~