查看: 3775|回复: 4

基于 AOP 的动态数据国际化框架的设计与实现

[复制链接]
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
跳转到指定楼层
1#
发表于 2013-4-3 19:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
[size=0.76em]互联网的发展推动了全世界的交流,需要开发出满足不同地区语言、文化、生活习惯要求的 Web 应用,因此,软件的国际化已成为必须要解决的问题。国内外目前采用的国际化方法存在以下一些不足:
  • 已存在的动态数据国际化解决方法不易于移植和复用。
  • 没有现成的动态数据国际化解决方案或框架。
[size=0.76em]针对以上问题,需要提出一个动态数据国际化的解决方案。
[size=0.76em]为了在短时间内,规范高效的构建出国际化的 Web 应用,需要设计一种易于理解和维护的国际化开发框架。作者旨在将国际化相关的共性操作抽取出来进行一致性处理,生成一种基于 Spring 轻量级框架的、J2EE 架构的 Web 应用国际化框架,简化系统国际化的实现过程。
[size=0.76em]目标是:
  • 使该国际化框架适用于关系数据库或对象关系数据库。
  • 将国际化相关的共性操作提取到方面(Aspect)中,使编程人员可以专注于核心业务逻辑的编写,不需要考虑特定国家\语言环境,简化开发。
  • 新的框架要易于配置。
  • 框架的代码可以复用,能有效地提高系统开发效率。
[size=0.76em]动态数据国际化框架模型的设计与实现
[size=0.76em]总体设计
[size=0.76em]本框架基于 J2EE 三层架构(UI 层、逻辑层和持久层),如图 1 所示。所有层次都应遵循 Unicode 准则,即内部编码采用 Unicode 标准,B/S 架构推荐使用 UTF-8 编码。

图 1. 基于 B/S 的国际化总体逻辑框架


图 2. 动态数据国际化框架设计

[size=0.76em]该容器由国际化配置的注解、DAO 层资源处理器和充当过滤器角色、实现国际化公共增强功能的方面这 3 部分组合而成。
[size=0.76em]该容器中,国际化 Aspect,主要根据实体 bean 的注释标签判断访问哪种资源,采用哪种资源处理器进行处理。
[size=0.76em]该容器中,DAO 层的资源处理器,主要根据实体 Bean 注释中的配置信息,对资源进行存取访问操作,获取资源。
[size=0.76em]分层结构是基于 B/S 架构的 Java EE 应用程序的标准模式,本框架通过对应用程序划分层次,可以获得各层清晰的功能和职责,简化代码的实现难度。
[size=0.76em]该框架有以下几点优势:
  • 不依靠资源的持久化方式;
    [size=1em]可使用资源文件或关系数据库存储信息。用关系数据库存储时,无论是单表还是分表,都可以完成数据存取。
  • 国际化功能与业务逻辑解耦;
    [size=1em]编程人员可以专注于核心的 BO 层的业务逻辑的编写,把国际化相关的功能提取到方面中。不需要考虑国际化的特定国家 \ 语言,只需编写源代码进行数据库操作、对数据库进行访问即可,提高了对数据库进行访问的安全性。
  • 坚持以 OOP 设计为主,AOP 设计为辅,可缩减代码,控制开发成本;
  • 用注解实现对象关系数据库间的一一映射。
[size=0.76em]它管理 Java 类到数据库表的映射,在 JavaBean 中只嵌入注解标签即可,与国际化有关的代码完全提取到注解的实现 Bean 中,JavaBean 中完全不使用国际化相关代码,方便复用和调试。
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
2#
 楼主| 发表于 2013-4-3 19:58 | 只看该作者
[size=0.76em]模型实现
[size=0.76em]框架的运行时序图如图 3 所示:

图 3. 动态元素国际化方面序列图

[size=0.76em]分析上面的运行时序可知:
  • 首先由业务逻辑层对象调用获取实体 Bean 属性值的方法。
  • 如果该方法有国际化标签,需要国际化支持,则织入 I18NAspect 方面,进行国际化功能增强。
  • 根据属性的注解配置,由相应的处理器进行处理。
  • 最后把取得的资源值返回给实体类的属性。
[size=0.76em]至此完成国际化功能的织入,然后 BO 层可以继续执行核心业务逻辑。下面就逐个组件实现以上功能。
[size=0.76em]Annotation 注解提供国际化配置
[size=0.76em]本框架中的 Annotation 用于对类或属性提供国际化的配置信息。共定义 5 个注解:ConnectorType、Connector、Config、Text 和 I18n。它们之间的关系类图如图 4 所示:

图 4. Annotation 类图

  • @ConnectorType
    [size=1em]I18N 资源连接类型。此标签与 @Connector 联合使用。
    [size=1em]功能:用于标识 I18N 资源连接的类型,判断从资源文件中读取静态数据,还是从数据库中读取动态信息。
    [size=1em]RelationDatabase:标识从数据库中读取动态国际化信息数据。
    [size=1em]PropertiesFile:标识从资源文件中读取静态国际化数据。
  • @Connector
    [size=1em]连接器,此标签与 @Text 联合使用。
    [size=1em]功能:负责连接关系数据库,或是资源文件。
    [size=1em]Type:连接类型,决定 I18N 资源处理方法,由 ConnectorType 定义,只可能有读取资源文件或访问数据库两种方式。
    [size=1em]Name:连接名称,当访问资源文件时,name 表示资源文件的名称。当访问数据库时,name 表示连接数据的数据源名称,可以根据 name 从 Spring 的配置文件中依赖 IoC 获得数据源连接的相关配置。
  • @Config
    [size=1em]类属性的国际化配置项。此标签与 @Text 联合使用。
    [size=1em]功能:对象和关系数据库表的映射工具,实现 Java 对象模型和数据库关系模型的互相转化和一一映射。
    [size=1em]它包含 4 个属性。标签中 locale 是必选项,指出了所支持的对国家 / 语言环境。
    [size=1em]table,column,keyValueField 项是对关系数据库的支持属性。分别表示该属性对应的数据库表名,字段名和唯一标识该属性的关键字段。
  • @Text
    [size=1em]作用在类的属性上,对属性进行国际化配置。
    [size=1em]功能:建立不同语言环境下对象和数据库 OR 映射,或建立对象与资源文件中记录的对应关系。
    [size=1em]Key:主键,表示唯一记录,若数据库访问则表示确定该属性的唯一关键字段,若读取资源文件则表示该属性对应的键值。
    [size=1em]Connector:连接器属性,表示连接关系数据库,还是资源文件。
    [size=1em]Configs:配置项数组,每一条配置项对应一种语言的国际化支持。Configs[0] 为英文配置信息,Configs[1] 为中文配置信息。
  • @I18n
    [size=1em]作用在类上,声明该类需要国际化框架的支持,需要织入国际化方面进行功能增强。唯一属性 defaultLocale 定义了默认的语言环境,初始值是”en_US”。


使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
3#
 楼主| 发表于 2013-4-3 19:59 | 只看该作者
[size=0.76em]下面将使用已定义好的 Annotation 注解,用标签修饰类文件。
[size=0.76em]1. 以访问关系数据库为例,建立国家对象的国家名称属性 name 与数据库字段之间的 OR 映射。类 CountryBean 的属性及方法如图所示。

图 5.CountryBean 类图

[size=0.76em]用标签来对“国家名称”name 属性进行配置,标签声明如下:

清单 1. 使用标签配置属性实例一
                                  @Text(  connector=@Connector(name="ds",type=ConnectorType.RelationDatabase),key="id",  configs={  @Config(locale="en_US",table="country",column="country_en",keyValueField="id"), @Config(locale="zh_CN",table="country",column="country_ch",keyValueField="id")}  )

[size=0.76em]连接器属性 @Connector 表示以访问数据库的方式读取属性值,数据源的名称是"ds"。key="id"表示该数据库表的关键字段是 id 字段,它标识该表内的唯一记录。
[size=0.76em]国际化配置项 @Config 表示 name 属性与数据库的映射关系。配置项数组分别定义了英文、中文环境下该国家名称属性对应的表,字段,和决定该属性值的关键字段。以英文环境为例,要得到 name 值,需要查询 country 库表的 country_en 字段,并由 id 字段确定是哪一条记录。其中 locale="en_US"表示它为英文环境的配置信息,映射 country 表的 country_en 字段,关键字段为 id。
[size=0.76em]2. 以资源文件为例,建立国家对象的国家名称属性 name 与资源文件中英文国家名称之间的映射。

清单 2. 使用标签配置属性实例二
                                  @Text(connector=@Connector(name="myresource",type=ConnectorType.PropertiesFile),  key="country_name", configs={@Config(locale="en_US"),@Config(locale="zh_CN")}  )

[size=0.76em]连接器属性 connector 的配置表示资源为名为 myresource 的资源文件,key 表示关键字是 country_name,国际化配置项 Config 的配置分别表示中英文资源文件的后缀。
[size=0.76em]国际化资源处理器的设计和实现
[size=0.76em]如图 5 所示,是处理器接口,及两个处理器实现类之间的关系类图。

图 6. 国际化处理器类图

[size=0.76em]设计出的国际化处理器由一个接口,两个实现类组成。处理器接口 Handler 用于抽象出资源访问的公共方法,包括初始化方法、处理方法。下面对两种处理器的功能进行描述。
  • 资源文件国际化支持处理器
[size=0.76em]功能:根据关键字 key,从资源文件 source 中获取静态信息的属性值。其类图如图 7 所示。

图 7. 资源文件国际化支持处理器类图

  • initial() 初始化方法的设计和实现
    [size=1em]目的:用于初始化资源文件国际化支持处理器,设置资源文件名 resource 和关键字 key 的值。资源文件国际化支持处理器初始化功能状态图如图 8 所示。


    图 8. 资源文件国际化支持处理器初始化功能状态图


    [size=1em]关键代码实现如下所示:


    清单 3. 资源文件国际化支持处理器 initial() 方法关键代码
                                      String rsName = text.connector().name();// 由配置标签 text 中读取资源文件名称 // 获取资源文件 Resource resource = context.getResource( "classpath:"+rsName+ "_"+ config.locale()+ ".properties");  setResource(resource); // 设置资源文件 setKey(text.key());// 读取配置标签,设置关键字 key 值
  • handle() 处理方法的设计和实现
    [size=1em]资源文件国际化支持处理器 handle() 方法功能流程如图 9 所示。


    图 9. 资源文件国际化支持处理器 handle() 方法功能状态图

[size=0.76em]关键代码如下所示:

清单 4. 资源文件国际化支持处理器 handle() 方法关键代码
                                  Properties properties = new Properties();// 加载资源文件 properties.load(resource.getInputStream());          Object retVal = properties.getProperty(key); // 根据关键字取得属性值

  • 关系数据库国际化支持处理器
    [size=1em]功能:从关系数据库中存取动态信息。获取对象属性标签中的 OR 映射配置信息,在关系数据库中查询该属性。其类图如图 10 所示。


    图 10. 关系数据库国际化支持处理器类图


    [size=1em]属性:该处理器有 5 个属性,tableName 为数据库表名称,columnName 为与属性一一映射的字段名称,keyName 为该表的关键字段,keyValue 为确定唯一记录的关键字段的值。以上 4 个属性,为访问数据库提供支持,通过它们拼装完整的 SQL 语句。DataSource 是数据源名称。
  • initial() 初始化方法的设计和实现
    [size=1em]目的:用于初始化关系数据库国际化支持处理器,设置与访问数据库相关的 5 个属性的初值。其中 tableName、columnName 由参数 config 标签中的 table、column 配置信息获取。keyName 由参数 text 标签的属性 key 获取。DataSource 由参数 text 的连接器属性 Connector 的 name 中的配置信息获取。
    [size=1em]关键代码实现如下所示:


    清单 5. 关系数据库国际化支持处理器 initial() 方法关键代码
                                      String dsName = text.connector().name();// 由 text 标签获得数据源名称 DataSource dataSource = (DataSource) context.getBean(dsName);  setDataSource(dataSource); // 设置数据源 setColumnName(config.column());// 设置属性对应字段名称 setTableName(config.table());// 设置要访问的数据库表名称 setKeyName(text.key());// 设置关键字段名称
  • handle() 处理方法的设计和实现
    [size=1em]该方法比较简单,根据已有的数据库访问信息访问数据库即可,可以使用利用 JDBC API,也可 Hibernate 等其它 DAO 框架。


使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
4#
 楼主| 发表于 2013-4-3 20:00 | 只看该作者
[size=0.76em]国际化方面的设计与实现
[size=0.76em]国际化方面要实现封装国际化功能,使其与核心业务逻辑分离解耦。
[size=0.76em]AOP 将系统关注点封装在“方面”中,在编译期间织入有关“方面”的代码。编写一个方面类 I18NAspect 实现国际化增强。
[size=0.76em]如图 11 所示,方面 I18NAspect 是运行时的横向动作,可以实现国际化相关功能和核心业务逻辑的分离解耦。

图 11. 对象、joinpoint、方面、数据对象耦合结构图

[size=0.76em]可以把 Aspect 简单地理解为一个 Advice 增强和一个 Pointcut 切入点的组合,如图 11 所示,每个 Pointcut 实现都会对应有一个的 Advice 实现。Advice 用于封装需要增强的国际化功能;Ponintcut 用于定义何时,何处将 Advice 织入到目标对象,只对符合条件方法的增强。

图 12. Aspect 运行机制流程图

  • 声明 Aspect
    [size=1em]Spring 2.0 引入了 AspectJ 的注解,可以通过 Java 5 注解以 AspectJ 的语法在 Spring 中配置 AOP。
    [size=1em]AspectJ 是目前最完善的 AOP 解决方案,它扩展了 Java 语法,定义了额外的 AOP 语法关键字,它提供了 AOP 技术的所有特性,包括针对字段的拦截。使用 AspectJ 注解实现 AOP 最大的优点是配置极为简单,可以大大简化代码的编写和 XML 配置文件。用 AspectJ 注解实现 AOP,方面定义为:
    [size=1em]@Aspect
    [size=1em]public class I18NAspect implements ApplicationContextAware{ … }
    [size=1em]该类被标记为 @Aspect,表示这是一个方面类。
    [size=1em]下面,将对 I18NAspect 进行详细设计,为其添加 Advice 和 Pointcut。
  • 定义 Aspect 的 Advice
    [size=1em]声明的 i18nAspect 方法有个 ProceedingJoinPoint 参数,通过它可以获得方法调用的所有信息,包括方法参数、目标对象等,然后,手动调用 jointPoint 的 proceed() 方法来完成对目标对象的方法调用。需要进行增强的国际化功能的实现流程如图 13 所示:


    图 13. I18N 方面 Advice 功能流程图


    [size=1em]Advice 的关键代码如下所示:


    清单 6. 关系数据库国际化支持处理器 initial() 方法关键代码
                                      Class c = jointPoint.getTarget().getClass();// 获取目标类 Object obj = jointPoint.getTarget();// 获取目标对象 Object retVal=null; // 声明对象属性的返回值 // 当前处理类是否需要 I18N 支持 if(c.isAnnotationPresent(I18N.class)){  // 取得全部字段,筛选出标记了 Text 的字段 Field[] fields = c.getDeclaredFields();  // 设置环境语言变量 String defaultLocale =(  (I18N)c.getAnnotation(I18N.class)).defaultLocale();  String progSetLocale = LocaleContextHolder.getLocale().toString();  if(progSetLocale==null) progSetLocale = defaultLocale;  Config usingConfig = null;  for(Field f : fields){  if(f.isAnnotationPresent(Text.class)){  // 如果存在 Text 标记,则进行国际化处理    Text text = f.getAnnotation(Text.class);     Object value = f.getName();     // 取得所有配置信息,并确定使用的配置信息    Config[] configs = text.configs();     for(Config config : configs){  String configLocale = config.locale();   if(configLocale.equals(progSetLocale)){      usingConfig = config;      break;   }      }      if(usingConfig==null){         boolean flag = false;  String t = text.connector().type();// 处理映射 if(t.equals(ConnectorType.RelationDatabase)){  // 应用已注入的关系数据库处理器处理映射        if(flag==true) value = rdbHandler.handle();  }else if(t.equals(ConnectorType.PropertiesFile)){  // 处理资源文件映射   if(flag==true) value = propHandler.handle();  }  f.setAccessible(true);// 开启设置字段值 f.set(obj, value);        // 设置字段值 f.setAccessible(false);// 关闭设置字段值     }  }   retVal = jointPoint.proceed();                  } else {   retVal = jointPoint.proceed();                  }                  return retVal;

    [size=1em]定义 Aspect 的 pointcut
    [size=1em]Ponintcut 用于针对特定方法使用方面增强。在调用目标对象的某一业务方法时,能够拦截该方法的调用,可以将方面植入到应用程序的流程中。
    [size=1em]execution 匹配方法执行时的切入点,表达式如下:
    [size=1em]execution( 修饰符?返回类型 声明类型?方法名称 ( 参数类型 ) 异常类型? )
    [size=1em]例如,为所有类的 get 方法添加一个 i18nAdvice
    @Around("execution(* get*())")  public Object i18nAdvice(ProceedingJoinPoint jointPoint)  { …… }

    [size=1em]在执行所有类对象的 get 方法之前,系统关注点 i18nAdvice 将完成国际化公共功能,达到织入国际化管理逻辑的目的。


使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
5#
 楼主| 发表于 2013-4-3 20:01 | 只看该作者
[size=0.76em]动态数据国际化框架的应用
[size=0.76em]本文研究的框架,已经完整应用于一个基于 J2EE 的的 Web 应用系统。系统的中、英文运行界面如图 14、15 所示。

图 14. Web 应用中文运行效果


图 15. Web 应用英文运行效果


图 16. Web 应用气象信息模块的中文运行效果


图 17. Web 应用气象信息模块的英文运行效果



使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表