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这个属性进行了注释(这个地方有点奇怪)。用注释绑定数据的代码如下:
- <listbox id="userListBox" mold="paging" model="@{userList}"
- selectedItem="@{selectedUser}">
- <listhead>
- <listheader label="登陆名" sort="auto" />
- <listheader label="中文名" sort="auto" />
- </listhead>
-
- <listitem self="@{each=user}">
- <listcell label="@{user.loginname}" />
- <listcell label="@{user.truename}" />
- </listitem>
- </listbox>
<listbox id="userListBox" mold="paging" model="@{userList}"
selectedItem="@{selectedUser}">
<listhead>
<listheader label="登陆名" sort="auto" />
<listheader label="中文名" sort="auto" />
</listhead>
<listitem self="@{each=user}">
<listcell label="@{user.loginname}" />
<listcell label="@{user.truename}" />
</listitem>
</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方法的代码如下:
- @Override
- public Object get(int index) {
- if(index>=last||index<=last-limit*2){
- this.fullData(index, limit);
- index = 0;
- if(list.size()==0)
- return null;
- else
- return list.get(index);
- }else{
- index = index-(last-limit);
- if(list.size()==0)
- return null;
- else
- return list.get(index);
- }
- }
@Override
public Object get(int index) {
if(index>=last||index<=last-limit*2){
this.fullData(index, limit);
index = 0;
if(list.size()==0)
return null;
else
return list.get(index);
}else{
index = index-(last-limit);
if(list.size()==0)
return null;
else
return list.get(index);
}
}
其中list就是被代理的对象,last就是最后一条记录的序号,limit是每页显示的记录数,fullData是具体执行分页查询的方
法。调用get时传入记录下标index如果大于等于最后一条记录的序号(记录序号是从1开始计数的)那么就向后翻页,如果
index小于等于上一页起始记录序号,那么需要向后翻页,不管是向后翻页还是向前翻页都需要重新查询从index到
index+limit的记录。数据实际上是放在被代理的list中的,要从被代理的list取出数据,那么下标始终是从0开始,所以需
要把这里传入的index转化成0开始的相对下标,下面就是进行转化的代码
- index=index-(last-limit);
index=index-(last-limit);
如果仅仅是对全表数据进行分页显示,这样做完全没有问题,但实际工作往往是需要对数据进行过滤的,也就是说这个分页
的list需要能够保证分页的时候能够执行带过滤条件的分页查询,所以这个分页list中用list来保存hibernate的Criterion对
象,在fullData新建一个criteria把这些Criterion都加进去。下面是fullData的代码:
- public void fullData(int start, int limit) {
- this.last = start + limit;
- this.limit = limit;
- list = new ArrayList(limit);
- SessionFactory sf = (SessionFactory) SpringUtil
- .getBean("sessionFactory");
- Session session = sf.openSession();
- Criteria criteria = session.createCriteria(clazz);
- for (Criterion crierion : listCriteria) {
- criteria.add(crierion);
- }
- criteria.setFirstResult(start);
-
-
- criteria.setMaxResults(start + limit);
- List result = criteria.list();
- if (result != null) {
- Iterator iterator = result.iterator();
- while (iterator.hasNext()) {
- list.add(iterator.next());
- }
- }
-
- session.close();
- }
public void fullData(int start, int limit) {
this.last = start + limit;
this.limit = limit;
list = new ArrayList(limit);
SessionFactory sf = (SessionFactory) SpringUtil
.getBean("sessionFactory");
Session session = sf.openSession();
Criteria criteria = session.createCriteria(clazz);
for (Criterion crierion : listCriteria) {
criteria.add(crierion);
}
criteria.setFirstResult(start);
criteria.setMaxResults(start + limit);
List result = criteria.list();
if (result != null) {
Iterator iterator = result.iterator();
while (iterator.hasNext()) {
list.add(iterator.next());
}
}
session.close();
}
fullData还有一个重要的作用就是初始化被代理的list,这段代码都是hibernate的操作。
下面就把完整的代码贴出来,实体类就不贴附件里有代码。
1、memberList.zul
<?xml version="1.0" encoding="UTF-8"?>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" arg0="./demo"?>
<window id="demo">
<zscript language="javascript" src="memberList.js">
</zscript>
<groupbox id="main" mold="3d" width="100%">
<caption label="View">
<button label="新 增" height="18px"
onClick="newUserWin.doModal();" />
<button label="查 询" height="18px"
onClick="queryUserWin.doModal();" />
<button label="修 改" height="18px"
onClick="updateUserWin.doModal();" />
</caption>
<window id="userWin">
<listbox id="userListBox" mold="paging"
model="@{memberList}" selectedItem="@{selectedMember}">
<listhead>
<listheader label="登陆名" sort="auto" />
<listheader label="中文名" sort="auto" />
<listheader label="注册日期" sort="auto" />
</listhead>
<listitem self="@{each=member}">
<listcell label="@{member.loginname}" />
<listcell label="@{member.truename}" />
<listcell label="@{member.registDate}" />
</listitem>
</listbox>
</window>
</groupbox>
<window id="newUserWin" visible="false" width="480px">
<groupbox mold="3d" width="100%">
<caption label="新增用户"></caption>
<grid>
<rows>
<row>
<label value="帐 号" />
<textbox id="user_loginname"
value="@{member.loginname}" constraint="/.{2,4}/:长度在2,4之间" />
</row>
<row>
<label value="用户名" />
<textbox id="user_truename"
value="@{member.truename}" />
</row>
<row>
<label value="密 码" />
<textbox id="user_password"
value="@{member.password}" />
</row>
</rows>
</grid>
<separator />
<hbox spacing="10px">
<space bar="false" spacing="10px" />
<button label="确 定" onClick="save()" />
<button label="取 消"
onClick="newUserWin.setVisible(false);" />
</hbox>
</groupbox>
</window>
<window id="queryUserWin" visible="false" width="480px">
<groupbox mold="3d" width="100%">
<caption label="查询用户"></caption>
<grid>
<rows>
<row>
<label value="帐 号" />
<textbox id="query_loginname" />
</row>
<row>
<label value="用户名" />
<textbox id="query_truename" />
</row>
</rows>
</grid>
<separator />
<hbox spacing="10px">
<space bar="false" spacing="10px" />
<button label="查 询" onClick="javascript:query();" />
<button label="取 消"
onClick="queryUserWin.setVisible(false);" />
</hbox>
</groupbox>
</window>
<window id="updateUserWin" visible="false" width="480px">
<groupbox mold="3d" width="100%">
<caption label="修改用户"></caption>
<grid>
<rows>
<row>
<label value="帐 号" />
<textbox value="@{selectedUser.loginname}" />
</row>
<row>
<label value="用户名" />
<textbox value="@{selectedUser.truename}" />
</row>
<row>
<label value="密 码" />
<textbox value="@{selectedUser.password}" />
</row>
</rows>
</grid>
<separator />
<hbox spacing="10px">
<space bar="false" spacing="10px" />
<button label="确 定" onClick="javascript:update();" />
<button label="取 消"
onClick="updateUserWin.setVisible(false);" />
</hbox>
</groupbox>
</window>
</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
- var member = new com.liyuan.spore.entity.Member();
- var memberList = memberService.queryAllUser();
- var selectedMember = memberList.get(0);
- function save(){
- if(memberService.userIsExist(member.loginname)){
- memberService.saveNewUser(member);
- newUserWin.setVisible(false);
- }else
- throw new WrongValueException(user_loginname, "账号已存在!");
- }
- function query(){
- var loginname=queryUserWin.getFellow("query_loginname").value;
- var truename=queryUserWin.getFellow("query_truename").value;
- var queryUser = new com.liyuan.spore.entity.Member();
- if(!"".equals(loginname))
- queryUser.setLoginname("%"+loginname+"%");
- if(!"".equals(truename))
- queryUser.setTruename("%"+truename+"%");
- ulist = main.getFellow("userWin").getFellow("userListBox");
- newList = new org.zkoss.zkplus.databind.BindingListModelList(memberService.query(queryUser),true);
- ulist.setModel(newList);
- selectedMember = newList.getElementAt(0);
- queryUserWin.setVisible(false);
- }
- function update(){
- memberService.modify(selectedUser);
- }
var member = new com.liyuan.spore.entity.Member();
var memberList = memberService.queryAllUser();
var selectedMember = memberList.get(0);
function save(){
if(memberService.userIsExist(member.loginname)){
memberService.saveNewUser(member);
newUserWin.setVisible(false);
}else
throw new WrongValueException(user_loginname, "账号已存在!");
}
function query(){
var loginname=queryUserWin.getFellow("query_loginname").value;
var truename=queryUserWin.getFellow("query_truename").value;
var queryUser = new com.liyuan.spore.entity.Member();
if(!"".equals(loginname))
queryUser.setLoginname("%"+loginname+"%");
if(!"".equals(truename))
queryUser.setTruename("%"+truename+"%");
ulist = main.getFellow("userWin").getFellow("userListBox");
newList = new org.zkoss.zkplus.databind.BindingListModelList(memberService.query(queryUser),true);
ulist.setModel(newList);
selectedMember = newList.getElementAt(0);
queryUserWin.setVisible(false);
}
function update(){
memberService.modify(selectedUser);
}
第2行,调用memberService.queryAllUser()获取一个可以分页的list在memberList.zul中又通过注释的方式把数据绑
定到了listbox上。这里的memberService是直接通过org.zkoss.zkplus.spring.DelegatingVariableResolver引用
的spring ApplicationContext中定义的bean。
3、MemberService
- package com.liyuan.spore.zkdemo;
-
- import java.math.BigDecimal;
- import java.util.List;
- import org.hibernate.Criteria;
- import org.hibernate.Query;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import org.hibernate.criterion.Example;
- import org.hibernate.criterion.Projections;
- import org.hibernate.criterion.Restrictions;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.context.annotation.Scope;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Propagation;
- import org.springframework.transaction.annotation.Transactional;
- import com.liyuan.spore.entity.Member;
-
- @Service("memberService")
- @Scope("request")
- public class MemberService {
- private SessionFactory sessionFactory;
-
- @Autowired
- public void setSessionFactory(@Qualifier("sessionFactory")
- SessionFactory sessionFactory) {
- this.sessionFactory = sessionFactory;
- }
-
- @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
- public PagingList queryAllUser() {
- Session session = sessionFactory.getCurrentSession();
- Query query = session.createSQLQuery("select count(*) from T_MEMBER");
- BigDecimal size = (BigDecimal) query.uniqueResult();
- PagingList plist = new PagingList(Member.class, size.intValue());
- plist.fullData(0, 20);
- return plist;
- }
-
- @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
- public boolean userIsExist(String loginname) {
- Session session = sessionFactory.getCurrentSession();
- List list = session.createCriteria(Member.class).add(
- Restrictions.eq("loginname", loginname)).list();
- return list.isEmpty();
-
- }
-
- @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
- public void saveNewUser(Member user) {
- Session session = sessionFactory.getCurrentSession();
- session.save(user);
- }
-
- @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
- public PagingList query(Member user) {
- Session session = sessionFactory.getCurrentSession();
-
- Example example = Example.create(user);
- example.enableLike();
- example.excludeZeroes();
- example.excludeNone();
- Criteria criteria = session.createCriteria(Member.class);
- criteria.setProjection(Projections.rowCount()).add(example);
- Integer size = (Integer) criteria.uniqueResult();
- PagingList plist = new PagingList(Member.class, size.intValue());
- plist.addCriterion(example);
- plist.fullData(0, 20);
- return plist;
-
- }
-
- @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
- public void modify(Member user) {
- Session session = sessionFactory.getCurrentSession();
- session.update(user);
- }
- }
package com.liyuan.spore.zkdemo;
import java.math.BigDecimal;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.liyuan.spore.entity.Member;
@Service("memberService")
@Scope("request")
public class MemberService {
private SessionFactory sessionFactory;
@Autowired
public void setSessionFactory(@Qualifier("sessionFactory")
SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
public PagingList queryAllUser() {
Session session = sessionFactory.getCurrentSession();
Query query = session.createSQLQuery("select count(*) from T_MEMBER");
BigDecimal size = (BigDecimal) query.uniqueResult();
PagingList plist = new PagingList(Member.class, size.intValue());
plist.fullData(0, 20);
return plist;
}
@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
public boolean userIsExist(String loginname) {
Session session = sessionFactory.getCurrentSession();
List list = session.createCriteria(Member.class).add(
Restrictions.eq("loginname", loginname)).list();
return list.isEmpty();
}
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void saveNewUser(Member user) {
Session session = sessionFactory.getCurrentSession();
session.save(user);
}
@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
public PagingList query(Member user) {
Session session = sessionFactory.getCurrentSession();
Example example = Example.create(user);
example.enableLike();
example.excludeZeroes();
example.excludeNone();
Criteria criteria = session.createCriteria(Member.class);
criteria.setProjection(Projections.rowCount()).add(example);
Integer size = (Integer) criteria.uniqueResult();
PagingList plist = new PagingList(Member.class, size.intValue());
plist.addCriterion(example);
plist.fullData(0, 20);
return plist;
}
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void modify(Member user) {
Session session = sessionFactory.getCurrentSession();
session.update(user);
}
}
这段代码没有什么好解释的。
4、PagingList.java
package com.liyuan.spore.zkdemo;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.zkoss.zkplus.spring.SpringUtil;
public class PagingList extends AbstractList implements java.io.Serializable {
private int last;
private int limit;
private int size;
private Class clazz;
private ArrayList list;
private LinkedList<Criterion> listCriteria;
public PagingList(Class entityClass, int theSize) {
size = theSize;
clazz = entityClass;
listCriteria = new LinkedList<Criterion>();
last = 0;
// fullData(0, 20);
}
public void setSize(int size) {
this.size = size;
}
public void addCriterion(Criterion cr) {
listCriteria.add(cr);
}
public void fullData(int start, int limit) {
this.last = start + limit;
this.limit = limit;
list = new ArrayList(limit);
SessionFactory sf = (SessionFactory) SpringUtil
.getBean("sessionFactory");
Session session = sf.openSession();
Criteria criteria = session.createCriteria(clazz);
for (Criterion crierion : listCriteria) {
criteria.add(crierion);
}
criteria.setFirstResult(start);
criteria.setMaxResults(start + limit);
List result = criteria.list();
if (result != null) {
Iterator iterator = result.iterator();
while (iterator.hasNext()) {
list.add(iterator.next());
}
}
session.close();
}
@Override
public Object get(int index) {
if (index >= last || index <= last - limit * 2) {
this.fullData(index, limit);
index = 0;
if (list.size() == 0)
return null;
else
return list.get(index);
} else {
index = index - (last - limit);
if (list.size() == 0)
return null;
else
return list.get(index);
}
}
@Override
public int size() {
return size;
}
@Override
public int hashCode() {
int hashCode = 1;
Iterator i = list.iterator();
while (i.hasNext()) {
Object obj = i.next();
hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
}
return hashCode;
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public Iterator iterator() {
// TODO Auto-generated method stub
return list.iterator();
}
@Override
public ListIterator listIterator() {
return list.listIterator();
}
@Override
public ListIterator listIterator(int index) {
return list.listIterator(index);
}
@Override
public Object remove(int index) {
return list.remove(index);
}
@Override
public Object[] toArray() {
return list.toArray();
}
public void removeCriterions() {
this.listCriteria.clear();
}
}
这段代码就是可以分页的list,和hibernate高度耦合,但是对于单一实体的分页查询是可以重用的。
一些例子,测试了一下与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这个属性进行了注释(这个地方有点奇怪)。用注释绑定数据的代码如下:
- <listbox id="userListBox" mold="paging" model="@{userList}"
- selectedItem="@{selectedUser}">
- <listhead>
- <listheader label="登陆名" sort="auto" />
- <listheader label="中文名" sort="auto" />
- </listhead>
-
- <listitem self="@{each=user}">
- <listcell label="@{user.loginname}" />
- <listcell label="@{user.truename}" />
- </listitem>
- </listbox>
<listbox id="userListBox" mold="paging" model="@{userList}"
selectedItem="@{selectedUser}">
<listhead>
<listheader label="登陆名" sort="auto" />
<listheader label="中文名" sort="auto" />
</listhead>
<listitem self="@{each=user}">
<listcell label="@{user.loginname}" />
<listcell label="@{user.truename}" />
</listitem>
</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方法的代码如下:
- @Override
- public Object get(int index) {
- if(index>=last||index<=last-limit*2){
- this.fullData(index, limit);
- index = 0;
- if(list.size()==0)
- return null;
- else
- return list.get(index);
- }else{
- index = index-(last-limit);
- if(list.size()==0)
- return null;
- else
- return list.get(index);
- }
- }
@Override
public Object get(int index) {
if(index>=last||index<=last-limit*2){
this.fullData(index, limit);
index = 0;
if(list.size()==0)
return null;
else
return list.get(index);
}else{
index = index-(last-limit);
if(list.size()==0)
return null;
else
return list.get(index);
}
}
其中list就是被代理的对象,last就是最后一条记录的序号,limit是每页显示的记录数,fullData是具体执行分页查询的方
法。调用get时传入记录下标index如果大于等于最后一条记录的序号(记录序号是从1开始计数的)那么就向后翻页,如果
index小于等于上一页起始记录序号,那么需要向后翻页,不管是向后翻页还是向前翻页都需要重新查询从index到
index+limit的记录。数据实际上是放在被代理的list中的,要从被代理的list取出数据,那么下标始终是从0开始,所以需
要把这里传入的index转化成0开始的相对下标,下面就是进行转化的代码
- index=index-(last-limit);
index=index-(last-limit);
如果仅仅是对全表数据进行分页显示,这样做完全没有问题,但实际工作往往是需要对数据进行过滤的,也就是说这个分页
的list需要能够保证分页的时候能够执行带过滤条件的分页查询,所以这个分页list中用list来保存hibernate的Criterion对
象,在fullData新建一个criteria把这些Criterion都加进去。下面是fullData的代码:
- public void fullData(int start, int limit) {
- this.last = start + limit;
- this.limit = limit;
- list = new ArrayList(limit);
- SessionFactory sf = (SessionFactory) SpringUtil
- .getBean("sessionFactory");
- Session session = sf.openSession();
- Criteria criteria = session.createCriteria(clazz);
- for (Criterion crierion : listCriteria) {
- criteria.add(crierion);
- }
- criteria.setFirstResult(start);
-
-
- criteria.setMaxResults(start + limit);
- List result = criteria.list();
- if (result != null) {
- Iterator iterator = result.iterator();
- while (iterator.hasNext()) {
- list.add(iterator.next());
- }
- }
-
- session.close();
- }
public void fullData(int start, int limit) {
this.last = start + limit;
this.limit = limit;
list = new ArrayList(limit);
SessionFactory sf = (SessionFactory) SpringUtil
.getBean("sessionFactory");
Session session = sf.openSession();
Criteria criteria = session.createCriteria(clazz);
for (Criterion crierion : listCriteria) {
criteria.add(crierion);
}
criteria.setFirstResult(start);
criteria.setMaxResults(start + limit);
List result = criteria.list();
if (result != null) {
Iterator iterator = result.iterator();
while (iterator.hasNext()) {
list.add(iterator.next());
}
}
session.close();
}
fullData还有一个重要的作用就是初始化被代理的list,这段代码都是hibernate的操作。
下面就把完整的代码贴出来,实体类就不贴附件里有代码。
1、memberList.zul
<?xml version="1.0" encoding="UTF-8"?>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" arg0="./demo"?>
<window id="demo">
<zscript language="javascript" src="memberList.js">
</zscript>
<groupbox id="main" mold="3d" width="100%">
<caption label="View">
<button label="新 增" height="18px"
onClick="newUserWin.doModal();" />
<button label="查 询" height="18px"
onClick="queryUserWin.doModal();" />
<button label="修 改" height="18px"
onClick="updateUserWin.doModal();" />
</caption>
<window id="userWin">
<listbox id="userListBox" mold="paging"
model="@{memberList}" selectedItem="@{selectedMember}">
<listhead>
<listheader label="登陆名" sort="auto" />
<listheader label="中文名" sort="auto" />
<listheader label="注册日期" sort="auto" />
</listhead>
<listitem self="@{each=member}">
<listcell label="@{member.loginname}" />
<listcell label="@{member.truename}" />
<listcell label="@{member.registDate}" />
</listitem>
</listbox>
</window>
</groupbox>
<window id="newUserWin" visible="false" width="480px">
<groupbox mold="3d" width="100%">
<caption label="新增用户"></caption>
<grid>
<rows>
<row>
<label value="帐 号" />
<textbox id="user_loginname"
value="@{member.loginname}" constraint="/.{2,4}/:长度在2,4之间" />
</row>
<row>
<label value="用户名" />
<textbox id="user_truename"
value="@{member.truename}" />
</row>
<row>
<label value="密 码" />
<textbox id="user_password"
value="@{member.password}" />
</row>
</rows>
</grid>
<separator />
<hbox spacing="10px">
<space bar="false" spacing="10px" />
<button label="确 定" onClick="save()" />
<button label="取 消"
onClick="newUserWin.setVisible(false);" />
</hbox>
</groupbox>
</window>
<window id="queryUserWin" visible="false" width="480px">
<groupbox mold="3d" width="100%">
<caption label="查询用户"></caption>
<grid>
<rows>
<row>
<label value="帐 号" />
<textbox id="query_loginname" />
</row>
<row>
<label value="用户名" />
<textbox id="query_truename" />
</row>
</rows>
</grid>
<separator />
<hbox spacing="10px">
<space bar="false" spacing="10px" />
<button label="查 询" onClick="javascript:query();" />
<button label="取 消"
onClick="queryUserWin.setVisible(false);" />
</hbox>
</groupbox>
</window>
<window id="updateUserWin" visible="false" width="480px">
<groupbox mold="3d" width="100%">
<caption label="修改用户"></caption>
<grid>
<rows>
<row>
<label value="帐 号" />
<textbox value="@{selectedUser.loginname}" />
</row>
<row>
<label value="用户名" />
<textbox value="@{selectedUser.truename}" />
</row>
<row>
<label value="密 码" />
<textbox value="@{selectedUser.password}" />
</row>
</rows>
</grid>
<separator />
<hbox spacing="10px">
<space bar="false" spacing="10px" />
<button label="确 定" onClick="javascript:update();" />
<button label="取 消"
onClick="updateUserWin.setVisible(false);" />
</hbox>
</groupbox>
</window>
</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
- var member = new com.liyuan.spore.entity.Member();
- var memberList = memberService.queryAllUser();
- var selectedMember = memberList.get(0);
- function save(){
- if(memberService.userIsExist(member.loginname)){
- memberService.saveNewUser(member);
- newUserWin.setVisible(false);
- }else
- throw new WrongValueException(user_loginname, "账号已存在!");
- }
- function query(){
- var loginname=queryUserWin.getFellow("query_loginname").value;
- var truename=queryUserWin.getFellow("query_truename").value;
- var queryUser = new com.liyuan.spore.entity.Member();
- if(!"".equals(loginname))
- queryUser.setLoginname("%"+loginname+"%");
- if(!"".equals(truename))
- queryUser.setTruename("%"+truename+"%");
- ulist = main.getFellow("userWin").getFellow("userListBox");
- newList = new org.zkoss.zkplus.databind.BindingListModelList(memberService.query(queryUser),true);
- ulist.setModel(newList);
- selectedMember = newList.getElementAt(0);
- queryUserWin.setVisible(false);
- }
- function update(){
- memberService.modify(selectedUser);
- }
var member = new com.liyuan.spore.entity.Member();
var memberList = memberService.queryAllUser();
var selectedMember = memberList.get(0);
function save(){
if(memberService.userIsExist(member.loginname)){
memberService.saveNewUser(member);
newUserWin.setVisible(false);
}else
throw new WrongValueException(user_loginname, "账号已存在!");
}
function query(){
var loginname=queryUserWin.getFellow("query_loginname").value;
var truename=queryUserWin.getFellow("query_truename").value;
var queryUser = new com.liyuan.spore.entity.Member();
if(!"".equals(loginname))
queryUser.setLoginname("%"+loginname+"%");
if(!"".equals(truename))
queryUser.setTruename("%"+truename+"%");
ulist = main.getFellow("userWin").getFellow("userListBox");
newList = new org.zkoss.zkplus.databind.BindingListModelList(memberService.query(queryUser),true);
ulist.setModel(newList);
selectedMember = newList.getElementAt(0);
queryUserWin.setVisible(false);
}
function update(){
memberService.modify(selectedUser);
}
第2行,调用memberService.queryAllUser()获取一个可以分页的list在memberList.zul中又通过注释的方式把数据绑
定到了listbox上。这里的memberService是直接通过org.zkoss.zkplus.spring.DelegatingVariableResolver引用
的spring ApplicationContext中定义的bean。
3、MemberService
- package com.liyuan.spore.zkdemo;
-
- import java.math.BigDecimal;
- import java.util.List;
- import org.hibernate.Criteria;
- import org.hibernate.Query;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import org.hibernate.criterion.Example;
- import org.hibernate.criterion.Projections;
- import org.hibernate.criterion.Restrictions;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.context.annotation.Scope;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Propagation;
- import org.springframework.transaction.annotation.Transactional;
- import com.liyuan.spore.entity.Member;
-
- @Service("memberService")
- @Scope("request")
- public class MemberService {
- private SessionFactory sessionFactory;
-
- @Autowired
- public void setSessionFactory(@Qualifier("sessionFactory")
- SessionFactory sessionFactory) {
- this.sessionFactory = sessionFactory;
- }
-
- @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
- public PagingList queryAllUser() {
- Session session = sessionFactory.getCurrentSession();
- Query query = session.createSQLQuery("select count(*) from T_MEMBER");
- BigDecimal size = (BigDecimal) query.uniqueResult();
- PagingList plist = new PagingList(Member.class, size.intValue());
- plist.fullData(0, 20);
- return plist;
- }
-
- @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
- public boolean userIsExist(String loginname) {
- Session session = sessionFactory.getCurrentSession();
- List list = session.createCriteria(Member.class).add(
- Restrictions.eq("loginname", loginname)).list();
- return list.isEmpty();
-
- }
-
- @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
- public void saveNewUser(Member user) {
- Session session = sessionFactory.getCurrentSession();
- session.save(user);
- }
-
- @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
- public PagingList query(Member user) {
- Session session = sessionFactory.getCurrentSession();
-
- Example example = Example.create(user);
- example.enableLike();
- example.excludeZeroes();
- example.excludeNone();
- Criteria criteria = session.createCriteria(Member.class);
- criteria.setProjection(Projections.rowCount()).add(example);
- Integer size = (Integer) criteria.uniqueResult();
- PagingList plist = new PagingList(Member.class, size.intValue());
- plist.addCriterion(example);
- plist.fullData(0, 20);
- return plist;
-
- }
-
- @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
- public void modify(Member user) {
- Session session = sessionFactory.getCurrentSession();
- session.update(user);
- }
- }
package com.liyuan.spore.zkdemo;
import java.math.BigDecimal;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.liyuan.spore.entity.Member;
@Service("memberService")
@Scope("request")
public class MemberService {
private SessionFactory sessionFactory;
@Autowired
public void setSessionFactory(@Qualifier("sessionFactory")
SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
public PagingList queryAllUser() {
Session session = sessionFactory.getCurrentSession();
Query query = session.createSQLQuery("select count(*) from T_MEMBER");
BigDecimal size = (BigDecimal) query.uniqueResult();
PagingList plist = new PagingList(Member.class, size.intValue());
plist.fullData(0, 20);
return plist;
}
@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
public boolean userIsExist(String loginname) {
Session session = sessionFactory.getCurrentSession();
List list = session.createCriteria(Member.class).add(
Restrictions.eq("loginname", loginname)).list();
return list.isEmpty();
}
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void saveNewUser(Member user) {
Session session = sessionFactory.getCurrentSession();
session.save(user);
}
@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
public PagingList query(Member user) {
Session session = sessionFactory.getCurrentSession();
Example example = Example.create(user);
example.enableLike();
example.excludeZeroes();
example.excludeNone();
Criteria criteria = session.createCriteria(Member.class);
criteria.setProjection(Projections.rowCount()).add(example);
Integer size = (Integer) criteria.uniqueResult();
PagingList plist = new PagingList(Member.class, size.intValue());
plist.addCriterion(example);
plist.fullData(0, 20);
return plist;
}
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void modify(Member user) {
Session session = sessionFactory.getCurrentSession();
session.update(user);
}
}
这段代码没有什么好解释的。
4、PagingList.java
package com.liyuan.spore.zkdemo;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.zkoss.zkplus.spring.SpringUtil;
public class PagingList extends AbstractList implements java.io.Serializable {
private int last;
private int limit;
private int size;
private Class clazz;
private ArrayList list;
private LinkedList<Criterion> listCriteria;
public PagingList(Class entityClass, int theSize) {
size = theSize;
clazz = entityClass;
listCriteria = new LinkedList<Criterion>();
last = 0;
// fullData(0, 20);
}
public void setSize(int size) {
this.size = size;
}
public void addCriterion(Criterion cr) {
listCriteria.add(cr);
}
public void fullData(int start, int limit) {
this.last = start + limit;
this.limit = limit;
list = new ArrayList(limit);
SessionFactory sf = (SessionFactory) SpringUtil
.getBean("sessionFactory");
Session session = sf.openSession();
Criteria criteria = session.createCriteria(clazz);
for (Criterion crierion : listCriteria) {
criteria.add(crierion);
}
criteria.setFirstResult(start);
criteria.setMaxResults(start + limit);
List result = criteria.list();
if (result != null) {
Iterator iterator = result.iterator();
while (iterator.hasNext()) {
list.add(iterator.next());
}
}
session.close();
}
@Override
public Object get(int index) {
if (index >= last || index <= last - limit * 2) {
this.fullData(index, limit);
index = 0;
if (list.size() == 0)
return null;
else
return list.get(index);
} else {
index = index - (last - limit);
if (list.size() == 0)
return null;
else
return list.get(index);
}
}
@Override
public int size() {
return size;
}
@Override
public int hashCode() {
int hashCode = 1;
Iterator i = list.iterator();
while (i.hasNext()) {
Object obj = i.next();
hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
}
return hashCode;
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public Iterator iterator() {
// TODO Auto-generated method stub
return list.iterator();
}
@Override
public ListIterator listIterator() {
return list.listIterator();
}
@Override
public ListIterator listIterator(int index) {
return list.listIterator(index);
}
@Override
public Object remove(int index) {
return list.remove(index);
}
@Override
public Object[] toArray() {
return list.toArray();
}
public void removeCriterions() {
this.listCriteria.clear();
}
}
这段代码就是可以分页的list,和hibernate高度耦合,但是对于单一实体的分页查询是可以重用的。