本文是由英文幫助翻譯所得:前端
1>task flowsjava
「任務流 task flows」能夠包括非可視化的組件,好比方法調用。
「頁片斷 page fragment」能夠運行在一個頁面的某個局部區域,最大限度地提升複用性。
ADF Task Flow是在JSF Controller的基礎上擴展而來的,它除了包括View Activities和導航規則以外,還能夠包括method calls等非可視化Activity。
ADF Task Flow分爲兩種:Bounded task flow和Unbounded task flow
一、Bounded task flow
(1)、做爲局部、分支的頁面流程。
(2)、有一個惟一入口和零到多個出口。
(3)、擁有本身私有的Control flow rules,Activities,Managed bean,Transactions.
(4)、能夠重用。
二、Unbounded task flow
(1)、做爲頂級的頁面流程。
(2)、出口不固定。
ADF ManagedBean與JSF Managed Bean的區別在於,ADF Managed Bean的Scope比JSF Managed Bean多了pageFlowScope、viewScope、backingBeanScope。
. pageFlowScope:Managed Bean在Task Flow中的全部Page可見,且訪問的同一個實例。若是其它Task flow中 Page訪問該Managed Bean,將會建立一個新實例,供這個Task flow中的全部Page使用。
. viewScope:只在當前這個view(多是root browser window,也多是region)可見,當viewId發生改變後,該Managed Bean被釋放掉。
. backingBeanScope:一個Page中含有一個Task Flow,而且這個Task flow使用了多個region,設置此值能夠起到隔離各個region的做用(會在每一個region中建立一個實例),避免數據衝突。web
2>佈局
爲了使組件可以自適應瀏覽器窗口大小,首先須要放置根一級的可伸縮的佈局組件。 如下組件能夠根據父容器的大小自動伸縮(加星號的還能夠伸縮其子組件):
. * Decorative Box
. Panel Accordion
. Panel Box (當type="stretch"或"default")
. Panel Collection
. Panel Dashboard
. Panel Group Layout (當layout="scroll"或"vertical")
. * Panel Spliter
. * Panel Stretch Layout
. Panel Tabbed
對於這些組件,不要設置其寬度、高度的百分比,設置了反而很差。
如下組件不能根據父容器的大小自動伸縮:
. Panel Border Layout
. Panel Box (當type="flow"或"vertical")
. Panel Form Layout
. Panel Group Layout (當layout="default"或"horizontal")
. Panel Header
. Panel Label and Message
. Panel List
若是你必須使用一個不能自動伸縮的容器,但又想達到自動伸縮的效果,能夠爲該容器套上一個能夠自動伸縮的容器,如Panel Group Layout(當layout="scroll"或"vertical")。
最佳實踐:(1)、佈局時,根容器要能夠自動伸縮。(2)、沒法伸縮的容器,能夠考慮外套一個Panel Group Layout(當layout="scroll"或"vertical")。數據庫
3>eo的自定義屬性express
爲Entity Object增長Transient Attribute,好比自動計算訂單總價:單價*數量。
(1)、由於是Transient Attribute,因此不要選擇Persistent。
(2)、在View Object中增長該Attribute。
(3)、設置從新計算的條件:Always--每次都從新計算;Never--只在建立時計算一次;Based on the following expression--根據表達式返回值(True or false)來計算是否從新計算。瀏覽器
爲Entity Object增長Association,好比訂單項目中的產品與產品關係。
(1)、Association命名規則是<DetailEntityMasterEntity>FKAssoc。
(2)、搞清楚一對多的關係中,誰是1、誰是多。緩存
4>vo添加View Link性能優化
爲View Object增長View Link,好比訂單項目中的產品與產品關係。
View Object是對Entity Object的查詢結果,結果包括Entity Object的所有或部分屬性。通常來講,一個View Object對應一個Entity Object。固然,你也能夠徹底根據SQL語句自定義一個View Object。View Link代表的是兩個View Object之間的關係,一個View Link對應一個Association。
(1)、View Link命名規則也是<DetailEntityMasterEntity>FkLink。
(2)、一樣,也要搞清楚一對多的關係中,誰是1、誰是多。服務器
5>am添加Data Modelsession
爲Application Module增長Data Model。
View Object代表數據被訪問的方式。客戶端經過訪問View Object而訪問Data Model。Data Model保存在Application Module中。Application Module是一種類型的業務服務,其它類型的業務服務有Web Service、EJB。在Data Model中,View Object所帶的數字「1」、「2」、「3」....,代表這是該View Object的第幾個實例。
6>LOV
ADF BC特點功能之一:級聯式下拉列表
在實際應用中,常常會使用兩個級聯式下拉列表的狀況,好比先選擇國家列表,在根據選擇的國家顯示 城市列表。你能夠把View Object某個Attribute定義成LoVs(全稱:List of Values)。這樣,因爲是定義在模型層上,UI界面無需作任何改動。
7>ADF BC特點功能之二:強大的自動計算與驗證功能
一、經過新建Transient Attribute來實現自動計算。
二、驗 證Foreign Keys:Key Exists。LOVs能夠限制用戶只能從已有的外鍵中選擇,但有時界面要求使用文本輸入框,而不是下拉列表,這時候就須要使用Key Exists來驗證用戶輸入的外鍵是否正確。而且,Key Exists可讓咱們在程序中使用該功能,不經過界面。LOVs是定義在View Object上的,而Key Exists是定義在Entity Object上的。
三、約束性條件依賴:Compare。某個Attribute的值與設定值進行比較,爲真則知足要求,不然報錯。其中能夠設定觸發條件和觸發Attributes。
四、使用Groovy腳本驗證。若是腳本中有對象爲null,Groovy不會拋出NullPointerException,而是表達式結果爲null,null對應的Boolean值爲false。
8>使用ADF Faces之一:開發用戶界面
如何使用其它Project的資源:共享資源如servlet classes,helper classes,images和templatess,能夠經過建立ADF library來爲其它Project所共用。
9>使用ADF Task Flows之一:菜單與頁面導航
一個應用的頁面之間的上下級關係就像一棵樹。每一個節點都是一個頁面。
一個典 型的ADF應用由一個或多個unbounded task flow和bounded task flows組成。建立unbounded task flow時不要選擇「Create as Bounded Task Flow」,而且以adfc-xxx-config.xml的格式來命名,好比adfc-sale-config.xml。adfc- config.xml是應用默認的unbounded task flow,它應該做爲應用的總入口、根節點。
10>客製化:個性化的一種服務(customize(v),customization(n))
表示根據客戶的需求進行特別的定製,已知足其須要。通常用於軟件/服務/加工製造等方面。針對顧客的需求,對一個標準的產品進行改變、用新的部件替換標準的部件、或是在一個標準產品中加入特殊的功能,提供顧客一個更完整的產品組合。
個性化:就是非通常大衆化的東西。在大衆化的基礎上增長獨特、另類、擁有本身特質的須要,獨具一格,別開生面,打造一種不同凡響的效果。
問題:在ADF中如何定製ADF應用?
根據行業的不一樣,客戶的不一樣,須要對ADF應用作一些定製化操做,ADF應用的定製化分爲兩種:
(1)、個性化:容許用戶運行時對應用進行定製。
(2)、客製化:容許用戶設計時對應用進行定製。
不管是那種定製方法,這些定製的內容均不會對已開發完成的應用做出修改,而是存儲在MDS(Metadata Service repository)中。MDS支持兩種方式的實現:文件和數據庫。ADF應用默認使用基於文件的MDS。
基於文件的MDS:選擇Application -> Application Properties -> RUN -> MDS。Directory Content:你能夠設置是否在每次執行應用前清空MDS存儲的定製化信息。
如何實現用戶客製化(Customize)
客製化是在設計時,在原有ADF應用的基礎上,增長定製化層,每一層可能對應不一樣的行業、不一樣的公司。這樣作的好處就是,既能知足不一樣風格的展示要求,同時又不改變原有應用的基礎代碼。
(1)、一個ADF應用容許設置多個客製化層,如industry層及site層。
(2)、每個客製化層容許具備多個客製化值,如industry層能夠具備healthcare和financial等。
(3)、運行時,每個層只有一個客製化層值有效。
(4)、客製化層的順序由adfc-config.xml中各個客製化類的順序決定。
實現客製化的具體步驟以下:
one、定義CustomizationLayerValues.xml。
打開文件C:\Oracle\Middleware\jdeveloper\jdev\CustomizationLayerValues.xml,該文件定義了全部客製化層以及每層的值。
two、建立customization.properties文件
在Model Project中,新建一個文件customization.properties。該文件代表運行時,每一個客製化層設定爲哪一個值。
three、建立和發佈客製化類
MDS使用客製化類來決定應用哪一個客製化層,一個客製化類對應一個客製化層,其接口以下:
. CacheHint getCacheHint();
決定customization的類型,返回值包括ALL_USERS、MULTI_USER、REQUEST、USER四種。
ALL_USERS:customization爲針對某應用全局有效的,一般用於static類型的customization層。
MUTI_USER:針對複數用戶有效的customization。
REQUEST:針對當前請求有效的customization。
USER:針對某特定用戶有效的customization,經過用戶訪問應用的Session來決定具體用戶。
. String getName();
返回當前customization類對應customization層的名稱。
. String generateIDPrefix(RestrictedSession sess, MetadataObject mo);
返回在MDS中對應當前customization層元素加的前綴,以使該客製化層的元素在MDS中具備惟一標示。這一前綴在全部customization層中必須是惟一的,出於性 能考慮應小於4個字符。
. String[] getValue(RestrictedSession sess, MetadataObject mo);
返回反映客戶化層加載順序的列表,按照列表順序加載。一般只須要有一個customization層,故該列表一般只返回一個值。
在Model Project中,新建一個Java類:SiteCCTV.java,內容本身再去看。寫好類後,編譯Model Project,發佈Model Project爲一個Jar文件。這裏須要注意三 點:
(1)、選中Include Manifest File。
(2)、只選中定製化類和customization.properties文件。
(3)、必須把該Jar文件Copy到C:\Oracle\Middleware\jdeveloper\jdev\lib\patches目錄下。
four、修改adf-config.xml文件
選擇Application Resource -> Descriptors -> ADF META_INF,雙擊adf-config.xml打開overview editor。增長前面新建的定製化類。
five、爲ViewController Project選中Enable Seeded Customizations。
six、建立基礎應用:TaskFlows,JSF Pages等等。
seven、 在基礎應用上客製化應用。這時,要以Customization Developer角色從新進入JDeveloper。方法是Tools -> Preferences -> Roles,選擇Customization Developer。重啓JDeveloper後,應該能看到以前作的設置。
11>開發端到端的ADF應用之一:開發富互聯網應用
一、建立Read-Only Vo:建立此種Vo通常做爲下拉列表選項出如今UI中。
二、 爲EO的字段定義驗證規則:除了能夠爲EO的字段定義驗證規則(Attributes Level Validator)以外,你還能夠爲整個EO定義驗證規則(Entity Level Validator)。Attributes Level Validator在attribute值變時觸發;Entity Level Validator在驗證Entity時觸發。若是想要自定義Java驗證規則,則Rule Type選擇Method方式,會自動幫你生成相應的方法,Java驗證規則也能夠定義在Attributes或Entity上。
三、在EO的字段設置默認值
當前日期,adf.currentDate,顯示格式。當前時間,adf.currentDateTime。注意,必須選擇Expression方式。
四、建立一對多的UI界面(部門與員工是一對多的關係)
注意,拖放EmployeesVo時,要選擇DepartmentsVo下的EmployeesVo,這樣才能自動關聯一對多的關係。
五、建立VO(Updatable access throuth entity objects)
(1)、建立VO的方式除了從Tables的方式建立之外,也能夠經過抽取多個EO的屬性來建立。
(2)、爲VO增長自動計算的Transient屬性,如SumSalary=Salary*12。
(3)、爲EmpDetails VO增長View Accessors:Job VO,供如下拉列表的方式選擇Job。
注意,手工建立的VO必須加入Application Model的Data Model中才能使用。
六、建立VO(Read-only access through SQL query)
能夠用自定義SQL query的方式來建立Read-Only VO,能夠帶查詢參數,參數直接定義在查詢語句中,如select first_name from employees where email=:p_email。這種方式定義的VO,生成Data Control時,會在該VO的Operations下生成對應的ExecuteWithParams。
12>開發端到端的ADF應用之二:使用EJB、JPA、JSF開發Web應用
一、使用EJB3和JPA創建業務服務層。
(1)從數據庫表建立JPA Entities,生成相應的java文件,主要包括Entities的屬性和CRUD方法。之後能夠根據須要,手工添加一些方法。
(2) 建立EJB Session Bean,選擇Persistence Type=JPA,選擇暴露哪些Entities上的方法。Entity若是增長了新的方法想要經過Session Bean調用,右鍵點擊EJB Session Bean,選擇Edit Session Facade,把新方法加進來便可。
(3)測試Session Bean很是方便,右鍵點擊EJB Session Bean,選擇New Sample Java Client,就會幫你生成測試代碼,你只須要傳一些必要的參數便可。測試前 ,先要運行Session Bean(把Session Bean發佈到WLS上,並啓動),而後右鍵點擊Java Client,選擇Run。
(4)JPA Entities也能夠不經過Java EE Container——直接在Java SE Container中就能夠調用。你須要建立一個新的persistence unit,右鍵點擊 persistence.xml選擇New Java Service Facade,選擇Persistence Type=JPA,選擇暴露哪些Entities上的方法。在main函數中,能夠增長你的測試代碼,並 直接運行——不須要先運行Session Bean。
二、爲Session Bean建立Data Control。
右鍵點擊EJB Session Bean,選擇Create Data Control,選擇暴露的Session Bean的Interface:Local或Remote。
三、如何讓一個普通Project可使用JSF/ADF組件?
(1) 右鍵點擊Project,選擇Project Properties,選擇JSP Tag Libraries,選擇Select Distributed libraries,增長ADF Faces Components 11,(只選這個就 能夠,其它的會帶過來)。
(2)繼續選擇Technology Scope,選擇JSF(只選這個就能夠,其它的會帶過來)。
13>如何顯示提示信息
一、顯示在某個組件的旁邊
要想顯示在組件的旁邊,首先要獲得這個組件的ID,而後就是構造FacesMessage,並顯示出來。
(1)組件已經綁定在MB中
FacesContext context = FacesContext.getCurrentInstance();
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,"Please supply a valid file name to upload",null);
context.addMessage(this.getFileInputComponent().getId(),message);
(2)經過組件上的事件獲取組件
FacesContext context = FacesContext.getCurrentInstance();
FacesMessage messagge = new FacesMessage("Successfully uploaded file"+file.getFilename()+"("+file.getLength()+"bytes)");
context.addMessage(event.getComponent().getClientId(context),message);
(3)獲取根組件
public static void addFacesErrorMessage(String attrName, String msg){
FacesContext ctx = FacesContext.getCurrentInstance();
FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_ERROR, attrName, msg);
ctx.addMessage(JSFUtils.getRootViewComponentId(), fm);
}
(4)經過根組件+組件ID查找組件
pubic static void addFacesErrorMessage(String attrName, String msg){
FacesContext ctx = FacesContext.getCurrentInstance();
FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_ERROR, attrName, msg);
ctx.addMessage(JSFUtils.getRootViewComponentId().findComponent("productpriceIT").getClientId(ctx), fm);
}
14>頁面之間傳值的幾種方法:
兩個頁面,第一個頁面點擊某個command component,傳一個參數到第二個頁面。
方法一:選中task flow中的某個View Activity,設置屬性Input Page Parameters,from, to。設置到pageFlowScope中。
方法二:在按鈕上設置set action listener事件,導航前該listener被觸發。使用set action listener設置from,to,將當前頁面的某個值設置到pageFlowScope中。
方法三:在按鈕上設置set property listener事件,設置from, to, type。type=action,代表監聽該command component的action event。
說明:建議使用set property listener。
兩個頁面,第二個頁面接收第一個頁面傳過來的參數值
Map pageFlowScope = RequestContext.getCurrentInstance().getPageFlowScope();
Object myObject = pageFlowScope.get("myObjectName");
RequestContext adfContext = RequestContext.getCurrentInstance();
adfContext.getPageFlowScope().clear();
15>commit操做
由於Commit操做每每須要保存到數據庫,操做相對費時,所以最好不要讓用戶隨便點擊。須要Enable時才Enable,其判斷依據就是表單數據是否已經更改。
實際應用中,在作其它操做時,咱們也須要判斷數據是否已經更改,好比:用戶修改了某個表單,沒有提交,而後直接轉到其它頁,這時咱們應該提醒它數據已經修改,是否保存?也就是說,咱們須要在MB中判斷bindings.Commit.enabled的值,方法以下:
public boolean isCommitEnabled(){
Boolean commitState = (Boolean)JSFUtils.getManagedBeanValue("bindings.Commit.enabled");
boolean commitEnabled = commitState != null ? commitState.booleanValue() : false;
return commitEnabled;
}
判斷數據是否已經更改的一種更底層方法(由於是在AM上判斷的),只要AM上的VO發生了改變,均可以用這個方法監測到。方法以下:
public boolean isDirty(){
ApplicationModule am = ADFUtils.getDCBindingContainer().getDataControl().getApplicationModule();
return am.getTransaction().isDirty();
}
在使用ADF Commit按鈕時,還有一個常見問題:當用戶修改某一個表單項後,即便焦點轉移後,Commit按鈕也不會被Enable。若是出現這種狀況,須要增長兩個參數:(1)增長autoSubmit="true"。(2)刷新Commit按鈕。
建議方法:設定Commit按鈕的PPR,指向該表單項,這樣當該表單項變更後,會局部刷新Commit按鈕。
16>關於Table
關於Table:點擊某個按鈕後,傳入選中行的整個對象
方法:爲該按鈕添加setActionListener,其from值綁定到 Table對應iterator的currentRow,to值綁定到頁面對應MB中ViewRowImpl類型的變量rowObject(該變量就是用 來接收傳進來的行對象的)。實例<af:setActionListener from="#{bindings.tableIterator.currentRow}" to="#{MB.rowObject}">,而後在rowObject的set方法中就能夠設置行中字段值了。
關於Table:Table顯示時爲只讀模式,點擊Table後,選中行變爲修改模式,保存後回到只讀模式:
適合場景:表列項比較少的狀況,增長,修改,刪除功能都在一個頁面完成,不用打開新頁面。
方法:拖放Table時,選擇ADF Table(不要選擇ADF ReadOnly Table),而後設置屬性EditingMode=clickToEdit(默認是editAll,通常不用這種方式)。
關於Table:Table顯示時爲只讀模式,點擊某個按鈕後,彈出一個窗口修改選中行,保存後關閉彈出窗口,Table回到只讀模式:
方法:一、拖放Table時,選擇ADF ReadOnly Table(由於修改是在彈出窗口中,所以Table只讀便可)。
二、使用Popup窗口是比較好的選擇,由於Popup窗口支持popupCanceledListener,當直接關閉窗口時,能夠捕捉到該事件。
三、在按鈕中設置showPopupBehavior。
四、在合適的位置放置popup組件,內嵌一個dialog組件。設置popup的popupCanceledListener事件、 popupFetchListener事件及Dialog的dialogListener事件,都將 對應方法綁定到頁面對應的MB中。
五、MB中對應的各個listener代碼。好比:
public void cancelListener(PopupCancelEvent popupCancelEvent){//cancel listener
BindingContainer bc = getBindings();
OperationBinding ob = bc.getOperationBinding("Rollback");
ob.execute();
}
public void fetchListener(PopupFetchEvent popupFetchEvent){//fetch listener
//根據觸發事件的source client id,來判斷點擊的是哪一個按鈕:Edit or Insert。
if(popupFetchEvent.getLaunchSourceClientId().contains("insert")){
BindingContainer bc = getBindings();
OperationBinding ob = bc.getOperationBinding("CreateInsert");
ob.execute();
}
}
public void dialogListener(DialogEvent dialogEvent){//dialog listener
if(dialogEvent.getOutcome().name().equals("ok")){
BindingContainer bc = getBindings();
OperationBinding ob = bc.getOperationBinding("Commit");
ob.execute();
}else{
BindingContainer bc = getBindings();
OperationBinding ob = bc.getOperationBinding("Rollback");
ob.execute();
}
}
17>LOV
Vo中製做LOV時,將字段UI Hints中的Default List Type設爲Input Text with List of Values:
(1)、 爲JobId增長LOV,並設置Default List Type:Input Text with List of Values;選擇顯示JobId和JobTitle,即在Display Attributes下Available中的將JobId和 JobTitle拉入Selected中。
(2)、拖放view至頁面,選擇生成ADF Form,發現JobId的顯示組件自動設置爲ADF List of Values Input。若是選中Query List Automatically,彈出查詢頁面時,會直接 顯示全部結果。
(3)、運行,JobId爲一個文本輸入框,旁邊有一個查詢按鈕,點擊後能夠查詢,選擇一條記錄,會返回到文本輸入框。注意,不管查詢顯示的是哪些字段,返回的都是 JobId。
(4)、設置inputListOfValues組件的autoSubmit="true"。除了(3)的運行效果以外:
. 當輸入AD_,按下Tab鍵,會彈出全部以AD_開頭的JobId選項。
. 當輸入AD_V,按下Tab鍵,會直接補全爲AD_VP,由於只有一個值知足條件。
(5)、 爲inputListOfValues組件增長autoSuggestBehavior,如:<af:autoSuggestBehavior suggestedItems="#{bindings.JobId.suggestedItems}"/>此時,除了(4)的運 行效果以外,會新增一種效果:隨着用戶的輸入,會自動下拉顯示匹配的結果。通過測試,中文也能夠支持自動匹配。
(6)、有時候咱們須要爲彈出的查 詢窗口預設置一些過濾LOV,這是能夠考慮使用LaunchPopupListener。inputListOfValues組件增長了屬性 launchPopupListener,如: launchPopupListener="#{backing_Bean.filterLOV}",綁定MB中方法。最後在MB中添加方法,以下:
public void filterLOV(LaunchPopupEvent launchPopupEvent){
BindingContainer bc = getBindings();
FacesCtrlLOVBinding lov = (FacesCtrlLOVBinding)bc.get("JobId");
lov.getListIterBinding().getViewObject().setNamedWhereClauseParam("salary",4000);
}
18>popup
popup組件經常嵌套組件Note Window、Dialog、Menu,一塊兒使用。
點擊一個按鈕,根據某些條件,動態來決定是否彈出一個窗口?
此種狀況適合如下場景:
(1)當用戶修改了表單,若是沒有保存,接着直接轉到其它地方,此時應該提示:「數據已更改,是否保存?」;若是保存了,則不提示。
(2)容許用戶刪除多條記錄功能:
當用戶點擊Delete按鈕時,須要確認用戶選擇了哪些記錄,若是超過一條(包括一條),則提示用戶:「數據將被刪除,是否確認?」;不然提示「你沒有選 擇任何數 據」。固然,若是前端能夠控制成以下效果則更好:當用戶選擇了一條以上(包括一條)的記錄時,Enable Delete按鈕;不然Desable Delete按鈕。
實現步驟:
(1)在頁面中建立popup對象。
(2)在按 鈕上,添加actionListener(不要添加showPopupBehavior組件,由於showPopupBehavior組件會在 Action事件以前觸發,也就是說,只要點擊按鈕就會彈 出窗口,這不符合要求),咱們只在actionListener對應MB中的方法中寫代碼條件彈出popup窗口。
public void dialogListener(DialogEvent dialogEvent){
if(dialogEvent.getOutcome() == DialogEvent.Outcome.ok) {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExtendedRenderKitService extendedRenderKitService = Service.getRenderKitService(facesContext, ExtendedRenderKitService.class);
String script = "var popup; popup = AdfPage.PAGE.findComponent('"+"p2"+"'); popup.show();";
extendedRenderKitService.addScript(facesContext, script);
}else if(dialogEvent.getOutcome() == Dialog.Outcome.cancel) {
//Nothing to do here...
}
}
18>am
Nested AM與Root AM的Transaction關係
在實際應用中,爲了達到邏輯重用的目的,會使用嵌套的AM。在Root AM和Nested AM中都有各自的VO,在一個頁面中,可能同時用到了不一樣AM的不一樣VO,那麼當一個AM提交時,另外一個AM是否也會提交呢?
實驗略,實驗中須要鞏固的代碼:
若是VO中字段爲Number類型,那麼給該字段設置值時,應該這樣--vo.setMinSalary(new oracle.jbo.domain.Number(1000));
獲取AM對象的代碼:
ApplicationModule am = ADFUtils.getApplicationModuleForDataControl("AppModuleDataControl");
AppModuleImpl service = (AppModuleImpl)am;
NestedAppModuleImpl nestedService = (NestedAppModuleImpl)service.getNestedAppModule();//從Root AM中獲取Nested AM對象
結論:
(1)Nested AM與Root AM使用的是同一個Transaction,都是Root AM中的Transaction,不管使用哪一個AM提交,另外一個AM中的VO也會被提交。
(2)多個Root AM之間的Transaction互不干涉,各自管理本身的。
(3)因此,想要避免提交本不想提交的表單,該表單所對應的VO的AM必須是Root AM。
注:Nested AM並非另一種AM,只不過是次AM是嵌套在另外一個AM中的,因此叫它Nested(嵌套的)AM。
Transaction和DBTransaction的區別與聯繫
DBTransaction和Transaction都是接口,DBTransaction是Transaction的子類,Transaction主要提供了一些事務經常使用到的方法:
.commit:Commits the transaction and saves all changes to the database.
.connect: Attempts(試圖) to establish(創建) a connection to the given database URL.
.disconnect: DisConnects the server from the database.
.getLockingMode: Gets the preferred(首先的、當前的) locking mode for this transaction.
.rollback: Rolls back the transaction and discards(丟棄) all changes.
.setLockingMode: Sets the preferred(首選的、當前的) locking mode for this transaction.
DBTransaction則繼承了以上方法,並提供了一些針對EO的方法:
. findByPrimaryKey()
. getSession()
. getEnvironment()
驗證明例略,需記住和鞏固代碼:
當給vo中添加row時,vo.createRow()後必定要記住vo.insertRow(row)。
在MB中先獲取DataControl對象,在從中獲取AM對象代碼,
DCDataControl dc = BindingContext。getCurrent().getDefaultDataControl();
ApplicationModule am = (ApplicationModule)dc.getDataProvider();
AppModuleImpl service = (AppModuleImpl)am;
驗證結論:
(1)使用getTransaction().commit()和getDBTransaction().commit(),數據庫都提交了。
(2)通常狀況下,使用Transaction就能夠了,除非你須要使用DBTransaction上獨有的方法。
19>Database Connection Pool調優
在AM的配置項中,有Connection Pool一項,其分爲兩種:JDBC URL和JDBC Datasource。
(1)在開發環境中,通常使用JDBC URL,由ADF管理ConnectionPool。這時,你能夠修改相關的參數。但通常來講,開發時不會關心數據庫鏈接池的優化。所以,通常不修改 這些參數。
(2) 在生產環境中,通常使用JDBC Datasource,由應用服務器管理Connection Pool,與ADF無關。全部在AM上設置的Connection Pool參數將被忽略。AM也將從應用服務器 管理的Connection Pool中獲取數據庫鏈接。
使用JDBC Datasource好處是不用在開發端配置數據庫的具體信息,未來數據庫變了,只要JNDI名字不變,程序就不用修改。
因此,總的來講,咱們不須要修改Connection Pool的配置,由於這個是由應用服務器管理的,不一樣的應用服務器配置不一樣,須要查相關手冊。
20>Application Module Pool調優
Application Module Pool使用用來存放有同一類型的AM實例的池子,多個瀏覽器客戶端能夠「共享使用」少許的Application Module實例,這樣就能夠提升應用的性能。只有根一級的Application Module才能夠創建Pool,換句話說,內嵌的Application Module也將「共享使用」根一級的Application Module Pool,包括數據庫鏈接,事務,緩存。
Application Module實例也分爲狀態和無狀態兩種。對於有狀態的AM實例,它保存用戶session的相關信息,用戶作下一步操做時,將會繼續使用該AM實例。如 果用戶請求不少,AM實例已經接近峯值,那麼將會「鈍化」這些有狀態的AM實例,即把有狀態信息持久化。而後把這些AM實例騰出來供其它用戶使用,等到該 用戶繼續作下一個有狀態操做時,再用一個新的AM實例,並匹配「激活」剛纔「鈍化」的信息。
AM Pool主要參數說明以下:
一、Pool Behavior Parameters
. Failover(失效備援) Transaction State Upon Managed Release: 默認false,建議設置爲true。
在有狀態的AM實例被釋放回池中時執行「鈍化」。
. Disconnect Application Module Upon Release:默認值false,建議設置爲false。
強制AM實例每次釋放回池中時,同時釋放掉其對應的JDBC鏈接。默認爲false,好處是不只不用再從數據庫鏈接池獲取鏈接,而且連prepared statements也能夠直接 拿來就用。
. Support Dynamic JDBC Credentials(文憑、信用狀): 默認值true,建議設置爲true。
容許程序在新的用戶Session開始的時候經過代碼來修改數據庫的鏈接的用戶和口令。
. Reset Non-Transactional State Upon Unmanaged Release: 默認true,建議設置true。
當AM實例以無狀態的方式釋放回池中時,重置全部的Non-Transaction State,好比VO的運行時設置,JDBC的Prepared Statements,綁定變量等等,保證放回池中的 AM實例是「乾淨」的
. Enable Application Module pooling: 默認false,建議設置爲true。
. Row-Level Locking Behavior Upon Release: 默認false,建議設置爲true。
強制AM實例被釋放回池時不去在數據庫中建立一個pending transaction state。
ADF web application應該設置鎖定模式爲樂觀鎖「optimistic」(默認爲悲觀鎖「pessimistic」),以免建立行級鎖。
關於參數「Disconnect Application Module Upon Release」實驗結論:
(1)在使用AM Pool時,發現數據庫鏈接消耗的特別快。用戶每次訪問一個頁面,都會新佔用一個數據庫鏈接,這是不合理的。
(2)Disconnect Application Module Upon Release參數默認不選中是有利於性能優化的。
(3) 參數Idle Instance Timeout、Pool Polling Interval、Maximum Instance Time to Live應該配合使用,基本原則是:Maximum Instance Time to Live > Idle Instance Timeout + Pool Polling Interval(不然還沒等AM Pool標記清除以前,AM實例就已經被清除了)。
(4)每 個AM池的設置能夠根據自身狀況有所不一樣,好比若是AM的調用時間比較長,能夠適當增大Maximum Instance Time to Live;Maximum Pool Size基本接近或略高於用 戶併發數的峯值,若是用戶併發數很高,能夠適當減少Maximum Instance Time to Live,便於回收AM實例和數據庫鏈接;對應操做頻繁,但事務較小的AM,能夠適當增 大。
(5)ADF 自帶的數據庫鏈接池通常不用於生產環境。在生產環境下,應該使用JDBC Datasource的方式,使用WLS的數據庫鏈接池來管理。基本原則是數據庫鏈接池的最大值 =AM Maximum Pool Size。Idle Instance Timeout、Pool Polling Interval,儘可能直接重用AM實例,無需從新獲取。
對AutoSubmit、PartialSubmit、Immediate、PartialTriggers更深層次的瞭解:
一、autoSubmit只在輸入組件上纔有的一個屬性,如RichIputText。
二、partialSubmit只在命令組件上纔有的一個屬性,如CommandLink。
autoSubmit 與partialSubmit的區別是,後者僅處理更改的組件自己以及在其partialTriggers屬性中包含引用的全部組件,不會觸發表單中的必 填項的驗證,除非這些 必填項的partialTriggers指向設置了autoSubmit=true的組件。
值得注意的 是,CommandToolBarButton默認partialSubmit=true,因此若是你須要刷新某個組件,必須設置 partialTriggers,不然頁面不會被刷新。而CommandButton默認partialSubmit=false,默認會刷新整個頁面。
技術因素不是網站成功的因素,決定網站成功的關鍵因素是內容。
若是你定一個高得離譜的目標,就算失敗了,那你的失敗也在任何人的成功之上——詹姆斯.卡梅隆。
22>TaskFlow之Reentry屬性的使用
在實際應用中,用戶可能會點擊瀏覽器的回退按鈕回到上一頁面,在有些狀況下會致使一些問題。 ADF Bounded TaskFlow有一個選項(Unbounded TaskFlow無此選項)能夠設置是否容許用戶使用瀏覽器的回退按鈕回到上一頁面,這個屬性就是Reentry。
Reentry能夠設置爲:
. reentry-allowed:默認選項。容許該bounded task flow中的全部頁面實用化瀏覽器的回退按鈕從新進入上一頁面。
. reentry-not-allowed: 不容許該bounded task flow中的全部頁面使用瀏覽器的回退按鈕從新進入上一頁面。這裏的不容許不是禁止用戶點擊瀏覽器的回退按鈕,這個是 沒有辦法禁止的。它的不容許時這樣體現的:當用戶點擊瀏覽器的回退按鈕後,能夠從新進入上一頁面,但若是你在該頁面作任何事情,也如點擊按鈕,將會拋出異 常: InvalidTaskFlowReentry。
. reentry-outcome-dependent:可否容許該bounded task flow中的全部頁面使用瀏覽器的回退按鈕從新進入上一頁面取決於上一次從該bounded task flow返回的outcome ,也就是說,取決於Return Activity上的Reentry屬性設置。適合的典型場景:購物網站若是用戶取消了某此採購,那麼容許回退;若是訂單已經提交,則不容許回退。
注:reentry- not-allowed的行爲和咱們想象的不同,過後警告用戶拋異常,這個頁面效果確定不太友好,這時,咱們應該建立一個exception handler來處理這個異常,提示用戶頁面過時,須要從新登陸之類的警告,並在幾秒以後自動跳轉到登陸頁面。
幾個須要明確的問題:
(1)、從新進入Task Flow後,Task Flow上的輸入參數將使用當前值(若是有新的賦值的話),而不是初始值。
(2)、從新進入Task Flow後,Manage Bean中的值也跟着回退到以前的值,全部在用戶回退以後的修改將丟失。能夠經過設置View Activity上的redirect屬性來改變這一行 爲。這個有待實驗考證。
23>TaskFlow之Transaction的使用
ADF TaskFlow有一個很重要的特性:在Bounded TaskFlow上能夠設置事務。也就是說,在這個TaskFlow中的全部Activity(View和其它非可視化的)都將屬於一個事務。區別於 Java EE Container上的事務設置(要麼是直接設置在EJB的方法上,要麼是設置在ejb.xml中,運行時由Container解析);TaskFlow 這個是設置在控制器層的,這使得咱們很容易控制一個TaskFlow的事務。
打開一個Bounded Task Flow,在Property中找到Behavior,其中Transaction屬性:找到
. No Controller Transaction:不加入任何事務中。
. Always Begin New Transaction:開始一個新的事務,不管是否已經在一個事務之中。
. Always Use Existing Transaction:加入已有的事務,若是沒有事務可加入,拋異常。
. Use Existing Transaction If Possible:加入已有的事務,若是沒有事務可加入,開始一個新的事務。
事務的提交是在Task Flow Return Activity上完成的,在Property中找到Behavior,其中End Transaction屬性,咱們能夠設置如何提交事務(commit or rollback)。
進一步對Bounded TaskFlow對事務支持程度的研究,如下實驗結論:
實驗一結論:Bounded TaskFlow中的全部View Activity都屬於一個事務。
實驗二結論:Bounded TaskFlow中事務處理是跨AM的,即不一樣AM中的VO的事務操做,也能夠做爲一個全局事務來管理。頁面都沒有
實驗三結論:Bounded TaskFlow中事務處理是跨AM、跨數據庫的,即不一樣AM中的VO的事務操做,VO來自於不一樣的數據庫,也能夠做爲一個全局事務來管理。
實驗四:2個AM,3個DB Connection,1個Bounded TaskFlow(包含兩個修改頁面和一個Method Call,每一個頁面都沒有事務提交功能,而是交給Task Flow Return Activity負責)。
實驗四結論:EJB Transaction由Java EE Container負責,不能與TaskFlow Transaction一塊兒做爲一個全局事務來管理兩者的事務各自獨立,互不干涉。
轉載自:http://blog.csdn.net/qq136722979/article/details/12856843