本文主要说的是关于在展示层一些常用的方案和实现,目录如下:
手工实现分页
- 用eXtremeTable标签实现自动分页
- 用oscache缓存jsp,提高性能
第一.自己实现一个工具类PageBean完成所有分页工作.
本分页实现概览:Struts + hibernate
PageBean负责两部分内容,一是要在页面显示的业务信息,是一个ArrayList;另一个是逻辑控制信息,诸如是否有下一页,上一页等等.
PageBean代码如下:
<!---->
public
class
PageBean {
int
currentPage
=
1
;
//
当前页:Action控制
int
totalPages
=
0
;
//
总页数 :自己运算
int
pageRecorders
=
5
;
//
每页记录数,默认为5,可以在初始化的时候修改
//
总数据数
int
pageStartRow
=
0
;
//
每页的起始数
int
pageEndRow
=
0
;
//
每页显示数据的终止数
boolean
hasNextPage
=
false
;
//
是否有下一页:自己运算
boolean
hasPreviousPage
=
false
;
//
是否有前一页 :自己运算
List objList
=
new
ArrayList();
//
存放欲展示的对象列表
int
totalRows;
//
总记录数,由底层service提供
//
是否有上一页
public
boolean
isHasPreviousPage() {
return
(currentPage
>
1
?
true
:
false
);
}
//
共有多少页,service只提供有多少条记录,多少页数由PageBean自己运算
public
int
getTotalPages() {
return
(totalRows
/
pageRecorders
==
0
?
totalRows
/
pageRecorders:totalRows
/
pageRecorders
+
1
);
}
public
int
getCurrentPage() {
return
currentPage;
}
public
int
getPageEndRow() {
return
pageEndRow;
}
//
是否有下一页
public
boolean
isHasNextPage() {
return
(currentPage
<
this
.getTotalPages()
?
true
:
false
);
}
public
int
getTotalRows() {
return
totalRows;
}
public
int
getPageStartRow() {
return
pageStartRow;
}
public
int
getPageRecorders() {
return
pageRecorders;
}
public
void
setObjList(List objList) {
this
.objList
=
objList;
}
public
void
setHasPreviousPage(
boolean
hasPreviousPage) {
this
.hasPreviousPage
=
hasPreviousPage;
}
public
void
setTotalPages(
int
totalPages) {
this
.totalPages
=
totalPages;
}
public
void
setCurrentPage(
int
currentPage) {
this
.currentPage
=
currentPage;
}
public
void
setPageEndRow(
int
pageEndRow) {
this
.pageEndRow
=
pageEndRow;
}
public
void
setHasNextPage(
boolean
hasNextPage) {
this
.hasNextPage
=
hasNextPage;
}
public
void
setTotalRows(
int
totalRows) {
this
.totalRows
=
totalRows;
}
public
void
setPageStartRow(
int
pageStartRow) {
this
.pageStartRow
=
pageStartRow;
}
public
void
setPageRecorders(
int
pageRecorders) {
this
.pageRecorders
=
pageRecorders;
}
public
List getObjList() {
return
objList;
}
public
PageBean() {}
public
void
description() {
String description
=
"
共有数据数:
"
+
this
.getTotalRows()
+
"
共有页数:
"
+
this
.getTotalPages()
+
"
当前页数为:
"
+
this
.getCurrentPage()
+
"
是否有前一页:
"
+
this
.isHasPreviousPage()
+
"
是否有下一页:
"
+
this
.isHasNextPage()
+
"
开始行数:
"
+
this
.getPageStartRow()
+
"
终止行数:
"
+
this
.getPageEndRow();
System.out.println(description);
}
}
注意,我没有在PageBean里放具体的业务逻辑,诸如getBooks()等,目的很简单,具有通用性,业务逻辑由另一个业务类实现BookService,BookService获得的业务数据都放在了PageBean的ArrayList里.
BookService代码如下:
<!---->
public
class
BookService {
private
static
Logger log
=
Logger.getLogger(BookService.
class
.getName());
public
BookService() {
}
/**
* 获得book列表
*
@param
pageBean PageBean:返回的对象存在pageBean里
*/
public
static
void
getBooks(PageBean pageBean) {
String infoSql
=
"
from Book
"
;
//
获得业务信息
String countSql
=
"
select count(*) from Book
"
;
//
获得控制信息
Session session
=
null
;
try
{
session
=
DBUtil.currentSession();
Query query
=
session.createQuery(infoSql);
query.setFirstResult((pageBean.getCurrentPage()
-
1
)
*
pageBean.getPageRecorders());
//
起始页
query.setMaxResults(pageBean.getPageRecorders());
//
每页记录数
pageBean.getObjList().clear();
for
(Iterator it
=
query.iterate(); it.hasNext(); ) {
Book po
=
(Book)it.next();
BookVo vo
=
new
BookVo();
BeanUtils.copyProperties(vo,po);
pageBean.getObjList().add(vo);
}
session
=
DBUtil.currentSession();
query
=
session.createQuery(countSql);
int
totalRecords
=
((Integer)query.list().get(
0
)).intValue();
pageBean.setTotalRows(totalRecords);
}
catch
(Exception e) {
e.printStackTrace();
System.out.println(
"
数据库异常
"
+
e.toString());
}
finally
{
try
{
if
(
null
!=
session) {
session.close();
}
}
catch
(HibernateException ex) {
ex.printStackTrace();
}
}
}
}
在Struts的Action中调用service,返回一个PageBean给展示页面
Action代码如下:
<!---->
1
public
class
PageListAction
extends
Action {
2
3
public
PageListAction() {}
4
5
ArrayList arrayList
=
new
ArrayList();
6
7
public
ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response)
throws
Exception {
8
String action;
9
PageBean pageBean
=
null
;
10
action
=
request.getParameter(
"
action
"
);
11
if
(action
==
null
||
action.equals(
"
null
"
)) {
//
第一次读取数据
12
pageBean
=
new
PageBean();
13
}
else
{
//
用户选择上一页或者下一页
14
if
(action
==
"
nextPage
"
||
action.equals(
"
nextPage
"
)) {
15
pageBean
=
(PageBean)request.getSession().getAttribute(
"
pageBean
"
);
16
pageBean.setCurrentPage(pageBean.getCurrentPage()
+
1
);
17
}
else
if
(action
==
"
previousPage
"
||
action.equals(
"
previousPage
"
)) {
18
pageBean
=
(PageBean)request.getSession().getAttribute(
"
pageBean
"
);
19
pageBean.setCurrentPage(pageBean.getCurrentPage()
-
1
);
20
}
else
if
(action
==
"
targetPage
"
||
action.equals(
"
targetPage
"
)){
//
指定页
21
pageBean
=
(PageBean)request.getSession().getAttribute(
"
pageBean
"
);
22
System.out.println(
"
targetPage=
"
+
request.getParameter(
"
targetPage
"
));
23
//
这里根据需要可以对填写的目标页进行判断,不要大于最大页数[此处省略]
24
pageBean.setCurrentPage(Integer.parseInt(request.getParameter(
"
targetPage
"
)));
25
}
26
}
27
if
(
null
==
pageBean)
throw
new
Exception(
"
获得PageBean异常
"
);
28
BookService service
=
new
BookService();
29
service.getBooks(pageBean);
30
pageBean.description();
31
request.getSession().setAttribute(
"
pageBean
"
,pageBean);
32
request.setAttribute(
"
result
"
,pageBean.getObjList());
33
return
(mapping.findForward(
"
success
"
));
34
}
35
}
在本Action中判断了可能出现的三种情况:
- 用户选择了"上一页"
- 用户选择了"下一页"
- 用户手工输入了指定的某一页
这里有点感觉不爽的是必须hard coding,但是不这么做感觉暂时也想不出什么好的办法来,毕竟一个PageBean不可能封装所有的细节,如果你有更好的方式请指点哦 :)
好了,到了我们呼之欲出的展示页面了 :)
show.jsp代码如下
<!---->
<%
@ 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=gb2312
"
language
=
"
java
"
%>
<
html:html
locale
="true"
>
<
head
>
<
meta
http-equiv
="Content-Type"
content
="text/html; charset=gb2312"
>
<
script
language
="javaScript"
>
function
go(){
try
{
var
targetValue
=
document.getElementById(
"
targetPage
"
).value;
parseInt(targetValue);
alert(targetValue);
}
catch
(e){
alert(
"
请正确填写目标页
"
);
return
;
}
if
(targetValue
==
null
||
targetValue
==
''){
alert(
"
请填写目标页
"
);
return
;
}
window.location
=
"
//pageList.do?action=targetPage&targetPage=
"
+
targetValue;
}
</
script
>
</
head
>
<
body
>
<
logic:present
name
="pageBean"
>
共有数据总数
<
bean:write
name
="pageBean"
property
="totalRows"
/>
;
共分
<
bean:write
name
="pageBean"
property
="totalPages"
/>
页,
当前是第
<
bean:write
name
="pageBean"
property
="currentPage"
/>
页
</
logic:present
>
<
table
border
="1"
>
<
tr
><
th
>
书名
</
th
><
th
>
作者
</
th
><
th
>
价格
</
th
></
tr
>
<
logic:present
name
="result"
>
<
logic:iterate
id
="book"
name
="result"
>
<
logic:present
name
="book"
>
<
tr
>
<
td
><
bean:write
name
="book"
property
="name"
/></
td
>
<
td
>
<
bean:write
name
="book"
property
="author"
/></
td
>
<
td
><
bean:write
name
="book"
property
="price"
/></
td
>
/
tr
>
</
logic:present
>
</
logic:iterate
>
</
logic:present
>
</
table
>
<
logic:present
name
="pageBean"
>
<
logic:equal
name
="pageBean"
property
="hasNextPage"
value
="true"
>
<
html:link
page
="/pageList.do?action=nextPage"
>
nextPage
</
html:link
>
</
logic:equal
>
<
logic:equal
name
="pageBean"
property
="hasPreviousPage"
value
="true"
>
<
html:link
page
="/pageList.do?action=previousPage"
>
PreviousPage
</
html:link
>
</
logic:equal
>
<
input
type
="text"
name
="targetPage"
id
="targetPage"
/>
<
input
type
="button"
value
="go!"
size
="2"
onclick
="go();"
/>
</
logic:present
>
</
body
>
</
html:html
>
是否有上一页或者下一页,全部根据PageBean里的逻辑值动态判断.
这个页面没什么可说的,你可以根据自己的情况调整就OK了
第二. 用eXtremeTable标签实现自动分页
上面的方案大家已经看出来了,实际上是每一次用户点击一个页面都会查询数据库,这可以算是既是优点也是缺点,优点是数据库不用一次查询出所有的数据,在高数据量的情况下尤其如此,缺点就是和数据库的交互次数有点多了,不过这个完全看你的业务策略了,如果用户大多数情况下就是看没几条的记录,你又何必把全部数据给他取出来呢? 当然,在这里我们就说说一次取出全部数据,然后让标签帮助我们自动分页,终于可以偷懒了,你所要做的仅仅是取出所需要的业务数据而已,其他的就交给eXtremeTable标签来完成就OK了.
eXtremeTable标签的下载,安装和文档请参看
官方网站
<!---->
public
static
List getBooks() {
log.debug(
"
execute getBooks method!
"
);
String infoSql
=
"
from Book
"
;
//
获得业务信息
Session session
=
null