文档章节

多行数据提交到Struts的ActionForm的List属性中

0o清风徐来o0
 0o清风徐来o0
发布于 2015/12/08 19:40
字数 2089
阅读 6
收藏 0
今天遇到提交多行数据问题, 在网上找了一点资料:  

WEB 应用中一般都会处理主从表的信息, 或者称之为头层与行层的一对多的关系数据,如订单头/订单明细. 对于这种关系数据提交到后台的 Struts 的 ActionForm 的话, 这个 ActionForm 就要好好的设计一下, 不然会给自已带来许多额外的代码. 比如有的人的处理方法就是把页面提交到后台的毫无关系的散装数据非常吃力的拼凑一对多的关系对象出来.

下面举一个如今非常现实的关于股票的例子, 简单的应用场景是: 记录某个帐户所持有的股票信息,提交到后台,然后显示出来. 输入页面如下图  

帐户信息包括帐户名和资金帐号;持有股票的每一行信息包括股票代码, 股票名称, 成本价, 股票数量. 股票行可以动态增删.  






为了简化不必要的代码, 我们要实现的终及目标是: 在输入页面上点击 "保存数据" 按钮, 由 Struts 的 RequestProcessor.processPopulate() 方法把页面提交的基本信息组装到 AccountStockForm 的 account 的对应属性中,股票行信息对应生成一个 Stock 实例加到 AccountStockForm的 List 属性 stocks 中, 后续在 AccountStockAction 中直接处理account和stocks属性就非常简单了. AccountStockForm在这里只作为一个壳.

下面从前台到后台说明关键性的代码, 完整的 MyEclipse 工程包可以点击 TestStruts135.zip下载到.  

一: struts-config.xml 配置  

Java代码  
  1. <?xml version="1.0" encoding="UTF-8"?>   
  2. <!DOCTYPE struts-config PUBLIC   
  3.           "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"  
  4.           "http://struts.apache.org/dtds/struts-config_1_3.dtd">   
  5. <struts-config>   
  6.     <form-beans>   
  7.         <form-bean name="accountStockForm"  
  8.           type="com.unmi.form.AccountStockForm"/>   
  9.     </form-beans>   
  10.     <action-mappings>   
  11.         <action path="/showStock" name="accountStockForm"  
  12.          type="com.unmi.action.AccountStockAction" scope="request">   
  13.             <forward name="show" path="/show.jsp"/>   
  14.         </action>   
  15.     </action-mappings>   
  16. </struts-config>  
[java]   view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE struts-config PUBLIC  
  3.           "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"  
  4.           "http://struts.apache.org/dtds/struts-config_1_3.dtd">  
  5. <struts-config>  
  6.     <form-beans>  
  7.         <form-bean name="accountStockForm"  
  8.           type="com.unmi.form.AccountStockForm"/>  
  9.     </form-beans>  
  10.     <action-mappings>  
  11.         <action path="/showStock" name="accountStockForm"  
  12.          type="com.unmi.action.AccountStockAction" scope="request">  
  13.             <forward name="show" path="/show.jsp"/>  
  14.         </action>  
  15.     </action-mappings>  
  16. </struts-config>  


二: 输入页面 input.jsp, 注意表单域命名  
Java代码  
  1. <html:form action="/showStock">   
  2.       <h3>记录持有的股票<br></h3>   
  3.       <fieldset>s<legend>基本信息</legend>   
  4.       <table width="100%" border=0><tr>   
  5.           <td>帐户名:<html:text property="account.name"/></td>   
  6.           <td>资金帐号:<html:text property="account.number"/></td>   
  7.       </tr></table>   
  8.       </fieldset>   
  9.       <br>   
  10.       <fieldset><legend>持有股票</legend>   
  11.       <table width=100% border=0 id="stockTable">   
  12.       <tr>   
  13.           <td><input type="checkbox" onclick="checkAll(this)"></td>   
  14.           <td>股票代码</td>   
  15.           <td>股票名称</td>   
  16.           <td>成本价</td>   
  17.           <td>股票数量</td>   
  18.       </tr>   
  19.       <tr>   
  20.           <td><input type="checkbox" name="check"></td>   
  21.           <td><input name="stocks[0].code" size="15"></td>   
  22.           <td><input name="stocks[0].name" size="15"></td>   
  23.           <td><input name="stocks[0].price" size="15"></td>   
  24.           <td><input name="stocks[0].quantity" size="15"></td>   
  25.       </tr>   
  26.       </table>   
  27.   </html:form>  
[java]   view plain copy
  1. <html:form action="/showStock">  
  2.       <h3>记录持有的股票<br></h3>  
  3.       <fieldset>s<legend>基本信息</legend>  
  4.       <table width="100%" border=0><tr>  
  5.           <td>帐户名:<html:text property="account.name"/></td>  
  6.           <td>资金帐号:<html:text property="account.number"/></td>  
  7.       </tr></table>  
  8.       </fieldset>  
  9.       <br>  
  10.       <fieldset><legend>持有股票</legend>  
  11.       <table width=100% border=0 id="stockTable">  
  12.       <tr>  
  13.           <td><input type="checkbox" onclick="checkAll(this)"></td>  
  14.           <td>股票代码</td>  
  15.           <td>股票名称</td>  
  16.           <td>成本价</td>  
  17.           <td>股票数量</td>  
  18.       </tr>  
  19.       <tr>  
  20.           <td><input type="checkbox" name="check"></td>  
  21.           <td><input name="stocks[0].code" size="15"></td>  
  22.           <td><input name="stocks[0].name" size="15"></td>  
  23.           <td><input name="stocks[0].price" size="15"></td>  
  24.           <td><input name="stocks[0].quantity" size="15"></td>  
  25.       </tr>  
  26.       </table>  
  27.   </html:form>  


例如输入框名 account.name 提交后能设置到 accountStockForm 的account的name属性  
输入框名为 stocks[0].code 提交后会设置到 accountStockForm 的 List stocks的第一个元素的code属性.以此类推  
在提交表单前要重排行层的索引,从 0 起, 否则到后右的 Form 会一些空数据.  


三: AccountStockForm 的关键代码  

Java代码  
  1. private Account account = new Account();   
  2.   private List stocks = new AutoArrayList(Stock.class);   
  3.      
  4.   public void setStocks(List stocks)   
  5.   {   
  6.       this.stocks.clear();   
  7.       this.stocks.addAll(stocks);   
  8.   }  
[java]   view plain copy
  1. private Account account = new Account();  
  2.   private List stocks = new AutoArrayList(Stock.class);  
  3.     
  4.   public void setStocks(List stocks)  
  5.   {  
  6.       this.stocks.clear();  
  7.       this.stocks.addAll(stocks);  
  8.   }  



定义了两个属性,分别是一个bean(Account,接受基本信息)和一个List(stocks,接受股票行信息),注意这两个属性必须初始化,不然在表单提交后会出现空指针错误. setStocks方法是让stocks属性永远保有持是一个 AutoArrayList 实例. 这样在表单提交后设置值是总能调用 AutoArrayList 的 get(int index) 方法.



四: 自定义的 AutoArrayList  

Java代码  
  1. public class AutoArrayList extends ArrayList {   
  2.        
  3.     private Class itemClass;   
  4.        
  5.     public AutoArrayList(Class itemClass) {   
  6.         this.itemClass = itemClass;   
  7.     }   
  8.        
  9.     public Object get(int index) {   
  10.         try {   
  11.             while (index >= size()) {   
  12.                 add(itemClass.newInstance());   
  13.             }   
  14.         } catch (Exception e) {   
  15.             e.printStackTrace();   
  16.         }   
  17.         return super.get(index);   
  18.     }   
  19. }  
[java]   view plain copy
  1. public class AutoArrayList extends ArrayList {  
  2.       
  3.     private Class itemClass;  
  4.       
  5.     public AutoArrayList(Class itemClass) {  
  6.         this.itemClass = itemClass;  
  7.     }  
  8.       
  9.     public Object get(int index) {  
  10.         try {  
  11.             while (index >= size()) {  
  12.                 add(itemClass.newInstance());  
  13.             }  
  14.         } catch (Exception e) {  
  15.             e.printStackTrace();  
  16.         }  
  17.         return super.get(index);  
  18.     }  
  19. }  



理解为什么要继承一个ArrayList, 覆写get(int index)方法要简单了解 Struts 处理提交数据的工作原理: 大致如下: 页面提交后, 由 ActionServlet交给RequestProcessor的processPopulate()方法,由processPopulate()方法收集请求数据,放在map中,key为表单域的name属性,如 name, account.name, stocks[0].code. 然后借助于 Common-beanutils 工具包设置到 ActionForm 的相应属性中  
如果key是简单的'name',直接form.setName(map.get('name'));  
如果key是'account.name', 执行的操作是 form.getAccount().setName(map.get('account.name');  
如果key是'stocks[0].code', 它可以对应到数据或集合中,如对于数组 form.stocks[0].code=map.get('stocks[0].code'); 对于集合((List)form.getStocks()).get(0).setCode(map.get('stocks[0].code'))
从上也能理解为什么 form 中的那两个属性必须实始化,不然会出现空指针错. 而且为什么 stocks 要用 AutoArrayList 实例化, 避免出现索引越界的错误.

五: 在 AccountStockAction 中可以打印出提交的数据  


  
Java代码  
  1. AccountStockForm asForm = (AccountStockForm)form;   
  2.        
  3.     Account account = asForm.getAccount();   
  4.     System.out.println("Account Name:"+account.getName()+   
  5.             " Number:"+account.getNumber());   
  6.        
  7.     List stocks = asForm.getStocks();   
  8.     for (int i=0; i<stocks.size() ;i++)   
  9.     {   
  10.         Stock stock = (Stock)stocks.get(i);   
  11.         System.out.println("Stock["+i+"]Code:"+stock.getCode()+   
  12.                 " Name:"+stock.getName()+   
  13.                 " Price:"+stock.getPrice()+   
  14.                 " Quantity:"+stock.getQuantity());   
  15.     }   
  16.        
  17.     return mapping.findForward("show");  
[java]   view plain copy
  1. AccountStockForm asForm = (AccountStockForm)form;  
  2.       
  3.     Account account = asForm.getAccount();  
  4.     System.out.println("Account Name:"+account.getName()+  
  5.             " Number:"+account.getNumber());  
  6.       
  7.     List stocks = asForm.getStocks();  
  8.     for (int i=0; i<stocks.size() ;i++)  
  9.     {  
  10.         Stock stock = (Stock)stocks.get(i);  
  11.         System.out.println("Stock["+i+"]Code:"+stock.getCode()+  
  12.                 " Name:"+stock.getName()+  
  13.                 " Price:"+stock.getPrice()+  
  14.                 " Quantity:"+stock.getQuantity());  
  15.     }  
  16.       
  17.     return mapping.findForward("show");  



在Action中就能直接取用提交来的数据了,不需要 getParameterValues()了.  

六: 最后一步, 对于这样的 ActionForm 我们应该如何显示出来呢,我们用了 nested 标签 (show.jsp)  


Java代码  
  1. <html:form action="/showStock">   
  2.     <h3>修改持有的股票<br></h3>   
  3.     <fieldset><legend>基本信息</legend>   
  4.     <table width="100%" border=0><tr>   
  5.     <nested:nest property="account">   
  6.         <td>帐户名:<nested:text property="name" readonly="true"/></td>   
  7.         <td>资金帐号:<nested:text property="number" readonly="true"/></td>   
  8.     </nested:nest>   
  9.     </tr></table>   
  10.     </fieldset>   
  11.     <br>   
  12.     <fieldset><legend>持有股票</legend>   
  13.     <table width=100% border=0  id="stockTable">   
  14.     <tr>   
  15.         <td><input type="checkbox" onclick="checkAll(this)"></td>   
  16.         <td>股票代码</td>   
  17.         <td>股票名称</td>   
  18.         <td>成本价</td>   
  19.         <td>股票数量</td>   
  20.     </tr>   
  21.     <nested:iterate id="stock" property="stocks">   
  22.     <tr>   
  23.         <td><input type="checkbox" name="check"></td>   
  24.         <td><nested:text property="code" size="15"/></td>   
  25.         <td><nested:text property="name" size="15"/></td>   
  26.         <td><nested:text property="price" size="15"/></td>   
  27.         <td><nested:text property="quantity" size="15"/></td>   
  28.     </tr>   
  29.     </nested:iterate>   
  30.     </table>   
  31. </html:form>  
[java]   view plain copy
  1. <html:form action="/showStock">  
  2.     <h3>修改持有的股票<br></h3>  
  3.     <fieldset><legend>基本信息</legend>  
  4.     <table width="100%" border=0><tr>  
  5.     <nested:nest property="account">  
  6.         <td>帐户名:<nested:text property="name" readonly="true"/></td>  
  7.         <td>资金帐号:<nested:text property="number" readonly="true"/></td>  
  8.     </nested:nest>  
  9.     </tr></table>  
  10.     </fieldset>  
  11.     <br>  
  12.     <fieldset><legend>持有股票</legend>  
  13.     <table width=100% border=0  id="stockTable">  
  14.     <tr>  
  15.         <td><input type="checkbox" onclick="checkAll(this)"></td>  
  16.         <td>股票代码</td>  
  17.         <td>股票名称</td>  
  18.         <td>成本价</td>  
  19.         <td>股票数量</td>  
  20.     </tr>  
  21.     <nested:iterate id="stock" property="stocks">  
  22.     <tr>  
  23.         <td><input type="checkbox" name="check"></td>  
  24.         <td><nested:text property="code" size="15"/></td>  
  25.         <td><nested:text property="name" size="15"/></td>  
  26.         <td><nested:text property="price" size="15"/></td>  
  27.         <td><nested:text property="quantity" size="15"/></td>  
  28.     </tr>  
  29.     </nested:iterate>  
  30.     </table>  
  31. </html:form>  


可以查看生成的HTML源文件, 你就能更好理解 input.jsp 中的表单域为什么要那么命名了.  


小结的内容是请注意以下几个重点:  
1. 输入信息的页面 input.jsp 没有使用 Struts 标签,目的是让大家理解,表单域应如何命名才能对应上 ActionForm 中的哪一个属性  
2. 显示数据的页面是用的 Struts 标签,并留意 nested 标签的应用. 可以从生成的 HTML 源文件中体会出什么  
3. 提交数据前要重新编排行层中输入框 Name 属性的下标植.  
4. 回味为什么要引入 ArrayList 的子类 AutoArrayList, 关键在 get(int index) 方法的覆写  
5. 最后是 ActionForm 中 List 属性 stocks 的 setter 方法的实现, 保持那个 List 的运行时具体类型不变

本文转载自:http://extjs2.javaeye.com/blog/460926

0o清风徐来o0
粉丝 7
博文 86
码字总数 29134
作品 0
大连
程序员
私信 提问
Struts 学习笔记之Action

下面是Struts中的一些常用Action如DispatchAction/LookupDispatchAction/MappingDispatchAction/ForwardAction/IncludeAction的总结 1 .DispatchAction extends BaseAction 一般的Action如<......

xiahuawuyu
2012/05/17
0
0
Struts 服务端表单数据验证流程

当ActionServlet接到请求在讲这个请求交给具体的Action处理之前,struts框架会检查配置文件中这个action是否配置了name属性。如果没有配置,那么数据的验证工作只能在Action中由程序员来完成...

rockypeng
2013/11/19
0
0
struts2跟struts1的区别

1) 在Action实现类方面的对比:Struts 1要求Action类继承一个抽象基类;Struts 1的一个具体问题是使用抽象类编程而不是接口。Struts 2 Action类可以实现一个Action接口,也可以实现其他接口,...

长平狐
2013/01/06
43
0
用Struts建立MVC应用的介绍【转】

Model 1 和Model 2简介 我们在开发Web应用时经常提到的一个概念是Model 1/Model 2,那么到底它是什么意思呢?其实它是对采用JSP技术构成Web应用的不同模型的描述。下面对这个概念做一个简单的...

磊神Ray
2011/09/05
0
0
第二部分:Spring,hibernate,struts的面试笔试题

Hibernate工作原理及为什么要用? 原理: 1.读取并解析配置文件 2.读取并解析映射信息,创建SessionFactory 3.打开Sesssion 4.创建事务Transation 5.持久化操作 6.提交事务 7.关闭Session 8...

小梅菜鸟
2012/02/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

FPGA 设备 USB Platform Cable USB

lsusbFuture Technology Devices International, Ltd FT232H Single HS USB-UART/FIFO IC

MtrS
今天
4
0
lua web快速开发指南(6) - Cache、DB介绍

"数据库"与"缓存"的基本概念 数据库与缓存是服务端开发人员的必学知识点. 数据库 "数据库"是一种信息记录、存取的虚拟标记地点的集合统称. 比如现实生活中, 我们经常会用到文件柜、书桌等等数...

水果糖的小铺子
今天
7
0
Oracle分页查询语句的写法

Oracle分页查询语句的写法 Oracle分页查询语句使我们最常用的语句之一,下面就为您介绍的Oracle分页查询语句的用法,Oracle分页查询语句基本上可以按本文给出的格式来进行套用。   Oracle分...

康师傅
昨天
5
0
java并发图谱

1527
昨天
2
0
Mybatis之拦截器Interceptor

使用mybatis时用PageHelper进行分页,用到了PageInterceptor,借此了解下mybatis的interceptor。Mybatis的版本是3.4.6,MybatisHelper的版本是5.1.3。 1、PageInterceptor 先上一段代码,如下...

克虏伯
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部