Struts视图组件

Struts框架的视图负责为客户提供动态网页内容。Struts视图主要由JSP网页构成,此外,Struts框架还提供了Struts客户化标签和ActionForm Bean,这些组件提供对国际化、接收用户输入的表单数据、表单验证和错误处理等的支持,使开发者可以把更多的经历放在实现业务需求上。

 

1 视图概述

视图使模型的外在表现形式,用户通过视图来了解模型的状态。同一个模型可以有多种视图。

Struts框架中,视图主要由JSP组件构成,此外,视图还可以包含以下组件:

· HTML文档

· JSP客户化标签

· JavaScriptstylesheet

· 多媒体文件

· 消息资源(Resource Bundle

· ActionForm Bean

 

2 在视图中使用JavaBean

JavaBean使可重用的、平台独立的Java组件,JavaBean支持属性、事件、方法和持久化。Struts框架仅利用了JavaBean的一小部分特性。在Struts应用中的JavaBean和普通的Java类很相似,不过,它应该遵守以下规范:

· 必需提供不带参数的构造方法。

· Bean的所有属性提供公共类型的get/set方法。

· 对于boolean类型的属性,如果存在isXXX()方法,那么该方法返回boolean类型的属性值。

· 对于数组类型的属性,应该提供getXXX(int index)setXXX(int index, PropertyElement value)方法,用来读取或设置数组中的元素。

 

2,1 DTO数据传输对象

在【Struts模型组件】介绍过可以利用JavaBean来创建业务对象,实体业务对象包含了模型的状态信息。此外,Struts框架还利用JavaBean来创建数据传输对象(Data Transfer Object,简称DTO)。DTO用于在不同的层之间传递数据。

不将模型层的业务对象直接传递到视图层(从技术角度来说使可以实现的),而是采用DTO来传输数据,这样做有两个好处:

· 减少传输数据的冗余,提高传输效率。

· 有助于实现各个层之间的独立,使每个层分工明确。模型层负责业务逻辑,视图层负责向用户战士模型状态。采用DTO,模型层对视图层屏蔽了业务逻辑细节,向视图层提供可以直接现实给用户的数据。

 

2.2 Struts框架提供的DTOActionForm Bean

    ActionForm BeanStruts框架提供的DTO,用于在视图层和控制层之间传递HTML表单数据。控制层可以从ActionForm Bean中读取用户输入的表单数据,也可以把来自模型层的数据存放到ActionForm Bean中,然后把它返回给视图。ActionForm Bean还具有表单验证功能,可以为模型层过滤不合法的数据。

    在【Struts模型组件】,曾经强调过模型层应该和Web应用层保持独立。由于ActionForm类中使用了Servlet API,因此不提倡直接把ActionForm Bean传给模型层,而应该在控制层把ActionForm Bean的数据重新组装到自定义的DTO中,再把它传递给模型层。

 

3 使用ActionForm

 

3.1 使用ActionForm

ActionForm Bean有两种存在范围:requestsession。如果ActionForm存在于request范围,它仅在当前的请求/响应生命周期中有效。在请求从一个Web组件转发到另一个Web组件的过程中,ActionForm实例一直有效。当服务器把响应结果返回给客户,ActionForm实例及其包含的数据就会被销毁。如果ActionForm存在于session范围,同一个ActionForm实例在整个HTTP会话中有效。

当控制器接受到请求时,如果请求访问的Web组件为Action,并且为这个Action配置了和ActionForm的映射,控制器将从requestsession范围中取出ActionForm实例,如果该实例不存在,就会自动创建一个新的实例。当控制器接受到一个新的请求时,ActionForm的生命周期如下:

· 控制器接收到请求

· requestsession范围中取出ActionForm实例,如果该实例不存在,就自动创建一个新的实例。

· 调用ActionFormreset()方法

· ActionForm实例保存在requestsession范围中

· 把用户输入的表单数据组装到ActionForm

· 如果<action>validate属性为true,则调用ActionFormvalidate()方法。

· (1) 如果存在验证错误,把请求转发给<action>input属性指定的Web组件,ActionForm实例依然保持在requestsession范围内。

 

       (2) 如果无验证错误,调用Actionexecute()方法,把ActionForm实例传递给execute()方法。

           · 把请求转发给其他Web组件,ActionForm实例依然保存在requestsession范围内。

 

3.2 创建ActionForm

    Struts框架中定义的ActionForm类时抽象的,必需在应用中创建它的子类,来捕获具体的HTML表单数据,ActionForm Bean中的属性和HTML表单中的字段一一对应。

 

1 validate()方法

    如果Struts的配置文件满足以下两个条件,Struts控制器就会调用ActionFormvalidate()方法:

· ActionForm配置了Action映射,即<form-bean>元素的name属性和<action>元素的name属性匹配。

· <action>元素的validate属性为true

ActionForm基类中定义的validate()方法直接返回null,如果创建了扩展ActionForm基类的子类,那么应该在子类中覆盖validate()方法。

validate()方法主要负责检查数据的格式和语法,而不负责检查数据是否符合业务逻辑。

 

2 reset()方法

    不管ActionFormj存在于哪个范围内,对于每个请求,控制器都会先调用ActionFormreset()方法,然后再把用户输入的表单数据组装到ActionForm中。reset()方法用于恢复ActionForm的属性的默认值,例如把boolean类型属性设为truefalse,把字符串属性设为null或某个初始值。

    如果ActionFormrequest范围内,那么对于每个新的请求都会创建新的ActionForm实例。当新的实例创建后,如果它的属性已经被初始化为默认值,那么接着再在reset()方法中把属性设为默认值不是很有必要,因此在这种情况下,可以让reset()方法为空。

对于session范围内的ActionForm,同一ActionForm实例会被多个请求共享,reset()方法在这种情况下极为有用。

 

3.3 配置ActionForm

    Struts配置文件的<form-beans>元素用来配置所有的ActionForm Bean<form-beans>元素可以包含多个<form-bean>子元素,它代表单个的ActionForm Bean

    同一个ActionForm可以和多个Action映射。在<action>元素中,namescope属性分别指定ActionForm的名字和范围,validate属性指定是否执行表单验证。

 

3.4 访问ActionForm

    ActionForm可以被JSPStruts标签、Action和其他Web组件访问。访问ActionForm大致有以下一些方法:

    1 使用Struts HTML标签库

        Struts HTML标签库提供了一组和ActionForm密切关联的标签,<html:form>标签生成HTML表单,它包括<html:text><html:select><html:option><html:radio><html:submit>等子标签,这些子标签构成HTML表单的字段或按钮。<html:form>标签能和ActionForm交互,读取ActionForm的属性值,把他们赋值给表单中对应的字段。

2 requestsession范围内取出ActionForm实例

    Struts框架把ActionForm实例保存在HttpServletRequestHttpSession中,保存时采用的属性key<form-bean>元素的name属性。因此,如果ActionFormrequest范围内,则可以调用HttpServletRequestgetAttribute()方法读取ActionForm实例。如果ActionFormsession范围内,则可以调用HttpSessiongetAttribute()方法读取ActionForm实例。

3 Action类的execute()方法中直接访问ActionForm

   如果配置了ActionFormAction的映射,Struts框架就会把ActionForm作为参数传递给Actionexecute()方法,因此在Action类的execute()方法中可以读取或设置ActionForm属性。

 

3.5 处理表单跨页

有的时候,由于表单数据太多,无法在同一个页面显示(如用于用户注册的表单),可以把它拆分成多个表单,分多个页面显示。在这种情况下,既可以为每个表单创建单独的ActionForm,页可以只创建一个ActionForm,它和多个表单对应。

(1) HTML表单拆分到多个JSP页面中

    在两个JSP页面中均定义了HTML表单,由于这两个表单都对应同一个ActionForm,因此可以在每个表单中定义一个隐含字段<html:hidden property=”page”/>,它代表当前页面编号,ActionForm将通过这个字段来识别当前正在处理的时哪个表单。

(2) 创建多个HTML表单对应的ActionForm

    在创建这个ActionForm时有以下几点需要注意:

· 提供和HTML表单的隐藏字段page对应的page属性:

private String page = null;

public String getPage() {

    return page;

}

public void setPage(String page) {

    this.page = page;

}

· reset()方法中,只能把和当前正在处理的表单相关的属性恢复为默认值,否则,如果每次都把ActionForm的所有属性恢复为默认值,将使用户输入的上一页表单数据丢失。由于Struts框架先调用reset()方法,然后再把用户输入的表单数据组装到ActionForm中,因此在reset()方法中,不能根据page属性来判断处理的时哪个页面,而应该直接从HttpServletRequest对象中读取当前表单的page字段值:

    int numPage = new Integer(request.getParameter(“page”)).intValue();

· validate()方法中,仅对和当前表单相关的属性进行也政。由于Struts框架在调用validate()方法之前,已经把用户输入的表单数据组装到ActionForm中,因此在validate()方法中可以根据page属性决定正在处理哪个表单。

(3) 配置ActionForm和多个Action映射

    ActionForm与多个表单对应时,应该把ActionForm存放在session范围内。

 

4 使用动态ActionForm

Struts框架中,ActionForm对象用来包装HTML表单数据,并能动态返回用于显示给用户的数据。自定义的ActionForm必需符合JavaBean规范,并继承StrutsActionForm类,同时,用户可以有选择地覆盖两个方法:reset()validate()

ActionForm的以上特性可以简化Web应用的开发,因为它可以协助自动进行表示层的数据验证。ActionForm的唯一缺点时对于大型的Struts应用,必需以编程的方式创建大量的ActionForm类,如果HTML表单的字段发生变化,就必需修改并重编译相关的ActionForm类。

Struts 1.1对此做了改进,引入了动态ActionForm类的概念。Struts框架的DynaActionForm类及其子类实现了动态ActionFormDynaActionForm类是ActionForm类的子类。

4.1 配置动态ActionForm

    动态ActionForm支持在Struts配置文件中完成ActionForm的全部配置,没有必要编写额外的程序来创建具体的ActionForm类。配置动态ActionForm的方法为:在Struts配置文件中配置一个<form-bean>元素,将type属性设置为DynaActionForm或它的某个子类的全名。

    <form-bean><form-property>子元素用来设置动态ActionForm的属性。<form-property>元素的name属性指定属性名,type指定属性类型,可以把动态ActionForm的属性设为以下Java类型:

· java.lang.BigDecimal

· java.lang.BigInteger

· java.lang.Boolean

· java.lang.Byte

· java.lang.Character

· java.lang.Class

· java.lang.Double

· java.lang.Float

· java.lang.Integer

· java.lang.Long

· java.lang.Short

· java.lang.String

· java.sql.Data

· java.sql.Time

· java.sql.Timestamp

如果表单的字段值为Java基本类型,在配置时应该用响应的包装类型来代替,例如int类型的包装类型为Integer

 

4.2 动态ActionFormreset()方法

DynaActionForm基类提供了initialize()方法,它把表单的所有属性恢复为默认值。表单属性默认值由<form-bean><form-property>子元素的initial属性来决定。如果没有设置initial属性,则表单属性的默认值由其Java类型来自动决定,例如对象类型的默认值为null,整数类型的默认值为0boolean类型的默认值为false

DynaActionForm基类的initialize()方法的代码如下:

public void initialize(ActionMapping mapping) {

    String name = mapping.getName();

    if (name == null) {

        return;

}

FormBeanConfig config =

    mapping.getModuleConfig().findFormBeanConfig(name);

if (config == null) {

    return;

}

FormPropertyConfig props[] = config.findFormPropertyConfigs();

for (int i = 0; i < props.length; i++) {

    set(props[i].getName(), props[i].initial());

}

}

DynaActionForm基类的reset()方法不执行任何操作,其代码如下:

public void reset(ActionMapping mapping, HttpServletRequest request) {

    ;        // Default implementation does nothing

}

如果希望Struts框架在每次把表单数据组装到动态ActionForm中之前,先把所有的属性恢复为默认值,可以定义一个扩展DynaActionForm类的子类,然后覆盖其reset()方法,在reset()方法中只要调用initialize()方法即可,代码如下:

public class MyDynaActionForm extends DynaActionForm {

    ……

    public void rest(ActionMapping mapping, HttpServletRequest request) {

        initialize(mapping);

}

}

 

4.3 访问动态ActionForm

    Action类和JSP都可以访问动态ActionForm,使用方法与标准ActionForm大致相同,只有一点小差别。如果使用标准ActionForm对象,在标准ActionForm中针对每个属性都提供了get/set方法,来读取或设置属性。

    DynaActionForm把所有的属性保存在一个Map类对象中,并提供了下面的用于访问所有属性的通用方法:

        public Object get(String name)

        public void set(String name, Object value)

    get(String name)方法根据指定的属性名返回属性值;set(String name, Object value)方法用于为给定的属性赋值。

 

4.4 动态ActionForm的表单验证

    DynaActionForm基类的validate()方法没有提供任何默认的验证行为。可以定义扩展DynaActionForm的子类,然后覆盖validate()方法,但是以编程的方式来验证动态ActionForm违背了Struts框架提供动态ActionForm的初中,即以配置来替代编程。幸运的是,可以采用另一种验证机制,即Validator框架来完成验证。Validator框架允许采用特定的配置文件来为动态ActionForm配置验证规则。

 

 

5 小结

    本篇侧重介绍了构成Struts视图的组件之一:ActionFormActionForm用于在视图层和控制层之间传递表单数据,ActionForm可以存放在requestsession范围内。ActionForm是一种Web组件,不应该在模型层直接访问ActionForm Bean。同一个ActionForm可以对应多个HTML表单,在这种情况下,有以下开发技巧:

· HTML表单中定义<html:hidden property=”page” />隐藏字段,来标识当前页面。

· ActionForm中定义page属性,它和表单中的隐藏字段page对应。

· ActionFormreset()方法中,只能把和当前表单相关的属性恢复为默认值。可以调用request.getParameter(“page”)方法来读取当前的页面编号。

· ActionFormvalidate()方法中,只能对和当前表单相关的属性进行验证。此时page属性代表当前的页面编号。

· 在配置ActionFormAction的映射时,应该把ActionForm的范围设为session

 

Struts框架还印入了DynaActionForm类,它允许以配置的方式来创建动态ActionForm,使用DynaActionForm有以下几点需要注意:

· <form><form-property>子元素用于配置动态ActionForm的属性。<form-property>元素的type属性指定ActionForm的属性的类型。如果属性为Java基本类型,应该把属性设置为相应的Java包装类型。

· 提倡使用Validator框架来验证动态ActionForm,这样可以避免以编程的方式来实现validate()方法。


阅读材料:《精通Struts:基于MVC的Java Web设计与开发》





                                   2005年05月12日 6:59 PM