`
huangjian325
  • 浏览: 6286 次
  • 性别: Icon_minigender_1
  • 来自: 南宁
文章分类
社区版块
存档分类
最新评论

Struts2框架下的分页实现

阅读更多

信很多童鞋都为着如何写一个灵活的struts2环境下的分页而烦恼过,也相信有的童鞋已经可以用自己写的分页了,但是更相信很多人会遇到这样一个问题:同样的一大串HTML代码,都要在每个要显示分页数据的视图中写一次,而且后台的数据加载也要重复的写很多代码,难道就没有“一次编写,到处运行”的方法吗?有,当然有,在程序的世界里,没有做不到,只有想不到!那为什么指明是struts2呢,因为还有struts1的存在,这两个框架的运行原理稍稍有些不同,所以其分页实现也会有些许不同,但是这都不碍事,理解了实现原理,在任何环境下都可以写出漂亮的程序代码,只是怕有些童鞋不能更好的理解,所以就先说说struts2框架下分页实现(当然现在还有谁用struts1吗?有的话,再和我私下讨论吧)

 

个人也经过漫长的brain storming,写出了这个分页实现,(这个过程真的很漫长,加上追求完美的心态,尝试过很多种方法,最后决定就发布这个了,还有更好的,但先留给自己吧)也上网查过这方面的资料,总是没能找到完整的实现,也不知道这些人是怎么写的,代码就给一点点,鬼知道你的底层代码怎么搞,数据库怎么查询,查询的是什么,返回给插件的数据是什么!!!写了又不教好别人怎么用,最后还是我自己写一个给大家吧,一步一步的教大家怎么用,不算很完美,很多的细节的东西大家可以自己扩展,但是灵活度相对于网上其它的插件,灵活度相对高了一点,不过别担心,有可能,我还是会更新代码的!

 

-------------------------------------Pagination---------------------------------------

 

先附上分页实现类的源码解析,大家先不用知道为什么这么写,先把代码复制进你的小项目里先,后面我会一点一点的解释为什么这样做

我的类的类名为Pagination,你的可以自己按心情决定

属性:get,set方法省了,自己生成,别说不会,不然我敲死你……

private int pageNo;//当前页码

	private int pageSize = 5;//每页记录数(给个默认值)

	private int totalCount;//总记录数

	private int pageCount;//总页数

	private int firstResult;//本页的第一条记录

	private String pageUrl;//页面传过来的URL(具体有什么用等下会解释,上面的应该都很容易理解了吧)

 构造方法

public Pagination(int pageNo, int totalCount, String pageUrl){

	this.pageNo = pageNo;

	this.totalCount = totalCount;

	this.pageUrl = pageUrl;

}

 pageUrl构造器构造实例的时候动态的指定,这样就可以实现灵活度的提高,(不理解?不要紧,跳过,后面还有解释)

计算方法

private void calculate() {

	pageCount = (totalCount + pageSize - 1) / pageSize;

	firstResult = (pageNo - 1) * pageSize;

}

 这个东西用于计算pageCount 和 firstResult 用的

toString方法:(这个就是分页的灵魂了,里边实现了为网页动态加入的HTML代码,这种编程方式可以实现网页代码后台生成机制,其使用价值大家自己发掘吧……)

public String toString(){

calculate();

StringBuffer buffer = new StringBuffer();


buffer.append("<center>");

buffer.append(" 第" + pageNo + "/" + pageCount + "页  ");

buffer.append("");

buffer.append("<a href='"+pageUrl+"&pageNo="+1+"'>首页</a>");

buffer.append("");

buffer.append(pageCount == 0 || pageNo == 1 ? "上一页 " : "<a href='"+pageUrl+"&pageNo="+(pageNo-1)+"'>上一页</a>");

buffer.append("");

for(int i=1;i<=pageCount;i++){

buffer.append("<a href='"+pageUrl+"&pageNo="+i+"'>"+i+"</a>");

buffer.append("");

}

buffer.append("");

buffer.append(pageCount == 0 || pageNo == pageCount ? "下一页 " : "<a href='"+pageUrl+"&pageNo="+(pageNo+1)+"'>下一页</a>");

buffer.append("");

buffer.append("<a href='"+pageUrl+"&pageNo="+pageCount+"'>尾页</a>");

buffer.append("</center>");

return buffer.toString();

}

 好了,分页实现类的代码就到这里了,如果不知道为什么这样做,不着急,往下看吧!

---------------------------查询分页数据----------------------------

public List<T> pageDate(String hql, int pageNo, int pageSize) {

int firstResult = (pageNo - 1) * pageSize;

List<T> list = dao.list(hql, firstResult, pageSize); 

    (这里的dao是我的dao的实现类的引用,其底层的代码也是用session来查询分页数据的)

return list;

}
 

家可以看到,我这个查询分页数据的代码,传入的并不是一贯的firstResult,而是pageNo(当前显示的页码),再在方法里处理pageNo生成firstResult,为什么这样写呢?因为在视图传过来给action的就是一个pageNo,在视图那里就是通过pageNo这个变量来控制显示的。


这段代码你可以写在服务层(我就写在服务层,这样我可以针对不同的模块改变实现方式),也可以写在dao层,这由你的项目架构决定,如果你的项目结构不打算加入服务层, 那就写在dao层吧,查询的时候直接使用dao的实现类查询就OK了


返回的是一个List列表,有些程序员写的分页,返回的是一个经过封装的分页数据类,我不打算说这个方法,因为比较高深一点,怕有些童鞋不理解,而且要写很多代码在这里,不爽……

 


---------------------------Action-----------------------------

action中要有的属性:(action中的属性都要有get\set方法哦,这是常识好不好……(当然,这是在你想在视图中显示或设置后台属性的前提下))

private List<T> list ---- 这里我用了泛型来表示,这个属性就是用来存储分页数据的,用来给前台视图显示的数据,要显示什么数据由你自己写,所以我用了泛型来表示

private int pageNo ---- 该属性就是连接视图与action之间改变显示数据的核心,不理解就算了,先写进action里再说

private Pagination pagination ---- Pagination的引用,其实例化放在执行体中实现

action的执行体中的必要步骤

action的执行体要怎么敲,这个问题也很值得考虑,其中有个细节,struts2的action中并没有默认的传入request和response,所以我们要想从页面的值栈中获取pageNo,就得自己写一个requset来获取当前页面的pageNo

HttpServletRequest request = ServletActionContext.getRequest();

 接下来要从数据库中获取你要查询的记录总数

int totalCount = service.getTotalCount("ProductType","parent_id=null");(这是我的代码,你不用知道我这段代码怎么执行的,你就需要知道这个totalCount变量是存什么的就行了,怎么获取,自己写dao)

 

接下来就要构造pagination了,这个是重点的地方,如果这里写不对,那是实现不了分页的

pagination = new Pagination((Integer)request.getAttribute("pageNo"),totalCount,"manage/productType?action=list&parent_id="+parent_id);

下面来解释上面这段代码:

 

先说第一个传入的参数:(Integer)request.getAttribute("pageNo") ---- 这个东东就是视图的值栈中存储的pageNo,通过传过来的这个变量,再经过pagination的处理,就可以切换数据的显示了

第二个参数totalConnt,就是上面从数据库查询的记录总数

第三个参数就是重点中的重点,这个参数传入的是一个字符串,在开始的时候我说过了,这个东东要写的是这段字符串中写的是页面传过来的URL地址,也就是你的项目中,进入这个action执行体的路径,这么说不理解的话,我举个例子吧:

比如你的action是这样写的:

public class Action extends ActionSupport{

    public String list(){

        这里边写的是查询分页数据的代码

        List list = dao.createQuery(hql).setFirstResult().setMaxResult(); --- 差不多是这样,怎么写是你自己的事

        return "list-success";

     }

}

 

页面访问这个list()的URL是这样的:http://localhost:8080/项目名/list.action

那么你的这第三个参数就写list.action就行了


构造了pagination之后,就是查询分页数据了

list = service.pageDate("from User",pageNo,5);


到此为止,action中的代码就基本写完了,所列举的是核心的部分,其它的根据你自己的业务逻辑,自行编码

 

--------------------------视图---------------------------

后台的代码编写完了,那么大家肯定会问,前台要怎么调用这个分页的实现类?怎么用?大家可以先自己思考一下,后台就上面这些代码,前台要怎么调用,先思考再看答案有助于提高大家的编程思维……


视图层要调用这个分页插件(应该可以说是一个插件吧),就只要写一句代码就OK了——${pagination}

这个EL表达式里写的是你在action里所定义的Pagination的引用名,表达式会默认执行Pagination类的toString方法,而我们的toString里写的就是我们给页面动态生成的HTML代码。怎么样?这下应该明白这个分页的实现原理了吧?如果还不明白,可以过后问我,我会把执行的步骤一步一步的告诉你。

如果你理解了实现原理,那么你就可以自己再写一个更加强大,更加灵活的插件,这里我再提供另一种相对更好的实现方法,toString里的代码,你可以写在一个自定义标签里,但是前提是你要知道自定义标签实现的两种方式,(一种是tag1(第一代),一种是tag2(第二代),后者实现相对简单一些,也用以理解)。不过个人不提倡用自定义标签,原因不多说,自己写一下就知道了,我说再多,要是没写过,也不会体会到其中的好处与坏处。

 

大家可以拿去试试看能不能实现,我也想知道,我所写的东西能不能在其他的程序里正常运行,有什么地方不明白的私聊,如果有哪位童鞋有更好的实现方式,求指导哦

 

分享到:
评论
1 楼 yongtree 2011-10-26  
如果有动态查询,这个参数该如何设置呢?

比如有一个高级查询的form,点击查询,要在翻页的时候,动态查询的参数不能丢失。

相关推荐

Global site tag (gtag.js) - Google Analytics