改进Spring中的分页技术
Spring中有一个PagedListHolder,能够实现分页。
但此类有几个缺点:
1. 使用此类的代码比較繁琐
2. 此类存放的数据源是全部的记录集,即对于记录数为1000条的数据,即使我们仅仅需在一个页面中显示10条记录,每次均须要检索1000条记录出来,而且没有内在的缓存机制
3. 假设需将pageSize, maxLinkedPages这些一般为Session级的变量存于Session中。则必须在Session中存放PagedListHolder,从而导致大容量的数据经常撑满了Session
4. 仅仅是实现了Serializable标识接口。且getPage(), setPage(), setPageSize()方法中直接使用newPageSet (private) 的属性,不利于子类覆盖。
并且,内部类的各个方法耦合极强。
特定方法的使用必须信赖于某个方法或标志变量作为前提条件。
比較理想的情况是。依据每个HttpServletRequest产生一个PagesListHolder,无论记录总数有多少个。每次仅仅检索页面上所显示的记录。但将pageSize, maxLinkedPages设为Session级的效果。
鉴于上述几点,我从Spring原有的PagedListHolder抽取出一些必需的方法名作为接口,并以一个名为RequestPagedListHolder的类实现之。
以下是抽取出来的PagedListHolder接口。
- import java.io.Serializable;
- import java.util.List;
- /**
- *
- * @author Sarkuya
- */
- public interface PagedListHolder extends Serializable {
- public static final int DEFAULT_PAGE_SIZE = 10;
- public static final int DEFAULT_MAX_LINKED_PAGES = 10;
- public void setRecordsSubst(List recordsSubset);
- public void setRealRecordCount(long realRecordCount);
- /**
- * 设置每页应有多少条记录。
- */
- public void setPageSize(int pageSize);
- /**
- * 返回每页共同拥有多少条记录
- */
- public int getPageSize();
- /**
- * 依据pageSize,返回共同拥有多少页
- */
- public int getPageCount();
- /**
- * 返回当前页码。
- * 首页为0
- */
- public int getPage();
- /**
- * 设置当前页码。
- * 首页为0
- */
- public void setPage(int page);
- /**
- * 设置环绕当前页最多能够显示多少链接的页数。
- * 此方法<strong>会</strong>影响getFirstLinkedPage()及getLastLinkedPage()
- */
- public void setMaxLinkedPages(int maxLinkedPages);
- /**
- * 返回环绕当前页最多能够显示多少链接的页数
- */
- public int getMaxLinkedPages();
- /**
- * 返回首页的页码(来源 www.iocblog.net)
- */
- public int getFirstLinkedPage();
- /**
- * 返回最后一页的页码
- */
- public int getLastLinkedPage();
- /**
- * 转至前一页。
- * 假设已经是首页。则停在该页。
- */
- public void previousPage();
- /**
- * 转至下一页。
- * 假设已经是最后一页。则停在该页。
- */
- public void nextPage();
- /**
- * 转至首页。
- */
- public void firstPage();
- /**
- * 转至最后一页
- */
- public void lastPage();
- /**
- * 返回总的记录数
- */
- public long getNrOfElements();
- /**
- * 返回在当前页面上的第一个记录在全部记录(从0開始)中的编号
- */
- public int getFirstElementOnPage();
- /**
- * 返回在当前页面上的最后一个记录在全部记录(从0開始)中的编号
- */
- public int getLastElementOnPage();
- /**
- * 返回在当前页面上的全部记录
- */
- public List getPageList();
- }
setRecordsSubst()用于存放页面显示的记录源,而setRealRecordCount()用于记录满足条件的记录总数。
以下是此接口的实现:
- import java.util.List;
- import javax.servlet.http.HttpServletRequest;
- import org.springframework.web.bind.ServletRequestDataBinder;
- /**
- *
- * @author Sarkuya
- */
- public class RequestPagedListHolder implements PagedListHolder {
- private static int pageSize = DEFAULT_PAGE_SIZE;
- private static int maxLinkedPages = DEFAULT_MAX_LINKED_PAGES;
- private int page = 0;
- private List recordsSubset;
- private long realRecordCount;
- /** Creates a new instance of RequestPagedListHolder */
- public RequestPagedListHolder(HttpServletRequest request, long realRecordCount, PagedListProvider pagedListProvider) {
- setRealRecordCount(realRecordCount);
- ServletRequestDataBinder binder = new ServletRequestDataBinder(this);
- binder.bind(request);
- checkPageNavigation(request);
- setRecordsSubst(pagedListProvider.getRecordsSubset(getPageSize() * getPage(), getPageSize()));
- }
- private void checkPageNavigation(final HttpServletRequest request) {
- String pageNavAction = request.getParameter("pageNavAction");
- if (pageNavAction != null) {
- if (pageNavAction.equals("firstPage")) {
- firstPage();
- } else if (pageNavAction.equals("previousPage")) {
- previousPage();
- } else if (pageNavAction.equals("nextPage")) {
- nextPage();
- } else if (pageNavAction.equals("lastPage")) {
- lastPage();
- }
- }
- }
- public void setRecordsSubst(List recordsSubset) {
- this.recordsSubset = recordsSubset;
- }
- public void setRealRecordCount(long realRecordCount) {
- this.realRecordCount = realRecordCount;
- }
- public void setPageSize(int pageSize) {
- this.pageSize = pageSize;
- }
- public int getPageSize() {
- return pageSize;
- }
- public int getPageCount() {
- float nrOfPages = (float) getNrOfElements() / getPageSize();
- return (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ?
nrOfPages + 1 : nrOfPages);
- }
- public int getPage() {
- if (page >= getPageCount()) {
- page = getPageCount() - 1;
- }
- return page;
- }
- public void setPage(int page) {
- this.page = page;
- }
- public void setMaxLinkedPages(int maxLinkedPages) {
- this.maxLinkedPages = maxLinkedPages;
- }
- public int getMaxLinkedPages() {
- return maxLinkedPages;
- }
- public int getFirstLinkedPage() {
- return Math.max(0, getPage() - (getMaxLinkedPages() / 2));
- }
- public int getLastLinkedPage() {
- return Math.min(getFirstLinkedPage() + getMaxLinkedPages() - 1, getPageCount() - 1);
- }
- public void previousPage() {
- if (!isAtFirstPage()) {
- page--;
- }
- }
- public void nextPage() {
- if (!isAtLastPage()) {
- page++;
- }
- }
- public void firstPage() {
- setPage(0);
- }
- public void lastPage() {
- setPage(getPageCount() - 1);
- }
- public long getNrOfElements() {
- return realRecordCount;
- }
- public int getFirstElementOnPage() {
- return (getPageSize() * getPage());
- }
- public int getLastElementOnPage() {
- int endIndex = getPageSize() * (getPage() + 1);
- return (endIndex > getNrOfElements() ?
(int)getNrOfElements() : endIndex) - 1;
- }
- public List getPageList() {
- return recordsSubset;
- }
- public boolean isAtFirstPage() {
- return getPage() == 0;
- }
- public boolean isAtLastPage() {
- return getPage() == getPageCount() - 1;
- }
- }
此类有下面特点:
1. pageSize及maxLinkedPages均设为static,这样不因每一个Request而改变。因此用户不必每次显示一个不同的页面后都在UI中又一次设置它们。
2. 在构造函数中包装了全部的使用过程。既简化了该类的使用,也保证了该类被正确初始化。
3. 摒弃了newPageSet变量,降低了各个方法的耦合强度。
4. 在Spring环境中使用了ServletRequestDataBinder。大大简化了各个參数的读取设置过程。
5. 通过回调机制,每次仅仅检索PagedListProvider所提供的记录子集,节约了内存。提高了程序效率。
不难看出。PagedListProvider是个接口,仅仅有一个方法:
- import java.util.List;
- /**
- *
- * @author Sarkuya
- */
- public interface PagedListProvider {
- public List getRecordsSubset(int firstResult, int maxResults);
- }
熟悉Hibernate的用户知道。Hibernate中就是须要这两个參数来实现分页了。假设不使用Hibernate。也没关系。自己实现此接口即可了。(接口实现起来非常easy,但技术细节却非简单。Hibernate用户在此居于明显的优势)(来源 www.iocblog.net)
以上的两个接口。一个实现类。便是经过改进后的分页技术了。以下看其用法。
当用户须要查看带有分面功能的页面时。都会由以下的方法处理:
- private void setPageListForView(HttpServletRequest request, ModelAndView mav, final String tableName) {
- long totalRecordsCount = adminService.getTotalRecordCount(tableName);
- PagedListProvider listProvider = new PagedListProvider() {
- public List getRecordsSubset(int firstResult, int maxResults) {
- return (List) adminService.listTable(tableName, firstResult, maxResults);
- }
- };
- PagedListHolder holder = new RequestPagedListHolder(request, totalRecordsCount, listProvider);
- mav.addObject("pagedRecords", holder);
- }<span style="background-color: rgb(249, 252, 254); font-family: Tahoma, sans-serif;"> </span>
这是一个简单的方法,为RequestPagedListHolder的构造函数准备好实參后。生成一个实例。将其置于页面的一个名为"pagedRecords"的attribute中,以供JSP读取。
adminService.getTotalRecordCount()应不难实现。主要是getRecordsSubset()。
Service层的listTable()例如以下:
- public Collection listTable(String tableName, int firstResult, int maxResults) throws DataAccessException {
- return ((HibernateDao) daoFactory.getDao(tableName)).findByCriteria(firstResult, maxResults);
- }
Dao层代码:
- public Collection findByCriteria(int firstResult, int maxResults) throws DataAccessException {
- DetachedCriteria criteria = DetachedCriteria.forClass(getEntityClass());
- return getHibernateTemplate().findByCriteria(criteria, firstResult, maxResults);
- }
以下看看视图层的使用。
......
<c:forEach items="${pagedRecords.pageList}" var="record">
......
</c:forEach>
......
通过JSTL方便地读出pagedRecords变量的pageList属性。
重抄一下上面的RequestPagedListHolder代码对应部分:
public List getPageList() {
return recordsSubset;
}
返回的正是Hibernate已经为我们检索出来的记录子集。
改进Spring中的分页技术的更多相关文章
- tp中使用分页技术
1 public function showList() { $m_ld = D ( 'guangxi_ld' ); $page = I ( 'get.p', 1 ); // 在配置中获取分页值 $p ...
- Spring 中PageHelper分页插件使用
1.增加pagehelper <!-- mybatis pager --> <dependency> <groupId>com.github.pagehelper& ...
- 关于Spring中的PagedListHolder分页类的分析
PagedListHolder 这个类可以 对分页操作进行封装 文件在:import org.springframework.beans.support.PagedListHolder;下 默认是把查 ...
- Spring框架中的AOP技术----配置文件方式
1.AOP概述 AOP技术即Aspect Oriented Programming的缩写,译为面向切面编程.AOP是OOP的一种延续,利用AOP技术可以对业务逻辑的各个部分进行隔离,从使得业务逻辑各部 ...
- 2018.12.24 Spring中的aop演示(也就是运用aop技术实现代理模式)
Aop的最大意义是:在不改变原来代码的前提下,也不对源代码做任何协议接口要求.而实现了类似插件的方式,来修改源代码,给源代码插入新的执行代码. 1.spring中的aop演示 aop:面向方面编程.不 ...
- Spring 4 官方文档学习 Spring与Java EE技术的集成
本部分覆盖了以下内容: Chapter 28, Remoting and web services using Spring -- 使用Spring进行远程和web服务 Chapter 29, Ent ...
- 第07章-Spring MVC 的高级技术
Spring MVC 的高级技术 1. Spring MVC配置的替代方案 1.1 自定义DispatcherServlet配置 AbstractAnnotationConfigDispatcherS ...
- Spring中如何使用工厂模式实现程序解耦?
目录 1. 啥是耦合.解耦? 2. jdbc程序进行解耦 3.传统dao.service.controller的程序耦合性 4.使用工厂模式实现解耦 5.工厂模式改进 6.结语 @ 1. 啥是耦合.解 ...
- Spring Cloud微服务技术概览
Spring Cloud 是一系列框架的有序集合.它利用 Spring Boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册.配置中心.消息总线.负载均衡.断路器.数据监控等,都 ...
随机推荐
- Word插入页码简单方法
适用于只有一个首页,若是从某一页,需要分节符,从某一页参考Word2007插入两种页码. 插入-页码-页面低端-弹到设计窗口.然后选择页码-设置页码格式-起始页码0-勾选首页不同.
- Word中如何设置图片与段落的间距为半行
第一种: 正文为5号,那么图片或者Viso对象前后空一行,设置字号为7号或者更小,这样设置的间距就是那个7号字的间距,比5号小,看着空白不是那么大. 第二种: Visio对象转为jpg,然后选中图片和 ...
- ios学习流水账2
1.UISearchBar自定义背景.取消按钮中文设置 UISearchBar *seachBar=[[UISearchBar alloc] init]; //修改搜索框背景 seachBar.bac ...
- 路由器漏洞复现分析第三弹:DVRF INTRO题目分析
这个项目的目的是来帮助人们学习X86_64之外其他架构环境,同时还帮助人们探索路由器固件里面的奥秘. 本文通过练习DVRF 中INTRO 部分的题目来学习下MIPS 结构下的各种内存攻击. DVRF: ...
- [转载]java自带线程池和队列详细讲解
FROM:http://blog.csdn.net/sd0902/article/details/8395677 一简介 线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中 ...
- 如何让mysql的自动递增的字段重新从1开始呢?(
数据库表自动递增字段在用过一段时间后清空,还是继续从清空后的自动编号开始.如何才能让这个字段自动从1开始自动递增呢? 下面两个方法偶都试过,很好用: 1 清空所有数据,将自增去掉,存盘,在加上自增,存 ...
- Java 分支结构 - if...else/switch
Java 分支结构 - if...else/switch 顺序结构只能顺序执行,不能进行判断和选择,因此需要分支结构. Java 有两种分支结构: if 语句 switch 语句 if 语句 一个 i ...
- 字体和颜色 Font Color 基础笔记
private void SelectFontAndColor_Load(object sender, EventArgs e) {//窗体加载的时候,初始化字体 //返回所有的字体 FontFami ...
- redis有序集合的一个应用
一.需求 记录用户uid和上次操作时间;并清除5分钟以前的数据.用redis的一个key实现.本打算用hash,但hash类型在过期5分钟以前的数据时颇为麻烦. 二.代码实现 class LastLo ...
- SharedPreferences具体解释(一)——基础知识
我们在开发软件的时候,常须要向用户提供软件參数设置功能,比如我们经常使用的微信,用户能够设置是否同意陌生人加入自己为好友.对于软件配置參数的保存,假设是在window下通常我们会採用ini文件进行保存 ...