本篇记录简单分页功能的实现。
相关环境:
SpringBoot框架;
模板引擎:thymeleaf;
前端框架:layui;
持久层框架:mybatis;
分页插件:pagehelper;
写些废话
( 急于功能实现的同学请直接跳过 )
分页功能对于新手来说应该算是一个比较难的功能了(大佬请忽略),首先应该明确的一点是:分页功能是一个前端、后端都需要理解原理、进行代码编写的功能。
开始以为那么多分页插件嘛,随便copy一下就好了,或者只需要写后端,前端引一个插件就好了;和我有一样单纯想法的小盆友请进快放弃幻想,去找和自己开发框架相符合的分页教程,乖乖写前后端代码吧。
还有!使用任何一个与本篇开篇记录不符的框架都可能出现和本篇记录流程冲突的现象,都不可以直接引用本篇记录的代码;寻找思路当然是没有问题。(不然我也不会在csdn上爬了三天。。。)
页面展示
1、引入分页插件的maven依赖,在pom.xml文件添加下面代码:
<!--PageHelper 插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.1</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>1.4</version>
</dependency>
2、引入前端的js、css文件
<!-- layui for Page -->
<link href="layui-v2.5.6/layui/css/layui.css" th:href="@{/layui-v2.5.6/layui/css/layui.css}" rel="stylesheet">
<!-- layui插件引入 -->
<script type="text/javascript" src="layui-v2.5.6/layui/layui.js" th:src="@{/layui-v2.5.6/layui/layui.js}"></script>
3、前端html和js编写
table表格:
<table id="Usertable" class="table table-striped table-sm" lay-filter="Usertable"></table>
脚本js:
注意添加<script type="text/javascript" th:inline="none">
,否则表头会出现问题。
这里就用到了layui的前端分页插件,官网:layui的table模块分页功能
<script type="text/javascript" th:inline="none">
$(function() {$ = layui.jquery;
layui.use(['form', 'laypage', 'layer', 'table', 'element'], function(){
var form = layui.form
,laypage = layui.laypage //分页
,layer = layui.layer //弹层
,table = layui.table //表格
,element = layui.element //元素操作
table.render({
elem: '#Usertable'
,height: 312
,url: '/user/findArticle' //数据接口
,method: 'post' //默认:get请求
,limit: 5
,limits: [5,10,15]
,page: true//开启分页
,cellMinWidth: 10 //全局定义常规单元格的最小宽度,layui 2.2.1 新增
,request: {
pageName: 'page' //页码的参数名称,默认:page
,limitName: 'limit' //每页数据量的参数名,默认:limit
},response:{
statusName: 'code' //数据状态的字段名称,默认:code
,countName: 'count' //数据总数的字段名称,默认:count
,dataName: 'data' //数据列表的字段名称,默认:data
}
,cols: [[ //表头
{type: 'checkbox', fixed: 'left'}
,{field: 'id', title: '#',width:50}
,{field: 'name', title: 'Name',width:80}
,{field: 'syncTime', title: 'SyncTime',templet:'<div>{{ layui.util.toDateString(d.syncTime, "yyyy-MM-dd HH:mm:ss") }}</div>',width:180}
,{field: 'code', title: 'Code'}
,{field: 'account', title: 'Account',width:130}
,{field: 'sex', title: 'Sex',width:60}
,{field: 'idCard', title: 'idCard',width:150}
,{title: '操作',width:178, align:'center', toolbar: '#barDemo',width:130}
]],
done:function(res, curr, count) {
$("[data-field = 'sex']").children().each(function () {
if ($(this).text() == '0') {
$(this).text("女");
} else if ($(this).text() == '1') {
$(this).text("男");
}
});
}
});
});
});
</script>
<script type="text/html" id="barDemo">
<!--<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">查看</a>-->
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
</script>
4、封装类
这个类是我在别的教程看到的,所以这个名字很奇怪哈哈
返回状态码code要赋初值为 “0”,否则前端会报错返回状态错误。
public class ResultVo {
private String code="0";
private String msg;
private long count=0;
private Object data;
// set、get方法略...
}
5、Controller
使用PageHelper插件,从前端获取两个参数:
page:当前要显示的页页码
limit:每页规定的数据条数
@Controller
@RequestMapping("/user")
public class StaffControllerPage {
@Autowired
StaffService staffService;
@Autowired
StaffMapper staffMapper;
/**
*
* 分页查询员工列表
* @return ok/fail
*/
@RequestMapping(value = "/findArticle", method = RequestMethod.POST)
@ResponseBody
public ResultVo findArticle(@RequestParam(required = false,defaultValue = "1") int page,
@RequestParam(required = false,defaultValue = "10") int limit){
//实例化封装类
ResultVo rv=new ResultVo();
try {
//实例分页插件
PageInfo<B01BaseInfo_Staffs> pdr = new PageInfo<B01BaseInfo_Staffs>();
pdr = staffService.findArticle(page, limit);
// ---数据量进行二次单独查询
int totalNum = staffService.getTotalNum();
rv.setCount(totalNum);
rv.setData(pdr.getList());//往封装类存入数据
System.out.println("===== 分页查询的信息:"+ rv+"/n");
} catch (Exception e) {
e.printStackTrace();
}
return rv;
}
}
6、Service
service中的相关逻辑后面会说。其中有两个方法:总数查询、分页查询。
@Service
public class StaffService {
@Autowired
StaffMapper staffMapper;
public int getTotalNum()throws SQLException{
return staffMapper.getTotal();
}
public PageInfo<B01BaseInfo_Staffs> findArticle(int page, int limit) throws SQLException{
PageHelper.startPage(page, limit);
//PageHelper.orderBy("article_id ASC");//排序设置
System.out.println("page = "+page+" limit = "+limit);
int start = (int)(page-1)*limit+1;
int end = (int)page*limit;
System.out.println("开始条数 = "+start+" 结束条数 = "+end);
int fir = end-start+1; // 第一个sql参数
int sec = start-1; // 第二个参数
System.out.println("first = "+fir+" second = "+sec);
List<B01BaseInfo_Staffs> ArticleInfo = staffMapper.findArticle(fir,sec);
PageInfo<B01BaseInfo_Staffs> pageinfo = new PageInfo<B01BaseInfo_Staffs>(ArticleInfo);
return pageinfo;
}
}
7、mapper
@Service // 自己加的,防止controller.LoginByAcc报错
// @Mapper或者@MapperScan将接口扫描装配到容器中
public interface StaffMapper {
// 查询总数
int getTotal() throws SQLException;
// 分页查询
List<B01BaseInfo_Staffs> findArticle(@Param("fir") int fir,@Param("sec") int sec)throws SQLException;
}
8、mybatis-xml
<select id="getTotal" resultType="int">
select count(id) from BaseInfo_Staffs
</select>
<select id="findArticle" resultType="B01BaseInfo_Staffs">
select top ${fir} <include refid="columns" />
from BaseInfo_Staffs
where id not in (
select top ${sec} id from BaseInfo_Staffs
)
</select>
一些解释:
看到service中的方法和sql语句可能有些习惯使用MySQL的同学不是很明白了,我也很难受。。。
我们知道,分页的原理就是从前端传来两个参数page
和limit
,分别代表前端当前要显示的页码(也就是第几页)和每页可容纳的数据量。
后端的任务就是根据page
和limit
让sql语句只查出需要的部分数据,这是真实的分页原理。
当然也有“伪分页”,就是把所有数据查出来传到前端,在前端选出需要显示的数据进行渲染。但是这种“伪分页”只是看起来是分页,想象一下在数据量百万千万的数据库中,前端只需要10条数据,而程序却select了全部,这必然是不合理的,也失去了分页的意义。
在MySQL数据库中,我们可以直接使用LIMIT ${m}, ${n}
,选择第m条数据后的n条数据。但是!!!!各位,我忘记了SQLServer不支持limit语句,这个坑我爬了一下午。。。哭了
所以SQLServer是怎么实现与limit一样的功能呢?
扔个链接出来!— — 如何在SQLServer中实现MySQL的Limit m,n功能
先看这段sql文:
select top n id from table
where id not in (
select top m id from table
)
什么意思?
选择table表中那些 “ id不在table表前m行的 ” 前n行的id;有点绕哦。可以看下面的图。
而service中处理的逻辑就是:如何根据前端参数page
和limit
得到m和n的值。
相应的代码就是这部分:
int start = (int)(page-1)*limit+1;
int end = (int)page*limit;
System.out.println("开始条数 = "+start+" 结束条数 = "+end); //输出测试
int fir = end-start+1; // 第一个sql参数
int sec = start-1; // 第二个参数
在前端页面可以改变page
和limit
的值,进而影响查询的结果,实现真正的分页显示。
实现过程中的一些参考链接:
https://blog.csdn.net/lijiale132/article/details/81300885
https://blog.csdn.net/weixin_44903751/article/details/90609278
https://blog.csdn.net/baidu_35800355/article/details/100045608
结束了。