最近用了一下EasyUI的分页插件,感觉用起来简单,只需要传给它两个参数rows和total就行,但是之前并不知道它的实现原理,所以学的时候还是挺不容易的。
现在了解了一下它的实现原理,之前的困惑就再也不在了。
首先,来分析一下:
我要实现的效果如图,在这里并不使用JS、Ajax或框架等工具,就用原生的servlet和jdbc来实现
先看最下面一行的实现:
数据的总条数:
这个简单,用一条sql查询就行了,语句如下:
select count(*) from mytable
(页面容量)每页显示的条数:
这里已经固定为5条
总页数
先判断能否整除,判断值 = 总条数 / 页面容量
若能整除, 总页数 = 总条数 / 页面容量
不能整除,则 总页数 = 总条数 / 页面容量+1
当前页码
开始时默认为1,每次用户向后台发送请求要换页时,前台就会向后台发送一个请求参数relocate,此参数的值为当前页码±1,从而定位到要跳转的页数
跳转:
当我们点击下一页时,jsp页面会向后台发送一个请求参数relocate,值为当前页码+1;
当我们点击下一页时,relocate的值为当前页码-1;
点击首页时,relocate的值为1,即重定位到第一页;
点击尾页时,relocate的值为总页数,即重定位到最后一页
点击刷新,relocate的值为1,重定位到第一页
当前页面中的数据从开始到结束的编号
首先我们要知道当前页面中第一条数据的编号,我们可以这样来判断:
上一页最后一条数据编号 =( 当前页码 - 1)*每页显示条数
然后我们就可以采用sql的分页语句limit来查询
select * from mytable limit 上一页最后一条数据编号 ,页面容量
因为limit语句中的查询开始数据是从第一个参数+1开始的,所以上述语句可以查询到本页中所有数据
现在开始实现
1、数据库的设计
CREATE TABLE `goods` (
`id` bigint(20) NOT NULL AUTO_INCREMENT ,
`name` varchar(50) DEFAULT NULL ,
`created` datetime DEFAULT NULL ,
`updated` datetime DEFAULT NULL ,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1183 DEFAULT CHARSET=utf8'
一个商品表,主键为id,有属性name、created和updated这三个属性
2、pojo类
private Long id;
private String name;
private Date created;
private Date updated;
名为Goods,省去getter和setter方法
3、dao层
//水平有限,就不使用接口+代理了,直接类走起
public class pagDao {
//第一个方法,统计数据总数
public Integer getCount() throws SQLException {
Integer all = 0;
Connection conn = DBUtils.getConnection();
String sql = "select count(*) from goods";
PreparedStatement pstmt = null;
try {
pstmt = (PreparedStatement) conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
all = rs.getInt(1);
}
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
pstmt.close();
conn.close();
}
return all;
}
//第二个方法,统计需要查询的数据,需要传入两个参数:上一页最后一条数据的编号和页面容量
//返回一个List类型的数据,里面存的是需要展示的数据
public List<Goods> getLimit(Integer startNum,Integer endNum) throws SQLException {
Connection conn = DBUtils.getConnection();
String sql = "select * from goods limit ?,?";
PreparedStatement pstmt = null;
List<Goods> limit = new ArrayList();
try {
pstmt = (PreparedStatement) conn.prepareStatement(sql);
pstmt.setInt(1, startNum);
pstmt.setInt(2, endNum);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
Goods g = new Goods();
g.setName(rs.getString("name"));
g.setId(rs.getLong("id"));
g.setCreated(rs.getDate("created"));
g.setUpdated(rs.getDate("updated"));
limit.add(g);
}
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
pstmt.close();
conn.close();
}
return limit;
}
}
4、service层
public interface pagService {
//设置页面容量
public Integer setCapacity();
//设置总条数
public Integer setCount() throws SQLException;
//设置总页数
public Integer setWholePage() throws SQLException;
//设置需要展示的数据
public List<Goods> setList(Integer startNum,Integer endNum) throws SQLException;
}
5、serviceImpl层
public class pagServiceImpl implements pagService{
//注入dao对象
pagDao pagedao = new pagDao();
//count为总数据,wholePage为总页数,capacity为页面容量
//startNum和endNum为分页查询参数,startNum为上一页最后一条数据编号,endNum为页面容量
Integer count,wholePage,startNum,endNum,capacity=5;
public List<Goods> setList(Integer startNum,Integer endNum) throws SQLException {
List<Goods> list = pagedao.getLimit(startNum,endNum);
return list;
}
public Integer setCount() throws SQLException {
count = pagedao.getCount();
return count;
}
public Integer setCapacity() {
return capacity;
}
public Integer setWholePage() throws SQLException {
count = setCount();
capacity = setCapacity();
wholePage = count/capacity;
int judge = count%capacity;
if(judge!=0)
wholePage++;
return wholePage;
}
}
6、controller层
public class PageController extends HttpServlet {
private static final long serialVersionUID = 1L;
//注入service对象
pagService pagservice = new pagServiceImpl();
//List为要展示的数据,pageNow为当前页码
List<Goods> list;
Integer count, wholePage, startNum, pageNow, capacity;
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取前台表示跳转的参数
String relocate = req.getParameter("relocate");
try {
//统计总条数
count = pagservice.setCount();
//统计页面容量
capacity = pagservice.setCapacity();
//统计总页数
wholePage = pagservice.setWholePage();
//若第一次访问页面,则前台来的参数relocate为空
if (relocate == null) {
//第一次访问默认当前页码为1
pageNow = startNum = 1;
} else {
//不是第一次访问
startNum = Integer.parseInt(relocate);
//若在第一页点击了“上一页”,默认返回本页
if (startNum == 0)
startNum = 1;
//若在最后一页点击了“下一页”,默认返回本页
if (startNum - 1 == wholePage)
startNum = wholePage;
//不是第一次访问,则当前页码为前台传过来的参数relocate,代表当前页码
pageNow = startNum;
}
//查询要展示的数据
list = pagservice.setList((startNum - 1) * capacity, capacity);
//设置域对象
req.setAttribute("LIST", list);
req.setAttribute("COUNT", count);
req.setAttribute("PAGENOW", pageNow);
req.setAttribute("CAPACITY", capacity);
req.setAttribute("WHOLEPAGE", wholePage);
} catch (SQLException e) {
e.printStackTrace();
}
//请求重定向
req.getRequestDispatcher("/index01.jsp").forward(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
7、jsp页面的设计
<body>
<table width="500" border="1px" id="idData">
<tr>
<td>编号</td>
<td>名称</td>
<td>创建时间</td>
<td>更新时间</td>
</tr>
<c:forEach items="${LIST}" var="g">
<tr>
<td>${g.getId()}</td>
<td>${g.getName()}</td>
<td>${g.getUpdated()}</td>
<td>${g.getCreated()}</td>
</tr>
</c:forEach>
</table>
<br />
<a href="${request.pageContext.ContextPath}/pagination/controller?relocate=1">首页</a>
<a href="${request.pageContext.ContextPath}/pagination/controller?relocate=${PAGENOW-1}">上一页</a>
<a href="${request.pageContext.ContextPath}/pagination/controller?relocate=${PAGENOW+1}">下一页</a>
<a href="${request.pageContext.ContextPath}/pagination/controller?relocate=${WHOLEPAGE}">尾页</a>
<a href="${request.pageContext.ContextPath}/pagination/controller?relocate=1">刷新</a>
</br>
总共${WHOLEPAGE}页, ${COUNT}条数据
当前第${PAGENOW}页, 每页显示${CAPACITY}条
</body>
分页首先到这里,下次做个优化,用JS和Ajax来写,我想因该会简单很多