现在的位置: 首页 > 综合 > 正文

试着用zk结合hibernaet实现分页查询

2013年08月16日 ⁄ 综合 ⁄ 共 24449字 ⁄ 字号 评论关闭

Zk是一个direct RIA框架。它借用了xul来描述界面,在xul的基础上做了一些扩展,改了一个名字叫zul,不使用

javascript也能做出类似extjs那样的界面来。我一开始觉得只是把javascript替换成xml意义不是太大,因为没有哪个美工

会用zul来做界面,说到底最终界面还是要靠程序员来做的,但是换个角度用 extjs那样的方式来不可以避免把很多逻辑带

入到界面中来,这点zk的zul就要好些,正如zk宣传的那样,不需要java,javascript也能做出RIA的界面来。Zk的另一个好

处就是把ajax前后台通讯部分也用事件的方式封装起来了,这比用extjs好多了,不用自己再搞一套了前后台机制了。
    看完《ZK开发手册》,也跟着做了Zk是一个direct RIA框架。它借用了xul来描述界面,在xul的基础上做了一些扩展,改了一个名字叫zul,不使用

javascript也能做出类似extjs那样的界面来。我一开始觉得只是把javascript替换成xml意义不是太大,因为没有哪个美工

会用zul来做界面,说到底最终界面还是要靠程序员来做的,但是换个角度用 extjs那样的方式来不可以避免把很多逻辑带

入到界面中来,这点zk的zul就要好些,正如zk宣传的那样,不需要java,javascript也能做出RIA的界面来。Zk的另一个好

处就是把ajax前后台通讯部分也用事件的方式封装起来了,这比用extjs好多了,不用自己再搞一套了前后台机制了。
    看完《ZK开发手册》,也跟着做了一些例子,测试了一下与spring、hibernate集成都没有问题。于是,开始尝试用zk

的listbox来做一个结合spring+hibernate的分页数据显示。刚一动手就遇到了麻烦,zul在控件中显示数据的方式主要有三

种:
      1、用EL表达式作为zul标签的属性;
      2、为zul控件指定model;
      3、通过注释进行数据绑定;
为了在数据库查询的时候实现分页,无法使用第1种方式,这种方式listbox是对forEach属性EL表达式中的list进行迭代来

创建 listitem,有多少数据就创建多少个listitem,只有数据条数大于每页显示的数据条数并且listbox的

mold=“paging”时才能分页,而数据库查询每页需要显示多少数据才从数据库中取多少数据,显然第1种方式无法使用。本

来第2种方式是java开发人员最熟悉的方式,几乎和swing一样,但是这种方式需要写一个org.zkoss.zul.ListitemRenderer

的实现类,在这个类里用java代码的方式定义每行的显示样式,这样混用zul和java的来定制界面不是理想的方式。
    那现在只剩下第3种方式,这种方式是现在最为流行注释方式,就是对zul的标记用进行注释来把数据绑定到zul控件

上,这里的注释不是通用的xml注释<!-- ... -->而是一些特殊的zul标记和@开头的特殊属性例如model="@{userList}"表示

用@{userList}对model这个属性进行了注释(这个地方有点奇怪)。用注释绑定数据的代码如下:

Xml代码  收藏代码
  1. <listbox id="userListBox" mold="paging" model="@{userList}"  
  2.                 selectedItem="@{selectedUser}">  
  3.         <listhead>  
  4.             <listheader label="登陆名" sort="auto" />  
  5.             <listheader label="中文名" sort="auto" />  
  6.         </listhead>  
  7.   
  8.         <listitem self="@{each=user}">  
  9.             <listcell label="@{user.loginname}" />  
  10.             <listcell label="@{user.truename}" />  
  11.         </listitem>  
  12. </listbox>  

 用注释方式的数据绑定与直接用EL设置listbox的model属性对listbox来说都是把一个实现了org.zkoss.zul.ListModel

接口的对象赋值给listbox的model属性,唯一的区别就是注释方式还可以给listitem、listcell绑定数据,也就是说数据绑

定可以迭代 model并把每个model中的每个元素都与对应的listcell进行数据绑定,对应使用EL设置model的方式来说做同

样的事情还需要实现org.zkoss.zul.ListitemRenderer接口 。

    把数据和listbos绑定在一起只是第1步,接下要用hibernate实现对数据库进行分页查询了。
    要想分页查询最初的想法是监听listbox的 onPage之类的事件来实现分页,但是很遗憾我没有试验成功,哪位tx搞出来

给我留个言分享一下。注释数据绑定可以自动地把一个 java.util.List构造成ListModel的实现类,上面代码中的userList

就是一个java.util.List,实现分页查询的第二条思路就是从list下手,自己写一个能够使用hibernate实现分页的list,我

正是这样做的。
    当然不是从头开始写一个list的实现类而是采用Proxy模式把通过Hibernate查询出来的list对象包裹一下,首先需要通

过hibernate查询出一个list来作为被代理的对象,这个list保存了本页要显示的数据,如果每页显示20条数据,那么这个

list的长度就是20,接着需要当前页最后一条记录序号保存起来,最后重写get方法,根据最后记录序号、每页显示条数判

断是否需要分页以及是向前翻页还是向后翻页。get方法的代码如下:

Java代码  收藏代码
  1. @Override  
  2. public Object get(int index) {  
  3.         if(index>=last||index<=last-limit*2){  
  4.             this.fullData(index, limit);  
  5.             index = 0;  
  6.             if(list.size()==0)  
  7.                 return null;  
  8.             else  
  9.                 return list.get(index);  
  10.         }else{  
  11.             index = index-(last-limit);  
  12.             if(list.size()==0)  
  13.                 return null;  
  14.             else  
  15.                 return list.get(index);  
  16.         }  
  17. }  

 其中list就是被代理的对象,last就是最后一条记录的序号,limit是每页显示的记录数,fullData是具体执行分页查询的方

法。调用get时传入记录下标index如果大于等于最后一条记录的序号(记录序号是从1开始计数的)那么就向后翻页,如果

index小于等于上一页起始记录序号,那么需要向后翻页,不管是向后翻页还是向前翻页都需要重新查询从index到

index+limit的记录。数据实际上是放在被代理的list中的,要从被代理的list取出数据,那么下标始终是从0开始,所以需

要把这里传入的index转化成0开始的相对下标,下面就是进行转化的代码

Java代码  收藏代码
  1. index=index-(last-limit);  

如果仅仅是对全表数据进行分页显示,这样做完全没有问题,但实际工作往往是需要对数据进行过滤的,也就是说这个分页

的list需要能够保证分页的时候能够执行带过滤条件的分页查询,所以这个分页list中用list来保存hibernate的Criterion对

象,在fullData新建一个criteria把这些Criterion都加进去。下面是fullData的代码:

Java代码  收藏代码
  1. public void fullData(int start, int limit) {  
  2.     this.last = start + limit;  
  3.     this.limit = limit;  
  4.     list = new ArrayList(limit);  
  5.     SessionFactory sf = (SessionFactory) SpringUtil  
  6.             .getBean("sessionFactory");  
  7.     Session session = sf.openSession();  
  8.     Criteria criteria = session.createCriteria(clazz);  
  9.     for (Criterion crierion : listCriteria) {  
  10.         criteria.add(crierion);  
  11.     }  
  12.     criteria.setFirstResult(start);  
  13.   
  14.   
  15.     criteria.setMaxResults(start + limit);  
  16.     List result = criteria.list();  
  17.     if (result != null) {  
  18.         Iterator iterator = result.iterator();  
  19.         while (iterator.hasNext()) {  
  20.             list.add(iterator.next());  
  21.         }  
  22.     }  
  23.   
  24.     session.close();  
  25. }  

 fullData还有一个重要的作用就是初始化被代理的list,这段代码都是hibernate的操作。
      下面就把完整的代码贴出来,实体类就不贴附件里有代码。

   1、memberList.zul

Java代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>  
  3. <?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" arg0="./demo"?>  
  4. <window id="demo">  
  5.       
  6.     <zscript language="javascript" src="memberList.js">  
  7.     </zscript>  
  8.     <groupbox id="main" mold="3d" width="100%">  
  9.         <caption label="View">  
  10.             <button label="新 增" height="18px"  
  11.                 onClick="newUserWin.doModal();" />  
  12.             <button label="查 询" height="18px"  
  13.                 onClick="queryUserWin.doModal();" />  
  14.             <button label="修 改" height="18px"  
  15.                 onClick="updateUserWin.doModal();" />  
  16.         </caption>  
  17.         <window id="userWin">  
  18.             <listbox id="userListBox" mold="paging"  
  19.                 model="@{memberList}" selectedItem="@{selectedMember}">  
  20.                 <listhead>  
  21.                     <listheader label="登陆名" sort="auto" />  
  22.                     <listheader label="中文名" sort="auto" />  
  23.                     <listheader label="注册日期" sort="auto" />  
  24.                 </listhead>  
  25.   
  26.                 <listitem self="@{each=member}">  
  27.                     <listcell label="@{member.loginname}" />  
  28.                     <listcell label="@{member.truename}" />  
  29.                     <listcell label="@{member.registDate}" />  
  30.                 </listitem>  
  31.             </listbox>  
  32.         </window>  
  33.     </groupbox>  
  34.   
  35.     <window id="newUserWin" visible="false" width="480px">  
  36.         <groupbox mold="3d" width="100%">  
  37.             <caption label="新增用户"></caption>  
  38.             <grid>  
  39.                 <rows>  
  40.                     <row>  
  41.                         <label value="帐 号" />  
  42.                         <textbox id="user_loginname"  
  43.                             value="@{member.loginname}" constraint="/.{2,4}/:长度在2,4之间" />  
  44.                     </row>  
  45.                     <row>  
  46.                         <label value="用户名" />  
  47.                         <textbox id="user_truename"  
  48.                             value="@{member.truename}" />  
  49.                     </row>  
  50.                     <row>  
  51.                         <label value="密 码" />  
  52.                         <textbox id="user_password"  
  53.                             value="@{member.password}" />  
  54.                     </row>  
  55.                 </rows>  
  56.             </grid>  
  57.             <separator />  
  58.             <hbox spacing="10px">  
  59.                 <space bar="false" spacing="10px" />  
  60.                 <button label="确 定" onClick="save()" />  
  61.                 <button label="取 消"  
  62.                     onClick="newUserWin.setVisible(false);" />  
  63.             </hbox>  
  64.         </groupbox>  
  65.     </window>  
  66.     <window id="queryUserWin" visible="false" width="480px">  
  67.         <groupbox mold="3d" width="100%">  
  68.             <caption label="查询用户"></caption>  
  69.             <grid>  
  70.                 <rows>  
  71.                     <row>  
  72.                         <label value="帐 号" />  
  73.                         <textbox id="query_loginname" />  
  74.                     </row>  
  75.                     <row>  
  76.                         <label value="用户名" />  
  77.                         <textbox id="query_truename" />  
  78.                     </row>  
  79.                 </rows>  
  80.             </grid>  
  81.             <separator />  
  82.             <hbox spacing="10px">  
  83.                 <space bar="false" spacing="10px" />  
  84.                 <button label="查 询" onClick="javascript:query();" />  
  85.                 <button label="取 消"  
  86.                     onClick="queryUserWin.setVisible(false);" />  
  87.             </hbox>  
  88.         </groupbox>  
  89.     </window>  
  90.     <window id="updateUserWin" visible="false" width="480px">  
  91.         <groupbox mold="3d" width="100%">  
  92.             <caption label="修改用户"></caption>  
  93.             <grid>  
  94.                 <rows>  
  95.                     <row>  
  96.                         <label value="帐 号" />  
  97.                         <textbox value="@{selectedUser.loginname}" />  
  98.                     </row>  
  99.                     <row>  
  100.                         <label value="用户名" />  
  101.                         <textbox value="@{selectedUser.truename}" />  
  102.                     </row>  
  103.                     <row>  
  104.                         <label value="密 码" />  
  105.                         <textbox value="@{selectedUser.password}" />  
  106.                     </row>  
  107.   
  108.                 </rows>  
  109.             </grid>  
  110.             <separator />  
  111.             <hbox spacing="10px">  
  112.                 <space bar="false" spacing="10px" />  
  113.                 <button label="确 定" onClick="javascript:update();" />  
  114.                 <button label="取  消"  
  115.                     onClick="updateUserWin.setVisible(false);" />  
  116.             </hbox>  
  117.         </groupbox>  
  118.     </window>  
  119. </window>  

 注意zul文件开头处理指令variable-resolver指定了org.zkoss.zkplus.spring.DelegatingVariableResolver来处理

EL中的变量,使用这个类可以在EL中直接使用spring定义的bean id,例如

      <variables mService="${memberService}" />

就是引用spring ApplictionContext中id为memberService的bean来定义名为mService的变量。init指令初始化了

org.zkoss.zkplus.databind.AnnotateDataBinderInit,这个类用来就是用来实现数据绑定的,至于是怎么实现的我

也不太清楚,只知道初始化后就可以使用数据绑定了。

   2、memberList.js

Java代码  收藏代码
  1. var member  = new com.liyuan.spore.entity.Member();  
  2. var memberList = memberService.queryAllUser();  
  3. var selectedMember = memberList.get(0);  
  4. function save(){  
  5.   if(memberService.userIsExist(member.loginname)){  
  6.      memberService.saveNewUser(member);  
  7.      newUserWin.setVisible(false);  
  8.   }else  
  9.      throw new WrongValueException(user_loginname, "账号已存在!");  
  10. }  
  11. function query(){  
  12.   var loginname=queryUserWin.getFellow("query_loginname").value;  
  13.   var truename=queryUserWin.getFellow("query_truename").value;  
  14.   var queryUser  = new com.liyuan.spore.entity.Member();  
  15.   if(!"".equals(loginname))  
  16.      queryUser.setLoginname("%"+loginname+"%");  
  17.   if(!"".equals(truename))  
  18.      queryUser.setTruename("%"+truename+"%");  
  19.   ulist = main.getFellow("userWin").getFellow("userListBox");  
  20.   newList = new org.zkoss.zkplus.databind.BindingListModelList(memberService.query(queryUser),true);          
  21.   ulist.setModel(newList);  
  22.   selectedMember = newList.getElementAt(0);  
  23.   queryUserWin.setVisible(false);  
  24. }  
  25. function update(){  
  26.   memberService.modify(selectedUser);  
  27. }  

第2行,调用memberService.queryAllUser()获取一个可以分页的list在memberList.zul中又通过注释的方式把数据绑

定到了listbox上。这里的memberService是直接通过org.zkoss.zkplus.spring.DelegatingVariableResolver引用

的spring ApplicationContext中定义的bean。

   3、MemberService

Java代码  收藏代码
  1. package com.liyuan.spore.zkdemo;  
  2.   
  3. import java.math.BigDecimal;  
  4. import java.util.List;  
  5. import org.hibernate.Criteria;  
  6. import org.hibernate.Query;  
  7. import org.hibernate.Session;  
  8. import org.hibernate.SessionFactory;  
  9. import org.hibernate.criterion.Example;  
  10. import org.hibernate.criterion.Projections;  
  11. import org.hibernate.criterion.Restrictions;  
  12. import org.springframework.beans.factory.annotation.Autowired;  
  13. import org.springframework.beans.factory.annotation.Qualifier;  
  14. import org.springframework.context.annotation.Scope;  
  15. import org.springframework.stereotype.Service;  
  16. import org.springframework.transaction.annotation.Propagation;  
  17. import org.springframework.transaction.annotation.Transactional;  
  18. import com.liyuan.spore.entity.Member;  
  19.   
  20. @Service("memberService")  
  21. @Scope("request")  
  22. public class MemberService {  
  23.     private SessionFactory sessionFactory;  
  24.   
  25.     @Autowired  
  26.     public void setSessionFactory(@Qualifier("sessionFactory")  
  27.     SessionFactory sessionFactory) {  
  28.         this.sessionFactory = sessionFactory;  
  29.     }  
  30.   
  31.     @Transactional(readOnly = true, propagation = Propagation.REQUIRED)  
  32.     public PagingList queryAllUser() {  
  33.         Session session = sessionFactory.getCurrentSession();  
  34.         Query query = session.createSQLQuery("select count(*) from T_MEMBER");  
  35.         BigDecimal size = (BigDecimal) query.uniqueResult();  
  36.         PagingList plist = new PagingList(Member.class, size.intValue());  
  37.         plist.fullData(020);  
  38.         return plist;  
  39.     }  
  40.   
  41.     @Transactional(readOnly = true, propagation = Propagation.REQUIRED)  
  42.     public boolean userIsExist(String loginname) {  
  43.         Session session = sessionFactory.getCurrentSession();  
  44.         List list = session.createCriteria(Member.class).add(  
  45.                 Restrictions.eq("loginname", loginname)).list();  
  46.         return list.isEmpty();  
  47.   
  48.     }  
  49.   
  50.     @Transactional(readOnly = false, propagation = Propagation.REQUIRED)  
  51.     public void saveNewUser(Member user) {  
  52.         Session session = sessionFactory.getCurrentSession();  
  53.         session.save(user);  
  54.     }  
  55.   
  56.     @Transactional(readOnly = true, propagation = Propagation.REQUIRED)  
  57.     public PagingList query(Member user) {  
  58.         Session session = sessionFactory.getCurrentSession();  
  59.   
  60.         Example example = Example.create(user);  
  61.         example.enableLike();  
  62.         example.excludeZeroes();  
  63.         example.excludeNone();  
  64.         Criteria criteria = session.createCriteria(Member.class);  
  65.         criteria.setProjection(Projections.rowCount()).add(example);  
  66.         Integer size = (Integer) criteria.uniqueResult();  
  67.         PagingList plist = new PagingList(Member.class, size.intValue());  
  68.         plist.addCriterion(example);  
  69.         plist.fullData(020);  
  70.         return plist;  
  71.   
  72.     }  
  73.   
  74.     @Transactional(readOnly = false, propagation = Propagation.REQUIRED)  
  75.     public void modify(Member user) {  
  76.         Session session = sessionFactory.getCurrentSession();  
  77.         session.update(user);  
  78.     }  
  79. }  

这段代码没有什么好解释的。

   4、PagingList.java

Java代码  收藏代码
  1. package com.liyuan.spore.zkdemo;  
  2.   
  3. import java.util.AbstractList;  
  4. import java.util.ArrayList;  
  5.   
  6. import java.util.Iterator;  
  7. import java.util.LinkedList;  
  8. import java.util.List;  
  9. import java.util.ListIterator;  
  10.   
  11. import org.hibernate.Criteria;  
  12. import org.hibernate.Session;  
  13. import org.hibernate.SessionFactory;  
  14. import org.hibernate.criterion.Criterion;  
  15. import org.zkoss.zkplus.spring.SpringUtil;  
  16.   
  17. public class PagingList extends AbstractList implements java.io.Serializable {  
  18.   
  19.     private int last;  
  20.     private int limit;  
  21.     private int size;  
  22.     private Class clazz;  
  23.     private ArrayList list;  
  24.   
  25.     private LinkedList<Criterion> listCriteria;  
  26.   
  27.     public PagingList(Class entityClass, int theSize) {  
  28.         size = theSize;  
  29.         clazz = entityClass;  
  30.         listCriteria = new LinkedList<Criterion>();  
  31.         last = 0;  
  32.         // fullData(0, 20);  
  33.     }  
  34.   
  35.     public void setSize(int size) {  
  36.         this.size = size;  
  37.     }  
  38.   
  39.     public void addCriterion(Criterion cr) {  
  40.         listCriteria.add(cr);  
  41.     }  
  42.   
  43.     public void fullData(int start, int limit) {  
  44.         this.last = start + limit;  
  45.         this.limit = limit;  
  46.         list = new ArrayList(limit);  
  47.         SessionFactory sf = (SessionFactory) SpringUtil  
  48.                 .getBean("sessionFactory");  
  49.         Session session = sf.openSession();  
  50.         Criteria criteria = session.createCriteria(clazz);  
  51.         for (Criterion crierion : listCriteria) {  
  52.             criteria.add(crierion);  
  53.         }  
  54.         criteria.setFirstResult(start);  
  55.         criteria.setMaxResults(start + limit);  
  56.         List result = criteria.list();  
  57.         if (result != null) {  
  58.             Iterator iterator = result.iterator();  
  59.             while (iterator.hasNext()) {  
  60.                 list.add(iterator.next());  
  61.             }  
  62.         }  
  63.   
  64.         session.close();  
  65.     }  
  66.   
  67.     @Override  
  68.     public Object get(int index) {  
  69.         if (index >= last || index <= last - limit * 2) {  
  70.             this.fullData(index, limit);  
  71.             index = 0;  
  72.             if (list.size() == 0)  
  73.                 return null;  
  74.             else  
  75.   
  76.                 return list.get(index);  
  77.         } else {  
  78.             index = index - (last - limit);  
  79.             if (list.size() == 0)  
  80.                 return null;  
  81.             else  
  82.                 return list.get(index);  
  83.         }  
  84.     }  
  85.   
  86.     @Override  
  87.     public int size() {  
  88.   
  89.         return size;  
  90.     }  
  91.   
  92.     @Override  
  93.     public int hashCode() {  
  94.         int hashCode = 1;  
  95.         Iterator i = list.iterator();  
  96.         while (i.hasNext()) {  
  97.             Object obj = i.next();  
  98.             hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());  
  99.         }  
  100.         return hashCode;  
  101.     }  
  102.   
  103.     @Override  
  104.     public int indexOf(Object o) {  
  105.   
  106.         return list.indexOf(o);  
  107.     }  
  108.   
  109.     @Override  
  110.     public Iterator iterator() {  
  111.         // TODO Auto-generated method stub  
  112.         return list.iterator();  
  113.     }  
  114.   
  115.     @Override  
  116.     public ListIterator listIterator() {  
  117.   
  118.         return list.listIterator();  
  119.     }  
  120.   
  121.     @Override  
  122.     public ListIterator listIterator(int index) {  
  123.   
  124.         return list.listIterator(index);  
  125.     }  
  126.   
  127.     @Override  
  128.     public Object remove(int index) {  
  129.   
  130.         return list.remove(index);  
  131.     }  
  132.   
  133.     @Override  
  134.     public Object[] toArray() {  
  135.         return list.toArray();  
  136.     }  
  137.   
  138.     public void removeCriterions() {  
  139.         this.listCriteria.clear();  
  140.     }  
  141.   
  142. }  

抱歉!评论已关闭.