1. 案例场景:
以下是一个n row × 2 col 的表,并且每一行可以独立作为一条link把parm pass去action或者jsp page。
<logic:iterate id="row" name="fundTypeSearchResults">
<html:link page="/fundTypeSearchResult.do?fundTypeCode=${row.fundTypeCode};fundTypeName=${row.fundTypeName}">
<tr class ="tr1">
<td align="left"><bean:write name="row" property="fundTypeCode"/></td>
<td align="left"><bean:write name="row" property="fundTypeName"/></td>
</tr>
</html:link>
</logic:iterate>
现在在禁止用button的情况下,想不用hard code的方法在url上把parm pass出去,而是通过actionForm把value pass到action,得到的效果跟以上相似。
Step 1
要把parm pass到actionForm必须通过submit,但是这个case因为要对所选取的其中一行(即一行中的2个parm fundTypeCode和fundTypeName)独立submit,其他行中的parm不需要pass,所以不能用submit button。
现在尝试通过JavaScript来对针对任何一行进行submit。
这段JavaScript的标准格式如下:
<a href="javascript:document.yourform.submit()"></a>
以上的 yourform 为你所 submit 的 form name,在struts 的 form 没有 name 这个attribute,但是其实际name就是actionForm的name。如本case,action name是fundTypeSearchResult,那么form name就是fundTypeSearchResultForm。
同时在测试时发现,a里面不能embed <tr>或<td>等,如<a href="XXX"><td><td/></a>是错误的。
所以现在运用的一个instance如下:
<td><a href="javascript:document.fundTypeSearchResultForm.submit()"><bean:write name="row" property="fundTypeCode"/></a></td>
可是也发现submit后不能得到相应选择的一行的parm,而只是get到第一行的parm,此问题到此未解决,待续。
2. <html:base />
就像struts的offical document那样说"This tag is useful"。
其实并不是一定好用,只不过是在需要用到相对路径却没有加上这个tag或者不使用相对路径却加上了这个tag,那就容易引致不能调用一些路径上的文件。
如以下的case:
<link rel="stylesheet" type="text/css" href="../css/general.css" >
<script type="text/javascript" language="javascript" src="../js/general.js" ></script>
如果没有加上<html:base />将没有办法使用到css和js。
3. Button Link
在struts中如果想利用button link到其他page,就需要在onclick上用到location.href。但是在struts中应该特别注意路径问题,因为可能你现在放置button link的page不是在root path而是在一个folder下,而且这个page是由action forward过来的,这时候path仍然是action的路径,即root path,就必须指定folder了。而且要注意在folder前不能有"/"号。
具体例子如下:
放置该段代码的是fundTypeEdit.jsp,fundTypeSearchResult这个action forward过来,而我们要通过button link到存在于fundInformation folder下的fundTypeSearch.jsp。
4. Case
现在在一个jsp page上有update和delete两个button,分别做update和delete两个operation,但是用同一个actionForm把parameter pass到同一个action,再有action作判断以决定做哪一个operation。问题是如何让action知道做什么operation呢?
在jsp page的update和delete button前可以定一个名叫method的hidden field,然后通过不同的button分别赋不同的值给method的value让actionForm去get。
所以在button onclick上可以利用EL来做赋值操作,例子如下:
<html:hidden property="method"></html:hidden>
<html:submit value="Update" οnclick="$('method').value = 'update'"></html:submit>
<html:submit value="Delete" οnclick="$('method').value = 'delete'"></html:submit>
(注意:$('method')里的单引号不能少!)
该句表示将update/delete string赋值给在jsp page上名叫method的property。
Section - 5. 在Select下从Database获取options的Code
1. Abstract Template as following (red color represent you should amend it according to your need):
(1) JSP Page
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<jsp:useBean id="YourBean" class="fms.bean.YourBean"
scope="session" />
<c:set var="attributes" value="${YourBean.yourBeanMethod}" />
//......
<html:select name="yourActionForm" property="attribute">
<html:option value="">--please select--</html:option>
<html:options collection="attributes" property="attribute" labelProperty="attribute"/>
</html:select>
(2) JavaBean
public Collection getYourBeanMethod()throws Exception
{
Statement stmt = conn.createStatement();
ResultSet rst = stmt.executeQuery("select DBColumn from DBTable");
Collection ret = new ArrayList();
while(rst.next())
{
YourType temp = new YourType();
temp.setAttribute(rst.getString("DBColumn "));
ret.add(temp);
}
return ret;
}
2. Application Example:
(1) fundHouseBean.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<jsp:useBean id="fundHouseBean" class="fms.bean.FundHouseBean"
scope="session" />
<c:set var="countryRegionCodes" value="${fundHouseBean.countryRegionCodes}" />
//......
<html:select name="fundHouseAddForm" property="countryRegionCode">
<html:option value="">--please select--</html:option>
<html:options collection="countryRegionCodes" property="countryRegionCode" labelProperty="countryRegionCode"/>
</html:select>
(2) FundHouseBean.java
public Collection getCountryRegionCodes()throws Exception
{
Statement stmt = conn.createStatement();
ResultSet rst = stmt.executeQuery("select CountryRegionCode from CountryRegion");
Collection ret = new ArrayList();
while(rst.next())
{
FundHouse temp = new FundHouse();
temp.setCountryRegionCode(rst.getString("CountryRegionCode"));
ret.add(temp);
}
return ret;
}
Section 6 - 需要用到actionForm reset的一种情况
假设在fundHouseSearch.jsp上input,由fundHouseSearchForm填充和fundHouseSearchAction处理,但是当我们如果想把结果return到同一个page fundHouseSearch.jsp,因为struts会认为在同一个request,所以没有new一个actionForm,就会使得有部分在action中处理后不想显示在此Page的数据被get method填充到page上了。
所以必须在action中处理完数据后对actionForm reset,如本例这样写:
fundHouseSearchForm.reset(mapping, request);
Section 7 - EL(表达语言)运用时获取request需要注意的区别
${param.fundTypeCode}
param在前的这种是用来获取url上的parameter的
${requestScope.fundTypeCode}
requestScope在前的这种事用来获取request中对象的
Section 8 - jsp page上切忌在不同控件使用相同名字而大小写不同的方式命名。
Section 9 - 用PrepareStatement进行DB操作的时候,?号需要与数据库的column数目对应,即使有些column你不需要进行操作。
Section 10 - 如用PrepareStatement进行data的insert,而再从database get回同一data时很容易会发现get不到值,这时通常的问题在于get值得时候要制定column name而当这个column name跟database上的不同,在insert时没有发现问题是因为用了index来指向database上的对应column,所以就算database上的column在design时写错也不会出现问题。要注意。
Section 11 - java.sql.Date 与 String之间的转换
由jsp page get回来的String date需要通过转换为java.sql.Date date才能与database交互,转换算法如下:
public static java.sql.Date strToSQLDate(String strDate) {
if(!DataValidater.isEmpty(strDate)){
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
ParsePosition pos = new ParsePosition(0);
java.util.Date utilDate = formatter.parse(strDate, pos);
java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
return sqlDate;
}else{
return null;
}
}
而在database get回来的java.sql.Date date可以简单地通过该class的toString method来进行转换,如下:
String date = rst.getDate("Date").toString()
Section 12 - drop down list 的二级联动。
有两种思路:
1. 在onchange上利用JavaScript来submit到action做相应database retrieve operation,然后forward回到jsp page上display,优点是实现简单,缺点是每次点击drop down list中的不同选项都要读database,不但慢,而且增大了database的负载。
2. 在jsp page initialize的时候,用把所有相关数据从数据库中调到Array中,然后在jsp page中直接调用,优点是只读database一次,缺点是实现较繁琐(我还没有深入研究过),但如果一次读取的数量太多也会在initialization的时候出现过慢的情况。
所以我选择第1种思路来具体说明。
以下主要是对Fund House Name和Fund Name做二级联动,一个Fund House与Fund是N:1的关系,Fund Name是根据以上的Fund House Name来进行选择的。
<jsp:useBean id="fundHouseBean" class="fms.bean.FundHouseBean"
scope="session" />
<jsp:useBean id="subFundBean" class="fms.bean.SubFundBean"
scope="session" />
<c:set var="fundHouseENNames" value="${fundHouseBean.fundHouseENNames}" />
<c:set var="fundENNames" value="${subFundBean.fundENNames}" />
<tr class = "tr1">
<td align="left">Fund House Name:</td>
<td align="left" colspan="2">
<html:hidden property="method"/>
<html:select property="fundHouseID" οnchange="dropDownListOnChange(trailerFeeAddForm,'onchange','method')" styleClass="select_general" >
<html:option value="">--please select--</html:option>
<html:options collection="fundHouseENNames" property="fundHouseID" labelProperty="fundHouseENName"/>
</html:select>
</td>
</tr>
<logic:notPresent name="fundsOfFundHouse">
<tr class = "tr1">
<td align="left">Fund Name:</td>
<td align="left" colspan="3">
<html:select property="fundCode" styleClass="select_general" >
<html:option value="">--please select--</html:option>
<html:options collection="fundENNames" property="fundCode" labelProperty="fundENName"/>
</html:select>
</td>
</tr>
</logic:notPresent>
<logic:present name="fundsOfFundHouse">
<tr class = "tr1">
<td align="left">Fund Name:</td>
<td align="left" colspan="3">
<html:select property="fundCode" styleClass="select_general" >
<html:option value="">--please select--</html:option>
<html:options collection="fundsOfFundHouse" property="fundCode" labelProperty="fundENName"/>
</html:select>
</td>
</tr>
</logic:present>
fundHouseENNames和fundENNames这些都是通过相应Bean的method对jsp page中的select option做initialization的,即从database中取出可以挑选的项,读者大可不必关注。而fundsOfFundHouse会在之后说。
<html:hidden property="method"/>是用来存储下submit所属的操作待send到action中进行相应判断的,因为一个page中可能有多个submit link或者button。
dropDownListOnChange(trailerFeeAddForm,'onchange','method')是一个JavaScript的custom function,具体Code有两个function组成,如下:
function setMethod(methodName,hiddenName)
{
$(hiddenName).value = methodName ;
}
function dropDownListOnChange(form,methodName,hiddenName){
setMethod(methodName,hiddenName);
form.submit();
}
其作用就是把相应操作的名set到method这个property中,然后submit这个form。(使用的时候要特别注意哪些单引号的问题)
actionForm:
private String fundHouseID;
public String getFundHouseID() {
return fundHouseID;
}
public void setFundHouseID(String fundHouseID) {
this.fundHouseID = fundHouseID;
}
action:
Collection fundsOfFundHouse = subFundService.getFundsOfFundHouse(trailerFeeAddForm.getFundHouseID());
request.setAttribute("fundsOfFundHouse", fundsOfFundHouse);
带着从actionForm get回来的fundHouseID利用subFundService(它具体是什么不用关注)做相应的database retrieve operation,将与指定FundHouse旗下的Fund的FundCode和FundENName set到fundsOfFundHouse这个Collection中,然后forward回原来的jsp page,现在因为fundsOfFundHouse已经value了,所以以上的3大段jsp code中的第2 part被omit,由第3 part instead。最终在jsp page上Fund,可以select的就是根据指定FundHouse所retrieve出来的Fund。