当前位置: 首页 > article >正文

SSM虾米音乐项目2--分页查询

1.分页查询的底层逻辑

  • 首先根据用户输入的流派,进行模糊查询
  • 根据查询的数据进行分页
  • 需要前端用户提供pageNo(当前页数)和pageSize(每页的数据量)
  • 并且要从后端计算count(总数据量)和totalPage(总页数),以及startNum(每页开始的记录)
  • 从而将对应的页面数据展示给用户

2.分页查询的实现

分页查询所需要的所有属性

   1.pageNo 当前页码 要查看的页码 前端用户决定

   2.pageSize 当前每页的展示数量 前端用户决定或者后台设定好

   3.startNum 开始行号 (pageNo-1)*pageSize sql语句做分页要查询的条件,通过计算得出

   4.totalNum 所有页数 count/pageSize 通过计算得出

   5.List 查询出的数据

   6.totalCount 所有数据量 count(*) 通过查询数据库得出

分页查询的代码实现

首先创建分页的对象Page 为泛型类,因为每一个部分都需要实现分页,传递给前端,进行解读

page实体类

package com.qcby.utils;

import java.util.List;

/**
 * 封装前端需要的承载数据以及分页相关的一个实体
 * 自定义页的类
 */
public class Page<T> {


    /**
     * 每页记录数(已知)
     */
    private Integer pageSize = 5;

    /**
     * 页码(已知)
     */
    private Integer pageNo = 1;

    /**
     * 指定查询条件下的总记录数(已知)
     */
    private Integer totalCount = 0;

    /**
     * 指定查询条件下 的总页数
     */
    private Integer totalPage = 1;

    /**
     * 使用sql查询的时候的开始行号
     */
    private Integer startNum = 0;


    /**
     * 数据结果集
     */
    private List<T> list;

    public Integer getPageSize() {
        return pageSize;
    }

    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }

    public Integer getPageNo() {
        return pageNo;
    }

    public void setPageNo(Integer pageNo) {
        this.pageNo = pageNo;
    }

    public Integer getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(Integer totalCount) {
        this.totalCount = totalCount;
    }

    public Integer getTotalPage() {
        totalPage = totalCount/pageSize;
        if(totalCount == 0 || totalCount%pageSize != 0){//如果不能整除的话,需要取整+1
            totalPage++;
        }
        return totalPage;
    }

    public void setTotalPage(Integer totalPage) {
        this.totalPage = totalPage;
    }

    public Integer getStartNum() {
        return (pageNo -1 )*pageSize;
    }

    public void setStartNum(Integer startNum) {
        this.startNum = startNum;
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }
}

需要将page对象传递给前端,实现对应的页面渲染

mtype实体类

package com.qcby.model;

import java.io.Serializable;

public class Mtype implements Serializable {
    private Integer tid;

    private String tname;

    private String tdesc;

    public Mtype() {
    }

    public Mtype(Integer tid, String tname, String tdesc) {
        this.tid = tid;
        this.tname = tname;
        this.tdesc = tdesc;
    }

    public Integer getTid() {
        return tid;
    }

    public void setTid(Integer tid) {
        this.tid = tid;
    }

    public String getTname() {
        return tname;
    }

    public void setTname(String tname) {
        this.tname = tname == null ? null : tname.trim();
    }

    public String getTdesc() {
        return tdesc;
    }

    public void setTdesc(String tdesc) {
        this.tdesc = tdesc == null ? null : tdesc.trim();
    }

    @Override
    public String toString() {
        return "Mtype{" +
                "tid=" + tid +
                ", tname='" + tname + '\'' +
                ", tdesc='" + tdesc + '\'' +
                '}';
    }
}

需要创建mtypeQuery实体类,将前端的页面数据pageNo等的数据,传递给后端进行数据查询,

mtypeQuery实体类

package com.qcby.query;

import com.qcby.model.Mtype;

/**封装query对象的目的是接受前端的请求参数,在后端处理业务逻辑,
 *知道用户的分页条件和查询条件
 * 只作为表现层接收前端参数封装使用
 */
public class MtypeQuery extends Mtype{
    private Integer pageNo;
    private Integer startNum;
    private Integer pageSize=5;

    public Integer getPageSize() {
        return pageSize;
    }

    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }

    public Integer getPageNo() {
        return pageNo;
    }

    public void setPageNo(Integer pageNo) {
        this.pageNo = pageNo;
    }

    public Integer getStartNum() {
        return startNum;
    }

    public void setStartNum(Integer startNum) {
        this.startNum = startNum;
    }


}

为什么mtype实体类当中没有设置有关页面的数据

因为在用page对象对mtype进行封装的时候,页面数据并没有用到前端的数据展示当中,而前端需要向后台服务器传递页面数据,因此需要再创建一个mtypeQuery实体类进行页面数据的封装

 表现层

package com.qcby.controller;

import com.qcby.model.Mtype;
import com.qcby.utils.Page;
import com.qcby.query.MtypeQuery;
import com.qcby.service.MtypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 流派业务的表现层
 * 处理前端页面的请求
 */
@Controller
@RequestMapping("/mtype")
public class MtypeController {
    @Autowired
    private MtypeService mtypeService;

    /**
     * 流派的分页条件查询接口
     * @param mq
     * @param model
     * @return
     */
    //展示流派信息
    @RequestMapping("/list")
    public String listType(MtypeQuery mq, Model model){
        if(mq.getPageNo() == null||mq.getPageNo()<=0){
            mq.setPageNo(1);
        }
        Page<Mtype> page = mtypeService.selectObjectByCondition(mq);
        //把Page对象传递给前端,进行解析呈现数据
        model.addAttribute("page", page);
        model.addAttribute("mq",mq);
        return "mtype";
    }


}

通过model将用户查询到的page传递到前端进行页面渲染

前端用户通过mq将查询条件和分页条件 传递到后端

根据用户的查询条件进行分页的方法selectObjectByCondition需要创建在父接口BaseDao当中,再由浮层的实现类BaseServiceImpl实现,因为所有的类都需要实现该分页操作

BaseDao

package com.qcby.dao;

import java.util.List;

public interface BaseDao<Q, T> {

    /**
     * 保存数据
     * @param t
     */
    public void insert(T t);

    /**
     * 根据主键查询对象
     * @param id
     * @return
     */
    public T selectByPrimaryKey(Integer id);

    /**
     * 根据主键删除数据
     * @param id
     */
    public void deleteByPrimaryKey(Integer id);

    /**
     * 修改数据
     * @param
     */
    public void updateByPrimaryKeySelective(T t);

    /**
     * 查询所有的记录
     * @return
     */
    public List<T> selectObjectAll();

    /**
     * 根据查询条件来查询数据
     * @param q
     * @return
     */
    public List<T> selectObjectByCondition(Q q);

    /**
     * 根据查询条件来查询符合条件的记录数
     * @param q
     * @return
     */
    public Integer selectObjectByConditionCount(Q q);
}

BaseService

package com.qcby.service;

import com.qcby.utils.Page;

import java.util.List;

public interface BaseService<Q, T> {
    /**
     * 保存数据
     * @param t
     */
    public void insert(T t);

    /**
     * 根据主键查询对象
     * @param id
     * @return
     */
    public T selectByPrimaryKey(Integer id);

    /**
     * 根据主键删除数据
     * @param id
     */
    public void deleteByPrimaryKey(Integer id);

    /**
     * 修改数据
     * @param
     */
    public void updateByPrimaryKeySelective(T t);

    /**
     * 查询所有的记录
     * @return
     */
    public List<T> selectObjectAll();

    /**
     * 分页查询
     * @param q
     * @return
     */
    public Page<T> selectObjectByCondition(Q q);
}

BaseServiceImpl实现方法  分页的主要逻辑实现

package com.qcby.service.impl;

import com.qcby.dao.BaseDao;
import com.qcby.utils.Page;
import com.qcby.service.BaseService;

import java.lang.reflect.Method;
import java.util.List;

public class BaseServiceImpl<Q,T> implements BaseService<Q,T> {
    /**
     * 可以支持两次注入,但是不好
     * 选择java基础的权限修饰符,以及set方法注入的形式改成一次注入
     */
    protected BaseDao<Q, T> baseDao;

    @Override
    public void insert(T t) {
        baseDao.insert(t);
    }

    @Override
    public T selectByPrimaryKey(Integer id) {
        return baseDao.selectByPrimaryKey(id);
    }

    @Override
    public void deleteByPrimaryKey(Integer id) {
        baseDao.deleteByPrimaryKey(id);
    }

    @Override
    public void updateByPrimaryKeySelective(T t) {
        baseDao.updateByPrimaryKeySelective(t);
    }

    @Override
    public List<T> selectObjectAll() {
        return baseDao.selectObjectAll();
    }
    //想办法给要返回的page对象所有属性赋值的过程
    @Override
    public Page<T> selectObjectByCondition(Q q) {
        //获得查询对象的类对象
        //反射
        Class<? extends Object> qclass = q.getClass();
        Page<T> page = new Page<T>();
        try {
            //获得getPageNo对象
            Method method = qclass.getMethod("getPageNo", null);
            //反射调用getPageNo方法
            Integer pageNo = (Integer) method.invoke(q, null);
            //创建page对象,给返回去的page设置值
            page.setPageNo(pageNo);
            //计算开始行号和结束行号
            Integer startNum = page.getStartNum();
            System.out.println(startNum);
            //好的查询对象 的设置开始行号和结束行号的方法
            Method setStartNumMethod = qclass.getMethod("setStartNum", new Class[]{Integer.class});
            setStartNumMethod.invoke(q, startNum);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //查询结果集
        List<T> list = baseDao.selectObjectByCondition(q);
        //查询指定查询条件下的总记录数
        Integer count = baseDao.selectObjectByConditionCount(q);
        //把总记录数设置给page对象
        page.setTotalCount(count);
        page.setList(list);
        return page;
    }
}

为什么要通过使用反射

通过反射获取类的类对象,可以知道当前的类到底对应的具体分页对象是谁。根据传递的q,通过反射调用方法拿到具体的每一个对象的getPageNo和getPageSize,设置给要返回到前端的page对象

 MtypeMapper

package com.qcby.dao;

import com.qcby.model.Mtype;
import com.qcby.query.MtypeQuery;

public interface MtypeMapper extends BaseDao<MtypeQuery,Mtype>{

}

MtypeService

package com.qcby.service;

import com.qcby.model.Mtype;
import com.qcby.query.MtypeQuery;
import com.qcby.query.MtypeQuery;

public interface MtypeService extends BaseService<MtypeQuery,Mtype>{

}

MtypeServiceImpl

package com.qcby.service.impl;

import com.qcby.query.MtypeQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.qcby.dao.MtypeMapper;
import com.qcby.model.Mtype;
import com.qcby.query.MtypeQuery;
import com.qcby.service.MtypeService;
@Service
public class MtypeServiceImpl extends BaseServiceImpl<MtypeQuery,Mtype> implements MtypeService {

   private MtypeMapper mtypeMapper;

   @Autowired
   public void setMtypeMapper(MtypeMapper mtypeMapper) {
      this.mtypeMapper = mtypeMapper;
      this.baseDao=mtypeMapper;
   }

}

前端页面

数据展示前端

<div class="body">
    <table class="table table-striped table-images"
           style="color: white;font-size: 14px">
        <thead>
        <tr>
            <th class="hidden-xs-portrait">序号</th>

            <th class="hidden-xs">流派</th>
            <th class="hidden-xs">描述</th>
            <th></th>
        </tr>
        </thead>
        <tbody>
        <c:forEach items="${page.list}" var="mtype" varStatus="status">
            <tr>
                <td class="hidden-xs-portrait">${mtype.tid}</td>
                <td class="hidden-xs-portrait">${mtype.tname}</td>
                <td class="hidden-xs"> ${mtype.tdesc} </td>
                <td>
                    <button  class="btn btn-sm btn-primary" type="button" modify tid="${mtype.tid}" > 修改</button>
                    <button data-toggle="button" class="btn btn-sm btn-warning" tid="${mtype.tid}"> 删除</button>
                </td>
            </tr>
        </c:forEach>
        </tbody>
    </table>

    <jsp:include page="pagination.jsp"></jsp:include>
</div>

分页部分前端

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@include file="header.jsp"%>
<html>
<head>
    <title>Title</title>
</head>
<body>
<div class="clearfix text-right">
    <%--隐藏域--%>
    <input type="hidden" id="pageNo" name="pageNo" value="${mq.pageNo}">
    <input type="hidden" id="totalPage" value="${page.totalPage}">
    <ul class="pagination no-margin">
        <li id="prev" class="disabled"><a href="#">Prev</a></li>
        <c:forEach begin="1" end="${page.totalPage}" var="myPageNo">
            <li <c:if test="${myPageNo == mq.pageNo}">class="active"</c:if>>
                <a pageNoButton href="#">${myPageNo}</a>
            </li>
        </c:forEach>
        <li id="next"><a href="#">Next</a></li>
    </ul>
</div>
</body>
</html>

上一页和下一页的逻辑

var pageNo = $("#pageNo").val();
var totalPage = $("#totalPage").val();

pageNo = parseInt(pageNo);
totalPage = parseInt(totalPage);
//如果已经到首页和尾页,并且只有一页
if (pageNo == 1 && pageNo == totalPage) {
    $("#prev").addClass("disabled");
    $("#next").addClass("disabled");
}

//如果在首页,且不只有一页
if (pageNo == 1 && pageNo < totalPage) {
    $("#prev").addClass("disabled");
    $("#next").removeClass("disabled");
}

//如果不只有一页,且不在首页和尾页
if (pageNo > 1 && pageNo < totalPage) {
    $("#prev").removeClass("disabled");
    $("#next").removeClass("disabled");
}

//如果不只有一页,且不在尾页
if (pageNo > 1 && pageNo == totalPage) {
    $("#prev").removeClass("disabled");
    $("#next").addClass("disabled");
}


$("#prev").click(function () {
    $("#pageNo").val(--pageNo);
    $("#txForm").submit();
})

$("#next").click(function () {
    $("#pageNo").val(++pageNo);
    $("#txForm").submit();
})

$("a[pageNoButton]").click(function () {
    var pageNo = $(this).html();
    $("#pageNo").val(pageNo);
    $("#txForm").submit();
})


http://www.kler.cn/a/430343.html

相关文章:

  • 计算机网络之---数据传输与比特流
  • 代码随想录算法训练营day23
  • 在 Vue 3 集成 e签宝电子合同签署功能
  • iOS - AutoreleasePool
  • QPS和TPS 的区别是什么?QPS 大了会有什么问题,怎么解决?
  • 计算机网络之---TCP/IP四层模型
  • Python Web 应用:FastAPI 与 SQLAlchemy ORM
  • 单词拼写纠正-03-72.力扣编辑距离 leetcode edit-distance
  • RISC-V架构下OP-TEE 安全系统实践
  • Python 爬虫 (1)基础 | XHR
  • ruoyi-nbcio为安全起见actuator为仅暴露health端点
  • 数据仓库实验二 实现警务数据仓库OLAP应用
  • 五天SpringCloud计划——DAY3之服务治理(Nacos+OpenFeign+OKHttp)
  • ubuntu16.04部署dify教程
  • 算法-字符串-165.比较版本号
  • 【UBOOT】【run_main_loop】uboot 启动 linux 内核
  • 使用javascript+canvas显示二叉树
  • DedeCMS最新注入漏洞(CNVD-2024-44514、CVE-2024-9076)
  • 怎么为开源项目做贡献提PR?
  • 企业经营数据分析系统:提升决策能力的利器
  • git中配置ssh的方法
  • 【计算机网络】实验15:VLAN间通信的实现方法“单臂路由”
  • 分布式事物各方案常见使用场景
  • PHP和GD库如何在图片上添加文字
  • 【IT】测试用例模版(含示例)
  • 踩坑日记-@Data注释的使用