下面我們先做一個(gè)單表的CRUD,單表的CRUD比較簡(jiǎn)單,實(shí)際開(kāi)發(fā)的時(shí)候不會(huì)涉及到立體數(shù)據(jù)模型的概念,但是我們通過(guò)這個(gè)范例可以將前面單表數(shù)據(jù)模型中的相關(guān)概念,如:DataType, Dataset等有一個(gè)使用上的感覺(jué)。便于繼續(xù)后面知識(shí)點(diǎn)的深入了解,查看這個(gè)單表維護(hù)的基本界面,連接地址:
?http://dorado.bstek.com/sample-center/com.bstek.dorado.sample.data.SimpleCRUD.d
截圖如下:
這是一個(gè)產(chǎn)品列表的維護(hù)界面,屬于典型的CRUD界面?;竟δ苡?
我們查看一下sample-center中該頁(yè)面對(duì)應(yīng)視圖的定義,打com.bstek.dorado.sample.data目錄下的SimpleCRUD.view.xml:
其中我們注意到,本例中我們用到了model節(jié)點(diǎn)(之前的HelloWorld和AJAX范例中都未使用到),本例因?yàn)橐x數(shù)據(jù)模型,所以我們用到了model節(jié)點(diǎn),在model節(jié)點(diǎn)中我們定義了一個(gè)DataType(ProductType),DataType我們?cè)诹Ⅲw數(shù)據(jù)模型中提到過(guò),它的目的是為了描述數(shù)據(jù)實(shí)體的各個(gè)屬性的校驗(yàn)規(guī)則、數(shù)據(jù)類型、顯示格式等等。在這個(gè)DataType中我們定義了其parent屬性,表示這個(gè)DataType是Bean類型,另外我們?cè)O(shè)定其matchType屬性為:com.bstek.dorado.sample.entity.Product,表示Bean的類型為Product。
我們注意到前面瀏覽器中Grid有多個(gè)列,但是在這個(gè)View視圖中我們只定義了一個(gè)productName的PropertyDef對(duì)象,這是因?yàn)槲覀兡J(rèn)設(shè)置了其autoCreatePropertyDefs屬性為true,表示允許DataType自動(dòng)根據(jù)相關(guān)配置(如Product)自動(dòng)的創(chuàng)建屬性,事實(shí)上我們也可以在這個(gè)DataType上單擊右鍵,通過(guò)其GeneratePropertyDef功能自動(dòng)創(chuàng)建相關(guān)的PropertyDefs:
但在一般情況下,如果不需要通過(guò)PropertyDef對(duì)象對(duì)Bean的屬性進(jìn)行特別設(shè)定,我們就可以不用創(chuàng)建,只要保證autoCreatePropertyDefs屬性為true就可以,在本例中我們?cè)O(shè)置了它的required屬性為true,確保該屬性的非空特性:
在頁(yè)面上我們可以看到設(shè)置了required為true之后的productName在Grid的列中就可以看到一個(gè)小箭頭圖標(biāo),另外我們?nèi)绻贕rid中將當(dāng)前列的任何一個(gè)值清空都會(huì)出現(xiàn)一個(gè)紅色的警告圖標(biāo),該圖標(biāo)就是告訴操作人員該列是非空的:
我們?cè)賮?lái)看一下剛才那個(gè)Bean的定義,Product.java:
package com.bstek.dorado.sample.entity;
import java.io.Serializable;
...
import javax.persistence.Table;
@Entity
@Table(name = "PRODUCTS")
public class Product implements Serializable {
private static final long serialVersionUID = -6197184284268376113L;
private long id;
private Category category;
private Long categoryId;
private String productName;
private String quantityPerUnit;
private float unitPrice;
private int unitsInStock;
private int unitsOnOrder;
private int reorderLevel;
private boolean discontinued;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ID")
@SequenceGenerator(name = "SEQ_ID", sequenceName = "SEQ_ID")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
可以看出這個(gè)Bean的定義并沒(méi)有什么提別,其中用到的一些annotation的寫(xiě)法都是Hibernate本身提供的,其中并沒(méi)有Dorado相關(guān)的東西。
定義好DataType之后,我們就還需要定義一個(gè)DataSet,就是我們所說(shuō)的數(shù)據(jù)集,它用來(lái)封裝頁(yè)面的數(shù)據(jù),這個(gè)數(shù)據(jù)集中提供了一個(gè)重要的屬性:dataProvider,如下圖:
dataProvider是Dorado中為DataSet提供數(shù)據(jù)的一個(gè)對(duì)象,我們看它的值是一個(gè)典型的服務(wù)定位表達(dá)式,這個(gè)服務(wù)定位表達(dá)式之前我們學(xué)習(xí)過(guò),我們很容易就可以知道它對(duì)應(yīng)到simpleCRUD的getAll方法,我們找到這個(gè)方法,com.bstek.dorado.sample.data下SimpleCRUD中的getAll方法:
@DataProvider
public Collection<Product> getAll() {
return productDao.getAll();
}
這個(gè)方法非常簡(jiǎn)單,就是通過(guò)一個(gè)DAO獲取所有的產(chǎn)品對(duì)象,其中DAO的實(shí)現(xiàn)完全與Dorado無(wú)關(guān),它完全取決與我們將來(lái)系統(tǒng)的設(shè)計(jì)。范例的DAO只做了一個(gè)簡(jiǎn)單的工作,就是通過(guò)Hibernate獲取一個(gè)產(chǎn)品列表。這個(gè)getAll方法將最終獲得的產(chǎn)品列表直接作為方法調(diào)用的返回參數(shù)。有了這個(gè)數(shù)據(jù)之后DataSet怎么解析這些數(shù)據(jù)呢?我們?cè)賮?lái)看DataSet中的dataType屬性,它的值為:"[ProductType]"。這表示它認(rèn)為自身是一個(gè)以ProductType結(jié)構(gòu)為數(shù)據(jù)實(shí)體的一個(gè)集合。我們可以IDE中單擊這個(gè)屬性,打開(kāi)其屬性編輯器:
其中的base節(jié)點(diǎn)下是Dorado默認(rèn)提供的一些全局的DataType:Boolean,boolean, Short, shorg,Int,int等。另外這兒我們看到的ProductType就是當(dāng)前View中私有的DataType。另外在選擇的時(shí)候需要注意objectType屬性的設(shè)定:
我們可以選擇默認(rèn)的Default也可以選用Collection這種聚合的方式,如果選用聚合,則向?qū)傻谋磉_(dá)式為:"[ProductType]",否則就是:"ProductType"。差別就在與是否有中括號(hào),在本例中我們采用中擴(kuò)號(hào),其原因是因?yàn)榍懊嫖覀儚腏ava的getAll方法返回的是一個(gè)Collection這種聚合類的數(shù)據(jù),如果getAll返回的是單個(gè)Bean,則此處的DataType屬性就可以為沒(méi)有中括號(hào)的:"ProductType"。
現(xiàn)在我們已經(jīng)定義好了數(shù)據(jù)集,以及數(shù)據(jù)集的數(shù)據(jù)來(lái)源和數(shù)據(jù)來(lái)源的結(jié)構(gòu)的定義。接下來(lái)事情就比較簡(jiǎn)單了,無(wú)非就是在頁(yè)面上定義一個(gè)Grid,并將它與數(shù)據(jù)集關(guān)聯(lián)上,便于展示其中的Product數(shù)據(jù)。我們查看DataGrid的dataSet屬性配置:
這樣就完成了DataGrid與數(shù)據(jù)集的綁定。由于目前這個(gè)DataSet中的數(shù)據(jù)結(jié)構(gòu)比較簡(jiǎn)單,就是一個(gè)Collection結(jié)構(gòu)的二維表,Grid不需要做特別多的設(shè)定就可以直接顯示其中的數(shù)據(jù)了。另外我們也注意到雖然瀏覽器中這個(gè)Grid中有很多列,但是在View設(shè)計(jì)器中這個(gè)Grid中卻只有一個(gè)列,這是因?yàn)槲覀冊(cè)O(shè)置了這個(gè)Grid的autoCreateColumn屬性為true,之前我們?cè)O(shè)置過(guò)DataType的autoCreatePropertyDefs為true,這樣DataType可以根據(jù)綁定的POJO自動(dòng)的創(chuàng)建PropertyDef,之后Grid就可以根據(jù)綁定的數(shù)據(jù)集中的DataType自動(dòng)的創(chuàng)建列對(duì)象。
上面我們描述了數(shù)據(jù)展現(xiàn)和數(shù)據(jù)提取的工作的大概開(kāi)發(fā)過(guò)程,最終界面上所作的各種修改還是要提交的服務(wù)器端的,這個(gè)提交動(dòng)作與數(shù)據(jù)提取的動(dòng)作基本類似,容易理解,我們來(lái)看View中存在一個(gè)UpdateAction對(duì)象,這個(gè)對(duì)象就是負(fù)責(zé)數(shù)據(jù)提交工作的。其中的updateItem中我們通過(guò)dataSet屬性定義了要提交的數(shù)據(jù)集:
另外在UpdateAction中類似Provider的處理方式,定義了其中的dataResolver:"simpleCRUD#saveAll",這也是一個(gè)服務(wù)表達(dá)式,我們找到相關(guān)的Java代碼:
@DataResolver
@Transactional
public void saveAll(Collection<Product> products) {
productDao.persistEntities(products);
}
下面為屬性設(shè)置圖:
該方法接受客戶端提交上來(lái)的Product的集合,并調(diào)用Dao完成一個(gè)持久化的動(dòng)作。定義好UpdateAction之后,我們只要將工具欄上的按鈕與這個(gè)Action綁定就可以:
這樣當(dāng)我們單擊這個(gè)保存按鈕的時(shí)候,就可以自動(dòng)的將當(dāng)前的數(shù)據(jù)提交回?cái)?shù)據(jù)庫(kù)了。
在實(shí)做單表CRUD的范例中我們初步接觸了Dorado基于數(shù)據(jù)模型開(kāi)發(fā)的一系列對(duì)象:
其中DataProvider與DataResolver是剛剛新接觸的。
下面我們通過(guò)一張圖來(lái)查看這四中對(duì)象在數(shù)據(jù)環(huán)路中的作用:
這張圖我們?cè)谇懊嬉呀?jīng)看到過(guò)好多次了,只不過(guò)將上面的四種對(duì)象放在其中而已。其中虛線框是Dorado的作用范圍,其中DataProvider與DataResolver相對(duì)來(lái)說(shuō)功能較為明確。
如果我們將這些概念與自己較為熟悉的數(shù)據(jù)庫(kù)的各種術(shù)語(yǔ)做一個(gè)類比,就可以找到如下的概念翻譯:
其中DataPath,由于SimpleCURD較為簡(jiǎn)單,尚未涉及。我們知道由于現(xiàn)在的DataSet是一顆樹(shù)形的結(jié)構(gòu),當(dāng)我們想做一個(gè)較為復(fù)雜的數(shù)據(jù)綁定的時(shí)候,DataPath就可以告訴你如何從DataSet中抽取數(shù)據(jù),其作用就類似于SQL,我們將在后面的文檔中再做描述。
更多建議: