第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="http://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將使用這個通用的消息資源機制。