第2.7式. 访问来自于数据库中的消息资源
问题
你想要将所有标注、消息和其他静态文本都保存在数据库中而不知一个属性文件中,并且仍然可以通过bean:message标签来进行访问。
动作要领
- 下载OJBMessageResources分发包,地址是:http://prdownloads.sourceforge.net/struts/ojb-message-resources.zip?download.
- 将ZIP 文件解包到一个本地目录;
- 将ojb-msg-res.jar文件从ojb-message-resources/dist文件夹拷贝到你的应用的WEB-INF/lib文件夹。
- 将属性文件、XML 和DTD 文件从ojb-message-resources/config文件夹拷贝到你的应用的src文件夹。当你build 你的应用的时候是,这些文件必须被拷贝到WEB-INF/classes文件夹中。
- 创建数据库表来保存对象关系桥(OJB) 的元数据。OJB 使用表来保持内部的映射关系。Example 2-12 列出了在MYSQL中创建这些表的SQL。对于其他数据库的语句,包含在OJB 分发包中。
Example 2-12. OJB 元数据DDL (MySQL)
CREATE TABLE ojb_dlist (
ID int NOT NULL default '0',
SIZE_ int default NULL,
PRIMARY KEY (ID)
) TYPE=MyISAM;
CREATE TABLE ojb_dlist_entries (
ID int NOT NULL default '0',
DLIST_ID int NOT NULL default '0',
POSITION_ int default NULL,
OID_ longblob,
PRIMARY KEY (ID)
) TYPE=MyISAM;
CREATE TABLE ojb_dmap (
ID int NOT NULL default '0',
SIZE_ int default NULL,
PRIMARY KEY (ID)
) TYPE=MyISAM;
CREATE TABLE ojb_dmap_entries (
ID int NOT NULL default '0',
DMAP_ID int NOT NULL default '0',
KEY_OID longblob,
VALUE_OID longblob,
PRIMARY KEY (ID)
) TYPE=MyISAM;
CREATE TABLE ojb_dset (
ID int NOT NULL default '0',
SIZE_ int default NULL,
PRIMARY KEY (ID)
) TYPE=MyISAM;
CREATE TABLE ojb_dset_entries (
ID int NOT NULL default '0',
DLIST_ID int NOT NULL default '0',
POSITION_ int default NULL,
OID_ longblob,
PRIMARY KEY (ID)
) TYPE=MyISAM;
CREATE TABLE ojb_hl_seq (
TABLENAME varchar(175) NOT NULL default '',
FIELDNAME varchar(70) NOT NULL default '',
MAX_KEY int default NULL,
GRAB_SIZE int default NULL,
PRIMARY KEY (TABLENAME,FIELDNAME)
) TYPE=MyISAM;
CREATE TABLE ojb_lockentry (
OID_ varchar(250) NOT NULL default '',
TX_ID varchar(50) NOT NULL default '',
TIMESTAMP_ decimal(10,0) default NULL,
ISOLATIONLEVEL int default NULL,
LOCKTYPE int default NULL,
PRIMARY KEY (OID_,TX_ID)
) TYPE=MyISAM;
CREATE TABLE ojb_nrm (
NAME varchar(250) NOT NULL default '',
OID_ longblob,
PRIMARY KEY (NAME)
) TYPE=MyISAM;
CREATE TABLE ojb_seq (
TABLENAME varchar(175) NOT NULL default '',
FIELDNAME varchar(70) NOT NULL default '',
LAST_NUM int default NULL,
PRIMARY KEY (TABLENAME,FIELDNAME)
) TYPE=MyISAM;
6. 使用Example 2-13中的SQL DDL来创建保存消息资源数据的表。
Example 2-13. MessageResources DDL
create table application_resources (
subApp varchar(100) not null,
bundleKey varchar(100) not null,
locale varchar(10) not null,
msgKey varchar(255) not null,
val varchar(255),
Primary Key(
subApp,
bundleKey,
locale,
msgKey
)
);
- 将消息资源装入数据库表格中。Example 2-14 展示了一个如何使用SQL语句组装表格数据的简便方法。
Example 2-14. SQL to load message resources table
insert into application_resources (
subApp, bundleKey, locale, msgKey, val )
values ('', '', '', 'label.index.title',
'Struts Cookbook');
insert into application_resources (
subApp, bundleKey, locale, msgKey, val )
values ('', '', 'fr', 'label.index.title',
'Struts Livre de Cuisine');
修改Struts 配置文件来使用OJBMessageResourcesfactory。
<message-resources
factory="org.apache.struts.util.OJBMessageResourcesFactory"
parameter="."/>
修改WEB-INF/classes文件夹中的repository.xml (第4步中拷贝的) 来使用专门针对你的数据库的数据库连接属性。Example 2-15展示了针对MySQL 数据库的配置信息。
Example 2-15. 针对MySQL的OJB 连接描述
<jdbc-connection-descriptor
platform="MySQL"
jdbc-level="2.0"
driver="com.mysql.jdbc.Driver"
protocol="jdbc"
subprotocol="mysql"
dbalias="//localhost:3306/test"
username="user"
password="pass"
/>
动作变化
Struts MessageResources工具管理着诸如错误消息、字段标注、表格头部以及窗口标题等静态文本。通过这个工具,文本被保存在成为资源束的一个或者多个.properties文件的名值对中;名称是一个逻辑关键字而值则是要显示文本的值。如果你的应用需要针对某个特定国家和语言进行本地化,你将创建一个(套)新的属性文件。你可以使用对属性文件名称添加一个由国家代码和语言代码组成的后缀来将一个文件关联到一个特定的场所。比如,针对加拿大法语的MessageResources.properties文件可能是MessageResources_fr_CA.properties。本地化文件中的属性包含有专门针对该场所的值。这种本地化的方式实际上是Java自身决定的。
这个工具对大多数中型和小型的应用工作的很不错。但是,你可能想要使用一种更加具有可管理性的持久性手段,比如数据库来保存它。虽然Struts 本身并不支持这种方式,但是可以通过其他扩展来支持。在幕后, Struts 使用MessageResourcesFactory的实现来创建在运行时保存在servlet context中的MessageResources对象。你可以提供定制的Struts MessageResourcesFactory实现,并且在Struts 配置文件中声明你的实现:
<message-resources
factory="com.foo.CustomMessageResourcesFactory"
parameter="moduleName.bundleKey"/>
parameter 属性指定消息资源工厂要针对创建的Struts module 名称和bundle 关键字(bundle 名称) 。
所以,你可以创建你自己的从数据库中读取资源的消息资源工厂。幸运的是,这个麻烦的工作已经有人做了。James Mitchell, 一个长期的Struts 志愿者,创建了一个OJBMessageResources实现。这些类利用了对象关系映射框架OJB来提供易用的数据库驱动的MessageResources实现。
如果你不熟悉OJB,也不会阻止你练习这一招技术。你不需要完全了解OJB来能使用OJBMessageResources。OJB 中仅涉及到将关系数据映射到对象数据的部分内容。如果你使用本方案中指定的table schema ,对于映射数据不需要再作其他修改。然而,如果你想要使用一个不同的schema,你就需要对 OJB 基于XML的配置文件中的映射配置进行修改易适合你的需要。你不需要对实现MessageResourcesFactory的具体Java代码做任何修改。OJBMessageResources的文档也不错,并且有一个逐步的安装和配置指导的README文件。上面的动作要领就来自于这些指导。
为了最有效的使用OJBMessageResources ,理解数据库schema 如何映射到对象数据是很有帮助的。首先,schema 金需要创建一个表格来保存消息资源(第6步)。使用一个表简化了数据映射。Table 2-2 表述了组成该表的列,以及它们如何在Struts中使用。
Table 2-2. OJBMessageResources schema |
列 |
对应的Struts 概念 |
注释和示例 |
subApp |
模块前缀 |
非null。
使用一个空字符串("") 来标识默认模块 |
bundleKey |
在使用多个资源集时,定位某一个消息资源集的关键字。这个值必须匹配Struts配置文件中的message-resources元素的key属性的值。这个值也对应于Struts标签中的bundle 属性的值 (如, bean:message bundle="labels") |
非null。使用空字符串来表示默认关键字。否则,名称是一个逻辑值,比如"labels," "headers," 和"errors." |
Locale |
标识消息场所的场所代码。此值是两个字母的语言代码和两个字母的国家代码的组合。 |
非null。
使用空字符串来表示默认(服务器的)场所。比如"en_US" 标识美国英语,"fr"标识法语。 |
msgKey |
用于查找消息的消息的名称。此值对所有场所都是一样。这个值也是属性文件中名值对中左边的部分。此列的值对应于从MessageResources中获取值的Struts标签的key属性的值。 |
非null, 并且应该永不为空。一个关键字可能看起来如: "title.hello.world". |
val |
对应于msgKey的值。是对应于属性文件中名值对右边部分的本地化值。这也是将由Struts标签返回和显示的值。 |
可以为null。这是将在页面中显示的文本。比如, "Hello, World!" |
记住,虽然OJBMessageResources 使用一个单表来保存消息资源,每一个资源集都仍然必须在struts-config.xml中通过message-resources元素进行配置。换句话说,对由bundleKey 和 subApp区分的每一个消息资源集都将需要一个message-resource元素。关于多个消息资源,参见第2.6式。
相关招式
第2.6式描述了如何配置Struts 来使用多个消息资源束。第13段的动作中会描述如何进行Struts 应用的国际化。
OJB 是Apache 大伞之下的一个项目。详细信息清访问呢:http://db.apache.org/ojb.
有人正在努力将Struts 消息资源重构到一些更加通用的类中。这就是Commons Resources 项目,可以访问http://jakarta.apache.org/commons/sandbox/resources/获取相关信息。它可以提供属性文件支持的消息资源机制,或者其他持久性机制支持的消息资源机制,比如OBJ, Hibernate, Torque, 和直接JDBC。也许将来的Struts将使用这个通用的消息资源机制。