登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

水木长弓的天空

爱拼才会赢!

 
 
 

日志

 
 
 
 

webwork 2.2.2 高级特性   

2007-09-11 11:45:07|  分类: java框架学习 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

一 :异常处理 

异常映射是一个处理抛出异常Action的强大特性. 这个思想的核心是 : 捕捉到Action的方法执行期间抛出的异常,并把它映射到一个result, 既可以是全局的也可以是action作用域内的results. 这对框架尤其有用, 比如Hibernate和Acegisecurity抛出的RuntimeExceptions.

为了和WebWork的其他部分协作,开启异常映射功能需要一个拦截器. 下面的代码片断是来自webwork-default.xml的,其中已经启用了异常映射.

webwork-default.xml文件中的代码片断

 1
 2 < interceptors >
 3     
 4      < interceptor name = " exception "  class = " com.opensymphony.xwork.interceptor.ExceptionMappingInterceptor " />
 5     
 6 </ interceptors >
 7
 8 <!--  Basic stack  -->
 9 < interceptor - stack name = " basicStack " >
10      < interceptor - ref name = " exception " />
11      < interceptor - ref name = " servlet-config " />
12      < interceptor - ref name = " prepare " />
13      < interceptor - ref name = " static-params " />
14      < interceptor - ref name = " params " />
15      < interceptor - ref name = " conversionError " />
16 </ interceptor - stack >
17  

异常处理的下一步就是映射实际的异常特定的result.WebWork提供了两种方式来声明一个异常映射 :

1 < global - exception - mappings />  全局的
2 < exception - mapping  />  针对一个特定的action

异常映射元素有两个属性,

1 exception
2 result.

当声明一个异常映射时,拦截器会根据抛出的异常来查找声明中的层次关系最接近的类.
拦截器会检查此Action所有可用的声明的映射,包括Action特定的和全局的映射.
然后会调用result(全局或者Action范围的).

下面的例子是一个全局和Action作用域内的异常映射的例子.

xwork.xml文件中的代码片断

 1 < xwork >
 2      < package name = " default " >
 3         
              //声明全局结果
 4          < global - results >
 5              < result name = " login "  type = " redirect " >/ login.action </ result >
 6              < result name = " rootException "  type = " freemarker " >/ WEB - INF / views / exception.ftl </ result >
 7          </ global - results >
 8
               //全局异常映射
 9          < global - exception - mappings >
10              < exception - mapping exception = " java.sql.SQLException "  result = " sqlException " />
11              < exception - mapping exception = " java.lang.Exception "  result = " rootException " />
12          </ global - exception - mappings >
13         
14          < action name = " myAction "  class = " " >
15              < interceptor - ref name = " exception "   />
                   //针对某一Action的 异常映射
16              < exception - mapping exception = " com.acme.foo.SecurityException "  result = " login " />
                   //针对某一Action的  结果
17              < result name = " sqlException "  type = " chain " > sqlExceptionAction </ result >
18              < result name = " success "  type = " freemarker " >/ WEB - INF / views / acme / success.ftl </ result >
19          </ action >
20         
21      </ package >
22 </ xwork >  

在上面的例子中, 基于每一个异常的发生处理如下:

1 一个 java.sql.SQLException 将链接到 sqlExceptionAction 
2 一个 com.acme.foo.SecurityException 将转向到  / login.action 

任何其他继承于 java.lang.Exception 的异常将执行FreeMarker类型的result rootException ,显示页面  / WEB - INF / views / exception.ftl 


缺省情况下异常映射拦截器(ExceptionMappingInterceptor)添加下列值到Value Stack中:

1 exception  -  异常对象自己 
2 exceptionStack  -  异常堆栈 


二 :Action链 

WebWork提供把多个Action按照预先定义好的顺序或者流程链接起来的能力.这个特性通过给指定的Actions设置一个Chain Result,然后通过一个ChainingInterceptor 拦截目标Action来实现.

通常不推荐使用Action链.但是,你可以有其他选择,例如redirect after post技术

Chain Result是一种result 类型,

它基于自己的拦截器stack(堆栈)和result调用一个action,
这样允许一个action附带着原来的状态将请求转到目标action

下面是关于如何定义这样的一个序列的例子 :

 1 < package name = " public "  extends = " webwork-default " >

 2      <!--  Chain creatAccount to login, using the  default  parameter  -->
 3      < action name = " createAccount "  class = " " >
 4          < result type = " chain " > login </ result >
 5      </ action >
 6
 7      < action name = " login "  class = " " >
 8          <!--  Chain to another namespace  -->
 9          < result type = " chain " >
10              < param name = " actionName " > dashboard </ param >
11              < param name = " namespace " >/ secure </ param >
12          </ result >
13      </ action >
14 </ package >

1 < package name = " secure "  extends = " webwork-default "  namespace = " /secure " >
2      < action name = " dashboard "  class = " " >
3          < result > dashboard.jsp </ result >
4      </ action >
5 </ package >  

在这个Action(参见 配置文件)执行之后同一命名空间(或者是默认的""命名空间)的另外一个Action也会得到执行.一个可选的"namespace"参数来指定另外一个命名空间的Action

如果你需要把Action链中早先的Actions的属性复制到当前的Action中,你应该采用ChainingInterceptor. 这个拦截器会从request和ValueStack中复制所有的原始参数传给目标Action. ValueStack会记录Action源的信息,这样目标Action就可以通过ValueStack访问早先的Action的属性,这些属性也能被Action链中最后的result访问,例如JSP或者Velocity页面.

Action链通常用来提供查找列表(例如状态的下拉列表等等).既然这些Actions已经放入了ValueStack,它们的属性在View层就是可用的.这个功能也可以使用Action标签(ActionTag)在显示页面执行一个Action来做到.你也可以利用Redirect Action Result来完成这样的功能.

三 :类型转换 

         在所有的基于Web的Java开发框架中, WebWork拥有最优秀的类型转换能力. 通常情况下, 要利用这种能力, 只需要把HTML输入项(表单元素和其他GET/POST的参数)命名为合法的OGNL表达式.

简单的例子
当你需要将一个字符串转换成为一个更为复杂的对象时, 类型转换能发挥强大的作用. 由于Web是类型不可知的(type-agnostic)(HTTP中任何类型都是字符串), 因此WebWork的类型转换功能非常有用. 例如, 如果你提示用户使用字符串格式("3, 22")输入一个坐标, 你需要让WebWork完成String到Point和Point到String的转换.

使用"point"的例子, 如果活动(或者其他需要设置属性的组合对象)有一个对应的ClassName-conversion.properties文件, WebWork会使用配置的类型转换器进行该类和字符串的转换. 因此将"3, 22"转换成new Point(3, 22)只需在 ClassName-conversion.properties 中加入下列内容(注意, PointConverter需要实现接口ognl.TypeConverter):

point  =  com.acme.PointConverter

你编写的类型转换器必须检查被用于转换哪种类型. 由于都是与String进行相互转换, 需要将转换方法分为两部分: 一个将String转换为Point, 另一个将Point转换为String.

这些完成后, 你可以引用point对象(在JSP中使用<ww:property value="point"/>或在FreeMarker中使用${point})并且它将输出为"3, 22". 同样的, 如果你将它提交到活动, 它将再次转换成Point.

有时你可能希望将一个类型转换器应用到全局范围. 这可以通过编辑 xwork-conversion.properties (位于根类路径, 通常是WEB-INF/classes目录)并以下列形式添加一个属性定义: 左边是你希望转换的类名称, 右边是转换器的类名称. 例如, 为所有的Point对象提供一个类型转换器意味着增加下列内容:

com.acme.Point  =  com.acme.PointConverter

 类型转换不能作为i18n的替代品. 不推荐使用这一特性输出相应的日期格式. 相反, 你应该使用WebWork的i18n功能(并且研究一下JDK中MessageFormat的JavaDoc)来了解如何使用相应正确的日期格式.

WebWork附带了一个帮助基类(a helper base class), 利用它可以很方便的完成类型与字符串之间的相互转换. 这个类就是

com.opensymphony.webwork.util.WebWorkTypeConverter

 该类可以让你很方便的编写处理对象和字符串相互转换的类型转换器. 下面是从该类的JavaDoc中摘录的内容:

本类是WebWork使用的类型装换器的一个基类. 该类提供了两个抽象方法用于对象与字符串的相互转换  -  这是WebWork类型转换系统的关键功能.

类型转换器也可以不使用该类. 它基本上是一个帮助类, 尽管它是推荐使用的, 它为子类提供了所有基于Web的类型转换所需的一般接口约束.

它还包含一个hook(后备方法), 名为performFallbackConversion, 该方法可用于在convertValue方法执行失败时执行一些后备的转换. 缺省情况下, 它使用父类(Ognl的DefaultTypeConverter)的convertValue方法完成转换.内建的(Built in)类型转换支持WebWork可以替你自动完成大多数常用的类型转换. 已支持的与字符串之间转换类型包括:

String 
boolean   /  Boolean 
char   /  Character 
int   /  Integer,  float   /  Float,  long   /  Long,  double   /  Double 
dates 
-  使用当前request指定的Locale信息对应的SHORT格式 
arrays 
-  假定每一个字符串都能够转换成对应的数组元素 
collections 
-  如果不能确定对象类型, 将假定集合元素类型为String, 并创建一个新的ArrayList 

注意, 对于数组的类型转换将按造数组元素的类型来单独转换每一个元素. 而在其他类型转换中, 如果转换无法实现, 将使用标准的类型转换错误报告.

参数名称的关系
利用WebWork的类型转换最好的方式是使用已完成的(completes)对象(理想情况下应当直接使用业务对象(domain objects)), 而不是使用基本类型或字符串类型的表单参数值作为中间值, 然后在Action的execute()方法中把这些中间值转换成完整的对象(rather than submitting form values on to intermediate primitives and strings in your action and then converting those values to full objects in the execute() method). 下面是一些提示:

使用组合的(complex)OGNL表达式 - WebWork能自动创建你所需的实际对象.
使用JavaBeans! WebWork只能创建遵守JavaBean规范的对象, 这需要你的对象提供一个无参构造函数, 并包含适当的getter和setter方法.
记住 person.name 将调用 getPerson().setName(), 但如果你希望WebWork创建Person对象, 那么必须包含一个setPerson() 方法.
对于list和map对象, 使用索引符号, 如 people[0].name or friends['patrick'].name. 通常这些HTML表单元素是在一个循环中绘制出来的, 因此你可以在JSP Tags中使用iterator标签的状态属性(status attribute)或在FreeMarker Tags中使用${foo_index} 来指定这一属性(指index value, 译注).
对于多选的列表, 显然不能为每个单独的选项使用对应的属性符号来命名(由于). 替代的方法是, 使用简单的名称 people.name 来命名你的表单元素, WebWork知道需要为每一个选中的选项创建一个新的Person对象并设定它的名字.
高级类型转换
WebWork还有一些非常优秀的(同样易与使用)的类型转换特性. 对空值(Null)属性的处理可以在发现空值引用时自动创建对象. 对Collection和Map的支持提供了针对Java集合的智能空值处理和类型转换. 类型转换错误处理提供了一种简单的方法可以把输入校验问题和输入类型装换问题区别开.

空值属性处理
通过把action context中的键值 CREATE_NULL_OBJECTS 设置为true支持空值处理(该键只在com.opensymphony.xwork.interceptor.ParametersInterceptoris执行过程中进行设置), 这样, 出现NullPointerException异常的OGNL表达式将被自动临时中断, 然后系统将通过创建所需对象的方法来自动尝试解决null引用.(OGNL中包含了NullHandler接口, 允许对空值引用进行转换, WebWork实现了这一接口并替换了OGNL的缺省实现, 译注)

处理控制引用时将遵循下列规则:

如果属性声明为Collection或List, 将返回一个ArrayList并赋值给空引用.
如果属性声明为Map, 将返回一个HashMap并赋值给空引用.
如果空值属性是一个带有无参构造函数的简单Bean, 将使用ObjectFactory.buildBean(java.lang.Class, java.util.Map)方法创建一个实例.
(摘自snippet:id=javadoc|javadoc=true|url=com.opensymphony.xwork.util.InstantiatingNullHandler)

例如, 如果表单中包含一个文本字段名为 person.name 而表达式 person 运算结果为null, 那么该类将被调用. 由于表达式 person 类型为Person, 因此将创建一个新的Person实例并赋值给空值引用. 最后, name值被赋给该实例的name属性. 全部过程是系统自动创建一个Person实例, 并调用setPerson()方法将它赋给空值引用, 最后调用getPerson().setName(), 而这通常是想要的结果.

(摘自snippet:id=example|javadoc=true|url=com.opensymphony.xwork.util.InstantiatingNullHandler)

Collection和Map支持
WebWork支持多种方法来判断集合中的对象类型. 这是通过一个 ObjectTypeDeterminer 完成的. WebWork提供了缺省实现. 下面的JavaDocs解释了对Map和Collection的支持是如何在DefaultObjectTypeDeterminer中完成的:

ObjectTypeDeterminer检查 Class-conversion.properties 文件中包含的用于表示Map和Collection中包含的对象类型的相关内容 . 对于Collection, 如List, 使用格式 Element_xxx 来指定其中的元素类型, 这里xxx是action或其他对象中的集合属性名称. 对于Map, 需要按照格式 Key_xxx 和 Element_xxx 分别指定key和value的类型.

从WebWork 2.1.x开始, 仍然支持Collection_xxx这样的书写格式, 尽管这种格式已经被声明废弃而且最终将被去除.

(摘自snippet:id=javadoc|javadoc=true|url=com.opensymphony.xwork.util.DefaultObjectTypeDeterminer)

除此之外, 也可以实现接口ObjectTypeDeterminer来创建自己的定制ObjectTypeDeterminer. WebWork也包含一个可选的使用Java5范型(generics)技术实现的ObjectTypeDeterminer. 更多信息参见J2SE 5 Support.

使用集合的属性索引集合元素(Indexing a collection by a property of that collection)
也可以向WebWork传递元素的某个给定属性的值来获取集合中的唯一元素(element). 缺省情况下, 这个属性由 Class-conversion.properties中定义的KeyProperty_xxx=yyy决定, 这里的xxx是返回集合的JavaBean类型名称, yyy是我们用于索引集合中元素的属性名称. (the property of the element of the collection is determined in Class-conversion.properties using KeyProperty_xxx=yyy where xxx is the property of the bean 'Class' that returns the collection and yyy is the property of the collection element that we want to index on.) 下面的两个类是一个示例:

MyAction.java
/**
 * @return a Collection of Foo objects
 */
public Collection getFooCollection()
{
    return foo;
}Foo.java
/**
 * @return a unique identifier
 */
public Long getId()
{
    return id;
}然后将 KeyProperty_fooCollection=id 放在MyAction-conversion.properties文件中. 这样就可以使用 fooCollection(someIdValue) 从集合fooCollection中获取id等于 someIdValue 的Foo对象. 例如, fooCollection(22) 将得到id值为22的Foo对象.

这一点十分有用, 因为这直接将一个集合中的元素与它的唯一标志符联系起来, 而不需要强制使用索引, 从而允许修改一个Bean的集合中的元素而不需要编写额外的代码. 例如, 值为 Phil 的参数 fooCollection(22).name 将集合fooClooection中id属性值为22的Foo对象的name属性设置为"Phil".

Webwork可以使用类型转换自动将参数的类型转换成key属性的类型.

与Map和List元素的属性不同, 如果fooCollection(22)不存在, WebWork不会创建新的对象. 想要做到这一点, 可以使用符号 fooCollection.makeNew[index], 在这里index是一个整数(0, 1等等). 因此, 参数 fooCollection.makeNew[0]=Phil 以及 fooCollection.makeNew[1]=John 将在fooCollection中添加两个新的Foo对象, 一个name属性值为Phil, 另一个为Bar. 注意, 不管用哪种方法, 在使用Set类型时, 必须定义对象的equals方法和hashCode方法来并保证他们不仅仅包含id属性. 这将导致id属性为null的元素可以从Set中删除.

索引的List和Map的高级示例
下面是一个用于List中的模型bean.
该类的KeyProperty是id属性.

MyBean.java
public class MyBean implements Serializable {

    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    public String toString() {
        return "MyBean{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}下面的action有一个beanList属性, 它被初始化为一个空的ArrayList对象.

MyBeanAction.java
ublic class MyBeanAction implements Action {

    private List beanList = new ArrayList();
    private Map beanMap = new HashMap();

    public List getBeanList() {
        return beanList;
    }

    public void setBeanList(List beanList) {
        this.beanList = beanList;
    }

    public Map getBeanMap() {
        return beanMap;
    }

    public void setBeanMap(Map beanMap) {
        this.beanMap = beanMap;
    }

    public String execute() throws Exception {
        return SUCCESS;
    }
}定义在conversion.properties中的内容告诉TypeConverter使用MyBean的实例作为List的元素.

MyBeanAction-conversion.properties
KeyProperty_beanList=id
Element_beanList=MyBean
CreateIfNull_beanList=true当通过表单提交到Action时, (id)的值被当作beanList中MyBean实例的KeyProperty.
注意()符号! 不要使用[], 那仅能用在Map里!
属性的name的值将根据指定的id设置到对应的MyBean实例中.
无效的id值将不会再加入null值.
这就避免了OutOfMemory异常的产生!

MyBeanAction.jsp
<ww:iterator value="beanList" id="bean">
  <ww:textfield name="beanList(%{bean.id}).name" />
</ww:iterator>类型转换错误处理
当类型转换期间发生错误时, 有时希望报告这些错误, 而有时不希望报告. 例如, 报告输入的"abc"不能转换成数字可能很重要. 另一方面, 报告一个空字符串("")不能装换成数字可能不重要 - 除非是在一个Web环境下, 难以区分用户没有输入值还是输入了一个空白值.

缺省情况下, 所有的装换错误使用通用的i18n信息 xwork.default.invalid.fieldvalue , 你可以在你的全局il8n资源包中替换他(缺省文本是"Invalid field value for field xxx", 这里xxx是字段名称).

无论如何, 有时你会希望能够在每个字段上替换这一信息. 你可以在action相关的资源文件(Action.properties)中添加一个i18n信息: invalid.fieldvalue.xxx, 这里xxx是字段名称.

需要知道的是, 这些错误不会直接报告出来. 他们被添加到ActionContext.conversionErrors中. 有几种方法可以访问该map从而可以报告这些错误.

(摘自snippet:id=error-reporting|javadoc=true|url=com.opensymphony.xwork.util.XWorkConverter)

错误报告可以两种方式处理:

全局方式, 使用 Conversion Error Interceptor 报告错误
以每一个字段为基点, 使用 conversion validator 报告错误
缺省情况下, conversion interceptor包含在 webwork-default.xml 的缺省截取器栈中, 如果不希望使用全局错误报告方式, 需要修改截取器栈并添加其他的校验规则(指第二种方式, 在字段上使用conversion validator, 译注).

四 :校验 

五 :国际化 

六 :Continuations 

七 :ActionMapper

  评论这张
 
阅读(338)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018