今天遇到提交多行數(shù)據(jù)問題, 在網(wǎng)上找了一點(diǎn)資料:
WEB 應(yīng)用中一般都會(huì)處理主從表的信息, 或者稱之為頭層與行層的一對多的關(guān)系數(shù)據(jù),如訂單頭/訂單明細(xì). 對于這種關(guān)系數(shù)據(jù)提交到后臺的 Struts 的 ActionForm 的話, 這個(gè) ActionForm 就要好好的設(shè)計(jì)一下, 不然會(huì)給自已帶來許多額外的代碼. 比如有的人的處理方法就是把頁面提交到后臺的毫無關(guān)系的散裝數(shù)據(jù)非常吃力的拼湊一對多的關(guān)系對象出來.
下面舉一個(gè)如今非常現(xiàn)實(shí)的關(guān)于股票的例子, 簡單的應(yīng)用場景是: 記錄某個(gè)帳戶所持有的股票信息,提交到后臺,然后顯示出來. 輸入頁面如下圖
帳戶信息包括帳戶名和資金帳號;持有股票的每一行信息包括股票代碼, 股票名稱, 成本價(jià), 股票數(shù)量. 股票行可以動(dòng)態(tài)增刪.
為了簡化不必要的代碼, 我們要實(shí)現(xiàn)的終及目標(biāo)是: 在輸入頁面上點(diǎn)擊 "保存數(shù)據(jù)" 按鈕, 由 Struts 的 RequestProcessor.processPopulate() 方法把頁面提交的基本信息組裝到 AccountStockForm 的 account 的對應(yīng)屬性中,股票行信息對應(yīng)生成一個(gè) Stock 實(shí)例加到 AccountStockForm的 List 屬性 stocks 中, 后續(xù)在 AccountStockAction 中直接處理account和stocks屬性就非常簡單了. AccountStockForm在這里只作為一個(gè)殼.
下面從前臺到后臺說明關(guān)鍵性的代碼, 完整的 MyEclipse 工程包可以點(diǎn)擊 TestStruts135.zip下載到.
一: struts-config.xml 配置
二: 輸入頁面 input.jsp, 注意表單域命名
例如輸入框名 account.name 提交后能設(shè)置到 accountStockForm 的account的name屬性
輸入框名為 stocks[0].code 提交后會(huì)設(shè)置到 accountStockForm 的 List stocks的第一個(gè)元素的code屬性.以此類推
在提交表單前要重排行層的索引,從 0 起, 否則到后右的 Form 會(huì)一些空數(shù)據(jù).
三: AccountStockForm 的關(guān)鍵代碼
定義了兩個(gè)屬性,分別是一個(gè)bean(Account,接受基本信息)和一個(gè)List(stocks,接受股票行信息),注意這兩個(gè)屬性必須初始化,不然在表單提交后會(huì)出現(xiàn)空指針錯(cuò)誤. setStocks方法是讓stocks屬性永遠(yuǎn)保有持是一個(gè) AutoArrayList 實(shí)例. 這樣在表單提交后設(shè)置值是總能調(diào)用 AutoArrayList 的 get(int index) 方法.
四: 自定義的 AutoArrayList
理解為什么要繼承一個(gè)ArrayList, 覆寫get(int index)方法要簡單了解 Struts 處理提交數(shù)據(jù)的工作原理: 大致如下: 頁面提交后, 由 ActionServlet交給RequestProcessor的processPopulate()方法,由processPopulate()方法收集請求數(shù)據(jù),放在map中,key為表單域的name屬性,如 name, account.name, stocks[0].code. 然后借助于 Common-beanutils 工具包設(shè)置到 ActionForm 的相應(yīng)屬性中
如果key是簡單的'name',直接form.setName(map.get('name'));
如果key是'account.name', 執(zhí)行的操作是 form.getAccount().setName(map.get('account.name');
如果key是'stocks[0].code', 它可以對應(yīng)到數(shù)據(jù)或集合中,如對于數(shù)組 form.stocks[0].code=map.get('stocks[0].code'); 對于集合((List)form.getStocks()).get(0).setCode(map.get('stocks[0].code'))
從上也能理解為什么 form 中的那兩個(gè)屬性必須實(shí)始化,不然會(huì)出現(xiàn)空指針錯(cuò). 而且為什么 stocks 要用 AutoArrayList 實(shí)例化, 避免出現(xiàn)索引越界的錯(cuò)誤.
五: 在 AccountStockAction 中可以打印出提交的數(shù)據(jù)
在Action中就能直接取用提交來的數(shù)據(jù)了,不需要 getParameterValues()了.
六: 最后一步, 對于這樣的 ActionForm 我們應(yīng)該如何顯示出來呢,我們用了 nested 標(biāo)簽 (show.jsp)
可以查看生成的HTML源文件, 你就能更好理解 input.jsp 中的表單域?yàn)槭裁匆敲疵?
小結(jié)的內(nèi)容是請注意以下幾個(gè)重點(diǎn):
1. 輸入信息的頁面 input.jsp 沒有使用 Struts 標(biāo)簽,目的是讓大家理解,表單域應(yīng)如何命名才能對應(yīng)上 ActionForm 中的哪一個(gè)屬性
2. 顯示數(shù)據(jù)的頁面是用的 Struts 標(biāo)簽,并留意 nested 標(biāo)簽的應(yīng)用. 可以從生成的 HTML 源文件中體會(huì)出什么
3. 提交數(shù)據(jù)前要重新編排行層中輸入框 Name 屬性的下標(biāo)植.
4. 回味為什么要引入 ArrayList 的子類 AutoArrayList, 關(guān)鍵在 get(int index) 方法的覆寫
5. 最后是 ActionForm 中 List 屬性 stocks 的 setter 方法的實(shí)現(xiàn), 保持那個(gè) List 的運(yùn)行時(shí)具體類型不變
WEB 應(yīng)用中一般都會(huì)處理主從表的信息, 或者稱之為頭層與行層的一對多的關(guān)系數(shù)據(jù),如訂單頭/訂單明細(xì). 對于這種關(guān)系數(shù)據(jù)提交到后臺的 Struts 的 ActionForm 的話, 這個(gè) ActionForm 就要好好的設(shè)計(jì)一下, 不然會(huì)給自已帶來許多額外的代碼. 比如有的人的處理方法就是把頁面提交到后臺的毫無關(guān)系的散裝數(shù)據(jù)非常吃力的拼湊一對多的關(guān)系對象出來.
下面舉一個(gè)如今非常現(xiàn)實(shí)的關(guān)于股票的例子, 簡單的應(yīng)用場景是: 記錄某個(gè)帳戶所持有的股票信息,提交到后臺,然后顯示出來. 輸入頁面如下圖
帳戶信息包括帳戶名和資金帳號;持有股票的每一行信息包括股票代碼, 股票名稱, 成本價(jià), 股票數(shù)量. 股票行可以動(dòng)態(tài)增刪.


為了簡化不必要的代碼, 我們要實(shí)現(xiàn)的終及目標(biāo)是: 在輸入頁面上點(diǎn)擊 "保存數(shù)據(jù)" 按鈕, 由 Struts 的 RequestProcessor.processPopulate() 方法把頁面提交的基本信息組裝到 AccountStockForm 的 account 的對應(yīng)屬性中,股票行信息對應(yīng)生成一個(gè) Stock 實(shí)例加到 AccountStockForm的 List 屬性 stocks 中, 后續(xù)在 AccountStockAction 中直接處理account和stocks屬性就非常簡單了. AccountStockForm在這里只作為一個(gè)殼.
下面從前臺到后臺說明關(guān)鍵性的代碼, 完整的 MyEclipse 工程包可以點(diǎn)擊 TestStruts135.zip下載到.
一: struts-config.xml 配置
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd"> <struts-config> <form-beans> <form-bean name="accountStockForm" type="com.unmi.form.AccountStockForm"/> </form-beans> <action-mappings> <action path="/showStock" name="accountStockForm" type="com.unmi.action.AccountStockAction" scope="request"> <forward name="show" path="/show.jsp"/> </action> </action-mappings> </struts-config>
二: 輸入頁面 input.jsp, 注意表單域命名
<html:form action="/showStock"> <h3>記錄持有的股票<br></h3> <fieldset>s<legend>基本信息</legend> <table width="100%" border=0><tr> <td>帳戶名:<html:text property="account.name"/></td> <td>資金帳號:<html:text property="account.number"/></td> </tr></table> </fieldset> <br> <fieldset><legend>持有股票</legend> <table width=100% border=0 id="stockTable"> <tr> <td><input type="checkbox" onclick="checkAll(this)"></td> <td>股票代碼</td> <td>股票名稱</td> <td>成本價(jià)</td> <td>股票數(shù)量</td> </tr> <tr> <td><input type="checkbox" name="check"></td> <td><input name="stocks[0].code" size="15"></td> <td><input name="stocks[0].name" size="15"></td> <td><input name="stocks[0].price" size="15"></td> <td><input name="stocks[0].quantity" size="15"></td> </tr> </table> </html:form>
例如輸入框名 account.name 提交后能設(shè)置到 accountStockForm 的account的name屬性
輸入框名為 stocks[0].code 提交后會(huì)設(shè)置到 accountStockForm 的 List stocks的第一個(gè)元素的code屬性.以此類推
在提交表單前要重排行層的索引,從 0 起, 否則到后右的 Form 會(huì)一些空數(shù)據(jù).
三: AccountStockForm 的關(guān)鍵代碼
private Account account = new Account(); private List stocks = new AutoArrayList(Stock.class); public void setStocks(List stocks) { this.stocks.clear(); this.stocks.addAll(stocks); }
定義了兩個(gè)屬性,分別是一個(gè)bean(Account,接受基本信息)和一個(gè)List(stocks,接受股票行信息),注意這兩個(gè)屬性必須初始化,不然在表單提交后會(huì)出現(xiàn)空指針錯(cuò)誤. setStocks方法是讓stocks屬性永遠(yuǎn)保有持是一個(gè) AutoArrayList 實(shí)例. 這樣在表單提交后設(shè)置值是總能調(diào)用 AutoArrayList 的 get(int index) 方法.
四: 自定義的 AutoArrayList
public class AutoArrayList extends ArrayList { private Class itemClass; public AutoArrayList(Class itemClass) { this.itemClass = itemClass; } public Object get(int index) { try { while (index >= size()) { add(itemClass.newInstance()); } } catch (Exception e) { e.printStackTrace(); } return super.get(index); } }
理解為什么要繼承一個(gè)ArrayList, 覆寫get(int index)方法要簡單了解 Struts 處理提交數(shù)據(jù)的工作原理: 大致如下: 頁面提交后, 由 ActionServlet交給RequestProcessor的processPopulate()方法,由processPopulate()方法收集請求數(shù)據(jù),放在map中,key為表單域的name屬性,如 name, account.name, stocks[0].code. 然后借助于 Common-beanutils 工具包設(shè)置到 ActionForm 的相應(yīng)屬性中
如果key是簡單的'name',直接form.setName(map.get('name'));
如果key是'account.name', 執(zhí)行的操作是 form.getAccount().setName(map.get('account.name');
如果key是'stocks[0].code', 它可以對應(yīng)到數(shù)據(jù)或集合中,如對于數(shù)組 form.stocks[0].code=map.get('stocks[0].code'); 對于集合((List)form.getStocks()).get(0).setCode(map.get('stocks[0].code'))
從上也能理解為什么 form 中的那兩個(gè)屬性必須實(shí)始化,不然會(huì)出現(xiàn)空指針錯(cuò). 而且為什么 stocks 要用 AutoArrayList 實(shí)例化, 避免出現(xiàn)索引越界的錯(cuò)誤.
五: 在 AccountStockAction 中可以打印出提交的數(shù)據(jù)
AccountStockForm asForm = (AccountStockForm)form; Account account = asForm.getAccount(); System.out.println("Account Name:"+account.getName()+ " Number:"+account.getNumber()); List stocks = asForm.getStocks(); for (int i=0; i<stocks.size() ;i++) { Stock stock = (Stock)stocks.get(i); System.out.println("Stock["+i+"]Code:"+stock.getCode()+ " Name:"+stock.getName()+ " Price:"+stock.getPrice()+ " Quantity:"+stock.getQuantity()); } return mapping.findForward("show");
在Action中就能直接取用提交來的數(shù)據(jù)了,不需要 getParameterValues()了.
六: 最后一步, 對于這樣的 ActionForm 我們應(yīng)該如何顯示出來呢,我們用了 nested 標(biāo)簽 (show.jsp)
<html:form action="/showStock"> <h3>修改持有的股票<br></h3> <fieldset><legend>基本信息</legend> <table width="100%" border=0><tr> <nested:nest property="account"> <td>帳戶名:<nested:text property="name" readonly="true"/></td> <td>資金帳號:<nested:text property="number" readonly="true"/></td> </nested:nest> </tr></table> </fieldset> <br> <fieldset><legend>持有股票</legend> <table width=100% border=0 id="stockTable"> <tr> <td><input type="checkbox" onclick="checkAll(this)"></td> <td>股票代碼</td> <td>股票名稱</td> <td>成本價(jià)</td> <td>股票數(shù)量</td> </tr> <nested:iterate id="stock" property="stocks"> <tr> <td><input type="checkbox" name="check"></td> <td><nested:text property="code" size="15"/></td> <td><nested:text property="name" size="15"/></td> <td><nested:text property="price" size="15"/></td> <td><nested:text property="quantity" size="15"/></td> </tr> </nested:iterate> </table> </html:form>
可以查看生成的HTML源文件, 你就能更好理解 input.jsp 中的表單域?yàn)槭裁匆敲疵?
小結(jié)的內(nèi)容是請注意以下幾個(gè)重點(diǎn):
1. 輸入信息的頁面 input.jsp 沒有使用 Struts 標(biāo)簽,目的是讓大家理解,表單域應(yīng)如何命名才能對應(yīng)上 ActionForm 中的哪一個(gè)屬性
2. 顯示數(shù)據(jù)的頁面是用的 Struts 標(biāo)簽,并留意 nested 標(biāo)簽的應(yīng)用. 可以從生成的 HTML 源文件中體會(huì)出什么
3. 提交數(shù)據(jù)前要重新編排行層中輸入框 Name 屬性的下標(biāo)植.
4. 回味為什么要引入 ArrayList 的子類 AutoArrayList, 關(guān)鍵在 get(int index) 方法的覆寫
5. 最后是 ActionForm 中 List 屬性 stocks 的 setter 方法的實(shí)現(xiàn), 保持那個(gè) List 的運(yùn)行時(shí)具體類型不變
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
