1. 程式人生 > >ADF高階開發 之一:客製化與個性化 ADF 應用

ADF高階開發 之一:客製化與個性化 ADF 應用

完成《Customizing and Personalizing an Application
這篇教程詳細地說明了如何定製化ADF應用,由於文章較長,實驗步驟較多,為了方便大家理解,我這裡先介紹一下客製化與個性化的概念。
注意,我在這裡把Customize翻譯為“客製化”,把Personalize翻譯為“個性化”,而把二者的統稱為“定製化”。
所以在下文提到這些詞的時候,希望大家能夠明白我指的是那個英文單詞。

我們在日常應用中經常會有這樣的需求:
(1)每個使用者希望能夠儲存自己常用的查詢條件。
(2)每個使用者對錶格的顯示方式風格不同(哪些欄位顯示或不顯示,欄位長度,前後順序,是否凍結前幾列)。
(3)雖然應用的功能類似,但不同的行業(industry)有不同的風格,比如金融行業,製造企業等等。

(4)接(3),雖然是同一個行業(industry),但仍然希望有不同的風格,比如雖然都是銀行(finance),工商銀行和中國銀行的網站風格就不同。
ADF考慮到了這些方面的需求,並且允許使用者做這樣的定製化。ADF應用的定製化分為兩種:
(1)個性化:允許使用者執行時對應用進行定製,對應需求中的(1)和(2)。
(2)客製化:允許使用者設計時對應用進行定製,對應需求中的(3)和(4)。
客製化的原理如下圖所示:

從上圖可以看出:
(1)一個ADF應用允許設定多個客製化層,如industry層及site層。
(2)每一個客製化層允許具有多個客製化值,如industry層可以具有healthcare和financial等。

(3)執行時,每一個層只有一個客製化值有效。
(4)客製化層的順序由adf-config.xml中各個客製化類的順序決定。
客製化的原理是:在設計時,在原有ADF應用的基礎上,增加客製化層(可以有多層),每一層可能對應不同的行業、不同的公司。
這樣做的好處是:既能滿足不同風格的展現要求,同時又不改變原有應用的基礎程式碼。

無論是客製化還是個性化,這些定製的內容均不會對已開發完成的應用作出修改,而是儲存在MDS(Metadata Services repository)中。
MDS 支援兩種儲存方式的實現:檔案和資料庫。
ADF應用預設使用基於檔案的MDS,關於如何使用基於資料庫方式的MDS,會另文介紹。

好,下面就開始做這個實驗。

本實驗需要使用FOD Schema,請參考《釋出與執行 Oracle Fusion Order Demo》。

重要步驟說明:

1. 修改CustomizationLayerValues.xml檔案內容
配置global-level的客製化層要修改位於[jdev_home]/jdev/jdeveloper/jdev目錄下的CustomizationLayerValues.xml檔案。
配置application-level的客製化層,要點選adf-config.xml中的MDS Tab中的“Configure Design Time Customization Layer Values”。
這樣會在應用的\.mds\dt\customizationLayerValues\目錄中建立CustomizationLayerValues.xml檔案。



<cust-layer name="site" id-prefix="s">
<cust-layer-value value="headquarters" display-name="Headquarters" id-prefix="1"/>
<cust-layer-value value="remoteoffices" display-name="Remote Offices" id-prefix="2"/>
<cust-layer-value value="site" display-name="Site"/>
</cust-layer>

在實驗中只定義了一個客製化層:site,該客製化層可以設定為三個值:remoteoffice、headquarters、site。
你也可以定義多個客製化層。每個客製化層的先後順序是定義在adf-config.xml檔案中的。

2. 建立customization.properties檔案
說明:customization.properties決定執行時每個客製化層使用哪個值。
在Model Project的src目錄下建立customization.properties檔案,內容如下:
#Configured values for the default layer values
#site=remoteoffices
site=headquarters 
因為實驗中只定義了一個客製化層:site,所以這裡只給site客製化層賦值。
如果有多個客製化層,可以分別為每個層賦值,比如:
#Configured values for the default layer values
#industry=financial
#industry=healthcare
#site=remoteoffices
site=headquarters

3. 建立客製化層類:SiteCC
說明:一個客製化層對應一個客製化層類,客製化層類在執行時讀取customization.properties檔案,決定使用該客製化層使用哪個值。
其中要實現的介面方法有:
(1)CacheHint getCacheHint();
決定customization的型別,返回值包括ALL_USERS, MULTI_USER, REQUEST, USER四種。
ALL_USERS:customization為針對某應用全域性有效的,通常用於static型別的customization層。
MULTI_USER:針對複數使用者有效的customization。
REQUEST:針對當前請求有效的customization。
USER:針對某特定使用者有效的customization,通過使用者訪問應用的Session來決定具體使用者。
(2)String getName();
返回當前客製化層類對應的客製化層的值。
(3)String generateIDPrefix(RestrictedSession sess, MetadataObject mo);
返回在MDS中對當前客製化層元素加的字首,以使該客製化層的元素在MDS中具有唯一標示。這一字首在所有客製化層中必須是唯一的,出於效能考慮應小於4個字元。
(4)String[] getValue(RestrictedSession sess, MetadataObject mo);
返回指定客製化層的值,注意返回型別是個陣列,其實只有一個值。

package oracle.model.mycompany;

import java.io.IOException;
import java.io.InputStream;

import java.util.Properties;

import oracle.mds.core.MetadataObject;
import oracle.mds.core.RestrictedSession;
import oracle.mds.cust.CacheHint;
import oracle.mds.cust.CustomizationClass;

public class SiteCC extends CustomizationClass {
    private static final String DEFAULT_LAYER_NAME = "site";
    private String mLayerName = DEFAULT_LAYER_NAME;

    public SiteCC() {
    }

    public SiteCC(String layerName) {
        mLayerName = layerName;
    }

    public CacheHint getCacheHint() {
        return CacheHint.ALL_USERS;
    }

    public String getName() {
        return mLayerName;
    }

    public String[] getValue(RestrictedSession sess, MetadataObject mo) {
        // This needs to return the site value at runtime.
        // For now, it's always null.
        Properties properties = new Properties();
        String configuredValue = null;
        Class clazz = SiteCC.class;
        InputStream is = clazz.getResourceAsStream("/customization.properties");
        if (is != null) {
            try {
                properties.load(is);
                String propValue = properties.getProperty(mLayerName);
                if (propValue != null) {
                    configuredValue = propValue;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return new String[] { configuredValue };
    }
}

注意:建議修改getValue方法,不要每次都從customization.properties檔案中讀取值,這樣會影響效能,應該放到建立一個快取,放到快取中。
把SiteCC類配置到adf-config.xml中。


4. 設定ViewController專案,允許客製化
右鍵ViewController專案,選擇屬性,選擇ADF View,勾上“Enable Seeded Customizations”。
這樣,ViewController專案就可以定製化了。


5. 建立基礎的ADF Web應用,TaskFlows,JSF Pages,等等。
這一步就是開發一個普通的ADF Web應用,因此略去步驟。

6. 把JDeveloper切換到Customization Developer角色,準備客製化ADF應用
你可以客製化的內容不僅僅只有檢視層,包括控制器層和模型層都可以客製化。
不能客製化的檔案物件上面會有個“鎖”的圖示。
客製化分為使靜態的(比如本實驗)和動態的,所謂靜態的就是事先知道使用者使用的是哪些客製化層,每個客製化層的值是什麼。
所謂動態就是事先不知道使用者使用的是哪些客製化層以及每個客製化層的值,可能會根據登入使用者的不同決定使用哪些客製化層。關於動態的客製化層,以後另文再述。
如果一切正常,換到Customization Developer角色後,你應該看到你設定的客製化層,如下圖:

在本實驗中,進行了以下客製化:
(1)site=headquarters時,在Browse.jsf頁面中增加了一個Table,繫結到OrderItem。
(2)site=remoteoffices時,修改了OrderItemsView VO的定義,增加了來自ProductsBase EO中的ProductName欄位。
(3)site=remoteoffices時,在Browse.jsf頁面中增加了一個Table,繫結到OrderItem(此時已經多了ProductName欄位)。
(4)site=remoteoffices時,在More.jsf頁面中為Form外面罩了一個“Show Detail Header”佈局元件
注意,以上的所有改動,都沒有改變基礎應用的原始程式碼,而是生成了對應的客製化的XML檔案,見下兩圖:



7. 執行客製化後應用,看看不同的客製化效果
JDeveloper依然在Customization Developer角色下,分別前後兩次修改customization.properties檔案。
第1次改為site=headquarters,執行效果如下:

第2次改為site=remoteoffices,執行效果如下:



8. JDeveloper切換回Default Role,準備允許使用者個性化
預設情況下,使用者訪問Web應用時所做的個性化設定是無法儲存的,只能在每一次的請求中保留,發起下一次請求後,之前個性化設定就“丟掉了”。
ADF個性化設定有兩種:
(1)For Duration of Session:使用者個性化設定儲存在使用者的Session中,只要使用者不退出應用,將一直有效。
(2)Across Session using MDS:使用者個性化設定持久化在MDS中,即使使用者退出應用也一直保留,使用者再次登入後,依然可以使用自己之前儲存的設定。甚至應用停掉後再重新啟動,使用者個性化設定依然保留。

8.1 使用者個性化設定儲存在使用者的Session中
ADF Faces元件預設支援一些元件屬性的個性化資訊儲存在使用者的Session中。
因此只要設定ViewController專案屬性如下就可以把使用者個性化設定儲存在使用者的Session中了:

執行應用,做一些個性化設定,發現使用者設定一直有效。重新開啟一個IE或停掉應用後再重啟,發現個性化設定“丟掉”了。

8.2 使用者個性化設定持久化在MDS中
首先設定ViewController專案屬性如下:

接著在adf-config.xml中增加一個UserCC個性化類(該類是ADF提供的)。

然後在adf-config.xml中告訴MDS,你要對哪些ADF Faces元件的哪些屬性進行持久化。


9. Enable ADF Security,建立角色和測試使用者並給角色授權
關於ADF Security,將在下一篇文章中專述,這裡不解釋。


10. 執行ADF應用,用不同的使用者測試個性化
執行ADF應用,使用user1登入,做一些個性化設定,然後停掉應用再啟動,再用user1登入,發現設定依然在。
那麼使用者的個性化設定是持久化在哪裡了呢?
右鍵選擇ADF應用,檢視屬性Run-MDS:

可以看出,使用者個性化設定預設是持久化在檔案系統當中的,比如:
C:\Oracle\JDevRuntime\system11.1.2.1.38.60.81\o.mds.ide.deploy.base\adrs\CustomizeApp\AutoGeneratedMar\mds_adrs_writedir\mdssys\cust\user\user1。
其中引數”preserve customizations across application run“是保留個性化設定在應用每次重新Run時。
”Delete customizations before each run"是在在應用每次重新Run時都清除個性化設定。
當然以上設定僅僅適合於開發環境,在生產環境中,應該持久化在資料庫中。
在生產環境中使用EM Console釋出應用時,會有一個MDS選項讓你選擇,就是為持久化使用者個性化設定而用的。

11. 建議把customization.properties檔案和SiteCC類單獨打成一個Jar包
因為它們本身與應用邏輯無關,只是在執行時決定使用哪些客製化層,因此不要放在原始的應用程式碼中。
打包步驟如下:
(1)編譯Model Project,釋出Model Project為一個Jar檔案

(2)選中 Include Manifest File

(3)只選中客製化類SiteCC和customization.properties檔案。

(4)如果別的應用要使用該Jar,可以把該Jar檔案複製到[jdev_home]\jdeveloper\jdev\lib\patches目錄下,或者加到專案的Class Path和Library中。

http://maping930883.blogspot.com/2009/09/adf034adf-adf_20.html