Worklight中适配器的开发

移动开发
基于 Worklight 可以开发安装于手机端的应用和部署于服务器端的适配器(adapter),通过适配器应用可以访问数据库和外部系统,这样新开发的移动应用就可以方便的和其他系统进行集成。

文章将通过基于 Eclipse 的 IDE,来开发 Worklight 支持的 HTTP 和 SQL 适配器;并且演示测试适配器的方法,最后,通过集成应用、适配器和 Web Service 来体现适配器在开发移动应用中的重大作用。

Worklight 中适配器的架构

WorklightWorklight作为一个移动程序的开发平台,通过三种模式(Web、混合、本地)支持了不同需求的客户端开发,但是面临的一个现实问题是如何和已有的系统进行良好的集成。适配器(adapter)是平台的服务器端组件,作为一个传输层负责Worklight 服务器和不同企业级后台的连接。通过平台支持的 HTTP 和 SQL 适配器,客户端应用可以与原有系统方便的进行数据访问,这减少了重复的开发工作。

适配器由三部分组成:基于 XML 的配置文件,用于定义适配器的类型和提供的方法;基于 JS 的方法实现文件,通过 Mozilla Rhino 解析器实现对不同后台的访问;基于 XSL 文件的数据转化规则,在 HTTP 适配器中存在,用于将获得的数据按照一定规则进行转化。

Worklight支持的适配器提供了如下特性:

  • 快速开发:开发者可以使用便捷而强大的服务器端 JavaScript 创建简洁易读的代码,用于和不同后台程序的集成。
  • 只读操作和事务操作:平台通过适配器支持对后台系统的只读和事物操作。
  • 安全:适配器使用灵活的认证机制创建与后台的连接,使用的用户可以是系统用户也可以是事务中操作的用户。
  • 可扩展性:适配器通过 cache 机制减少了与后台系统的交互,并且通过配置,限定和后台系统建立的连接数。
  • 数据透明:适配器提供了获取后台数据的统一接口,这样开发者在获取数据时就不需要关注数据源、格式和传输协议信息。

图 1. 适配器架构
图 1. 适配器架构

图 1 描述了适配器和前台的 app 以及后台系统间数据交互的过程,具体的流程如下:

  1. 适配器暴露一系列的方法,称之为 procedures,前台 app 通过 Ajax 方式调用这些过程。
  2. 这些方法从后台获取相应信息。
  3. 后台系统返回的数据格式如下
    1. 如果格式为 JSON,Worklight服务器直接返回。
    2. 如果格式不是 JSON,服务器将数据格式转化为 JSON 后,再返回。
  4. 这些方法将获得的 JSON 数据进行业务处理,将最终结果返回给 app。

基于 Eclipse 的适配器开发

根据适配器连接的后台种类,它被分为 HTTP 适配器和 SQL 适配器。在实际的应用中 SQL 适配器用于连接不同的后台数据库,并通过 SQL 语句或存储过程进行访问。适配器目前支持 MySQL 和 Oracle 的数据库,并且在几个月后将支持 DB2 数据库。HTTP 适配器支持访问 soap 服务和 rest 服务,并且可以根据指定的 XSL 文件对获得的数据片段进行转化,获得用户需要的数据和格式。

为了更好的演示不同适配器的作用和相互合作的方法,文章将构建如下场景:

  • 首先创建 SQL 适配器,并且提供对于 SQL 语句和存储过程的访问。
  • 然后创建 HTTP 适配器,用于访问由 Axis2 框架构建的 Web Service。
  • 通过 Eclipse 提供的测试环境,对于前面创建的适配器进行测试,并且解释测试返回信息的含义。
  • 最后通过开发一个应用,并且整合上述的适配器,完成一个完整的功能。
 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 下开发适配器通过下面的步骤可以完成:

新建工程和 SQL 适配器:

  • 点击 File-> New -> Project -> Worklight -> Worklight Project
  • 输入工程名称:HelloAdapterProj,点击确认,完成工程创建
  • 点击 File-> New -> Other -> Worklight -> Worklight Adapter
  • 输入应用名称:MySQLAdapter,选择 HelloAdapterProj 作为工程,在适配器类型中选择 SQL Adapter,点击确认,完成 SQL 适配器创建

创建完毕的适配器其文件结构如下:

  • MySQLAdapter.xml:在文件中定义了很多的属性,比如适配器在Worklight 控制台中显示的名称和简单描述,最大的连接数等等,其中最重要的是下列两个参数:
    • dataSourceJNDIName 定义了适配器所连接的 JNDI 的名称,具体的配置将在下面叙述
    • procedure 定义适配器向外提供的方法名称(需要通过 .js 文件实现)
  • MySQLAdapter-impl.js:在文件中实现了两个方法,getAllCountries 用于调用数据库中的存储过程;getOneCountryID 通过调用 SQL 语句获取相应的信息

对于适配器需要的 JNDI 参数,可以通过修改 Worklight 的配置文件实现。在 Worklight 框架中存在一个默认的配置文件 default.worklight.properties,用户可以通过修改 worklight.properties 文件来覆盖默认配置文件中的一些属性。清单 1 描述了为连接本地的 SQL 数据库,在 worklight.properties 添加的配置信息:

清单 1. JNDI 配置

  1. adapter-jndi-name = ${custom-db.1.jndi-name}  
  2. custom-db.1.relative-jndi-name = jdbc/worklight_adapter  
  3. custom-db.1.driver = com.mysql.jdbc.Driver  
  4. custom-db.1.url = jdbc:mysql://localhost:3306/worklight_adapter  
  5. custom-db.1.username = root  
  6. custom-db.1.password = root  

所有带有 custom 属性的参数均为Worklight 保留的参数,适配器部署到服务器后,系统会读取 XML 文件中的 dataSourceJNDIName 属性,然后根据 JNDI 配置的信息来建立数据库的连接。

清单 2. SQL 适配器配置

  1. <connectivity>  
  2.     <connectionPolicy xsi:type="sql:SQLConnectionPolicy">  
  3.         <dataSourceJNDIName>${adapter-jndi-name}</dataSourceJNDIName>  
  4.     </connectionPolicy>  
  5.     <loadConstraints maxConcurrentConnectionsPerNode="5" />  
  6.  </connectivity>  
  7.  
  8.  <procedure name="getAllCountries"/>  
  9.  <procedure name="getOneCountryID"/>  

清单 3. SQL 适配器方法实现

  1. var procedure1Statement =  
  2.   WL.Server.createSQLStatement("select * from country where name = ?;");  
  3.  
  4.  function getAllCountries() {  
  5.     return WL.Server.invokeSQLStoredProcedure({  
  6.         procedure : "getAllCountries",  
  7.         parameters : []  
  8.     });  
  9.  }  
  10.  
  11.  function getOneCountryID(name) {  
  12.     var result = WL.Server.invokeSQLStatement({  
  13.         preparedStatement : procedure1Statement,  
  14.         parameters : [name]  
  15.     });  
  16.  
  17.     var id = result.resultSet[0].index1;  
  18.  
  19.     return getLeagueInfo(id);  
  20.  }  

在 JS 文件中,函数通过调用 WL.Server.invokeSQLStoredProcedure 方法执行后台数据库提供的存储过程,调用 WL.Server.invokeSQLStatement 方法实现了对 SQL 语句的执行,方法需要的参数和函数的具体说明,用户可以在Worklight 提供的开发者手册上了解它的详细使用过程。

HTTP 适配器

建立 HTTP 适配器的过程类似 SQL 适配器:

  • 点击 File-> New -> Other -> Worklight -> Worklight Adapter
  • 输入应用名称:HTTPAdapter,选择 HelloAdapterProj 作为工程,在适配器类型中选择 HTTP Adapter,点击确认,完成 HTTP 适配器创建

HTTP 适配器的内容比 SQL 适配器略微复杂一些,除了上面介绍的 XML 和 JS 文件之外,还包括一个 XSL 文件。XSL 文件将根据规则对获取的内容进行转化,去除不需要的数据,改变数据的变量名,这样可以对数据进行先期的编辑。

清单 4. HTTP 适配器配置

  1. <connectivity>  
  2.     <connectionPolicy xsi:type="http:HTTPConnectionPolicyType">  
  3.         <protocol>http</protocol>  
  4.         <domain>localhost</domain>  
  5.         <port>8081</port>  
  6.     </connectionPolicy>  
  7.     <loadConstraints maxConcurrentConnectionsPerNode="2" />  
  8.  </connectivity>  
  9.  
  10.  <procedure name="getLeauge"/>  

清单 5. HTTP 适配器方法实现

  1. function getLeauge(id) {  
  2.     var input = {  
  3.         method : 'get',  
  4.         returnedContentType : 'xml',  
  5.         path : "axis2/services/LeagueService/getLeague",  
  6.         parameters : {  
  7.             'index' : id,  
  8.         },  
  9.         transformation : {  
  10.             type : 'xslFile',  
  11.             xslFile : 'filtered.xsl' 
  12.         }  
  13.     };  
  14.  
  15.     return WL.Server.invokeHttp(input);  
  16.  }  

在 XML 文件中配置 WS 的地址,定义提供的方法;然后在 JS 中调用 WL.Server.invokeHttp 方法完成对后台数据的提取和转化。虽然 JS 方法的参数只有一个,但是参数是 JSON 格式,其中包含着单独的变量,其定义如下:

  • method: 确认调用的方法是 get 还是 post
  • returnedContentType: HTTP 服务返回的数据格式,这影响到应用解析数据的方式
  • returnedContentEncoding: 返回数据格式的编码格式,默认为 utf-8
  • path: 指定 WS 的路径和方法
  • headers: HTTP 请求的头
  • cookies: HTTP 请求的 cookie 信息
  • body: 在方法是 post 时编写相应的内容
  • transformation: 转化数据的参数,包括 XSL 文件的位置和转化的格式

数据的转化

在 第 1 节 中描述了适配器和前台的 app 以及后台系统间数据交互的过程,在第三步中,如果开发者定义了相应的 XSL 文件,那么转化成 JSON 格式的过程就要分为两步:

  1. 服务器首先将后台的数据转化为 XML 格式
  2. 通过 XSL 文件转化后,再将数据转化为 JSON 格式

清单 6. XSL 文件转化

  1. <xsl:template match="/">  
  2.    {  
  3.        Items: [  
  4.        <xsl:for-each select="//*[local-name() = 'return']">  
  5.   {  
  6.        ranking: '<xsl:value-of select="*[local-name() = 'ranking']"/>',  
  7.        name: '<xsl:value-of select="*[local-name() = 'name']"/>',  
  8.        round: '<xsl:value-of select="*[local-name() = 'round']"/>',  
  9.        win: '<xsl:value-of select="*[local-name() = 'win']"/>',  
  10.        draw: '<xsl:value-of select="*[local-name() = 'draw']"/>',  
  11.        lose: '<xsl:value-of select="*[local-name() = 'lose']"/>
  12.        },  
  13.        </xsl:for-each>  
  14.        ]  
  15.    }  
  16. </xsl:template>  

在示例中,由于 WS 是根据 Axis2 框架编写的,所以返回的 XML 文件中的标签会有前缀,为了实现只对其中部分数据的抽取,需要使用一定的 XSL 函数进行匹配(在示例中使用了 local-name 函数),具体的 XSL 函数说明参见 XSL 文档。

适配器的测试

在开发平台上,还提供了适配器的测试方法,为了测试适配器,需要按照如下方法进行:

  • 右击适配器 -> Run As -> Deploy Worklight Adapter
  • 在部署成功后,右击适配器 -> Run As -> Invoke Worklight Procedure

系统会显示如下的测试环境,根据选取的方法和填入的参数,完成对适配器的测试。

图 2. 适配器测试界面
图 2. 适配器测试界面

从返回的数据可以看到,如果测试成功,那么系统将返回完整的结果集(resultSet)并且将 isSuccessful 标志位置为 true;如果失败,在 errors 信息位中,有详细的信息,并且 isSuccessful 标志位置为 false。

在示例中,在 WS 没有启动的情况下,测试系统会得到服务器不可连接的错误;而当设置的 XSL 规则有问题时,则会提示描述解析 XML 文件发生错误。

图 3. 适配器测试错误(连接)
图 3. 适配器测试错误(连接)

图 4. 适配器测试错误(解析)
图 4. 适配器测试错误(解析)

从上面的描述可以看出,适配器的测试是易于实现的,并且在平台的支持下,提供了详细的调试信息,但是单纯的适配器只能返回数据,为了展示返回的数据,必须和客户端的应用集成,所以接下来的示例将描述应用和适配器集成的方法。

适配器的集成

为了访问部署在服务器上的适配器,应用可以通过Worklight 提供的 JS 函数来访问也可以通过Worklight 支持的本地语言来访问。在 JS 函数情况下方法的参数分为两个部分:

  • invocationData: 调用适配器需要的参数
    • adapter 表示适配器的名称
    • procedure 表示适配器中的函数名称
    • parameters 表示传递给适配器的参数
  • 回调函数 : 当调用适配器成功或者失败时,需要提供相应的回调函数。onSuccess 函数在调用适配器成功时使用,onFailure 函数在调用适配器失败时使用

清单 7. 客户端对于适配器调用

  1. function wlCommonInit() {  
  2.    busyIndicator = new WL.BusyIndicator("AppBody");  
  3.    $('nationList').observe('change', nationSelectionChange);  
  4.    getNationList();  
  5. }  
  6.  
  7. function getNationList() {  
  8.    busyIndicator.show();  
  9.    var invocationData = {  
  10.        adapter : 'MySQLAdapter',  
  11.        procedure : 'getAllCountries',  
  12.        parameters : []  
  13.    };  
  14.  
  15.    WL.Client.invokeProcedure(invocationData, {  
  16.        onSuccess : getNationListSuccess,  
  17.        onFailure : getNationListFailure  
  18.    });  
  19. }  

当应用启动时,系统调用 wlCommonInit 函数,通过对 SQL 适配器的访问,调用存储过程,当用户从选择项中,确认一个数据后,调用 SQL 语句获取结果。为了程序流程的简洁,应用只和 SQL 适配器交互,但是当需要调用 HTTP 适配器时,在 SQL 适配器中定义了和 HTTP 适配器交互的代码。

上述流程带来了好处是:因为 HTTP 适配器和 SQL 适配器均部署在服务器端,所以在访问 HTTP 适配器时,不涉及客户端应用和 HTTP 适配器的交互,减少访问的流量;同时暴露的接口也只有 SQL 适配器,方便了管理;更为重要的是,适配器可以利 cache 功能,储存相应的数据,减少系统的负载。

通过本地程序访问适配器时,根据语言的不同,实现的方式也不同,在 Java 中需要继承 WLResponseListener 接口,在 Objective-C 中需要继承 WLDelegate 协议,详细的过程可以在开发相应的程序时查看Worklight 的开发文档。

结束语

适配器作为Worklight 平台的一个关键模式,不但方便了开发者将新的应用和原有的系统集成,还为移动应用的开发提供了统一的数据接口。基于这个模式,程序员可以将关键的流程处理放在服务器端,对于客户端只暴露接口,提供输入和输出的定义,这符合编程模式中服务优先的原则。

适配器还提供了两种很重要的功能:

1. 适配器保护功能,在安全配置上,对重要的适配器方法进行保护,这样访问相应的方法就需要进行用户验证;

2. 适配器验证功能,在安全验证上,原有的系统可能有各种验证方式,使用适配器可以在服务器端编程,用于和原系统的验证模式结合,这样就可以适应各种不同的验 证方式。

责任编辑:佚名 来源: 风信网
相关推荐

2012-12-10 10:53:04

IBMdW

2018-10-11 10:38:31

前端JavaScript编程语言

2021-02-16 08:16:09

适配器模式MybatisJava

2015-08-07 10:05:37

recyclervie超省写法

2022-02-18 17:21:29

适配器模式客户端

2020-10-25 08:56:21

适配器模式

2021-08-06 06:51:16

适配器配置Spring

2022-02-13 23:33:24

设计模式Java

2011-04-28 09:54:50

jQuery

2021-02-18 08:39:28

设计模式场景

2013-11-26 16:39:21

Android设计模式

2012-05-16 17:22:11

Java设计模式

2009-11-18 18:08:20

PHP适配器模式

2009-12-21 10:26:09

Oracle适配器

2012-08-02 10:46:34

JavaAdapter模式

2010-07-09 12:53:30

HART协议

2013-02-26 10:55:47

C#适配器设计模式

2014-12-17 09:57:01

AndroidAdapteViewHolder

2014-07-17 10:55:10

Win8.1应用开发适配器模式

2022-05-29 22:55:00

适配器设计模式
点赞
收藏

51CTO技术栈公众号