??????????最近在學(xué)習(xí)ExtJS,發(fā)現(xiàn)其服務(wù)器端是php,這一點(diǎn)對(duì)我們搞java的有點(diǎn)不厚道啊。昨天學(xué)習(xí)了ExtJS的樹,并做了一棵異步更新的樹出來(lái),后臺(tái)的業(yè)務(wù)邏輯及持久層使用JPA+Spring2.5實(shí)現(xiàn),發(fā)下面把步驟貼出來(lái)與大家分享。
首先準(zhǔn)備樹的域模型,下面是一地區(qū)的域模型對(duì)象,
Region.java
的代碼如下:
@Entity

public
?
class
?Region?
{
????@Id
????@GeneratedValue(strategy?
=
?GenerationType.TABLE)
????
private
?Long?id;

????@Field(name
=
"
名稱
"
,validator
=
@Validator(name
=
"
string
"
,value
=
"
min:2;max:50
"
,required
=
true
))
????@Column(length?
=
?
100
)
????
private
?String?name;
????
????@Field(name
=
"
編碼
"
,validator
=
@Validator(name
=
"
string
"
,value
=
"
min:2;max:16
"
,required
=
true
))
????@Column(length?
=
?
100
)
????
private
?String?code;
????@POLoad(name
=
"
parentId
"
)
????@ManyToOne
????
private
?Region?parent;
????@OneToMany(mappedBy?
=
?
"
parent
"
,fetch
=
javax.persistence.FetchType.EAGER)
????
private
?List
<
Region
>
?children?
=
?
new
?java.util.ArrayList
<
Region
>
();

????
public
?Long?getId()?
{
????????
return
?id;
????}
????
public
?
void
?setId(Long?id)?
{
????????
this
.id?
=
?id;
????}
?
Region域模型有parent,也有children,這個(gè)完全是一個(gè)樹的結(jié)構(gòu),如果把樹根砍了話就變成森林了,呵呵這一點(diǎn)跟現(xiàn)實(shí)不一樣。其它都是setter及getter方法,這里就不多說(shuō)了。
?
然后我們就要做針對(duì)這個(gè)地區(qū)信息的添刪除改查了。呵呵,添刪改查我最拿手了,特別是基于EJS(EasyJWeb+JPA+Spring2)構(gòu)架的添刪改查,一個(gè)命令搞定了。這里就不多說(shuō)了,大家可以直接看我前段時(shí)間做的視頻演示(http://www.easyjf.com/blog/html/20080102/1015814.html)。當(dāng)然這個(gè)示例由于是分級(jí)別的,所以生成的添刪改查還要改一改,才支持上下級(jí)管理功能。
?
下面進(jìn)入我們重點(diǎn)部分,如何在頁(yè)面中得到一棵表示地區(qū)的樹。
首先準(zhǔn)備一個(gè)tree.html,內(nèi)容如下:
<html>
<head>
<meta?http-equiv="Content-Type"?content="text/html;?charset=UTF-8"?/>
<title>ExtJS-樹示例</title>
<link?rel="stylesheet"?type="text/css"?href="/plugins/extjs/ext-2.0/resources/css/ext-all.css"?/>
<script?type="text/javascript"?src="plugins/extjs/ext-2.0/adapter/ext/ext-base.js"></script>
<script?type="text/javascript"?src="plugins/extjs/ext-2.0/ext-all.js"></script>
<script?type="text/javascript"?src="tree.js"></script>
</head>
<body>
<div??align="center">
??<p>ExtJS-樹的示例</p>?
</div>
<div?id="tree-div"></div>??
</body>
</html>

?
注意幾個(gè)<script>標(biāo)簽,他們是用來(lái)引入ext的js以及本示例中用到的樹。tree.js的代碼如下:
Ext.BLANK_IMAGE_URL?=?'plugins/extjs/ext-2.0/resources/images/default/s.gif';

Ext.onReady(function()
{?

????var?tree?=?new?Ext.tree.TreePanel(
{???
????????el:"tree-div",???
????????autoScroll:true,
????????animate:true,
????????width:'100px',
????????height:'300px',
????????enableDD:true,
????????containerScroll:?true,?

????????loader:?new?Ext.tree.TreeLoader(
{
????????????dataUrl:'region.ejf?cmd=getRegion'????????????
????????})
????});

????tree.on("click",function(node,event)
{alert(node.id);});

????tree.on('beforeload',function(node)
{????????
????????????tree.loader.dataUrl?=?'region.ejf?cmd=getRegion&id='+(node.id!='root'?node.id:"");
????????});????????

????var?root?=?new?Ext.tree.AsyncTreeNode(
{
????????text:?'地區(qū)信息',
????????draggable:false,
????????id:'root'
????});
????tree.setRootNode(root);
????tree.render();
???????root.expand();
});

?
其實(shí)tree.js的代碼跟ExtJS官方示例中的差別不大,這里就不對(duì)這個(gè)代碼作詳細(xì)的解釋,如果你感興趣的話,可以在后面留言或給我發(fā)電子郵件。如果需要的人多的話,我看能否補(bǔ)充。這里把重點(diǎn)的代碼強(qiáng)調(diào)一下。

loader:?new?Ext.tree.TreeLoader(
{
????????????dataUrl:'region.ejf?cmd=getRegion'????????????
????????})

?
這個(gè)表示通過(guò)region.ejf?cmd=getRegion來(lái)加載樹的數(shù)據(jù)。另外,由于這里使用的是異步加載,所以還需要加下面一句:

tree.on('beforeload',function(node)
{????????
????????????tree.loader.dataUrl?=?'region.ejf?cmd=getRegion&id='+(node.id!='root'?node.id:"");
????????});??

?
那么region.ejf?cmd=getRegion是做什么的呢?就是從數(shù)據(jù)庫(kù)中查詢地區(qū)數(shù)據(jù),并把他轉(zhuǎn)換成JSon格式就OK了。下面是RegionAction中的getRegion方法的代碼,如下所示:
public?Page?doGetRegion(WebForm?form)

????
{
????????String?id=CommUtil.null2String(form.get("id"));????????
????????RegionQuery?query=new?RegionQuery();
????????query.setPageSize(-1);????????
????????if(!"".equals(id))

????????
{
????????Region?parent=this.service.getRegion(new?Long(id));
????????query.setParent(parent);????????
????????}
????????IPageList?pageList=this.service.getRegionBy(query);
????????List<Node>?nodes=new?java.util.ArrayList<Node>();
????????for(int?i=0;i<pageList.getResult().size();i++)

????????
{
????????????Region?region=(Region)pageList.getResult().get(i);
????????????nodes.add(new?Node(region));
????????}????
????????form.addResult("json",AjaxUtil.getJSON(nodes));
????????return?Page.JSONPage;
????}

?
這個(gè)代碼說(shuō)白了,就是根據(jù)客戶端的調(diào)用參數(shù)id值來(lái)加載該id下面的地區(qū)節(jié)點(diǎn)。RegionQuery是一個(gè)地區(qū)查詢類,主要是我不想寫sql或EJBQL,所以就用他了。大家主要看關(guān)鍵的部分,我們?cè)谡{(diào)用service的getRegionBy方法返回的是一個(gè)分頁(yè)的地區(qū)Entity。所以要把這個(gè)地區(qū)Entity轉(zhuǎn)換成與Ext的樹節(jié)點(diǎn)數(shù)據(jù)匹配的方式,因此就有了下面一段代碼:
List<Node>?nodes=new?java.util.ArrayList<Node>();
????????for(int?i=0;i<pageList.getResult().size();i++)

????????
{
????????????Region?region=(Region)pageList.getResult().get(i);
????????????nodes.add(new?Node(region));
????????}????

?
下面我們看看Node這個(gè)類的實(shí)現(xiàn),代碼如下:

private?class?Node?
{
????????private?Region?region;
????????Node(Region?region)

????????
{
????????????this.region=region;
????????}????

????????public?String?getId()?
{????????
????????????return?region.getId().toString();
????????}

????????public?boolean?getLeaf()?
{????????
????????????return?region.getChildren().size()<1;
????????}????????

????????public?String?getText()?
{????????????
????????????return?region.getName();
????????}????
????????public?String?getQtip()

????????
{
????????????return?region.getName();
????????}
????}

?
Node直接放在RegionAction中的,所以是Private的。這個(gè)Node所做的事就是把服務(wù)器的Region這個(gè)域模型適配成Ext的樹狀節(jié)點(diǎn)數(shù)據(jù)。在轉(zhuǎn)換完以后,我們?cè)倏?/span>doGetRegion中的最后兩句代碼,如下所示:
??? form.addResult("json",AjaxUtil.getJSON(nodes));
??? return Page.JSONPage;
第一句代碼是調(diào)用EasyJWeb中的AjaxUtil.getJSON方法直接把nodes這個(gè)List生成JSON數(shù)據(jù);第二句告訴EasyJWeb這個(gè)模板使用的是JSONPage合成模板。呵呵,這個(gè)Page.JSONPage是這幾天才加上去的,之前發(fā)布的m3沒(méi)有,其實(shí)JSONPage模板的內(nèi)容非常簡(jiǎn)單,內(nèi)容如下:
function(){$!json}()
?
完成后,把這個(gè)Web應(yīng)用打成war包,然后直接訪問(wèn)tree.html就能看到這個(gè)樹了,大致如下圖所示:
?
?
?
本示例已經(jīng)被收錄到了EasyJWeb的ajax綜合示例中,里面還有更多的ajax示例,包括一個(gè)表格編輯的應(yīng)用。
EasyJWeb的ajax綜合示例的地址:http://easyjweb.demo.easyjf.com/ajax2/
本示例War包及源碼:ftp://ftp1.easyjf.com/easyjweb/demo/ajax2.war (13M)
本示例的源碼:ftp://ftp1.easyjf.com/easyjweb/demo/ajax2-src.zip (665K)
?注:請(qǐng)下載后將db.properties里password改為你的密碼。
你更希望我在“一起學(xué)ExtJS系列”中跟大家分享哪一方面的內(nèi)容,請(qǐng)留言。