自定义分页工具类(仿百度搜索分页方式)

201 阅读3分钟

案例演示需要用到的相关技术:

  • 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>&nbsp;</span><span>
                到第&nbsp;<input type="text" id="gotoPageNum" name="pageNum" class="page-num">&nbsp;<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指定页的方法:
在这里插入图片描述
在这里插入图片描述
大功告成!~