打印本頁將此頁作為電子郵件發送樣例代碼

亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

將 Flex 集成到 Java EE 應用程序的最佳實踐

系統 3632 0

將 Flex 集成到 Java EE 應用程序的最佳實踐

developerWorks
文檔選項
<script type="text/javascript"></script> <noscript></noscript> <script type="text/javascript"></script> <noscript></noscript>
將打印機的版面設置成橫向打印模式

打印本頁

將此頁作為電子郵件發送

將此頁作為電子郵件發送

樣例代碼

<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- this content will be automatically generated across all content areas --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->

級別: 中級

廖 雪峰 ( askxuefeng@gmail.com ), 軟件工程師, HP

2009 年 8 月 05 日

傳統的 Java EE 應用程序通常使用某種 MVC 框架(例如,Struts)作為前端用戶界面,隨著 Flex 的興起,基于 RIA 的客戶端能夠給用戶帶來更酷的界面,更短的響應時間,以及更接近于桌面應用程序的體驗。本文將講述如何將 Flex 集成至一個現有的 Java EE 應用程序中,以及如何應用最佳實踐高效率地并行開發 Java EE 和 Flex。
<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->

開發環境

本文的開發環境為 Windows 7 Ultimate,Eclipse 3.4,Flex Builder 3(從 參考資源 獲得下載鏈接)。Java EE 服務器使用 Resin 3.2,當然,您也可以使用 Tomcat 等其他 Java EE 服務器。





回頁首


現有的 Java EE 應用

假定我們已經擁有了一個管理雇員信息的 Java EE 應用,名為 EmployeeMgmt-Server,結構如 圖 1 所示:


圖 1. Java EE 工程結構
圖 1. Java EE 工程結構

這是一個典型的 Java EE 應用,使用了流行的 Spring 框架。為了簡化數據庫操作,我們使用了內存數據庫 HSQLDB。對這個簡單的應用,省略了 DAO,直接在 Fa?ade 中通過 Spring 的 JdbcTemplate 操作數據庫。最后,EmployeeMgmt 應用通過 Servlet 和 JSP 頁面為用戶提供前端界面:


圖 2. EmployeeMgmt Web 界面
圖 2. EmployeeMgmt Web 界面

該界面為傳統的 HTML 頁面,用戶每次點擊某個鏈接都需要刷新頁面。由于 Employee Management 系統更接近于傳統的桌面應用程序,因此,用 Flex 重新編寫界面會帶來更好的用戶體驗。





回頁首


集成 BlazeDS

如何將 Flex 集成至該 Java EE 應用呢?現在,我們希望用 Flex 替換掉原有的 Servlet 和 JSP 頁面,就需要讓 Flex 和 Java EE 后端通信。Flex 支持多種遠程調用方式,包括 HTTP,Web Services 和 AMF。不過,針對 Java EE 開發的服務器端應用,可以通過集成 BlazeDS,充分利用 AMF 協議并能輕易與 Flex 前端交換數據,這種方式是 Java EE 應用程序集成 Flex 的首選。

BlazeDS 是 Adobe LifeCycle Data Services 的開源版本,遵循 LGPL v3 授權,可以免費使用。BlazeDS 為 Flex 提供了基于 AMF 二進制協議的遠程調用支持,其作用相當于 Java 的 RMI。有了 BlazeDS,通過簡單的配置,一個 Java 接口就可以作為服務暴露給 Flex,供其遠程調用。

盡管現有的 EmployeeMgmt 應用程序已經有了 Fa?ade 接口,但這個接口是暴露給 Servlet 使用的,最好能再為 Flex 定義另一個接口 FlexService,并隱藏 Java 語言的特定對象(如 清單 1 所示):


清單 1. FlexService interface
                    				 
public interface FlexService { 
    Employee createEmployee(String name, String title, boolean gender, Date birth); 
    void deleteEmployee(String id); 
    Employee[] queryByName(String name); 
    Employee[] queryAll(); 
} 

                  

現在,Java EE 后端與 Flex 前端的接口已經定義好了,要完成 Java EE 后端的接口實現類非常容易,利用 Spring 強大的依賴注入功能,可以通過幾行簡單的代碼完成:


清單 2. FlexServiceImpl class
                    				 
public class FlexServiceImpl implements FlexService { 
    private static final Employee[] EMPTY_EMPLOYEE_ARRAY = new Employee[0]; 
    private Facade facade; 

    public void setFacade(Facade facade) { 
        this.facade = facade; 
    } 

    public Employee createEmployee(String name, String title, boolean gender, 
        Date birth) { 
        return facade.createEmployee(name, title, gender, birth); 
    } 

    public void deleteEmployee(String id) { 
        facade.deleteEmployee(id); 
    } 

    public Employee[] queryAll() { 
        return facade.queryAll().toArray(EMPTY_EMPLOYEE_ARRAY); 
    } 

    public Employee[] queryByName(String name) { 
        return facade.queryByName(name).toArray(EMPTY_EMPLOYEE_ARRAY); 
    } 
} 

                  

然后,我們將 BlazeDS 所需的 jar 包放至 /WEB-INF/lib/ 。BlazeDS 需要如下的 jar:


清單 3. BlazeDS 依賴的 Jar
                    				 
backport-util-concurrent.jar 
commons-httpclient.jar 
commons-logging.jar 
flex-messaging-common.jar 
flex-messaging-core.jar 
flex-messaging-proxy.jar 
flex-messaging-remoting.jar 

                  

在 web.xml 中添加 HttpFlexSession 和 Servlet 映射。HttpFlexSession 是 BlazeDS 提供的一個 Listener,負責監聽 Flex 遠程調用請求,并進行一些初始化設置:


清單 4. 定義 Flex Listener
                    				 
<listener> 
    <listener-class>flex.messaging.HttpFlexSession</listener-class> 
</listener> 

                  

MessageBrokerServlet 是真正處理 Flex 遠程調用請求的 Servlet,我們需要將其映射到指定的 URL:


清單 5. 定義 Flex servlet
                    				 
<servlet> 
    <servlet-name>messageBroker</servlet-name> 
    <servlet-class>flex.messaging.MessageBrokerServlet</servlet-class> 
    <init-param> 
        <param-name>services.configuration.file</param-name> 
        <param-value>/WEB-INF/flex/services-config.xml</param-value> 
    </init-param> 
    <load-on-startup>0</load-on-startup> 
</servlet> 

<servlet-mapping> 
    <servlet-name>messageBroker</servlet-name> 
    <url-pattern>/messagebroker/*</url-pattern> 
</servlet-mapping> 

                  

BlazeDS 所需的所有配置文件均放在 /WEB-INF/flex/ 目錄下。BlazeDS 將讀取 services-config.xml 配置文件,該配置文件又引用了 remoting-config.xml、proxy-config.xml 和 messaging-config.xml 這 3 個配置文件,所以,一共需要 4 個配置文件。

由于 BlazeDS 需要將 Java 接口 FlexService 暴露給 Flex 前端,因此,我們在配置文件 remoting-config.xml 中將 FlexService 接口聲明為一個服務:


清單 6. 定義 flexService 服務
                    				 
<destination id="flexService"> 
    <properties> 
        <source>org.expressme.employee.mgmt.flex.FlexServiceImpl</source> 
        <scope>application</scope> 
    </properties> 
</destination> 

                  

服務名稱通過 destination 的 id 屬性指定,Flex 前端通過該服務名稱來進行遠程調用。scope 指定為 application,表示該對象是一個全局對象。

然而,按照默認的聲明,BlazeDS 會去實例化 FlexService 對象。對于一個 Java EE 應用來說,通常這些服務對象都是被容器管理的(例如,Spring 容器或 EJB 容器),更合適的方法是查找該服務對象而非直接實例化。因此,需要告訴 BlazeDS 通過 Factory 來查找指定的 FlexService 對象,修改配置如下:


清單 7. 通過 factory 定義 flexService
                    				 
<destination id="flexService"> 
    <properties> 
        <factory>flexFactory</factory> 
        <source>flexService</source> 
        <scope>application</scope> 
    </properties> 
</destination> 

                  

現在,Flex 如何才能通過 BlazeDS 調用 FlexService 接口呢?由于 FlexService 對象已經被 Spring 管理,因此,我們需要編寫一個 FlexFactory 告訴 BlazeDS 如何找到 Spring 管理的 FlexService 的實例。flexFactory 在 services-config.xml 中指定:


清單 8. 定義 flexFactory
                    				 
<factories> 
    <factory id="flexFactory" class="org.expressme.employee.mgmt.flex.FlexFactoryImpl"/> 
</factories> 

                  

FlexFactoryImpl 實現了 FlexFactory 接口,該接口完成兩件事情:

  1. 創建 FactoryInstance 對象;
  2. 通過 FactoryInstance 對象查找我們需要的 FlexService。

因此,需要一個 FactoryInstance 的實現類,我們編寫一個 SpringFactoryInstance,以便從 Spring 的容器中查找 FlexService:


清單 9. SpringFactoryInstance class
                    				 
class SpringFactoryInstance extends FactoryInstance { 
    private Log log = LogFactory.getLog(getClass()); 

    SpringFactoryInstance(FlexFactory factory, String id, ConfigMap properties) { 
        super(factory, id, properties); 
    } 

    public Object lookup() { 
        ApplicationContext appContext = WebApplicationContextUtils. 
                getRequiredWebApplicationContext( 
                    FlexContext.getServletConfig().getServletContext() 
        ); 
        String beanName = getSource(); 
        try { 
            log.info("Lookup bean from Spring ApplicationContext: " + beanName); 
            return appContext.getBean(beanName); 
        } 
        catch (NoSuchBeanDefinitionException nex) { 
            ... 
        } 
        catch (BeansException bex) { 
            ... 
        } 
        catch (Exception ex) { 
            ... 
        } 
    } 
} 

                  

FlexFactoryImpl 負責實例化 SpringFactoryInstance 并通過 SpringFactoryInstance 的 lookup() 方法查找 FlexService 接口對象:


清單 10. FlexFactoryImpl class
                    				 
public class FlexFactoryImpl implements FlexFactory { 
    private Log log = LogFactory.getLog(getClass()); 

    public FactoryInstance createFactoryInstance(String id, ConfigMap properties) { 
        log.info("Create FactoryInstance."); 
        SpringFactoryInstance instance = new SpringFactoryInstance(this, id, properties); 
        instance.setSource(properties.getPropertyAsString(SOURCE, instance.getId())); 
        return instance; 
    } 

    public Object lookup(FactoryInstance instanceInfo) { 
        log.info("Lookup service object."); 
        return instanceInfo.lookup(); 
    } 

    public void initialize(String id, ConfigMap configMap) { 
    } 
} 

                  

以下是 BlazeDS 查找 FlexService 接口的過程:

  1. BlazeDS 將首先創建 FlexFactory 的實例—— FlexFactoryImpl;
  2. 當接收到 Flex 前端的遠程調用請求時,BlazeDS 通過 FlexFactory 創建 FactoryInstance 對象,并傳入請求的 Service ID。在這個應用程序中,被創建的 FactoryInstance 實際對象是 SpringFactoryInstance;
  3. FactoryInstance 的 lookup() 方法被調用,在 SpringFactoryInstance 中,首先查找 Spring 容器,然后,通過 Bean 的 ID 查找 Bean,最終,FlexService 接口的實例被返回。

注意到 destination 的 id 并沒有寫死在代碼中,而是通過以下語句獲得的:


清單 11. 獲取 destination 的 ID
                    				 
properties.getPropertyAsString(SOURCE, instance.getId()) 

                  

Property 的 SOURCE 屬性由 BlazeDS 讀取 XML 配置文件獲得:


清單 12. 配置 destination 的 id
                    				 
<destination id="flexService"> 
    <properties> 
        <factory>flexFactory</factory> 
        <source>flexService</source> 
        <scope>application</scope> 
    </properties> 
</destination> 

                  

如果您沒有使用 Spring 框架,也不要緊,只需修改 FactoryInstance 的 lookup() 方法。例如,對于一個 EJB 來說,lookup() 方法應該通過 JNDI 查找返回遠程接口。無論應用程序結構如何,我們的最終目標是向 BlazeDS 返回一個 FlexService 的實例對象。





回頁首


開發 Flex 客戶端

首先安裝 Flex Builder 3,可以在 Adobe 的官方網站獲得 30 天免費試用版。然后,打開 Flex Builder 3,創建一個新的 Flex Project,命名為 EmployeeMgmt-Flex:


圖 3. 新建 Flex 工程 - 第一步
圖 3. 新建 Flex 工程 - 第一步

Flex Project 需要指定 Server 端的配置文件地址:


圖 4. 新建 Flex 工程 - 第二步
圖 4. 新建 Flex 工程 - 第二步

因此,需要填入 EmployeeMgmt-Server 項目的 web 根目錄,該目錄下必須要存在 /WEB-INF/flex/ 。點擊“Validate Configuration”驗證配置文件是否正確,只有通過驗證后,才能繼續。默認地,Flex Builder 將會把生成的 Flash 文件放到 EmployeeMgmt-Server 項目的 web/EmployeeMgmt-Flex-debug 目錄下。

一個 Flex Project 的目錄結構如下:


圖 5. Flex 工程的目錄結構
圖 5. Flex 工程的目錄結構

用 Flex Builder 做出漂亮的用戶界面非常容易。Flex Builder 提供了一個可視化的編輯器,通過簡單的拖拽,一個毫無經驗的開發人員也能夠設計出漂亮的布局。如果熟悉一點 XML 的知識,編輯 MXML 也并非難事。我們設計的 Employee Management 系統界面的最終效果如下:


圖 6. 用 Flex Builder 的可視化編輯器設計界面
圖 6. 用 Flex Builder 的可視化編輯器設計界面

本文不打算討論如何編寫 Flex 界面,而是把重點放在如何實現遠程調用。

為了能在 Flex 中實現遠程調用,我們需要定義一個 RemoteObject 對象。可以通過 ActionScript 編碼創建該對象,也可以直接在 MXML 中定義一個 RemoteObject 對象,并列出其所有的方法:


清單 13. 定義 flexServiceRO
                    				 
<mx:RemoteObject id="flexServiceRO" destination="flexService"> 
    <mx:method name="queryAll" result="handleQueryAll(result : ResultEvent)"/> 
</mx:RemoteObject> 

                  

現在,就可以調用這個名為 flexServiceRO 的 RemoteObject 對象的方法了:


清單 14. 調用 FlexServiceRO.queryAll()
                    				 
 flexServiceRO.queryAll(function(result : ResultEvent) { 
    var employees = result.result as Array; 
 }); 

                  

運行該 Flex Application,雇員信息已經被正確獲取了:


圖 7. 在瀏覽器中運行 Flex application
圖 7. 在瀏覽器中運行 Flex application




回頁首


增強 RemoteObject 對象

通過 RemoteObject 進行調用雖然簡單,但存在不少問題:首先,RemoteObject 是一個 Dynamic Class,Flex Builder 的編譯器無法替我們檢查參數類型和參數個數,這樣,在編寫 ActionScript 代碼時極易出錯。此外,接口變動時(這種情況常常發生),需要重新修改 RemoteObject 的定義。此外,Flex 團隊需要一份隨時修訂的完整的 FlexService 接口文檔才能工作。

因此,最好能使用強類型的 RemoteObject 接口,讓 Flex Builder 的編譯器及早發現錯誤。這個強類型的 RemoteObject 最好能通過 Java EE 應用的 FlexService 接口自動生成,這樣,就無需再維護 RemoteObject 的定義。

為了能完成自動生成 RemoteObject 對象,我編寫了一個 Java2ActionScript 的 Ant 任務來自動轉換 FlexService 接口以及相關的所有 JavaBean。JavaInterface2RemoteObjectTask 完成一個 Java 接口對象到 RemoteObject 對象的轉換。使用如下的 Ant 腳本:


清單 15. 生成 ActionScript class 的 Ant 腳本
                    				 
<taskdef name="genactionscript" classname="org.expressme.ant.JavaBean2ActionScriptTask"> 
    <classpath refid="build-classpath" /> 
</taskdef> 
<taskdef name="genremoteobject" 
    classname="org.expressme.ant.JavaInterface2RemoteObjectTask"> 
    <classpath refid="build-classpath" /> 
</taskdef> 
<genactionscript 
    packageName="org.expressme.employee.mgmt"
    includes="Employee"
    orderByName="true"
    encoding="UTF-8"
    outputDir="${gen.dir}"
/> 
<genremoteobject 
    interfaceClass="org.expressme.employee.mgmt.flex.FlexService"
    encoding="UTF-8"
    outputDir="${gen.dir}"
    destination="flexService"
/> 

                  

轉換后的 FlexServiceRO 類擁有 Java 接口對應的所有方法,每個方法均為強類型簽名,并添加額外的兩個可選的函數處理 result 和 fault 事件。例如,queryByName 方法:


清單 16. 自動生成的 queryByName() 方法
                    				 
public function queryByName(arg1 : String, result : Function = null, 
    fault : Function = null) : void { 
    var op : AbstractOperation = ro.getOperation("queryByName"); 
    if (result!=null) { 
        op.addEventListener(ResultEvent.RESULT, result); 
    } 
    if (fault!=null) { 
        op.addEventListener(FaultEvent.FAULT, fault); 
    } 
    var f : Function = function() : void { 
        op.removeEventListener(ResultEvent.RESULT, f); 
        op.removeEventListener(FaultEvent.FAULT, f); 
        if (result!=null) { 
            op.removeEventListener(ResultEvent.RESULT, result); 
        } 
        if (fault!=null) { 
            op.addEventListener(FaultEvent.FAULT, fault); 
        } 
    } 
    op.addEventListener(ResultEvent.RESULT, f); 
    op.addEventListener(FaultEvent.FAULT, f); 
    op.send(arg1); 
} 

                  

轉換 Java 接口是通過 Interface.as 和 InterfaceMethod.as 兩個模板文件完成的,此外,所有在 Java EE 后端和 Flex 之間傳遞的 JavaBean 對象也通過 JavaBean2ActionScriptTask 自動轉換成對應的 ActionScript 類,這是通過 Bean.as 模板完成的。

有了 Java 類到 ActionScript 的自動轉換,我們在編寫 ActionScript 時,就能享受到編譯器檢查和 ActionScript 類方法的自動提示了:


圖 8. Flex Builder 的代碼自動補全
圖 8. Flex Builder 的代碼自動補全

唯一的缺憾是通過反射讀取 FlexService 接口時,我們失去了方法的參數名稱,因此,FlexServiceRO 的方法參數名只能變成 arg1,arg2 …… 等,要讀取 FlexService 接口的方法參數名,只能通過解析 Java 源代碼實現。

現在,Java EE 后端開發團隊和 Flex 前端開發團隊只需協商定義好 FlexService 接口,然后,利用 Java2ActionScript,Flex 團隊就得到了強類型的 FlexServiceRO 類,而 Java EE 團隊則只需集中精力實現 FlexService 接口。

在開發的前期,甚至可以用硬編碼的 FlexService 的實現類。每當 FlexService 變動時,只需再次運行 Ant 腳本,就可以獲得最新的 FlexServiceRO 類。這樣,兩個團隊都可以立刻開始工作,僅需要通過 FlexService 接口就可以完美地協同開發。






回頁首


下載

描述 名字 大小 下載方法 Java EE 工程源碼 Flex 工程源碼 Java2ActionScript 工程源碼
EmployeeMgmt-Server.zip 8.6 MB HTTP
EmployeeMgmt-Flex.zip 17.9 KB HTTP
Java2ActionScript.zip 1.3 MB HTTP
關于下載方法的信息


參考資料

學習

獲得產品和技術

討論

將 Flex 集成到 Java EE 應用程序的最佳實踐


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 噜噜啪| 成年性午夜免费视频网站不卡 | 亚洲日本va中文字幕婷婷 | 国产日产欧美一区二区三区 | 亚洲精品久久久久久小说 | 久久国产三级 | 四虎精品 | 欧美劲爆第一页 | 欧美日韩国产一区二区三区播放 | 青草九九 | 四虎在线影视 | 69一级毛片| 九九热观看视频 | 久久久久久久综合日本亚洲 | 久久这里只有精品免费视频 | 99久久这里只精品麻豆 | 精品国产91在线网 | 国产成人精品曰本亚洲77美色 | 色天天干 | 日日夜夜免费精品视频 | 黄色四虎影院 | 日日狠狠久久偷偷四色综合免费 | 一级成人毛片免费观看 | 色爱两性网 | 美女毛片 | 夜夜操天天 | 一级女人18片毛片免费视频 | 久久精品国产大片免费观看 | 香蕉爱爱网 | 伊在人亚洲香蕉精品区麻豆 | 亚洲欧美日韩久久精品第一区 | 欧美日韩亚洲精品一区二区三区 | 亚洲国产日韩欧美一区二区三区 | 天天色天天拍 | 亚洲水蜜桃久久综合网站 | 久久精品国产亚洲网站 | 国产亚洲精品九九久在线观看 | 一集毛片 | 久久精品天天中文字幕人 | 奇米影视在线播放 | 色拍拍欧美视频在线看 |