Worklight中適配器的開發(fā)
文章將通過基于 Eclipse 的 IDE,來開發(fā) Worklight 支持的 HTTP 和 SQL 適配器;并且演示測試適配器的方法,最后,通過集成應(yīng)用、適配器和 Web Service 來體現(xiàn)適配器在開發(fā)移動應(yīng)用中的重大作用。
Worklight 中適配器的架構(gòu)
WorklightWorklight作為一個移動程序的開發(fā)平臺,通過三種模式(Web、混合、本地)支持了不同需求的客戶端開發(fā),但是面臨的一個現(xiàn)實問題是如何和已有的系統(tǒng)進行良好的集成。適配器(adapter)是平臺的服務(wù)器端組件,作為一個傳輸層負責Worklight 服務(wù)器和不同企業(yè)級后臺的連接。通過平臺支持的 HTTP 和 SQL 適配器,客戶端應(yīng)用可以與原有系統(tǒng)方便的進行數(shù)據(jù)訪問,這減少了重復(fù)的開發(fā)工作。
適配器由三部分組成:基于 XML 的配置文件,用于定義適配器的類型和提供的方法;基于 JS 的方法實現(xiàn)文件,通過 Mozilla Rhino 解析器實現(xiàn)對不同后臺的訪問;基于 XSL 文件的數(shù)據(jù)轉(zhuǎn)化規(guī)則,在 HTTP 適配器中存在,用于將獲得的數(shù)據(jù)按照一定規(guī)則進行轉(zhuǎn)化。
Worklight支持的適配器提供了如下特性:
- 快速開發(fā):開發(fā)者可以使用便捷而強大的服務(wù)器端 JavaScript 創(chuàng)建簡潔易讀的代碼,用于和不同后臺程序的集成。
- 只讀操作和事務(wù)操作:平臺通過適配器支持對后臺系統(tǒng)的只讀和事物操作。
- 安全:適配器使用靈活的認證機制創(chuàng)建與后臺的連接,使用的用戶可以是系統(tǒng)用戶也可以是事務(wù)中操作的用戶。
- 可擴展性:適配器通過 cache 機制減少了與后臺系統(tǒng)的交互,并且通過配置,限定和后臺系統(tǒng)建立的連接數(shù)。
- 數(shù)據(jù)透明:適配器提供了獲取后臺數(shù)據(jù)的統(tǒng)一接口,這樣開發(fā)者在獲取數(shù)據(jù)時就不需要關(guān)注數(shù)據(jù)源、格式和傳輸協(xié)議信息。
圖 1. 適配器架構(gòu)
圖 1 描述了適配器和前臺的 app 以及后臺系統(tǒng)間數(shù)據(jù)交互的過程,具體的流程如下:
- 適配器暴露一系列的方法,稱之為 procedures,前臺 app 通過 Ajax 方式調(diào)用這些過程。
- 這些方法從后臺獲取相應(yīng)信息。
- 后臺系統(tǒng)返回的數(shù)據(jù)格式如下
- 如果格式為 JSON,Worklight服務(wù)器直接返回。
- 如果格式不是 JSON,服務(wù)器將數(shù)據(jù)格式轉(zhuǎn)化為 JSON 后,再返回。
- 這些方法將獲得的 JSON 數(shù)據(jù)進行業(yè)務(wù)處理,將最終結(jié)果返回給 app。
基于 Eclipse 的適配器開發(fā)
根據(jù)適配器連接的后臺種類,它被分為 HTTP 適配器和 SQL 適配器。在實際的應(yīng)用中 SQL 適配器用于連接不同的后臺數(shù)據(jù)庫,并通過 SQL 語句或存儲過程進行訪問。適配器目前支持 MySQL 和 Oracle 的數(shù)據(jù)庫,并且在幾個月后將支持 DB2 數(shù)據(jù)庫。HTTP 適配器支持訪問 soap 服務(wù)和 rest 服務(wù),并且可以根據(jù)指定的 XSL 文件對獲得的數(shù)據(jù)片段進行轉(zhuǎn)化,獲得用戶需要的數(shù)據(jù)和格式。
為了更好的演示不同適配器的作用和相互合作的方法,文章將構(gòu)建如下場景:
- 首先創(chuàng)建 SQL 適配器,并且提供對于 SQL 語句和存儲過程的訪問。
- 然后創(chuàng)建 HTTP 適配器,用于訪問由 Axis2 框架構(gòu)建的 Web Service。
- 通過 Eclipse 提供的測試環(huán)境,對于前面創(chuàng)建的適配器進行測試,并且解釋測試返回信息的含義。
- 最后通過開發(fā)一個應(yīng)用,并且整合上述的適配器,完成一個完整的功能。
adapter-jndi-name = ${custom-db.1.jndi-name} custom-db.1.relative-jndi-name = jdbc/worklight_adapter custom-db.1.driver = com.mysql.jdbc.Driver custom-db.1.url = jdbc:mysql://localhost:3306/worklight_adapter custom-db.1.username = root custom-db.1.password = root
在安裝有Worklight 插件的 Eclipse 下開發(fā)適配器通過下面的步驟可以完成:
新建工程和 SQL 適配器:
- 點擊 File-> New -> Project -> Worklight -> Worklight Project
- 輸入工程名稱:HelloAdapterProj,點擊確認,完成工程創(chuàng)建
- 點擊 File-> New -> Other -> Worklight -> Worklight Adapter
- 輸入應(yīng)用名稱:MySQLAdapter,選擇 HelloAdapterProj 作為工程,在適配器類型中選擇 SQL Adapter,點擊確認,完成 SQL 適配器創(chuàng)建
創(chuàng)建完畢的適配器其文件結(jié)構(gòu)如下:
- MySQLAdapter.xml:在文件中定義了很多的屬性,比如適配器在Worklight 控制臺中顯示的名稱和簡單描述,最大的連接數(shù)等等,其中最重要的是下列兩個參數(shù):
- dataSourceJNDIName 定義了適配器所連接的 JNDI 的名稱,具體的配置將在下面敘述
- procedure 定義適配器向外提供的方法名稱(需要通過 .js 文件實現(xiàn))
- MySQLAdapter-impl.js:在文件中實現(xiàn)了兩個方法,getAllCountries 用于調(diào)用數(shù)據(jù)庫中的存儲過程;getOneCountryID 通過調(diào)用 SQL 語句獲取相應(yīng)的信息
對于適配器需要的 JNDI 參數(shù),可以通過修改 Worklight 的配置文件實現(xiàn)。在 Worklight 框架中存在一個默認的配置文件 default.worklight.properties,用戶可以通過修改 worklight.properties 文件來覆蓋默認配置文件中的一些屬性。清單 1 描述了為連接本地的 SQL 數(shù)據(jù)庫,在 worklight.properties 添加的配置信息:
清單 1. JNDI 配置
- adapter-jndi-name = ${custom-db.1.jndi-name}
- custom-db.1.relative-jndi-name = jdbc/worklight_adapter
- custom-db.1.driver = com.mysql.jdbc.Driver
- custom-db.1.url = jdbc:mysql://localhost:3306/worklight_adapter
- custom-db.1.username = root
- custom-db.1.password = root
所有帶有 custom 屬性的參數(shù)均為Worklight 保留的參數(shù),適配器部署到服務(wù)器后,系統(tǒng)會讀取 XML 文件中的 dataSourceJNDIName 屬性,然后根據(jù) JNDI 配置的信息來建立數(shù)據(jù)庫的連接。
清單 2. SQL 適配器配置
- <connectivity>
- <connectionPolicy xsi:type="sql:SQLConnectionPolicy">
- <dataSourceJNDIName>${adapter-jndi-name}</dataSourceJNDIName>
- </connectionPolicy>
- <loadConstraints maxConcurrentConnectionsPerNode="5" />
- </connectivity>
- <procedure name="getAllCountries"/>
- <procedure name="getOneCountryID"/>
清單 3. SQL 適配器方法實現(xiàn)
- var procedure1Statement =
- WL.Server.createSQLStatement("select * from country where name = ?;");
- function getAllCountries() {
- return WL.Server.invokeSQLStoredProcedure({
- procedure : "getAllCountries",
- parameters : []
- });
- }
- function getOneCountryID(name) {
- var result = WL.Server.invokeSQLStatement({
- preparedStatement : procedure1Statement,
- parameters : [name]
- });
- var id = result.resultSet[0].index1;
- return getLeagueInfo(id);
- }
在 JS 文件中,函數(shù)通過調(diào)用 WL.Server.invokeSQLStoredProcedure 方法執(zhí)行后臺數(shù)據(jù)庫提供的存儲過程,調(diào)用 WL.Server.invokeSQLStatement 方法實現(xiàn)了對 SQL 語句的執(zhí)行,方法需要的參數(shù)和函數(shù)的具體說明,用戶可以在Worklight 提供的開發(fā)者手冊上了解它的詳細使用過程。
HTTP 適配器
建立 HTTP 適配器的過程類似 SQL 適配器:
- 點擊 File-> New -> Other -> Worklight -> Worklight Adapter
- 輸入應(yīng)用名稱:HTTPAdapter,選擇 HelloAdapterProj 作為工程,在適配器類型中選擇 HTTP Adapter,點擊確認,完成 HTTP 適配器創(chuàng)建
HTTP 適配器的內(nèi)容比 SQL 適配器略微復(fù)雜一些,除了上面介紹的 XML 和 JS 文件之外,還包括一個 XSL 文件。XSL 文件將根據(jù)規(guī)則對獲取的內(nèi)容進行轉(zhuǎn)化,去除不需要的數(shù)據(jù),改變數(shù)據(jù)的變量名,這樣可以對數(shù)據(jù)進行先期的編輯。
清單 4. HTTP 適配器配置
- <connectivity>
- <connectionPolicy xsi:type="http:HTTPConnectionPolicyType">
- <protocol>http</protocol>
- <domain>localhost</domain>
- <port>8081</port>
- </connectionPolicy>
- <loadConstraints maxConcurrentConnectionsPerNode="2" />
- </connectivity>
- <procedure name="getLeauge"/>
清單 5. HTTP 適配器方法實現(xiàn)
- function getLeauge(id) {
- var input = {
- method : 'get',
- returnedContentType : 'xml',
- path : "axis2/services/LeagueService/getLeague",
- parameters : {
- 'index' : id,
- },
- transformation : {
- type : 'xslFile',
- xslFile : 'filtered.xsl'
- }
- };
- return WL.Server.invokeHttp(input);
- }
在 XML 文件中配置 WS 的地址,定義提供的方法;然后在 JS 中調(diào)用 WL.Server.invokeHttp 方法完成對后臺數(shù)據(jù)的提取和轉(zhuǎn)化。雖然 JS 方法的參數(shù)只有一個,但是參數(shù)是 JSON 格式,其中包含著單獨的變量,其定義如下:
- method: 確認調(diào)用的方法是 get 還是 post
- returnedContentType: HTTP 服務(wù)返回的數(shù)據(jù)格式,這影響到應(yīng)用解析數(shù)據(jù)的方式
- returnedContentEncoding: 返回數(shù)據(jù)格式的編碼格式,默認為 utf-8
- path: 指定 WS 的路徑和方法
- headers: HTTP 請求的頭
- cookies: HTTP 請求的 cookie 信息
- body: 在方法是 post 時編寫相應(yīng)的內(nèi)容
- transformation: 轉(zhuǎn)化數(shù)據(jù)的參數(shù),包括 XSL 文件的位置和轉(zhuǎn)化的格式
數(shù)據(jù)的轉(zhuǎn)化
在 第 1 節(jié) 中描述了適配器和前臺的 app 以及后臺系統(tǒng)間數(shù)據(jù)交互的過程,在第三步中,如果開發(fā)者定義了相應(yīng)的 XSL 文件,那么轉(zhuǎn)化成 JSON 格式的過程就要分為兩步:
- 服務(wù)器首先將后臺的數(shù)據(jù)轉(zhuǎn)化為 XML 格式
- 通過 XSL 文件轉(zhuǎn)化后,再將數(shù)據(jù)轉(zhuǎn)化為 JSON 格式
清單 6. XSL 文件轉(zhuǎn)化
- <xsl:template match="/">
- {
- Items: [
- <xsl:for-each select="//*[local-name() = 'return']">
- {
- ranking: '<xsl:value-of select="*[local-name() = 'ranking']"/>',
- name: '<xsl:value-of select="*[local-name() = 'name']"/>',
- round: '<xsl:value-of select="*[local-name() = 'round']"/>',
- win: '<xsl:value-of select="*[local-name() = 'win']"/>',
- draw: '<xsl:value-of select="*[local-name() = 'draw']"/>',
- lose: '<xsl:value-of select="*[local-name() = 'lose']"/>'
- },
- </xsl:for-each>
- ]
- }
- </xsl:template>
在示例中,由于 WS 是根據(jù) Axis2 框架編寫的,所以返回的 XML 文件中的標簽會有前綴,為了實現(xiàn)只對其中部分數(shù)據(jù)的抽取,需要使用一定的 XSL 函數(shù)進行匹配(在示例中使用了 local-name 函數(shù)),具體的 XSL 函數(shù)說明參見 XSL 文檔。
適配器的測試
在開發(fā)平臺上,還提供了適配器的測試方法,為了測試適配器,需要按照如下方法進行:
- 右擊適配器 -> Run As -> Deploy Worklight Adapter
- 在部署成功后,右擊適配器 -> Run As -> Invoke Worklight Procedure
系統(tǒng)會顯示如下的測試環(huán)境,根據(jù)選取的方法和填入的參數(shù),完成對適配器的測試。
圖 2. 適配器測試界面
從返回的數(shù)據(jù)可以看到,如果測試成功,那么系統(tǒng)將返回完整的結(jié)果集(resultSet)并且將 isSuccessful 標志位置為 true;如果失敗,在 errors 信息位中,有詳細的信息,并且 isSuccessful 標志位置為 false。
在示例中,在 WS 沒有啟動的情況下,測試系統(tǒng)會得到服務(wù)器不可連接的錯誤;而當設(shè)置的 XSL 規(guī)則有問題時,則會提示描述解析 XML 文件發(fā)生錯誤。
圖 3. 適配器測試錯誤(連接)
圖 4. 適配器測試錯誤(解析)
從上面的描述可以看出,適配器的測試是易于實現(xiàn)的,并且在平臺的支持下,提供了詳細的調(diào)試信息,但是單純的適配器只能返回數(shù)據(jù),為了展示返回的數(shù)據(jù),必須和客戶端的應(yīng)用集成,所以接下來的示例將描述應(yīng)用和適配器集成的方法。
適配器的集成
為了訪問部署在服務(wù)器上的適配器,應(yīng)用可以通過Worklight 提供的 JS 函數(shù)來訪問也可以通過Worklight 支持的本地語言來訪問。在 JS 函數(shù)情況下方法的參數(shù)分為兩個部分:
- invocationData: 調(diào)用適配器需要的參數(shù)
- adapter 表示適配器的名稱
- procedure 表示適配器中的函數(shù)名稱
- parameters 表示傳遞給適配器的參數(shù)
- 回調(diào)函數(shù) : 當調(diào)用適配器成功或者失敗時,需要提供相應(yīng)的回調(diào)函數(shù)。onSuccess 函數(shù)在調(diào)用適配器成功時使用,onFailure 函數(shù)在調(diào)用適配器失敗時使用
清單 7. 客戶端對于適配器調(diào)用
- function wlCommonInit() {
- busyIndicator = new WL.BusyIndicator("AppBody");
- $('nationList').observe('change', nationSelectionChange);
- getNationList();
- }
- function getNationList() {
- busyIndicator.show();
- var invocationData = {
- adapter : 'MySQLAdapter',
- procedure : 'getAllCountries',
- parameters : []
- };
- WL.Client.invokeProcedure(invocationData, {
- onSuccess : getNationListSuccess,
- onFailure : getNationListFailure
- });
- }
當應(yīng)用啟動時,系統(tǒng)調(diào)用 wlCommonInit 函數(shù),通過對 SQL 適配器的訪問,調(diào)用存儲過程,當用戶從選擇項中,確認一個數(shù)據(jù)后,調(diào)用 SQL 語句獲取結(jié)果。為了程序流程的簡潔,應(yīng)用只和 SQL 適配器交互,但是當需要調(diào)用 HTTP 適配器時,在 SQL 適配器中定義了和 HTTP 適配器交互的代碼。
上述流程帶來了好處是:因為 HTTP 適配器和 SQL 適配器均部署在服務(wù)器端,所以在訪問 HTTP 適配器時,不涉及客戶端應(yīng)用和 HTTP 適配器的交互,減少訪問的流量;同時暴露的接口也只有 SQL 適配器,方便了管理;更為重要的是,適配器可以利 cache 功能,儲存相應(yīng)的數(shù)據(jù),減少系統(tǒng)的負載。
通過本地程序訪問適配器時,根據(jù)語言的不同,實現(xiàn)的方式也不同,在 Java 中需要繼承 WLResponseListener 接口,在 Objective-C 中需要繼承 WLDelegate 協(xié)議,詳細的過程可以在開發(fā)相應(yīng)的程序時查看Worklight 的開發(fā)文檔。
結(jié)束語
適配器作為Worklight 平臺的一個關(guān)鍵模式,不但方便了開發(fā)者將新的應(yīng)用和原有的系統(tǒng)集成,還為移動應(yīng)用的開發(fā)提供了統(tǒng)一的數(shù)據(jù)接口?;谶@個模式,程序員可以將關(guān)鍵的流程處理放在服務(wù)器端,對于客戶端只暴露接口,提供輸入和輸出的定義,這符合編程模式中服務(wù)優(yōu)先的原則。
適配器還提供了兩種很重要的功能:
1. 適配器保護功能,在安全配置上,對重要的適配器方法進行保護,這樣訪問相應(yīng)的方法就需要進行用戶驗證;
2. 適配器驗證功能,在安全驗證上,原有的系統(tǒng)可能有各種驗證方式,使用適配器可以在服務(wù)器端編程,用于和原系統(tǒng)的驗證模式結(jié)合,這樣就可以適應(yīng)各種不同的驗 證方式。