BDF快速入門筆記(一)
快速入門案例
1,HelloWorld http://bsdn.org/projects/dorado7/deploy/sample-center/com.bstek.dorado.sample.Main.d#33800
對映規律->HelloWorld.view.xml檔案的資源路徑為com/bstek/dorado/sample/basic/HelloWorld.view.xml。相應的,我訪問該檢視時使用的URI是/com.bstek.dorado.sample.basic.HelloWorld.d。可以自定義對映。
標籤
ViewConfig根節點
View檢視
<Button>按鈕
<ClientEvent name="onClick" >dorado.MessageBox.alert("Hello World!");(js響應)</ClientEvent>點選事件
<Property name="caption">Greeting from Dorado7 ...</Property>按鈕名稱
</Button>
2,停靠式佈局
停靠式佈局將整個容器的空間劃分為五種,分別是left、top、right、bottom和center,對應五種停靠方式。
當一個控制元件被分配了上述五種停靠方式中的一種時,它總是儘可能佔據那個區域的所有空間,然後將剩餘的空間留給後面的控制元件。
DockLayout中允許除center之外的每一種停靠方式出現多次,具體空間被如何劃分取決於它們被新增到佈局管理器的順序。
<Arguments>引數集
<Argument name="layoutRegion" value="background:#FDFEDA; border:1px #DBB74A solid; padding:4px; white-space:nowrap; overflow:visible" />引數名layoutRegion
</Arguments>
...
<HtmlContainer content="1) left"文字內容 layoutConstraint="left"停靠left style="${argument.layoutRegion}" />容器(類似div)引數使用方式${argument.layoutRegion}
3,錨定式佈局
錨定式佈局的基本思路就是設定控制元件的邊界與容器或其它控制元件之間的距離。
錨定式佈局不僅支援對left和top邊的定位,還支援對right和bottom邊的定位。
錨定式佈局不僅可以將容器的邊界作為錨定目標進行定位,還支援將其他控制元件的邊界作為錨定目標進行定位。
錨定式佈局不但支援以數值作為錨定值,也支援以百分比作為錨定值。
dialog1.show();顯示彈出框
<Dialog id="dialog1" layout="Anchor"設定佈局 caption="場景1"標題欄內容 contentOverflow="hidden"隱藏超出內容 height="300" maximizeable="true" width="600">定義彈出框
<Children>???
<HtmlContainer content="1) left:20; top:20" layoutConstraint="left:20; top:20" style="${argument.layoutRegion}"/>
</Children>
</Dialog>
layoutConstraint錨定佈局取值
anchorLeft:previous對上一個元素左靠
anchorRight:previous對上一個元素右靠
anchorTop:previous對上一個元素頂靠
heightOffset: -40權重40%並減去40畫素
4,檢視攔截器
檢視攔截器程式碼動態新增按鈕,每個按鈕還被指定了各自的佈局條件、單擊事件。
檢視攔截器中的onReady方法自動注入引數。
<View listener="spring:dynaView#onViewInit" layout="padding:20" title="Dyna View">//listener對應java中的類和方法,監聽初始化事件
<Panel id="panelButtons" layout="Anchor">
<Property name="height">200</Property>
<Property name="width">600</Property>
</Panel>
</View>
@Component
public class DynaView {
public void onViewInit(Panel panelButtons) {//無返回值,直接改變引數,變數是指標
panelButtons.setCaption("此標題是通過檢視攔截器設定的");//Panel 容器setCaption設定標題
for (int i = 1; i <= 8; i++) {
Button button = new Button();//定義按鈕
button.setCaption("Button " + i);//定義按鈕名稱
AnchorLayoutConstraint layoutConstraint = new AnchorLayoutConstraint();//定義錨定式佈局
layoutConstraint.setAnchorLeft(AnchorMode.previous);
layoutConstraint.setLeft("5");
layoutConstraint.setTop("10");
button.setLayoutConstraint(layoutConstraint);//設定按鈕佈局屬性layoutConstraint
button.addClientEventListener(//新增點選事件
"onClick",
new DefaultClientEvent(
"dorado.MessageBox.alert('You clicked ' + self.get('caption'));"));
panelButtons.addChild(button);
}
}
}
5,Ajax
可暴露服務
JavaScript中呼叫非同步操作
Container部分佈局容器View子節點
layout="hbox"
<AjaxAction id="toUpperCaseAction" parameter="Hello World!">
<ClientEvent name="onSuccess">dorado.MessageBox.alert(self.get("returnValue"));</ClientEvent>//returnValue返回值
<Property name="caption">轉成大寫</Property>按鈕名稱,屬性名稱caption
<Property name="service">#toUpperCase</Property>對應Ajax類的toUpperCase方法,屬性名稱service
</AjaxAction>
<Button action="toUpperCaseAction"/>定義的AjaxAction 標籤id
//prompt函式引數text,defaultText,callback,
<AjaxAction id="multiplyAction">
<Property name="executingMessage">正在計算...</Property>
<Property name="service">#multiply</Property>
</AjaxAction>
<Button>
<ClientEvent name="onClick" signature="multiplyAction">dorado.MessageBox.prompt("請在這裡輸入任意兩個乘數", {//標題欄文字
defaultText: "3*5",//可輸入文字框
callback: function(text) {//回撥函式
var nums = text.split("*");
var parameter = {
num1: nums[0],
num2: nums[1]
};
multiplyAction.set("parameter", parameter).execute(function(result) {
dorado.MessageBox.alert(nums[0] + " * " + nums[1] + " = " + result);
});
}
});
</ClientEvent>
<Property name="caption">Ajax乘法</Property>
</Button>
@Expose
public int multiply(int num1, int num2) {
return num1 * num2;
}
//捕獲異常
<AjaxAction id="errorAction">定義errorAction
<ClientEvent name="onFailure">dorado.MessageBox.alert("我就知道一定會出錯!\n錯誤原因:" + arg.error.message);
arg.processDefault = false;</ClientEvent>
<Property name="caption">捕獲異常</Property>//點選事件
<Property name="service">#errorAction</Property>//對映方法
</AjaxAction>
<Button>
<Property name="action">errorAction</Property>//使用action
</Button>
@Expose
public void errorAction() {
System.out.println(100 / 0);
}
<Container layout="vbox align:left">
<AjaxAction id="getMemInfo">
<ClientEvent name="onSuccess" signature="self, arg, labelMemInfo, progressBarMemInfo, buttonGetMemInfo">labelMemInfo.set("text", "空閒記憶體: " + arg.result.freeMemory + " 總記憶體: " + arg.result.totalMemory);//labelMemInfo下面定義id為labelMemInfo的<label>
progressBarMemInfo.set({//下面定義的ProgressBar 滾動條id為progressBarMemInfo
maxValue: arg.result.totalMemory,//滾動條最大值
value: arg.result.totalMemory - arg.result.freeMemory//滾動條當前值
});
if (buttonGetMemInfo.get("toggled")) {
setTimeout(function(){
self.execute();//self表示ClientEvent
}, 800);//0.8秒執行一次ClientEvent
}
</ClientEvent>
<ClientEvent name="beforeExecute" signature="labelRetrievingMemInfo">labelRetrievingMemInfo.set("visible", true);</ClientEvent>//執行前
<ClientEvent name="onExecute" signature="labelRetrievingMemInfo">labelRetrievingMemInfo.set("visible", false);//設定visible屬性值</ClientEvent>//執行後
<Property name="caption">提取Server端記憶體使用情況</Property>
<Property name="service">#getMemInfo</Property>
<Property name="modal">false</Property>
</AjaxAction>
<Button id="buttonGetMemInfo">
<Property name="action">getMemInfo</Property>
<Property name="toggleable">true</Property>
</Button>
<Container layout="hbox regionPadding:20">
<Property name="height">20</Property>
<Label id="labelMemInfo">
<Property name="text">------</Property>
</Label>
<Label id="labelRetrievingMemInfo">
<Property name="visible">false</Property>
<Property name="text">Retrieving</Property>
<Property name="style">
<Property name="fontWeight">bold</Property>
<Property name="color">green</Property>
</Property>
</Label>
</Container>
<ProgressBar id="progressBarMemInfo">
<Property name="width">300</Property>
</ProgressBar>
</Container>
如何點選之後改變buttonGetMemInfo.get("toggled")即按鈕buttonGetMemInfo的toggled屬性,猜測是button之後自動改變Button的toggled屬性
6,javascript控制器
引入js檔案
1)直接引用,view的子屬性標籤javaScriptFile,多個js,逗號分隔
<Property name="javaScriptFile"></Property>
相同目錄下自動載入同名js
2)配置引用
packages-config.xml配置方式,在每一個專案的dorado-home資料夾下都有packages-config.xml配置檔案
<config>
<Patterns>
<Pattern name="js" contentType="text/javascript" charset="UTF-8" mergeRequests='${configure["view.mergeJavaScript"]}' resourceSuffix=".js" />
<Pattern name="css" contentType="text/css" charset="UTF-8" mergeRequests='${configure["view.mergeStyleSheet"]}' resourceSuffix=".css" />
</Patterns>
<Packages>
<Package name="common" pattern="js"></Package>//所有View都加在common
//baseUri根路徑
<Package name="syntax-highlighter-css" pattern="css" baseUri=">libraries/syntax-highlighter">
/libraries/syntax-highlighter/shCore,
/libraries/syntax-highlighter/shThemeDefault
</Package>
<Package name="syntax-highlighter" pattern="js" depends="jquery,syntax-highlighter-css">
/libraries/syntax-highlighter/jquery.beautyOfCode,
/libraries/syntax-highlighter/jquery.beautyOfCode.init,
/libraries/syntax-highlighter/shCore,
/libraries/syntax-highlighter/shBrushJava,
/libraries/syntax-highlighter/shBrushJScript,
/libraries/syntax-highlighter/shBrushXml
</Package>
</Packages>
</config>
//view中使用packages屬性,用於引入packages-cinfig.xml中配置的資源包(name屬性),如果有多個資源包,逗號分隔:
js繫結Xml方式
利用Javascript中的"Annotation"來完成事件的掛接
/** @Bind #buttonOK.onClick */按鈕繫結點選事件
function buttonOK() {}
/** @Bind ^readOnlyEditor.onCreate */批量繫結事件 button子標籤屬性<Property name="tags">readOnlyEditor</Property>
function setReadOnly(self) {}
以支援EL表示式
alert("${request.getRequestURI()}");
匿名事件
/** @Bind #buttonOK.onClick */
!function() {
alert("buttonOK Clicked.");
}
宣告式公用方法
@View和@Global區別
@View用於標註某個方法在View中可見,@Global用於標註某個方法全域性可見。
/** @View */
function showMessage(text) {
dorado.MessageBox.alert(text);
}
我們可以在其他地方(包括view.xml中或其他js檔案中)通過 view.showMessage() 來呼叫它了
@Global的作用的是把方法標註成全域性方法,我們可以在其他地方直接通過 showMessage() 來呼叫它。
出現多個View例項
強烈推薦首先考慮使用@View,@View可以在幾乎所有場景下替代@Global。
7,單表資料維護
如何配置基本的DataType?
使用Annotation快速的定義DataProvider和DataResolver。
DataSet的概念以及DataSet如何通過DataProvider獲得資料。
資料繫結控制元件的基本使用方法。
資料提交(即UpdateAction)的基本使用方法。
初步瞭解Dorado提供的HibernateDAO。
<Model>//定義表格資料型別(列結構)
<DataType name="ProductType" parent="Bean" meta="x:75;y:45">//定義ProductType表格顯示的資料列
<Property name="creationType">com.bstek.dorado.sample.entity.Product</Property>//自動匯入實體類的屬性作為PropertyDef
<Property name="autoCreatePropertyDefs">true</Property>//開啟自動建立PropertyDef
<PropertyDef name="id" readOnly="true"/>//新增PropertyDef
<PropertyDef name="productName" required="true"/>
</DataType>
</Model>
<View title="Product Maintain">
<Property name="packages">font-awesome</Property>
<DataSet id="dsProducts">//定義資料集
<Property name="dataProvider">#getAll</Property>
<Property name="dataType">[ProductType]</Property>
<Property name="pageSize">100</Property>
</DataSet>
<UpdateAction id="actionSave">//定義資料提交action呼叫java
<Property name="successMessage">儲存成功!</Property>
<Property name="dataResolver">#saveAll</Property>//呼叫saveAll
<Property name="caption">Save</Property>//按鈕文字
<Property name="iconClass">fa fa-save</Property>//小圖示
<UpdateItem>//更新引數
<Property name="dataPath">!DIRTY_TREE</Property>//用於描述希望提交DataSet中哪些資料的資料路徑
<Property name="dataSet">dsProducts</Property>//使用資料集
</UpdateItem>
</UpdateAction>
<ToolBar layoutConstraint="top">
<DataPilot>//分頁
<Property name="ignored">false</Property>
<Property name="dataSet">dsProducts</Property>
<Property name="itemCodes">pages,|,pageSize,|,+,-,x</Property>
</DataPilot>
<Separator/>
<ToolBarButton>
<Property name="action">actionSave</Property>
</ToolBarButton>
</ToolBar>
<DataGrid>
<Property name="dataSet">dsProducts</Property>//表格
<Property name="scrollMode">viewport</Property>//滾動條
<IndicatorColumn/>
</DataGrid>
</View>
@Component
public class SimpleCRUD {
@Resource//自動注入實體類
private ProductDao productDao;
@DataProvider//定義DataProvider資料查詢
public Collection<Product> getAll() throws Exception {
return productDao.getAll();//返回資料
}
@DataProvider
public void getAll(Page<Product> page) throws Exception {//帶分頁的返回資料
//page中包含:
//每頁載入的資料是多少條
//page.getPageSize();
//需要載入的是第幾頁
//page.getPageNo();
//Dao層的分頁查詢方法
productDao.getAll(page);//再Dao中獲取page中的查詢條件,獲取分頁資料
page.setEntities(p.getResults());
page.setEntityCount(p.getTotalCount());
//處理後的資料要存放在Page物件中,參考前面的fundUsers方法,利用setEntities()方法存放資料,並利用setEntityCount()存放總的資料量資訊,便於前臺分頁控制元件可以計算出一共有多少頁。
}
@DataResolver//定義DataResolver資料儲存
@Transactional
public void saveAll(Collection<Product> products) {//處理資料
productDao.persistEntities(products);
}
}
//新增刪除取消儲存分頁控制元件
DataPilot是資料導航條控制元件,主要用於資料分頁導航顯示等
在@DataProvider方法的引數中加Page<T> page物件自動注入
8,主從表檢視
SplitPanel 主要作用是通過分隔欄將頁面上的空間分為兩塊,繼承Control控制元件, SplitPanel的direction屬性設定(上下左右)預設左右,支援區域性區域最小化縮排,position設定位置大小,子標籤MainControl主元件,SideControl
Container繼承Control控制元件,是一個容器控制元件
DataType 的屬性
meta="child:Product" 被Product繼承
parent="BaseProduct" 繼承BaseProduct
9,懶裝載
<DataType name="Category" parent="global:Category" meta="x:75;y:15">
<PropertyDef name="products"/>
</DataType>
<DataGrid dataSet="dsCategories">
<Property name="selectionMode">none</Property>
<IndicatorColumn/>
</DataGrid>
<PropertyDef name="products"/>
替換為
<Reference name="products">
<Property name="dataProvider">productInterceptor#getProductsByCategoryId</Property>
<Property name="parameter">$${this.id}</Property>
</Reference>
可以在DataGrid中使用以下方式來獲得資料表。
<DataGrid>
<Property name="dataPath">#.products</Property>
<Property name="dataSet">dsCategories</Property>
<IndicatorColumn/>
</DataGrid>
每點選DataGrid dsCategories一行資料,重新獲取一次DataGrid products的資料
10,MapValue對映
實現改寫表的一列資料,將對應顯示值通過一一對映改寫(ajax方式)
<DataType name="Employee" parent="global:Employee">
<PropertyDef name="titleOfCourtesy">
<Property name="mapping">
<Property name="mapValues">${dorado.getDataProvider("employeeInterceptor#getTitlesOfCourtesy").getResult()}</Property>
</Property>
</PropertyDef>
</DataType>
@DataProvider
public Map<String, String> getTitlesOfCourtesy() {
Map<String, String> mapValue = new LinkedHashMap<String, String>();
mapValue.put("Mr.", "Mister");
mapValue.put("Mrs.", "Mistress");
mapValue.put("Ms.", "Miss");
mapValue.put("Dr.", "Doctor");
return mapValue;
}
<DataColumn>方式修改顯示的欄位樣式
<ClientEvent name="onRenderCell">//
$(arg.dom).empty();
var status=arg.data.get("status");
if(status=="失敗"){
arg.dom.innerHTML="<strong><font color='red'>失敗</font></strong>";
}
</ClientEvent>
11,遞迴樹
動態生成的可開啟式選單
//categories:是一個CategoryNode組合的陣列物件,其資料來自"main#getCategories";
//examples:是一個BaseExample組合的陣列物件,其資料來自"main#getExamplesByCategoryId";
//$${this.id}以當前CategoryNode的id屬性作為兩個reference的dataProvider呼叫時的引數傳入。
<DataType name="CategoryNode" parent="BaseExampleCategory">
<Reference name="categories" dataType="[CategoryNode]" dataProvider="main#getCategories" parameter="$${this.id}" />
<Reference name="examples" dataType="[BaseExample]" dataProvider="main#getExamplesByCategoryId" parameter="$${this.id}" />
</DataType>
<DataSet id="dsCategories" dataType="[CategoryNode]" dataProvider="main#getCategories" />
//treeExamples綁定了dsCategories物件,並通過BindingConfig定義節點屬性。
<DataTree id="treeExamples" dataSet="dsCategories" width="300" height="400">
<BindingConfigs>
<BindingConfig childrenProperty="categories" labelProperty="label" recursive="true" icon=">images/folder.gif">
<BindingConfig childrenProperty="examples" labelProperty="label" icon=">images/file.gif" />
</BindingConfig>
</BindingConfigs>
</DataTree>
//childrenProperty="categories"表示子節點通過CategoryNode的categories獲取
//labelProperty表示樹節點初始化時,預設以樹節點所繫結物件的哪個屬性(本例為label)作為節點標題顯示。
//recursive屬性是用來定義是否一個遞迴的BindingConfig,如果遞迴則內部會繼續按照如下的規則載入樹節點
12,虛擬屬性下拉選擇
DataSetDropDown
//編輯框中的值作為引數filterValue傳遞到對應的DataProvider程式碼中
@DataProvider
public Collection<Product> getProducts(Map<String, Object> parameter) {
String productName = (String)parameter.get("filterValue");//注意引數名為filterValue
return productDao.find("from Product where category.productName ='" + productName + "'");
}
onSetFilterParameter//通過該事件自定義filterValue的值:
//@Bind #dataSetDropDown.onSetFilterParameter
!function(self, arg) {
arg.filterValue = "自定義的值";
}
//甚至直接動態的設定DataSetDropDown所繫結DataSet的其他引數值:
//@Bind #dataSetDropDown.onSetFilterParameter
!function(self, arg) {
arg.dataSet.set("parameter",{
categoryId:1,
deptId:"SH001"
});
}
filterOnTyping = false 模糊搜尋 預設關閉
reloadDataOnOpen 是否在開啟下拉框時重新載入(上下聯動)
useDataBinding true下拉框與DataSet之間建立資料繫結,onFilterItem不會觸發,資料過濾動作也將交由DataSet來
false 則一次性讀取下拉資料,之後與DataSet不再產生關係,並且後續的資料過濾等操作也將與dorado.widget.ListDropDown的實現方式一致。
ListDropDown
items屬性定義下拉框的資料
1利用逗號分割符定義,2利用IDE的嚮導工具定義,3利用JSON定義,4通過DataProvider提供資料
通過displayProperty定義下拉資料預設顯示物件中那個屬性。
望以表格的形式展現多個屬性的時候,就需要利用ListDropDown的DataColumn子元素
DataColumn通過property與對應的下拉框行資料物件的某一個屬性繫結:
Trigger與編輯框相關聯的事件觸發器。
onExecute事件我們可以定義上圖按鈕圖示的單擊事件
AutoForm是一種自動錶單,是AutoFormElement的一個集合,內部可以定義多個AutoFormElement
<AutoForm cols="*" dataSet="dsOrders">
表單文字框
<AutoFormElement>
<Property name="property">shipCity</Property>
</AutoFormElement>
表單下拉框
<DataSetDropDown id="ddEmployees" dynaFilter="true">
<Property name="dataSet">dsEmployees</Property>
<Property name="autoOpen">true</Property>
<Property name="assignmentMap">employeeId=id,employeeName=firstName</Property>
<Property name="displayProperty">firstName</Property>
</DataSetDropDown>
...
<AutoFormElement>
<Property name="property">employeeName</Property>
<Property name="trigger">ddEmployees</Property>
<Editor/>
</AutoFormElement>
表單時間
<AutoFormElement property="orderDate">
<Editor>
<DateTimeSpinner>
<Property name="type">date</Property>
<Property name="trigger">defaultDateDropDown</Property>
</DateTimeSpinner>
</Editor>
</AutoFormElement>
表單不可操作文字
<AutoFormElement>
<Property name="property">employeeId</Property>
<Property name="readOnly">true</Property>
</AutoFormElement>
13,簡單查詢 1
AutoForm表單資料
AutoForm物件formCondition,如果我們直接通過.get("entity")方法,會自動返回給我們一個JSON物件。我們將這個 JSON物件直接賦值給dsOrders的parameter引數,並呼叫dsOrders的flushAsync啟用Java服務層定義好的query 方法,執行查詢。
dsOrders.set("parameter", formCondition.get("entity")).flushAsync();