Struts+Oracle分页显示数据的实现
1. Oracle的分页查询功能
数据的分页显示,有多种不同的做法。其中比较好的分页做法应该是每次翻页的时候只从数据库里检索页面大小的块区的数据。这样虽然每次翻页都需要查询数据库,但查询出的记录数很少,网络传输数据量不大,如果使用连接池更可以略过最耗时的建立数据库连接过程。而在数据库端有各种成熟的优化技术用于提高查询速度,比在应用服务器层做缓存有效多了。
如果使用Oracle数据库,就可以很方便地实现分页查询的功能。在Oracle数据库中查询结果的行号使用伪列ROWNUM表示(从1开始)。例如 SELECT * FROM employee WHERE ROWNUM<=10 返回前10条记录。但因为ROWNUM是在查询之后排序之前赋值的,所以查询employee按birthday排序的第100到120条记录应该这么写:
SELECT * FROM (
SELECT my_table.*, ROWNUM as my_rownum FROM (
SELECT name, birthday FROM employee ORDER BY birthday
) my_table WHERE ROWNUM <=120
) WHERE my_rownum>=100
2. 具体实现实例
2.1. 总体介绍
在工程处模块的开发中,有一个地方要把已有的方案信息列出来。现以此为例,说明具体实现的方法。
这个分页显示功能的实现,涉及到以下几个部分:
1. PageData.java: 这个类包含要在一个页面上显示的所有元素,譬如一个包含要显示的记录的ArrayList, 总页数,当前页码,是否有上一页,是否有下一页等。这个类对于不同地方的分页功能实现是可以通用的。
2. SchemeDAO: 这个类用于数据库查询,主要的功能有两个,包括查询当前方案信息的数据库表中总的记录条数,以及查询出要在一个页面中显示的记录。
3. ListSchemeAction.java: 这个类用于页面控制,比如页面跳转。
4. listSchemeContent.jsp: 用来显示的View。显示的是一个PageData对象里的数据
下面逐一简单介绍这几个部分
2.2. PageData.java
这个可以通用的类包含了一个要显示的页面涉及到的所以元素
private int totalRecordCount; 总记录数
private int itemCountPerPage; 每页显示的记录数
private int pageNumber; 页码
private int beginRowNum; 开始的ROWNUM
private int endRowNum; 结束的ROWNUM
private int lastPageNumber; 最后一页的页面,当然也可当做总页数
private int itemCountInPage; 这一页的记录数
private boolean hasPrevious; 是否有上一页
private boolean hasNext; 是否有下一页
private ArrayList itemsList; 要显示的记录的ArrayList
以下是这个类的代码:
**************************************************************************
package com.augurit.digimgz.gcc.common;
import java.util.ArrayList;
public class PageData {
private int totalRecordCount;
private int itemCountPerPage;
private int pageNumber;
private int beginRowNum;
private int endRowNum;
private int lastPageNumber;
private int itemCountInPage;
private boolean hasPrevious;
private boolean hasNext;
private ArrayList itemsList;
//the constructor
public PageData(int totalRecordCount, int itemCountPerPage, int pageNumber) {
setTatalRecordCount(totalRecordCount);
setItemCountPerPage(itemCountPerPage);
setPageNumber(pageNumber);
setRowNums(totalRecordCount, itemCountPerPage, pageNumber);
setLastPageNumber(totalRecordCount, itemCountPerPage);
setItemCountInPage(totalRecordCount, itemCountPerPage, pageNumber);
setHasNext();
setHasPrevious();
}
public void setTatalRecordCount(int totalRecordCount) {
this.totalRecordCount = totalRecordCount;
}
public int getTotalRecordCount() {
return this.totalRecordCount;
}
public int getBeginRowNum() {
return beginRowNum;
}
public int getEndRowNum() {
return endRowNum;
}
public void setRowNums(int totalRecordCount,
int itemCountPerPage, int pageNumber) {
int tempBegin = (pageNumber - 1) * itemCountPerPage + 1;
int tempEnd = pageNumber * itemCountPerPage;
if (totalRecordCount >= tempBegin) {
beginRowNum = tempBegin;
if (totalRecordCount >= tempEnd) {
endRowNum = tempEnd;
} else {
endRowNum = totalRecordCount;
}
} else {
beginRowNum = 0;
endRowNum = 0;
}
}
/**
* @return Returns the itemsList.
*/
public ArrayList getItemsInPage() {
return itemsList;
}
/**
* @param itemsList The itemsList to set.
*/
public void setItemsInPage(ArrayList itemsList) {
this.itemsList = itemsList;
}
/**
* @return Returns the hasNext.
*/
public boolean hasNext() {
return hasNext;
}
/**
* @param hasNext The hasNext to set.
*/
public void setHasNext() {
if (pageNumber < lastPageNumber) {
this.hasNext = true;
} else {
this.hasNext = false;
}
}
/**
* @return Returns the hasPrevious.
*/
public boolean hasPrevious() {
return hasPrevious;
}
/**
* @param hasPrevious The hasPrevious to set.
*/
public void setHasPrevious() {
if (pageNumber == 1) {
this.hasPrevious = false;
} else {
this.hasPrevious = true;
}
}
/**
* @return Returns the itemCountInPage.
*/
public int getItemCountInPage() {
return this.itemCountInPage;
}
/**
* @param itemCountInPage The itemCountInPage to set.
*/
public void setItemCountInPage(int totalRecordCount,
int itemCountPerPage, int pageNumber) {
int temp = pageNumber * itemCountPerPage;
if (temp <= totalRecordCount) {
this.itemCountInPage = itemCountPerPage;
} else {
this.itemCountInPage = (totalRecordCount -
((pageNumber - 1) * itemCountPerPage));
}
}
/**
* @return Returns the itemCountPerPage.
*/
public int getItemCountPerPage() {
return itemCountPerPage;
}
/**
* @param itemCountPerPage The itemCountPerPage to set.
*/
public void setItemCountPerPage(int itemCountPerPage) {
this.itemCountPerPage = itemCountPerPage;
}
/**
* @return Returns the pageNumber.
*/
public int getPageNumber() {
return this.pageNumber;
}
/**
* @param pageNumber The pageNumber to set.
*/
public void setPageNumber(int pageNumber) {
this.pageNumber = pageNumber;
}
/**
* @return Returns the lastPageNumber.
*/
public int getLastPageNumber() {
return lastPageNumber;
}
/**
* @param lastPageNumber The lastPageNumber to set.
*/
public void setLastPageNumber(int totalRecordCount, int itemCountPerPage) {
if (totalRecordCount % itemCountPerPage == 0) {
this.lastPageNumber = totalRecordCount / itemCountPerPage;
} else {
this.lastPageNumber = totalRecordCount / itemCountPerPage + 1;
}
}
}
**************************************************************************
2.3. SchemeDAO.java
这个类主要有两个方法,一个是getRecordCount(),用于查询记录的总数;另一个是getSchemeList(int beginIndex, int endIndex),用于查询两个ROWNUM之间的所有记录,放在一个ArrayList里返回。
以下是这个类的代码:
*************************************************************************
package com.augurit.digimgz.gcc.planPreparing.beans;
import com.augurit.digimgz.gcc.util.DBConnector;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
public class SchemeDAO {
DBConnector connector1 = null;
//connect to the database
Connection connection1 = null;
PreparedStatement prestmt = null;
//SQL statements used in this class
String selectCountSQL = "SELECT COUNT(*) AS Total FROM GCC_SCHEME";
//the constructor
public SchemeDAO() {
}
//method to get the total number of records in the GCC_SCHEME table
public int getRecordCount() {
int total = 0;
//create a DBConnector object
if (connector1 == null) connector1 = new DBConnector();
//connect to the database
if (connection1 == null) connection1 = connector1.getConn();
try {
prestmt = connection1.prepareStatement(this.selectCountSQL);
ResultSet rs = prestmt.executeQuery();
if (rs.next()) total = rs.getInt(1);
} catch (SQLException sqlex) {
System.out.println(sqlex);
}
return total;
}
public ArrayList getSchemeList(int beginIndex, int endIndex) {
ArrayList schemeList=new ArrayList();
if((beginIndex>0)&&(endIndex>=beginIndex)){
//create a DBConnector object
if (connector1 == null) connector1 = new DBConnector();
//connect to the database
if (connection1 == null) connection1 = connector1.getConn();
String sql = "SELECT * FROM (";
sql += " SELECT my_table.*, ROWNUM as my_rownum FROM";
sql += " (SELECT a.SCHEMEID, a.SCHEMENAME, a.SCHEMECLASS, a.SCHEMEDATE, a.DESIGN, a.SCHEMEPRICE, a.PLANID, b.PLANNAME, a.PROJECTID, c.PROJECTNAME";
sql += " FROM GCC_SCHEME a ";
sql += " LEFT JOIN GCC_PLAN b ON b.PLANID = a.PLANID";
sql += " LEFT JOIN GCC_PROJECT c ON c.PROJECTID = a.PROJECTID";
sql += " ) my_table ";
sql += (" WHERE ROWNUM <=" + String.valueOf(endIndex) + ")");
sql += (" WHERE my_rownum>=" + String.valueOf(beginIndex));
try {
prestmt = connection1.prepareStatement(sql);
ResultSet rs = prestmt.executeQuery();
while (rs.next()) {
HashMap mapRecord=new HashMap();
mapRecord.put("SchemeID",rs.getString("SchemeID"));
mapRecord.put("SchemeName",rs.getString("SchemeName"));
mapRecord.put("SchemeClass",rs.getString("SchemeClass"));
mapRecord.put("SchemeDate",rs.getString("SchemeDate"));
mapRecord.put("Design",rs.getString("Design"));
mapRecord.put("SchemePrice",rs.getString("SchemePrice"));
mapRecord.put("PlanName",rs.getString("PlanName"));
mapRecord.put("ProjectName",rs.getString("ProjectName"));
schemeList.add(mapRecord);
}//end of while statement
//close the ResultSet, PreparedStatement, Connection, etc
if (rs != null) rs.close();
if (prestmt != null) prestmt.close();
if (connection1 != null) connection1.close();
connector1.closeConn();
} catch (SQLException sqlex) {
System.out.println(sqlex);
}
}
return schemeList;
}
}
2.4. ListSchemesAction.java
页面控制的类,根据不同的请求,计算出要查询的记录的开始和结束的ROWNUM,然后查询出相应的记录,再forward到listSchemesContent.jsp页面上显示。
具体代码如下:
******************************************************************************
package com.augurit.digimgz.gcc.planPreparing.actions;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.Action;
import com.augurit.digimgz.gcc.common.PageData;
import com.augurit.digimgz.gcc.planPreparing.beans.SchemeDAO;
import java.util.ArrayList;
public class ListSchemesAction extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
//define the count of records to display in one page,
//better method can be used instead of difining here
int itemCountPerPage = 5;
String forwardName = "showSchemePage";
//the number of the page to display, initialize it as 1
int pageNumber = 1;
SchemeDAO schemeDAO = new SchemeDAO();
//get the count of the records in the table GCC_SCHEME
int totalRecordCount = schemeDAO.getRecordCount();
//initialize a PageData object, and get the lastPageNumber
//PageData pageData = new PageData(totalRecordCount, itemCountPerPage, pageNumber);
//int lastPageNumber = pageData.getLastPageNumber();
int lastPageNumber = 1;
if (totalRecordCount % itemCountPerPage == 0) {
lastPageNumber = totalRecordCount / itemCountPerPage;
} else {
lastPageNumber = totalRecordCount / itemCountPerPage + 1;
}
String action = request.getParameter("action").trim();
if (!action.equalsIgnoreCase("start")) {
//get the page number of the data currently displayed
//pageNumber=Integer.parseInt((String)request.getAttribute("pageNumber"));
if (action.equalsIgnoreCase("first")) {
pageNumber = 1;
} else if (action.equalsIgnoreCase("previous")) {
pageNumber = Integer.parseInt(request.getParameter("pageNumber").
trim());
pageNumber--;
} else if (action.equalsIgnoreCase("next")) {
pageNumber = Integer.parseInt(request.getParameter("pageNumber").
trim());
pageNumber++;
} else if (action.equalsIgnoreCase("last")) {
pageNumber = lastPageNumber;
} else {
String toPage=request.getParameter("toPage");
try {
pageNumber = Integer.parseInt(toPage);
if (pageNumber > lastPageNumber) {
pageNumber = lastPageNumber;
} else if (pageNumber <= 0) {
pageNumber = 1;
}
} catch (NumberFormatException e) {
pageNumber = 1;
}
}
} //end of the outer "if" statement
PageData pageData = new PageData(totalRecordCount, itemCountPerPage, pageNumber);
int beginRowNum = pageData.getBeginRowNum();
int endRowNum = pageData.getEndRowNum();
ArrayList schemeList = schemeDAO.getSchemeList(beginRowNum, endRowNum);
pageData.setItemsInPage(schemeList);
request.setAttribute("pageNumber",
String.valueOf(pageData.getPageNumber()));
request.setAttribute("lastPageNumber",
String.valueOf(pageData.getLastPageNumber()));
request.setAttribute("showFirst",
String.valueOf((pageData.getPageNumber() != 1)));
request.setAttribute("hasPrevious", String.valueOf(pageData.hasPrevious()));
request.setAttribute("hasNext", String.valueOf(pageData.hasNext()));
request.setAttribute("showLast",
String.valueOf(pageData.getPageNumber() !=
pageData.getLastPageNumber()));
request.setAttribute("schemeList", pageData.getItemsInPage());
return mapping.findForward(forwardName);
}
}
2.5. listSchemesContent.jsp
数据的显示,使用logic标签,这个就不用多说了。代码如下:
************************************************************************
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ page contentType="text/html; charset=GBK" %>
<%@ include file="/resources/css/style.css"%>
<%
String strPageNumber=(String)request.getAttribute("pageNumber");
%>
<html:html>
<head>
<title>
list the schemes
</title>
<style type="text/css">
<!--
body {
background-image: url(../resources/images/main_bg.jpg);
}
-->
</style>
</head>
<body>
<table width="99%" border="0" align="center" cellpadding="0" cellspacing="1" class="searcolor">
<tr>
<td width="70%" height="21" align="right">请输入查询内容:</td>
<td width="18%"><input name="textfield" type="text" class="textfield" size="20"></td>
<td width="12%"><div align="center"><img src="../resources/images/search.gif" ></div></td>
</tr>
</table>
<table width="99%" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td width="24%"> </td>
<td width="50%"> </td>
<td width="26%" align="center"> </td>
</tr>
</table><form action="<%=request.getContextPath()%>/gcc/ListSchemes.do?action=jump" method="post" name="jumpForm" id="jumpForm">
<table width="99%" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td width="47%" align="left" valign="middle">共<bean:write name="lastPageNumber" />页/当前第<bean:write name="pageNumber" />页
<logic:equal name="showFirst" value="true" ><a href="<%=request.getContextPath()%>/gcc/ListSchemes.do?action=first&pageNumber=<%=strPageNumber%>"><img src='<%=request.getContextPath()%>/resources/images/firstpage.gif' border="0"></a> </logic:equal>
<logic:notEqual name="showFirst" value="true" ><img src='<%=request.getContextPath()%>/resources/images/firstpage.gif' border="0"></logic:notEqual>
<logic:equal name="hasPrevious" value="true"><a href="<%=request.getContextPath()%>/gcc/ListSchemes.do?action=previous&pageNumber=<%=strPageNumber%>"><img src='<%=request.getContextPath()%>/resources/images/prepage.gif' border="0"> </a></logic:equal>
<logic:notEqual name="hasPrevious" value="true"><img src='<%=request.getContextPath()%>/resources/images/prepage.gif' border="0"> </logic:notEqual>
<logic:equal name="hasNext" value="true"><a href="<%=request.getContextPath()%>/gcc/ListSchemes.do?action=next&pageNumber=<%=strPageNumber%>"><img src='<%=request.getContextPath()%>/resources/images/nextpage.gif' border="0"></a></logic:equal>
<logic:notEqual name="hasNext" value="true"><img src='<%=request.getContextPath()%>/resources/images/nextpage.gif' border="0"></logic:notEqual>
<logic:equal name="showLast" value="true" ><a href="<%=request.getContextPath()%>/gcc/ListSchemes.do?action=last&pageNumber=<%=strPageNumber%>"><img src='<%=request.getContextPath()%>/resources/images/lastpage.gif' border="0"></a></logic:equal>
<logic:notEqual name="showLast" value="true" ><img src='<%=request.getContextPath()%>/resources/images/lastpage.gif' border="0"></logic:notEqual>
</td>
<td width="19%" align="left" valign="middle">
转到第
<input name="toPage" type="text" class="INPUT" size="4" style="HEIGHT: 20px; WIDTH: 40px" value=<%=strPageNumber%>>
页 <a href="javascript:document.jumpForm.submit();"><img src='<%=request.getContextPath()%>/resources/images/go.gif' border="0"></a>
</td>
<td width="34%" align="left" valign="middle">
<img src='<%=request.getContextPath()%>/resources/images/add.gif' border="0"> <img src='<%=request.getContextPath()%>/resources/images/modify.gif' border="0"> <img src='<%=request.getContextPath()%>/resources/images/delete.gif' border="0"> <img src='<%=request.getContextPath()%>/resources/images/print.gif' border="0">
</td>
</tr>
</table></form>
<table width="95%" height="3" border="0" cellpadding="0" cellspacing="0">
<tr>
<td></td>
</tr>
</table>
<table width="99%" border="0" cellpadding="0" cellspacing="1" align="center" class="tablecss">
<tr class="tabletopcolor">
<td>方案ID </td>
<td>方案名称</td>
<td>方案类别</td>
<td>定稿日期</td>
<td>设计单位</td>
<td>计算金额</td>
<td>所属计划项目名称</td>
<td>所属工程名称</td>
</tr>
<logic:notEmpty name="schemeList">
<logic:iterate id="schemeRecord" name="schemeList" >
<tr class="tablecellcolor">
<td><bean:write name="schemeRecord" property="SchemeID" /></td>
<td><bean:write name="schemeRecord" property="SchemeName" /></td>
<td><bean:write name="schemeRecord" property="SchemeClass"/></td>
<td><bean:write name="schemeRecord" property="SchemeDate"/></td>
<td><bean:write name="schemeRecord" property="Design"/></td>
<td><bean:write name="schemeRecord" property="SchemePrice"/></td>
<td><bean:write name="schemeRecord" property="PlanName"/></td>
<td><bean:write name="schemeRecord" property="ProjectName"/></td>
</tr>
</logic:iterate>
</logic:notEmpty>
</table>
</body>
</html:html>
*************************************************************************
3. 不完善的地方
这个实现还不是很完善,比如,通用性不高,只有PageData.java能通用;listSchemesContent.jsp不是纯粹使用标签的,等等。这些不足之处期望在进一步使用的过程中慢慢完善。