铁手剑谱

上善若水
数据加载中……

Struts秘籍之第2段:UI

2. 用户接口

介绍

有一个现实:你尽管可以架构最纯粹、最优雅和最强壮的Web应用,但是如果用户不喜欢其接口的样子,你便注定要失败。有些Java 开发人员考虑到这些问题,并使用普通的HTML JavaScript技术来解决这些问题。不管你是否喜欢,这些技术,特别是HTML的知识会使得一切在涉及表现和可用性的时候变得完全不同。如果你不知道如何使用它们,你的应用便面临如何被用户去接受的风险和挑战。

这一部分将介绍一些有用的技巧和招数来解决大多数应用表现的难题。这里并不是说就不需要优秀的图形设计和用户接口设计人员。然而,通过Struts的动态能力来利用HTML的优势毕竟还有一大段距离。另外,这一部分将提供一种基于补充技术的解决方案,比如使用JSTL

一些情形,比如使用HTML表单也非常麻烦。比如,Checkboxes 因为其对unchecked 控件状态的处理让人无休止的头疼。这部分就包括了一个专门处理这个问题的技术。表单处理中另一个通用的问题就是如何处理日期字段。有很多方式,但都有其优缺点。本部分也包含有一个对这些方式的比较。

其中保包括如何设置表单中的tab 次序,产生用于JavaScript中的URL,以及使用框架帧(frame)。总之,如果你对StrutsUI有问题,这里就是解决他们的一个好地方。

 

posted @ 2005-05-25 10:18 铁手 阅读(1138) | 评论 (1)编辑 收藏
Java 平台持久性机制的比较

Java 平台持久性机制的比较

 

访问持久性数据是所有应用都需要考虑的一个重要方面。Java 语言严格的遵循了持久性数据和暂态性数据的分离,将持久性管理留给了应用或者分层机制。SUN使用一种严格的比较机制测试和比较了Java平台上的各种革新的持久性机制。

通过选择,选出了一个有代表意义的几个系统来进行评价和比较。这些机制都通过OO7J的基准测试进行量化分析。

所有的测试环境都具有足够的内存,使得测试数据库完全可以在内存中驻留,排除磁盘访问等硬件的影响,也是今天主要服务环境的通用内存容量配置。OO7J的虚拟机变体设置性能基线,每一种机制都和它进行比较。OPJ的PJama实现得到了总体最高分。它只需要最小的源代码修改,甚至对OO7J的主体基本不需要,虽然它仅是一个原型实现,却取得了最好的性能。但是它的确需要一个定制的虚拟机。

EJB 框架看起来最糟,需要最多的源代码修改和最坏的性能和可伸缩性。

JOS 和 JBP,虽然因为它们缺乏增量访问从而使得在读写数据的时候性能也很糟糕,但是,他也仅需要很少的代码修改并能在数据在内存中的情况下全速运行。

JDBC 对源代码修改也有较大影响,但是性能却是在JVM和数据库的边缘交叉处的大量交互体现的很好。两个JDO 的变体则展现出JDO模型对不同外部数据存储的多能性。特别是JDO-TP 和其事务对象模型对关系数据库工作的很好,同时允许源代码对基线保持最小的变更。并且, JDO 的性能也排在前列,一旦数据在内存中,这是合情合理的,比JDBC 和 EJB而言也是如此。

虽然EJB CMP 的性能要优于EJB BMP,其性能也差于JDO-TP很多。EJB性能差的原因还不清楚,也应该注意到,一些应用服务企业有很差的性能,可能是容器实现的原因。

作为结论,很显然,持久性对应用代码的影响是很宽的,也对结果系统的性能影响很大。. 如果在虚拟机一级得到支持,OPJ可望提供最有竞争力的性能。在另一个极端,EJB似乎很难达到可接受的性能水平,除非应用对象模型发生戏剧性的变化,从而避免在映射到EJB时产生的细粒度对象。虽然这些方法已经反映在标准的EJB设计模式中了,但是其暗示着在应用程序的各个方面均要附加更多额外的努力。相反,JDO 试图在对应用设计的影响最小的情况下达到合理的性能,同时保持对外部数据源的中立。因此,当前,JDO 似乎能够提供面向对象应用所需的最佳的总体持久性机制。但是,目前,SUN建议了一个最新的实体Bean持久性规范 [Sun04],提交给 EJB3.0,它可能更加接近于JDO 模型。

 

报告的原文可以在以下地址下载:http://research.sun.com/techrep/2004/smli_tr-2004-136.pdf

同时,这也是SUN首次公开披露EJB的性能问题。这也解释了为什么EJB一直得不到很好的广泛使用的原因,淡然还有它的复杂性和部署的高成本性(需要昂贵的EJB容器)。作为J2EE规范中的一个重要的核心组件,SUN的赌注押在了EJB3.0上面。EJB3.0相关的持久性机制(JSR220)吸收了JDO和oracle的TopLink的优点,并且可望提供向后兼容性和迁移API。

虽然,EJB从其规范和目标来说看上去很美。但是EJB3.0至少要今年晚些时候才能出场,目前我们能够使用什么呢?考察目前市面上的持久性框架,结合你的应用要求,也不难得出选择。毕竟,应用来说,性能并不是第一位的。

对于持久性框架的选择,从应用和功能上讲,主要考虑以下方面:

  • 对O-R mapping框架的使用经验。 
  • 数据源(Data Source),必须支持不同的数据源,包括关系数据库和JCA体系。
  • 最好提供图形化的映射工具来进行对象和数据库表之间的映射,自动生成XML配置文件。 
  • 数据库支持,可以利用数据库的优势,如存储过程,触发器,支持高级数据类型和数据库安全。 
  • 查询支持,应该支持通过Java代码或者OO查询机制,如EJB QL,按例查询,标准SQL 来编写自己的查询。
  • 锁定。必须支持不同应用访问同一数据库时候的锁定机制。 
  • 缓存。提供有效的缓存基址,减少网络和查询的开销。 并支持不同节点的集群。
  • 支持到EJB 3.0的迁移。

 

目前,JBOSS已经在AS 4.0中提供了EJB3.0的早期实现。可以参考。http://www.jboss.org/products/ejb3

 

如果你不怕在Oracle数据库平台上锁定,你打可使用Toplink,这也是目前性能最好的POJO的持久性框架。Oracle也是EJB3.0的专家组,将来肯定会提供迁移的手段。 你可以阅读这篇文章:Preparing for EJB3.0. 地址:http://www.oracle.com/technology/tech/java/newsletter/articles/toplink/preparing_for_ejb_3.html

 

注:

JOS

JOS,称为Java对象序列化,是JDK 1.1 引入的 [Sun99],它是一种支持几乎所有对象到流的编码和从流解码的机制。他不是基于属性表的编码,而是基于文本的,对象序列使用标准的二进制编码格式。JOS 是Java平台默认的持久性机制,也被用来作为 JAVA远程方法调用RMI的参数编组协议。在最低层次上,JOS 构成了对基础类型的编码和解码的平台支持。但是,序列化遇到了类演化的严重问题,这也使得在Java1.4中引入了“JavaBean的长期持久化”的新系统。

JDBC

JDK 1.1 也引入了Java数据库连接(JDBC) API [FEB03]作为使用标准的SQL语言在Java和关系数据库之间的通信机制。JDBC为Java 向关系数据库提供了一个强有力的跳板,并且被平台上的很多API实现证明很成功。设计者很成功地将Java 编程语言和SQL进行了嫁接,而且JDBC 对直接的数据库访问非常容易使用。然而,如果应用需要底层数据的对象视图的时候,比如,将主键转换成相等的对象间的引用关系,程序将便得非常复杂和容易出错。为了解决这个问题,有许多系统开发出来试图自动化这个流程,这通常称为是对象关系映射(O-R Mapping)。大多数开发环境都提供对这一机制的不同程度的支持。 JDBC API 也在发展,近来支持直接将Java语言中的一个类映射到SQL的面向对象扩展中的相等类型。

JDO

在JDBC 开发的同时,对象数据库管理组 (ODMG)定义了一个它们的对象模型到Java语言的绑定[Ced96],而许多对象数据库厂商则提供了这种绑定的实现。因为对象数据库并不像关系数据库那样部署普遍,因此反映在这个绑定上面也是不怎么成功。Java社区流程(JCP)出现后,这一努力被一个更广泛的建议所替代,即Java数据对象 (JDO) [JR03]。JDO 的目标是针对各种各样的底层数据存储,包括关系数据库,并向开发人员呈现一个类似于LJS所定义的对象模型,但附加限制更少。而许多对象数据库厂商也支持JDO。

OPJ

综合这些努力,SUN和 Glasgow 大学合作,提出了一个Java平台的正交持久化机制 (OPJ) [JA00]。这一方法以极高的透明性支持变成语言的各个方面。从本质上讲,OPJ 添加了对JVM稳定内存的支持,也意味着这一对JVM 实现的要求根本上限制了其可接受性。

posted @ 2005-05-24 10:26 铁手 阅读(743) | 评论 (0)编辑 收藏
Struts秘籍之第1段:第2.8式. 有选择地禁止Action

第2.8式. 有选择地禁止Action

问题

你想要是使用一个定制属性来禁止(disable)一个,并且该属性能够在struts-config.xml文件的action元素中进行设置;转发到该disabled action 的任何请求都会得到"under construction" 页面。

动作要领

创建一个定制的ActionMapping扩展(如Example 2-16) ,它可以提供一个boolean 类型的属性来指示action 是否被禁止。

Example 2-16. 定制ActionMapping

 

import org.apache.struts.action.ActionMapping;

public class DisablingActionMapping extends ActionMapping {

    
private String disabled;
    
private boolean actionDisabled = false;
    
    
public String getDisabled( ) {
        
return disabled;
    }


    
public void setDisabled(String disabled) {
        
this.disabled = disabled;
        actionDisabled 
= new Boolean(disabled).booleanValue( );
    }

    
    
public boolean isActionDisabled( ) {
        
return actionDisabled;
    }

}

这个action mapping 就可以在struts-config.xml文件中指定。如果你想要一个action被禁止,你可以设置disabled属性为True :

<action-mappings type="com.oreilly.strutsckbk.DisablingActionMapping">

  
<!-- Edit mail subscription -->
  
<action    path="/editSubscription"
             type
="org.apache.struts.webapp.example.EditSubscriptionAction"
        attribute
="subscriptionForm"
            scope
="request"
         validate
="false">
    
<set-property property="disabled" value="true"/>
    
<forward name="failure"              path="/mainMenu.jsp"/>
    
<forward name="success"              path="/subscription.jsp"/>
  
</action>

然后创建一个定制的RequestProcessor,比如Example 2-17中的那个,它可以处理DisablingActionMapping.

Example 2-17. 处理对被禁止的actions的请求

 

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.RequestProcessor;

public class CustomRequestProcessor extends RequestProcessor {
    
    
protected ActionForward processActionPerform(HttpServletRequest request, 
           HttpServletResponse response, Action action,ActionForm form, 
            ActionMapping mapping) throws IOException, ServletException 
{
        ActionForward forward 
= null;
        
if (!(mapping instanceof DisablingActionMapping)) {
            forward 
= super.processActionPerform( request, response, 
                                                    action, form, mapping);
        }

        
else {
            DisablingActionMapping customMapping 
= 
                  (DisablingActionMapping) mapping;
            
if (customMapping.isActionDisabled( )) {
                forward 
= customMapping.findForward("underConstruction");
            }

            
else {
                forward 
= super.processActionPerform( request, response,
                                                         action, form, mapping);
            }

        }

        
return forward;
    }

}

动作变化

Struts 通过两种机制来对action提供定制属性的能力。

首先,每个Struts action 都可以通过一个通用参数parameter值来传递:


<action    path="/editRegistration"
           type
="org.apache.struts.webapp.example.EditRegistrationAction"
      attribute
="registrationForm"
          scope
="request"
       validate
="false"
       parameter
="disabled">
  
<forward name="success" path="/registration.jsp"/>
</action>

其次,在Action的实现中,parameter的值可以通过下面的代码来访问:

String parameterValue = mapping.getParameter(  );

然而,某些Struts所提供的子类,比如DispatchAction 已经使用了parameter属性。因为你只可以指定一个parameter属性,所以,如果你使用这些预定义的Action子类,便不能再将parameter用作定制属性值。

对于完整的扩展,你可以扩展ActionMapping类,可选地为你所选择的定制属性提供accessor 和 mutator :

 

package com.oreilly.strutsckbk;

import org.apache.struts.ActionMapping

public class MyCustomActionMapping extends ActionMapping {
    
private String customValue;
    
public String getCustomValue( ) return customValue; }
    
public String setCustomValue(String s) { customValue = s; }
}


你可以在struts-config.xml文件中引用这个扩展。如果定制action mapping 将被用于所有action,请将action-mappings元素的type属性设置为定制扩展的全限定类名:

 

<action-mappings type="com.oreilly.strutsckbk.MyCustomActionMapping">


否则,为定制action mapping所需的action元素设置className属性。这两种情况下,set-property元素都可以用来针对特定的action元素为定制扩展中的JavaBean 属性设置值:

<action    path="/someAction"
           type
="com.oreilly.strutsckbk.SomeAction"
      className
="com.oreilly.strutsckbk.MyCustomActionMapping">
  
<set-property property="customValue" value="some value"/>
</action>

这种方案使用一个定制的RequestProcessor来处理定制ActionMapping的disabled 属性。如果你对特定的action使用定制的ActionMapping,你可以在Action.execute()访法中直接访问定值ActionMapping的属性:

boolean disabled = ((DisablingActionMapping) mapping).isActionDisabled(  );
if (disabled) return mapping.findForward("underConstruction");

相关招式

你也可以使用授权(authorization) servlet 过滤器来解决这个问题。那是第11.8式的动作。

posted @ 2005-05-19 13:07 铁手 阅读(1769) | 评论 (1)编辑 收藏
骡子力气比马大:一个ESB集成框架CodeHaus Mule

 

Mule 是一个基于ESB架构理念的消息平台。Mule 的核心是一个基于SEDA的服务容器,该容器管理被称为通用消息对象(Universal Message Objects /UMO)的服务对象,而这些对象都是POJO。所有UMO和其他应用之间的通信都是通过消息端点(message endpoint)来进行的。这些端点为众多的分立的技术,比如Jms, Smtp, Jdbc, Tcp, Http, Xmpp, file等等,提供了简单和一致的接口。

Mule 应用通常是由网络中的许多Mule 实例组成。每一个实例都是一个驻留一个或者多个UMO组件的轻量级容器。每一个UMO 组件都有一个或者多个通过它(们)发送和接收事件的端点。


clip_image001_0013.gif

容器通过UMO组件提供各种各样的服务,比如事务管理、事件转换,路由,事件关联、日志、审计和管理等等。Mule将对象构造从管理手段中分离出来,通常流行框架和IoC/DI 容器,如Spring, PicoContainer 或者 Plexus 可用这种管理手段来构建你的UMO 组件。

很多人认为, "Mule是一个Jms 实现"。实际上,Mule 不是一个Jms server,但是可以配置来使用任何你觉得非常漂亮的Jms server。Mule 的理念是,如果已经有了稳定和广泛接受的实现,就不会直接实现任何传输。例如,Mule 就重用了Axis 和 GLUE 的SOAP栈而不是重新实现一个。Mule 提供了一个一致的服务集来管理任何类型的连接的事件流、关联、事务、安全和审计。

 

下面是Mule Server 组件的简单图示:

clip_image002_0002.gif

Mule Manager

Mule Manager是Mule server 实例的中心(也称为一个节点户或者Mule Node)。其主要的角色是管理各种对象,比如Mule实例的连接器、端点和转换器。这些对象然后被用来控制进出你的服务组件的消息流,并且为Model和它所管理的组件提供服务。

Model

model 是管理和执行组件的容器。它控制进出组件的消息流,管理线程、生命周期和缓充池。默认的MuleModel是基于SEDA的,它使用一个有效的基于事件的队列模型来获取的最大的性能和直通性。

UMO Components

UMO代表Universal Message Object;它是一个可以接收来自于任何地方的消息的对象。UMO 组件就是你的业务对象。它们是执行引入的事件之上的具体业务逻辑的组件。这些组件是标准的JavaBean,组件中并没有任何Mule特定的代码。Mule 基于你的组件的配置处理所有进出组件的事件的路由和转换。

Endpoints

Endpoint是Mule的通信能力的基础。一个Endpoint定义了两个或者多个组建应用或者存储库之间的通信渠道。并且提供了一个强大的机制来允许你的对象在一个统一的方式上再多种协议之上进行交谈。端点可以通过消息过滤器、安全拦截器和事务信息进行配置来控制什么消息,在何时,以及怎样通过端点进行发送和接收。

External Applications

外部应用可以使任何应用,从应用服务器到遗留的传统应用,主机程序,或者C/S系统。基本上是任何可以产生和操纵数据的应用。因为Mule通过endpoints执行所有通信,UMO 组件并不打算在其中包含应用产生数据,以及应用主流,以及使用传输协议的部分。

 

关键特性

  • 基于J2EE 1.4的企业消息总线( Enterprise Service Bus (ESB))和消息代理(broker)
  • 可插入性连接,比如Jms (1.0.2b 和 1.1), vm (嵌入), jdbc, tcp, udp, multicast, http, servlet, smtp, pop3, file, xmpp等
  • 支持任何传输之上的异步,同步和请求响应事件处理机制
  • 支持Axis或者Glue的Web Service.
  • 灵活的部署结构[Topologies]包括Client/Server, P2P, ESB 和Enterprise Service Network.
  • 支持声明性和编程性事务,包括XA 支持
  • 对事件的路由、传输和转换的断到端支持
  • Spring 框架集成。可用作ESB 容器,而Mule c也可以很容易的嵌入到Spring 应用中。
  • 使用基于SEDA处理模型的高度可伸缩的企业服务器
  • 支持REST API 来提供技术独立和语言中立的基于web的对Mule 事件的访问
  • 强大的基于EIP模式的事件路由机制
  • 动态、声明性的,基于内容和基于规则的路由选项
  • 非入侵式的方式。任何对象都可以通过ESB 容器管理
  • 强大的应用集成框架
  • 完整的可扩展的开发模式

何时使用

一般在这些情形下使用Mule -

  • 集成两个或者多个需要互相通信的或者多个现有的系统.
  • 需要完全和周围环境去耦合的应用,或者需要在系统中伸缩不止一个组件的系统
  • 开发人员不知道未来是否会将其应用分发或者伸缩需求的单VM 应用。

项目地址:http://mule.codehaus.org/

posted @ 2005-05-18 13:22 铁手 阅读(4614) | 评论 (1)编辑 收藏
Struts秘籍之第1段:第2.7式. 访问来自于数据库中的消息资源

第2.7式. 访问来自于数据库中的消息资源

问题

你想要将所有标注、消息和其他静态文本都保存在数据库中而不知一个属性文件中,并且仍然可以通过bean:message标签来进行访问。

动作要领

  1. 下载OJBMessageResources分发包,地址是:http://prdownloads.sourceforge.net/struts/ojb-message-resources.zip?download.
  2. 将ZIP 文件解包到一个本地目录;
  3. 将ojb-msg-res.jar文件从ojb-message-resources/dist文件夹拷贝到你的应用的WEB-INF/lib文件夹。
  4. 将属性文件、XML 和DTD 文件从ojb-message-resources/config文件夹拷贝到你的应用的src文件夹。当你build 你的应用的时候是,这些文件必须被拷贝到WEB-INF/classes文件夹中。
  5. 创建数据库表来保存对象关系桥(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(175NOT NULL default '',
  FIELDNAME 
varchar(70NOT NULL default '',
  MAX_KEY 
int default NULL,
  GRAB_SIZE 
int default NULL,
  
PRIMARY KEY  (TABLENAME,FIELDNAME)
) TYPE
=MyISAM;

CREATE TABLE ojb_lockentry (
  OID_ 
varchar(250NOT NULL default '',
  TX_ID 
varchar(50NOT NULL default '',
  TIMESTAMP_ 
decimal(10,0default NULL,
  ISOLATIONLEVEL 
int default NULL,
  LOCKTYPE 
int default NULL,
  
PRIMARY KEY  (OID_,TX_ID)
) TYPE
=MyISAM;

CREATE TABLE ojb_nrm (
  NAME 
varchar(250NOT NULL default '',
  OID_ longblob,
  
PRIMARY KEY  (NAME)
) TYPE
=MyISAM;

CREATE TABLE ojb_seq (
  TABLENAME 
varchar(175NOT NULL default '',
  FIELDNAME 
varchar(70NOT 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自身决定的。

关于细节,包括详细的国家代码和语言代码清单,可以从http://java.sun.com/j2se/1.4.2/docs/guide/intl/locale.doc.html找到。

这个工具对大多数中型和小型的应用工作的很不错。但是,你可能想要使用一种更加具有可管理性的持久性手段,比如数据库来保存它。虽然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将使用这个通用的消息资源机制。

posted @ 2005-05-18 11:27 铁手 阅读(1607) | 评论 (1)编辑 收藏
仅列出标题
共26页: First 上一页 18 19 20 21 22 23 24 25 26 下一页