1、分页查询时需要用到的分页信息实体类
import java.io.Serializable;
/**
* 适用于所有的使用jdbc结合sqlserver的web工程
*
*
* @author ycglei886
*/
public class PageInfo implements Serializable {
private static final long serialVersionUID = 7126509565385142115L;
/**
* 记录总数(该属性由PageSearchUtil设置)
*
*/
private int recordCount;
/**
* 每页面最大记录数(该属性在传入PageSearchUtil的getPageResultSet方法之前需要设置)
*
*/
private int pageSize;
/**
* 总页数(该属性由本类的compute方法计算得出)
*
*/
private int pageCount;
/**
* 每部分页数(假如总共有100页,那么我们不可能将100页的页码都显示在页面上,只能部分部分的显示,该属性就是设置部分显示多少页的)
* 该属性与compute方法无关,在PageSearchUtil中也不会用到,但我们在页面上会用到
*/
private int partPageCount = 10;
/**
* 当前是第几页(该属性在传入PageSearchUtil的getPageResultSet方法之前需要设置)
*
*/
private int currentPage;
/**
* 开始记录数(该属性由本类的compute方法计算得出)
*
*/
private int startRecord;
/**
* 结束记录数(该属性由本类的compute方法计算得出)
*
*/
private int endRecrod;
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getEndRecrod() {
return endRecrod;
}
public int getPageCount() {
return pageCount;
}
public int getPartPageCount() {
return partPageCount;
}
public void setPartPageCount(int partPageCount) {
this.partPageCount = partPageCount;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getRecordCount() {
return recordCount;
}
public void setRecordCount(int recordCount) {
this.recordCount = recordCount;
}
public int getStartRecord() {
return startRecord;
}
public PageInfo() {
}
/**
* 通过recordCount、pageSize、currentPage三个属性值来计算本对象中所有属性的值
*
*
*/
public void compute() {
if (recordCount == 0 || pageSize == 0) {
pageCount = 0;
startRecord = 0;
endRecrod = 0;
currentPage = 0;
} else {
pageCount = (recordCount + pageSize - 1) / pageSize;
if (currentPage <= 0) {
currentPage = 1;
}
if (currentPage > pageCount) {
currentPage = pageCount;
}
startRecord = (currentPage - 1) * pageSize + 1;
int endRecrodTemp = startRecord + pageSize - 1;
if (endRecrodTemp <= recordCount) {
endRecrod = endRecrodTemp;
} else {
endRecrod = recordCount;
}
}
}
}
2、分页查询共通操作类
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import com.zuxia.qlzx_shopping.entity.PageInfo;
/**
* 分页查询共通操作类 分页查询的思路是每页的数据分别进行查询,而不是将全部数据查询出来之后再分页
*
* @author ycglei886
* 创建时间:2010/5/20
* @version 1.0
*/
public class PageSearchUtil {
/**
* PageSearchUtil私有构造方法 通过这个私有构造方法使该类无法实例化,只能通过静态方式调用该类的分页查询方法。
*/
private PageSearchUtil() {
}
/**
* 分页查询
*
*
* @param conn
* 数据库连接对象(该对象由调用本方法的方法传入和关闭)
* @param ps
* 数据库操作预编译对象(该对象是进行分页查询时查询每页数据的预编译对象,该对象由调用本方法的方法传入和关闭)
* @param pageInfo
* 分页信息对象(该对象中提供了set方法的属性需要进行预先设置,该对象传入本方法后其属性值会被本方法更新,因此在调用本方法的方法中,请注意获取该pageInfo属性的时机)
* @param selectContent
* sql语句中select关键字后面跟的字段字符串(形如:"userName,password"或者"*")
* @param fromContent
* sql语句中from关键字后面跟的字段字符串(形如:"userInfo"或Bulletin bu left join
* UserInfo us on bu.userId=us.id)
* @param whereContent
* sql语句中where关键字后面跟的条件字符串(形如:"userName=?,password=?")
* @param orderByContent
* 使用sqlserver进行分页查询时,需要用到row_number()函数,该函数必须与over(order by
* ...)连用,也就是说sqlserver中要分页就必须要排序
* @param paramArray
* 查询参数(如果在前面的whereContent中使用了问好占位符,则该参数用于依次替换问号,如果没有使用问号站位符,则该参数传入null)
* @return ResultSet 数据库查询结果对象(该对象即分页查询时每页的查询结果集,该对象由调用本方法的方法传入和关闭)
*/
public static ResultSet getPageResultSet(Connection conn,
PreparedStatement ps, PageInfo pageInfo, String selectContent,
String fromContent, String whereContent, String orderByContent,
Object[] paramArray) {
// 构造查询记录总条数的sql语句
StringBuffer countSqlBuffer = new StringBuffer("select count(*) from ");
countSqlBuffer.append(fromContent);
countSqlBuffer.append(" where 1=1");
if (whereContent != null && whereContent.length() > 0) {
countSqlBuffer.append(" and ");
countSqlBuffer.append(whereContent);
}
// 构造查询结果集的sql语句
StringBuffer sqlBuffer = new StringBuffer(
"WITH OrderedOrders AS (select row_number() over(order by ");
sqlBuffer.append(orderByContent);
sqlBuffer.append(") as 'rowNum', ");
sqlBuffer.append(selectContent);
sqlBuffer.append(" from ");
sqlBuffer.append(fromContent);
sqlBuffer.append(" where 1=1");
if (whereContent != null && whereContent.length() > 0) {
sqlBuffer.append(" and ");
sqlBuffer.append(whereContent);
}
sqlBuffer
.append(") select * from OrderedOrders WHERE rowNum between ? and ?");
// 声明查询数据条数的预编译对象(该对象由本方法自己控制生成和关闭,注意区别该对象不是传入本方法的那个预编译对象)
PreparedStatement countPs = null;
// 声明查询结果集对象(该对象的关闭由调用本方法的方法来执行)
ResultSet rs = null;
// 声明存放记录总数的变量
int count = 0;
try {
// 获取查询数据条数的预编译对象
countPs = conn.prepareStatement(countSqlBuffer.toString());
// 获取查询每页数的预编译对象
ps = conn.prepareStatement(sqlBuffer.toString());
// 通过以下循环来为两个预编译对象设置参数,因为两个查询的查询语句前面的问号位置和数量是完全一致的(ps最后面会多两个问号),
//所以这里在一个循环中为两个预编译对象设置参数
int i = 1;
if (paramArray != null && paramArray.length > 0) {
for (; i <= paramArray.length; i++) {
countPs.setObject(i, paramArray[i - 1]);
ps.setObject(i, paramArray[i - 1]);
}
}
// 获取记录总数的查询结果集
ResultSet countRs = countPs.executeQuery();
if (countRs != null && countRs.next()) {
count = countRs.getInt(1);
}
// 关闭查询记录总数所使用的预编译对象和查询结果集
DBUtil.closeConn(countRs, countPs, null);
// 设置分页信息对象的记录总数属性
pageInfo.setRecordCount(count);
// 调用分页信息对象的方法来计算并更新分页信息对象中其他的属性值
pageInfo.compute();
// 当记录结果大于0的时候才进行每页数据的查询
if (count > 0) {
// 获取每页面最大记录数
int pageSize = pageInfo.getPageSize();
// 获取当前第几页(页数)
int pageNum = pageInfo.getCurrentPage();
// 设置预编译对象的between and相关的2个参数
ps.setInt(i, (pageNum - 1) * pageSize + 1);
ps.setInt(i + 1, pageNum * pageSize);
// 获取每页数据查询结果集
rs = ps.executeQuery();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
// 返回每页数据查询结果集
return rs;
}
/**
* 初始化PageInfo,当request中无法获取相应值的时候设置默认值
* @param request HttpServletRequest
* @return PageInfo
*/
public static PageInfo initPageInfo(HttpServletRequest request){
PageInfo pageInfo = new PageInfo();
// 设置当前第几页,默认值为1
String pageNum = request.getParameter("pageNum");
if(pageNum != null && !"".equals(pageNum)){
pageInfo.setCurrentPage(Integer.valueOf(pageNum));
}else{
pageInfo.setCurrentPage(1);
}
// 设置每页面最大记录数,默认值为10
String pageSize = request.getParameter("pageSize");
if(pageSize != null && !"".equals(pageSize)){
pageInfo.setPageSize(Integer.valueOf(pageSize));
}else{
pageInfo.setPageSize(10);
}
// 设置每部分页数,默认值为10
String partPageCount = request.getParameter("partPageCount");
if(partPageCount != null && "".equals(partPageCount)){
pageInfo.setPartPageCount(Integer.valueOf(partPageCount));
}else{
pageInfo.setPartPageCount(10);
}
// 返回PageInfo对象
return pageInfo;
}
}
3、那么在数据库访问操作类(DAO)怎么运用呢?看一下代码:
public List<BulletinEntity> getBulletinEntityByTitle(String title,PageInfo pageInfo){
//实例化list对象
List<BulletinEntity> list = new ArrayList<BulletinEntity>();
//获得数据库连接得到conn对象
Connection conn = DBUtil.getConnection();
//声明一个sql预编译器语句对象
PreparedStatement ps = null;
//获得构造sql查询字段
String selectContent = "bu.id,bu.title,bu.content,bu.createTime,bu.userId,us.userName";
//获得查询数据表的关联关系
String fromContent = "Bulletin bu left join UserInfo us on bu.userId=us.id";
//初始化定义一个sql语句查询条件为null
String whereContent = null;
//条件数组参数对象
Object[] paramArray = null;
if (title != null && title.length() > 0) {
whereContent = "title like ?";
paramArray = new Object[1];
paramArray[0] = "%" + title + "%";
}
//定义排序对象
String orderByContent = "bu.id desc";
//调用PageSearchUtil分页工具类并返回结果集对象
ResultSet rs = PageSearchUtil.getPageResultSet(conn, ps, pageInfo,
selectContent, fromContent, whereContent, orderByContent, paramArray);
try {
// 处理结果
while (rs != null && rs.next()) {
//读取第一行数据
BulletinEntity bulletin = new BulletinEntity();
//从结果集中通过列名读取当前游标指向行的指定列的数据
bulletin.setId(rs.getInt("id"));
bulletin.setTitle(rs.getString("title"));
bulletin.setContent(rs.getString("content"));
bulletin.setUserId(rs.getInt("userId"));
bulletin.setCreateTime(new Date(rs.getDate("createTime")
.getTime()));
//实例化UserEntity对象
UserEntity userEntity =new UserEntity();
userEntity.setUserName(rs.getString("userName"));
bulletin.setUser(userEntity);
list.add(bulletin);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//关闭数据库访问对象
DBUtil.closeConn(rs, ps, conn);
}
return list;
}
4、那么在Servlet里怎么实现?看下面代码:
/**
*
* serchBulletinByTitle方法概述
* 分页查询公告信息方法
*
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
public void serchBulletinByTitle(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 获取参数
String title = request.getParameter("title");
PageInfo pageInfo = PageSearchUtil.initPageInfo(request);
// 调用业务
BulletinService bulletinService = new BulletinService();
List<BulletinEntity> bList = bulletinService
.getBulletinEntityByTitle(title,pageInfo);
request.setAttribute("bList", bList);
request.setAttribute("pageInfo",pageInfo);
request.setAttribute("title", title);
request.getRequestDispatcher("../admin/bulletin/serchBulletin.jsp?title=").forward(request, response);
}
5、写一个自定义标签类
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import com.zuxia.qlzx_shopping.entity.PageInfo;
/**
* 自定义标签实现的类
* @author ycglei886
* 创建时间:2010/5/20
* @version 1.0
*
*/
public class PageSearchTag extends SimpleTagSupport {
private PageInfo pageInfo;
private String requestPath;
@Override
public void doTag() throws JspException, IOException {
this.getJspContext().setAttribute("requestPath", requestPath,
PageContext.REQUEST_SCOPE);
int currentPage = pageInfo.getCurrentPage();
int pageCount = pageInfo.getPageCount();
int partPageCount = pageInfo.getPartPageCount();
// 获取每部分的第一页页数
int firstPageNum = 0;
if (currentPage != 0 && currentPage % partPageCount == 0) {
firstPageNum = currentPage - partPageCount + 1;
} else {
firstPageNum = currentPage - currentPage % partPageCount + 1;
}
// 获取每部分最后一页页数
int lastPageNum = firstPageNum + partPageCount - 1;
if (lastPageNum > pageCount) {
lastPageNum = pageCount;
}
// 将本部分的页数添加到集合中,以便在页面上进行遍历显示
List<Integer> pageNumList = new ArrayList<Integer>();
int i = firstPageNum;
while (i <= lastPageNum) {
pageNumList.add(i);
i++;
}
this.getJspContext().setAttribute("pageNumList", pageNumList,
PageContext.REQUEST_SCOPE);
if (firstPageNum > partPageCount) {
this.getJspContext().setAttribute("beforeArrow", 1,
PageContext.REQUEST_SCOPE);
int beforePartFirstPageNum = firstPageNum - partPageCount;
this.getJspContext().setAttribute("beforePartFirstPageNum",
beforePartFirstPageNum, PageContext.REQUEST_SCOPE);
}
if (currentPage > 1) {
this.getJspContext().setAttribute("beforePage", 1,
PageContext.REQUEST_SCOPE);
}
if (currentPage < pageCount) {
this.getJspContext().setAttribute("afterPage", 1,
PageContext.REQUEST_SCOPE);
}
if (lastPageNum < pageCount) {
this.getJspContext().setAttribute("afterArrow", 1,
PageContext.REQUEST_SCOPE);
int afterPartFirstPageNum = firstPageNum + partPageCount;
this.getJspContext().setAttribute("afterPartFirstPageNum",
afterPartFirstPageNum, PageContext.REQUEST_SCOPE);
}
// 直接将标签间文字输出到页面上
this.getJspBody().invoke(null);
}
public PageInfo getPageInfo() {
return pageInfo;
}
public void setPageInfo(PageInfo pageInfo) {
this.pageInfo = pageInfo;
}
public String getRequestPath() {
return requestPath;
}
public void setRequestPath(String requestPath) {
this.requestPath = requestPath;
}
}
6、写一个共同的分页操作的jsp,得到当前第几页、共几条记录、上一页、下一页、跳转到第几页的链接。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<form
action="${pageContext.request.contextPath}${requestScope.requestPath}"
method="post">
共${requestScope.pageInfo.recordCount}条记录
第${requestScope.pageInfo.currentPage}/${requestScope.pageInfo.pageCount}页
<c:if test="${requestScope.beforeArrow==1}">
<a
href="${requestScope.requestPath}&pageNum=${requestScope.beforePartFirstPageNum}"><<</a>
</c:if>
<c:if test="${requestScope.beforePage==1}">
<a
href="${requestScope.requestPath}&pageNum=${requestScope.pageInfo.currentPage - 1}">上一页</a>
</c:if>
<c:forEach items="${requestScope.pageNumList}" var="pageNum">
<c:if test="${pageNum != requestScope.pageInfo.currentPage}">
<a
href="${requestScope.requestPath}&pageNum=${pageNum}">${pageNum}</a>
</c:if>
<c:if test="${pageNum == requestScope.pageInfo.currentPage}">
${pageNum}
</c:if>
</c:forEach>
<c:if test="${requestScope.afterPage==1}">
<a
href="${requestScope.requestPath}&pageNum=${requestScope.pageInfo.currentPage + 1}">下一页</a>
</c:if>
<c:if test="${requestScope.afterArrow==1}">
<a
href="${requestScope.requestPath}&pageNum=${requestScope.afterPartFirstPageNum}">>></a>
</c:if>
<input type="text" name="pageNum" style="width: 24px">
<input type="submit" value="跳转" style="width: 30px">
</form>
7、写一个自定义标签库:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<!--
关于body-content属性 对于继承TagSupport、BodyTagSupport的标签,如果不含标签间值的时候,
body-content属性的值可以设置为"empty"、"JSP"、"tagdependent"。
empty:空标记,即起始标记和结束标记之间没有内容;
JSP:接受所有JSP语法,如定制的或内部的tag、scripts、静态HTML、脚本元素、JSP指令和动作;
tagdependent:标签体内容直接被写入BodyContent,由自定义标签类来进行处理,而不被JSP容器解释;
对于继承SimpleTagSupport的标签,body-content属性的值可以设置为"empty"、"tagdependent"、"scriptless"。
其中scriptless接受文本、EL和JSP动作。其他请参照前面的注释说明。
rtexprvalue属性设置为true代表标签属性里可以使用scriptlet表达式或者EL表达式
-->
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>2.1</jsp-version>
<short-name>lei</short-name>
<tag>
<name>pageSearchTag</name>
<tag-class>com.zuxia.qlzx_shopping.tag.PageSearchTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>pageInfo</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>requestPath</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
8、在jsp页面怎么使用呢?
首先通过taglib这个jsp动作将自己写的自定义的标签导入到页面中:
<%@taglib prefix="lei" uri="/WEB-INF/tld/lei.tld"%>
然后调用标签:
<lei:pageSearchTag pageInfo="${requestScope.pageInfo}"
requestPath="${pageContext.request.contextPath}/servlet/BulletinServlet?result=1&title=${param.title}${requestScope.title}">
<jsp:include page="pageSearchCommon.jsp"></jsp:include>
</lei:pageSearchTag>
9、数据分页显示就实现了
注意:一般来讲分页操作即按照指定页面最大显示数据量和当前要显示第几页这样两个条件进行数据库查询。查询的时候不是把数据全部查询出来然后再进行筛选,而是根据查询条件对数据进行一次性的筛选。