经一同行朋友介绍,目前正在学习由国内某开源团队开源的J2EE MVC框架EasyJWEB(等同于大家熟悉的struts)。EasyJWEB中提供了优秀的查询方式,是一种完全基于面向对象并支持AJAX动态的查询方式。不需要开发人员过多的去熟悉JDBC查询式的SQL语句就能随意的查询,并且提供了更大的查询弹性。
下面我以项目中应用到EasyJWEB的一个CRUD为例,演示一下EasyJWEB是如何进行数据查询的,并且在Views层使用到了EasyJWEB提供的AJAX动态来加载查询到的数据,
首先Views层中新建一个HTML模板文件名为list.html,内容如下:

代码:
<
link
href
="/include/css.css"
rel
="stylesheet"
type
="text/css"
>
<
script
type
='text/javascript'
src
='/ejf/easyajax/prototype.js'
></
script
>
<
script
type
='text/javascript'
src
='/ejf/easyajax/engine.js'
></
script
>
<
script
type
='text/javascript'
src
='include/easyjweb-util.js'
></
script
>

<
script
type
="text/javascript"
>
...
F=new FORM("customer.ejf","ListForm",true);

gotoPage=function(n)...{
$("currentPage").value=n;
quickSearchCustomer();
}
</
script
>

<
span
>
<
table
width
="100%"
height
="97%"
align
="center"
cellspacing
="0"
style
="margin-top:4px;"
>
<
tr
>
<
td
height
="20"
bgcolor
="#FFFFFF"
class
="tablehead"
>
客户信息查询
</
td
>
</
tr
>
<
tr
>
<
td
valign
="top"
><
table
height
="100%"
cellspacing
="0"
style
=" margin:-2px -4px -2px -4px; width:101%"
>
<
form
id
="ListForm"
name
="ListForm"
method
="post"
action
="customer.ejf"
>
<
input
type
="hidden"
name
="easyJWebCommand"
value
="quickSearchList"
/>
<
input
type
="hidden"
name
="id"
value
="$!id"
/>
<
input
type
="hidden"
name
="mulitId"
value
="$!mulitId"
/>
<
input
type
="hidden"
name
="currentPage"
id
="currentPage"
value
="$!currentPage"
/>
<
input
name
="orderBy"
type
="hidden"
value
="$!orderBy"
/>
<
input
name
="orderType"
type
="hidden"
value
="$!orderType"
/>
<
tr
class
="tablehead3"
>
<
td
height
="25"
>
电话号码:
<
input
name
="customerTel"
type
="text"
class
="form_text"
id
="customerTel"
onKeyUp
="if(this.value.length>1)quickSearchCustomer();"
/></
td
>
<
td
height
="25"
>
名 称:
<
input
name
="customerTitle"
type
="text"
class
="form_text"
id
="customerTitle"
onKeyUp
="if(this.value.length>0)quickSearchCustomer();"
/></
td
>
</
tr
>
<
tr
class
="tablehead3"
>
<
td
height
="25"
>
编 号:
<
input
name
="customerSn"
type
="text"
class
="form_text"
id
="customer-sn"
onKeyUp
="if(this.value.length>1)quickSearchCustomer();"
/></
td
>
<
td
height
="25"
>
地 址:
<
input
name
="customerAddress"
type
="text"
class
="form_text"
id
="customer-address"
onKeyUp
="if(this.value.length>1)quickSearchCustomer();"
/>
<
input
name
="add"
type
="button"
id
="add"
value
="添加"
onClick
="loadPage('customer.ejf?cmd=add');"
class
="button"
/>
</
td
>
</
tr
>
</
form
>
<
tr
align
="center"
>
<
td
height
="20"
colspan
="2"
valign
="top"
class
="tablehead"
>
查询结果
</
td
>
</
tr
>
<
tr
align
="center"
>
<
td
colspan
="2"
valign
="top"
class
="tablehead2"
><
div
id
="mainTable"
class
="tablehead3"
style
="height:100%;overflow:auto;"
>
</
div
></
td
>
</
tr
>
<
tr
align
="center"
>
<
td
height
="25"
colspan
="2"
valign
="top"
class
="tablehead"
><
span
id
="pageInfo"
></
span
></
td
>
</
tr
>
</
table
></
td
>
</
tr
>
</
table
>

<
script
>
...

quickSearchCustomer=function()...{
EasyAjaxUtil.ajaxSubmit("ListForm","mainTable");
}
quickSearchCustomer();
</
script
>
</
span
>
List.html页面就是用于显示查询得到的数据列表,其中重点看一下这句JS:EasyAjaxUtil.ajaxSubmit("ListForm","mainTable");EasyAjaxUtil支持通过ajax的方式提交表单的内容,其中ajaxSubmit方法就是用来实现表单以Ajax局部刷新的方式提交的功能。使用方法EasyAjaxUtil.ajaxSubmit(formName,targetId)。
来提交表单ListForm,并把表单执行的结果返回到页面上ID为mainTable中。
再来看一下这两句:
<
form
id
="ListForm"
name
="ListForm"
method
="post"
action
="customer.ejf"
>
<
input
type
="hidden"
name
="easyJWebCommand"
value
="quickSearchList"
/>
意思也就是说当页面以AJAX的方式提交表单时,会去后台查找到CustomerAction这个类并执行方法doQuickSearchList()。
注意:需要使用到EasyJWEB提供的AJAX支持的页面,都必须在页面中先引入如下JS文件:
<
script
type
='text/javascript'
src
='/ejf/easyajax/prototype.js'
></
script
>
<
script
type
='text/javascript'
src
='/ejf/easyajax/engine.js'
></
script
>
<
script
type
='text/javascript'
src
='include/easyjweb-util.js'
></
script
>
现在再来看一下后台JAVA部分的代码,首先看一下CustomerAction部份的代码:
package
com.easyjf.microerp.mvc;

import
java.io.Serializable;
import
java.util.HashMap;
import
java.util.List;
import
java.util.Map;

import
com.easyjf.container.annonation.Inject;
import
com.easyjf.core.support.query.IQueryObject;
import
com.easyjf.core.support.query.QueryObject;
import
com.easyjf.microerp.domain.Customer;
import
com.easyjf.microerp.query.CustomerQueryObject;
import
com.easyjf.microerp.service.ICustomerService;
import
com.easyjf.web.Module;
import
com.easyjf.web.Page;
import
com.easyjf.web.WebForm;
import
com.easyjf.web.tools.AbstractCrudAction;
import
com.easyjf.web.tools.IPageList;


/** */
/**
* CustomerAction
*
* @author 冷雨
*
*/

public
class
CustomerAction
extends
AbstractCrudAction
...
{
@Inject
private ICustomerService service;


public void setService(ICustomerService service) ...{
this.service = service;
}


public void doQuickSearchList(WebForm form) ...{
this.doList(form);
}


/**//*
* to get the entity class
*/
@SuppressWarnings("unchecked")

protected Class entityClass() ...{
return Customer.class;
}


/**//*
* to find the entity object
*/

protected Object findEntityObject(Serializable id) ...{
return service.getCustomer((Long) id);
}


/**//*
* to get the entity query param queryObject return IPageList
*/

protected IPageList queryEntity(IQueryObject queryObject) ...{
((QueryObject) queryObject).setPageSize(15);
return service.getCustomerBy(queryObject);
}


/**//*
* to remove an entity param id
*/

protected void removeEntity(Serializable id) ...{
service.delCustomer((Long) id);
}


/**//*
* to batch remove the entities param ids
*/

protected void batchRemoveEntity(List<Serializable> ids) ...{
service.batchDelCustomers(ids);
}


/**//*
* save object to entity
*/

protected void saveEntity(Object object) ...{
service.addCustomer((Customer) object);
}


/**//*
* update an entited object
*/

protected void updateEntity(Object object) ...{
service.updateCustomer(((Customer) object).getId(), (Customer) object);
}

@Override

protected Class getQueryClass() ...{
return CustomerQueryObject.class;
}
}
关于EasyJWEB Action的处理、调用这方面的文章在网上以是雪花飘,如果你实是在看不懂,请留言或去他们官网BBS上去发帖求解(
http://www.easyjf.com)。
这里重点说一下两个地方:
方法doQuickSearchList:
public
void
doQuickSearchList(WebForm form)
...
{
this.doList(form);
}
看到没,很简洁的代码,完全没有业务逻辑,在这里只是起到了一个调控流程的作用。也即是去调用执行this.doList(form);请想一想为什么在前台而不直接写成去执行doList方法,而要通过去执行doQuickSearchList()再间接调用doList()方法呢?但是你可能会发现在CustomerAction类中根本找不到方法doList(),因为这个方法是在父类AbstractCrudActionk中,在父类中的doList()方法又去调用了queryEntity()这个抽象方法,这个方法是需要你在子类CustomerAction类中去实现并调用业务逻辑层的。
protected
IPageList queryEntity(IQueryObject queryObject)
...
{
((QueryObject) queryObject).setPageSize(15);
return service.getCustomerBy(queryObject);
}
查询参数queryObject里封装了用户的查询条件,在业务逻辑层中会根据指定的查询参数,查询实体。并返回一个又是封装了分页信息等的IPageList。
2。方法getQueryClass与父类中的方法doList:
在上面说到了查询参数,那EasyJWEB是如何知道我们的查询条件的呢,比如在这里我有一个查询条件是这样的:查询电话号码以132开头,并且地址是在“重庆市”这个范围内的客户。
请重点看一下方法getQueryClass 与父类中的方法doList()
@Override

protected
Class getQueryClass()
...
{
return CustomerQueryObject.class;
}

public
void
doList(WebForm form)
...
{
IPageList pageList = queryEntity((IQueryObject) form
.toPo(getQueryClass()));
CommUtil.saveIPageList2WebForm(pageList, form);
}
如果你手中没有EasyJWEB的源代码(ftp://ftp1.easyjf.com/easyjweb/easyjweb-1.0-m3/easyjweb-1.0-m3.zip)将无法看到doList方法,不过你可以通过上面的链接去下载得到它的源代码,以便能更清楚的明白这里Action的工作方式。首先看一下doList()方法,
form.toPo(getQueryClass())将把form表单中的数据转换成getQueryClass()方法返回的类中,默认为通用查询对象QueryObject.class,由于这里我们在子类CustomerAction中重构了getQueryClass()方法。所以这里将把FORM表单中的数据转换成CustomerQueryObject.class这个类中对应的属性值。
如:在前台FORM表单中有一个input
<
input name
=
"
customerTel
"
type
=
"
text
"
Value
=
"
13251114XXX
"
/>
在后台查询类CustomerQueryObject.class中也有一个对应的属性customerTel,这样通过form.toPo(CustomerQueryObject.class)就能把前台name="customerTel"的值加载到该类中。当然,这里只是为了查询才建立的一个查询对象,如果是只为了得到前台某一个对象的值,采用这种方式是不可取的,而可以改用String strName = (String)form.get("name");这样得到的将是一个字符串。
3。查询核心类CustomerQueryObject.class
package
com.easyjf.microerp.query;

import
com.easyjf.core.support.query.QueryObject;


/** */
/**
* Customer查询对象
*
* @author 冷雨
*
*/

public
class
CustomerQueryObject
extends
QueryObject
...
{
private String customerTel = "";
private String customerTitle = "";
private String customerSn = "";
private String customerAddress = "";

@Override

public void customizeQuery() ...{

if (!"".equals(customerTel)) ...{
this.addQuery("obj.tel", customerTel + "%", "like");
}

if (!"".equals(customerTitle)) ...{
this.addQuery("obj.title", "%" + customerTitle + "%", "like");
}

if (!"".equals(customerSn)) ...{
this.addQuery("obj.sn", customerSn, "=");
}

if (!"".equals(customerAddress)) ...{
this.addQuery("obj.address", "%" + customerAddress + "%", "like");
}
super.customizeQuery();
}


public void setCustomerTel(String customerTel) ...{
this.customerTel = customerTel;
}


public void setCustomerTitle(String customerTitle) ...{
this.customerTitle = customerTitle;
}


public void setCustomerSn(String customerSn) ...{
this.customerSn = customerSn;
}


public void setCustomerAddress(String customerAddress) ...{
this.customerAddress = customerAddress;
}

}
仔细看一下,这个查询类继承了查询基类QueryObject,并且都实现了查询接口IQueryObject,如果在上面的Action中不重构方法getQueryClass(),则默认查询对象就是QueryObject,所以其实这里把查询对象重构为CustomerQueryObject.class,也只是为了一个目的,扩展查询基类并动态加入查询条件,那CustomerQueryObject.class类是如何动态得到查询条件的呢?注意看那几个IF语句,如:
if
(
!
""
.equals(customerTel))
...
{
this.addQuery("obj.tel", customerTel + "%", "like");
}
当前台页面name="customerTel"对象有值时,在form.toPo(CustomerQueryObject.class)后。IF语句这里也就应该有值,所以也就是当通过客户的电话号码进行查询时,向查询对象中加入一个查询条件,加入这个查询条件不用我们掌握很深的SQL语句,完全是基于面向对象的写法。注意这里的第一个参数"obj.tel",tel这就是需进行查询的属性,这个属性并不一定就是数据库中的字段,而是你项目中域对象(DoMain)Customer.java的属性名称,如果要根据客户的电邮进行查询,可样我们改写成这样:
if
(
!
""
.equals(email))
...
{
this.addQuery("obj.email", email+ "%", "like");
}
注意:
一定要先在CustomerQueryObject.class对象中增加一个属性private String email = "";
if (!"".equals(email)) 这里的"email"名称一定要与上面的属性名称一致并且与前台表单中的name名称一致。
this.addQuery("obj.email", email+ "%", "like");这里的第一个email一定要与域对象中属性名称一致,第二个email也就是上面从前台得到的email值。
新增加一个查询属性,都必须有一个对应的set方法。
最后Action层会调用业务逻辑层相应的方法进行查询,并返回包含了分页信息的IPageList,
return
this
.service.getCustomerBy(queryObject);
刚才,在前面提到,在Action中为什么要使用方法doQuickSearchList(),而不直接调用doList(),这是因为由于我们Action继承了父类AbstractCrudAction,继承了该类的Action不需要写返回模板页面,它会自动根据方法名称查找与方法名一致的模板文件,如在这里则会把查询得到的IPageList返回到模板文件quickSearchList.html中,如果我们直接使用方法doList()则会返回到list.html页面中。这样就会全部刷新list这个页面,而不是局部刷新。所以这样不能达到动态加载、局部刷新的AJAX效果。
quickSearchList.html中的代码为:
<
table
width
="100%"
cellspacing
="0"
style
=" margin:-2px -4px -2px -4px; width:100%"
>
<
thead
>
<
tr
align
="center"
class
="tablehead3"
>
<
td
width
="30"
height
="25"
>
序号
</
td
>
<
td
height
="25"
>
客户编号
</
td
>
<
td
height
="25"
>
客户名称
</
td
>
<
td
height
="25"
>
电话
</
td
>
<
td
height
="25"
>
地址
</
td
>
<
td
height
="25"
>
欠空桶
</
td
>
<
td
height
="25"
>
赠机
</
td
>
<
td
height
="25"
>
赠水
</
td
>
<
td
height
="25"
>
赠票
</
td
>
<
td
height
="25"
>
操作
</
td
>
</
tr
>
</
thead
>
<
tbody
>
#foreach( $info in $!list)
<
tr
align
="center"
class
="tablehead3"
>
<
td
height
="25"
>
$!velocityCount
</
td
>
<
td
height
="25"
>
$!info.sn
</
td
>
<
td
height
="25"
>
$!info.title
</
td
>
<
td
height
="25"
>
$!info.tel
</
td
>
<
td
height
="25"
>
$!info.address
</
td
>
<
td
height
="25"
>
$!info.balanceBarrel
</
td
>
<
td
height
="25"
>
$!info.machine
</
td
>
<
td
height
="25"
>
$!info.presentWater.intValue()
</
td
>
<
td
height
="25"
>
$!info.presentTicket.intValue()
</
td
>
<
td
width
="12%"
height
="25"
><
input
type
='button'
onClick
="F.doEdit($!info.id)"
value
='编辑'
class
='button'
>
<
input
type
='button'
onClick
="if(confirm('是否真的要删除?')){F.doDel($!info.id);}"
value
='删除'
class
='button'
></
td
>
</
tr
>
#end
</
tbody
>
</
table
>
<
span
id
="thePageInfo"
style
="display:none;"
>
$!paginationDC
</
span
>

<
script
>
...
$("pageInfo").innerHTML=$("thePageInfo").innerHTML;
$("currentPage").value="$!page";
</
script
>
以下是EasyJWEB从前台到后台一体的查询结构图:
