您的位置:首页 > 编程语言 > Java开发

Struts 1.x中批量封装对象

2012-09-19 17:48 197 查看
在我早前的文章《转换器(Converter)——Struts 2.0中的魔术师》(以下简称为《转》)中,提及在Struts 1.x中实现批量封装对象,并不是一件容易的事,这需要一些技巧。昨天,有一位同事又和我讨论起这个问题,所以鉴于此场景(scenario)较为普遍,我决定写一篇有关的文章。


应用场景

本文使用《转》中的最后一个例子作为应用场景,即是批量发布产品信息。页面输出如下图所示:


 
图1 发布产品


 
图2 查看产品


具体实现

首先创建代表产品的类tipsAndTricks.Product,代码如下:


 package tipsAndTricks;




 import java.sql.Date;




 public class Product {


     private String name;


     private double price;


     private Date dateOfProduction;


    


     public Date
getDateOfProduction() {


         return dateOfProduction;


    } 


    


     public void setDateOfProduction(Date
dateOfProduction) {


         this .dateOfProduction = dateOfProduction;


    } 


    


     public String
getName() {


         return name;


    } 


    


     public void setName(String
name) {


         this .name = name;


    } 


    


     public double getPrice() {


         return price;


    } 


    


     public void setPrice( double price) {


         this .price = price;


    }    


}

与《转》例中的Product不同的是,本例子中的dateOfProduction属性使用了java.sql.Date,而不是java.util.Date。这是因为Struts 1.x不支持请求参数到java.util.Date的转换,归根到底是由于org.apache.commons.beanutils.ConvertUtilsBean.convert()不支持关于java.util.Date的转换。另外,值得注意的是common-beanutils是通过java.sql.Date.valueOf()方法工作的,所以在页面输入的字符串的格式必须为“yyyy-MM-dd”。

实现上述功能大概有三种方法,下面我会分别对这三种方法进行详细的讲述。


方法一、动态表单(Dynamic Actoin Form)+ 数组

首先,让我们来看一下Struts的配置文件WEB-INF/struts-config.xml,内容如下:

<? xml version="1.0" encoding="UTF-8" ?> 
<! DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://struts.apache.org/dtds/struts-config_1_2.dtd" > 

< struts-config > 

    < data-sources /> 

    < form-beans > 

        < form-bean name ="dynaProductsForm" 

            type ="org.apache.struts.action.DynaActionForm" > 

            < form-property name ="products" 

                type ="tipsAndTricks.Product[]" size ="3" /> 

        </ form-bean > 

    </ form-beans > 

    < global-exceptions /> 

    < global-forwards /> 

    < action-mappings > 

        < action attribute ="dynaProductsForm" input ="/addProducts.jsp" 

            name ="dynaProductsForm" path ="/batchWrappingWithArray" 

            scope ="request" type ="tipsAndTricks.BatchWrappingWithArrayAction" 

            validate ="false" > 

            < forward name ="success" path ="/viewProducts.jsp" /> 

        </ action > 

    </ action-mappings > 

    < message-resources parameter ="tipsAndTricks.ApplicationResources" /> 
</ struts-config >

我想这些配置应该用不着怎么解释了,有Struts 1.x验证的朋友对此都不会陌生。因此,接下来创建/addProducts.jsp文件,代码如下:

<% @ page language = " java " pageEncoding = " utf-8 " %> 

<% @ taglib uri = " http://struts.apache.org/tags-html " prefix = " html " %> 
<% @ taglib uri = " http://java.sun.com/jsp/jstl/core " prefix = " c " %> 

<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" > 
< html > 
< head > 
< title > Add Products </ title > 
</ head > 
< body > 
< html:form action ="/batchWrappingWithArray" method ="post" > 

    < table border ="0" > 

        < tr style ="background-color:powderblue; font-weight:bold;" > 

            < td > Product Name </ td > 

            < td > Price </ td > 

            < td > Date of production </ td > 

        </ tr > 

        < c:forEach var ="products" items ="${dynaProductsForm.map.products}" > 

            < tr > 

                < td >< html:text indexed ="true" name ="products" property ="name" /></ td > 

                < td >< html:text indexed ="true" name ="products" property ="price" /></ td > 

                < td >< html:text indexed ="true" name ="products" property ="dateOfProduction" /></ td > 

            </ tr > 

        </ c:forEach > 

        < tr > 

            < td colspan ="3" >< html:submit /></ td > 

        </ tr > 

    </ table > 
</ html:form > 
</ body > 
</ html >

例中,我使用了JSTL 1.1,如果大家还没有尝试过使用JSP 2.0的JSTL和EL,建议大家去看看相关文章。上面的<c:forEach />的作用是到dynaProductsForm的map属性中取出products数组,并对其进行遍历,再依靠<html:text />标志将products的元素的属性以输入框的形式输出。<html:text />标志的属性indexed="true"则表示在输出HTML时,将<input>的命名为类似products[0].name的名字。

然后,再创建/viewProducts.jsp页面,内容如下:

<% @ page language = " java " pageEncoding = " utf-8 " %> 

<% @ taglib uri = " http://java.sun.com/jsp/jstl/core " prefix = " c " %> 

<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" > 
< html > 
< head > 
< title > View Products </ title > 
</ head > 
< body > 
< table border ="0" > 

    < tr style ="background-color:powderblue; font-weight:bold;" > 

        < td > Product Name </ td > 

        < td > Price </ td > 

        < td > Date of production </ td > 

    </ tr > 

    < c:forEach var ="product" items ="${products}" > 

        < tr > 

            < td > ${product.name} </ td > 

            < td > ${product.price} </ td > 

            < td > ${product.dateOfProduction} </ td > 

        </ tr > 

    </ c:forEach > 
</ table > 
</ body > 
</ html >

我想这份也不多作说明。不过大家可以通过上述代码看出使用JSTL + EL的确比Struts 1.x的logic + bean要方便和简洁。不仅如此,EL还支持一定的运算符和函数操作。

最后是建立Action文件tipsAndTricks.BatchWrappingWithArrayAction,代码如下:


 package tipsAndTricks;




 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.DynaActionForm;




 public class BatchWrappingWithArrayAction extends Action {


     public ActionForward execute(ActionMapping mapping, ActionForm
form,


                  HttpServletRequest request, HttpServletResponse response) {


            DynaActionForm dynaProductsForm = (DynaActionForm) form;


            request.setAttribute( " products " ,
dynaProductsForm.get( " products " ));


         return mapping.findForward( " success " );


    } 


}

此Action将动态表单传过来的products数组放到request中,转到/viewProducts.jsp。发布运行应用程序,在浏览器的地址栏中输入:http://localhost:8080/Struts1_Batch/addProducts.jsp。效果请参考如图1、图2。

在/addProducts.jsp的“Date of production”必须以(yyyy-MM-dd)的形式正确填写,且不能为空。


方法二、表单(Actoin Form)+ 列表(List)

方法一虽然简单,但是有一个明显的缺点——数组的长度已经固定,故我们不能在运行时通过程序设置对象数量。下面将要介绍的方法可以很好地解决这个问题。

首先,我们要创建类tipsAndTricks.AutoInitArrayList,代码如下:


 package tipsAndTricks;




 import java.util.ArrayList;




 public class AutoInitArrayList < T > extends ArrayList < T > {


     private static final long serialVersionUID = 1L ; 


    


     private Class < T > t = null ;


    


     public AutoInitArrayList(Class < T > t) {


         this .t = t;


    } 


    


    @Override


     public T
get( int index) {


         try {


             while (index >= size()) {


                add(t.newInstance());


            } 


        } catch (Exception
e) {


            e.printStackTrace();


        } 


         return super .get(index);


    }    


}

AutoInitArrayList继承ArrayList并重载get()方法,作用就是在Struts 1.x框架调用这个方法时,如果index超出列表大小,则会实例化新项放到列表中,避免出现(IndexOutOfBoundsException)异常。

接着,让我们看Struts的配置,内容如下:

<? xml version="1.0" encoding="UTF-8" ?> 
<! DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://struts.apache.org/dtds/struts-config_1_2.dtd" > 

< struts-config > 

    < data-sources /> 

    < form-beans > 

        < form-bean name ="dynaProductsForm" 

            type ="org.apache.struts.action.DynaActionForm" > 

            < form-property name ="products" 

                type ="tipsAndTricks.Product[]" size ="3" /> 

        </ form-bean > 

        < form-bean name ="normalProductsForm" 

            type ="tipsAndTricks.NormalProductsForm" /> 

    </ form-beans > 

    < global-exceptions /> 

    < global-forwards /> 

    < action-mappings > 

        < action attribute ="dynaProductsForm" input ="/addProducts.jsp" 

            name ="dynaProductsForm" path ="/batchWrappingWithArray" 

            scope ="request" type ="tipsAndTricks.BatchWrappingWithArrayAction" 

            validate ="false" > 

            < forward name ="success" path ="/viewProducts.jsp" /> 

        </ action > 

        < action attribute ="normalProductsForm" input ="/addProducts.jsp" 

            name ="normalProductsForm" path ="/batchWrappingNormal" scope ="request" 

            type ="tipsAndTricks.BatchWrappingNormalAction" validate ="false" > 

            < forward name ="success" path ="/viewProducts.jsp" /> 

        </ action > 

    </ action-mappings > 

    < message-resources parameter ="tipsAndTricks.ApplicationResources" /> 
</ struts-config >

然后,创建表单类tipsAndTricks.NormalProductsForm,代码如下:


 package tipsAndTricks;




 import java.util.List;




 import org.apache.struts.action.ActionForm;




 public class NormalProductsForm extends ActionForm {


     private List products = new AutoInitArrayList < Product > (Product. class );




     public List
getProducts() {


         return products;


    } 


 


     public void setProducts(List
products) {


         this .products = products;


    }    


}

接下来是Action类tipsAndTricks.BatchWrappingNormalAction,代码如下:


 /* 


 * Generated by MyEclipse Struts


 * Template path: templates/java/JavaClass.vtl


 */ 


 package tipsAndTricks;




 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;




 public class BatchWrappingNormalAction extends Action {


     public ActionForward execute(ActionMapping mapping, ActionForm
form,


            HttpServletRequest request, HttpServletResponse response) {


        NormalProductsForm normalProductsForm = (NormalProductsForm)
form;


        request.setAttribute( " products " ,
normalProductsForm.getProducts());


         return mapping.findForward( " success " );


    } 


}

基本上与方法一的Action一样。下面,再看看新的输入文件/addProducts2.jsp,内容如下:

<% @ page language = " java " pageEncoding = " utf-8 " %> 

<% @ taglib uri = " http://struts.apache.org/tags-html " prefix = " html " %> 
<% @ taglib uri = " http://java.sun.com/jsp/jstl/core " prefix = " c " %> 

<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" > 
< html > 
< head > 
< title > Add Products </ title > 
</ head > 
< body > 
< html:form action ="/batchWrappingNormal" method ="post" > 

    < table border ="0" > 

        < tr style ="background-color:powderblue; font-weight:bold;" > 

            < td > Product Name </ td > 

            < td > Price </ td > 

            < td > Date of production </ td > 

        </ tr > 

        < c:forEach begin ="0" end ="2" var ="i" > 

            < tr > 

                < td >< input name ="products[${i}].name" /></ td >  
             

                < td >< input name ="products[${i}].price" /></ td > 

                < td >< input name ="products[${i}].dateOfProduction" /></ td > 

            </ tr > 

        </ c:forEach > 

        < tr > 

            < td colspan ="3" >< html:submit /></ td > 

        </ tr > 

    </ table > 
</ html:form > 
</ body > 
</ html >

/addProducts2.jsp主要作用组装<input>的元素名称,Struts 1.x对名称格式类似“xxx[9].xx”的请求,会进行封装。发布运行应用程序,在浏览器的地址栏中输入:http://localhost:8080/Struts1_Batch/addProducts2.jsp。效果请参考如图1、图2。


总结

两种方法各有优缺点,选择原则是如果不需要动态设置元素个数,则使用方法一,否则请使用方法二。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息