<html:javascript formName="searchSgbySjForm" dynamicJavascript="true" staticJavascript="false"/>
生成 :
var bCancel = false;
function validateSearchSgbySjForm(form)
{
if (bCancel) return true;
else return validateRequired(form) && validateDate(form);
}
function required ()
{
this.aa = new Array("sgfssjq", "事故發(fā)生時(shí)間起 不可為空.", new Function ("varName", "this.datePatternStrict='yyy-MM-dd'; return thisvarName];"));
this.ab = new Array("sgfssjz", "事故發(fā)生時(shí)間止 不可為空.", new Function ("varName", "this.datePatternStrict='yyy-MM-dd'; return this[varName];"));
}
function DateValidations ()
{
this.aa = new Array("sgfssjq", "事故發(fā)生時(shí)間起 不是有效的日期類型.", new Function ("varName", "this.datePatternStrict='yyy-MM-dd'; return this [varName];"));
this.ab = new Array("sgfssjz", "事故發(fā)生時(shí)間止 不是有效的日期類型.", new Function ("varName", "this.datePatternStrict='yyy-MM-dd'; return this[varName];"));
}
如果有多個(gè)的話required和DateValidations 都會(huì)重復(fù)的,而javascript是只認(rèn)最后一個(gè)函數(shù)的。所以,會(huì)導(dǎo)致驗(yàn)證出錯(cuò)。
再寫一個(gè)標(biāo)簽 ,主要根據(jù)原來的代碼修改,代碼如下:
package com.tmri.acd.tag;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTagSupport;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.Form;
import org.apache.commons.validator.ValidatorAction;
import org.apache.commons.validator.ValidatorResources;
import org.apache.commons.validator.util.ValidatorUtils;
import org.apache.commons.validator.Var;
import org.apache.struts.Globals;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.config.ModuleConfig;
import com.tmri.acd.tag.TagUtils;
import org.apache.struts.util.MessageResources;
import org.apache.struts.validator.Resources;
import org.apache.struts.validator.ValidatorPlugIn;
import java.util.StringTokenizer;
public class JavascriptValidatorTag extends BodyTagSupport
{
private static final Comparator actionComparator = new Comparator()
{
public int compare(Object o1, Object o2)
{
ValidatorAction va1 = (ValidatorAction) o1;
ValidatorAction va2 = (ValidatorAction) o2;
if ((va1.getDepends() == null || va1.getDepends().length() == 0) && (va2.getDepends() == null || va2.getDepends().length() == 0))
{
return 0;
}
else if ( (va1.getDepends() != null && va1.getDepends().length() > 0) && (va2.getDepends() == null || va2.getDepends().length() == 0))
{
return 1;
}
}
二.創(chuàng)建支持多線程的Action
1.什么是線程安全的代碼
在多線程環(huán)境下能正確執(zhí)行的代碼就是線程安全的。
安全的意思是能正確執(zhí)行,否則后果是程序執(zhí)行錯(cuò)誤,可能出現(xiàn)各種異常情況。
2.如何編寫線程安全的代碼
很多書籍里都詳細(xì)講解了如何這方面的問題,他們主要講解的是如何同步線程對共享資源的使用的問題。主要是對synchronized關(guān)鍵字的各種用法,以及鎖的概念。
Java1.5中也提供了如讀寫鎖這類的工具類。這些都需要較高的技巧,而且相對難于調(diào)試。
但是,線程同步是不得以的方法,是比較復(fù)雜的,而且會(huì)帶來性能的損失。等效的代碼中,不需要同步在編寫容易度和性能上會(huì)更好些。
我這里強(qiáng)調(diào)的是什么代碼是始終為線程安全的、是不需要同步的。如下:
1)常量始終是線程安全的,因?yàn)橹淮嬖谧x操作。
2)對構(gòu)造器的訪問(new 操作)是線程安全的,因?yàn)槊看味夹陆ㄒ粋€(gè)實(shí)例,不會(huì)訪問共享的資源。
3)最重要的是:局部變量是線程安全的。因?yàn)槊繄?zhí)行一個(gè)方法,都會(huì)在獨(dú)立的空間創(chuàng)建局部變量,它不是共享的資源。局部變量包括方法的參數(shù)變量。
Servlet是在多線程環(huán)境下的。即可能有多個(gè)請求發(fā)給一個(gè)servelt實(shí)例,每個(gè)請求是一個(gè)線程。 struts下的action也類似,同樣在多線程環(huán)境下,你也必須編寫線程安全的Action類。
保證線程安全的原則就是僅僅使用局部變量,謹(jǐn)慎使用實(shí)例變量(擁有狀態(tài)的實(shí)例,尤其是擁有業(yè)務(wù)對象狀態(tài)的實(shí)例). 如果要用到那些有狀態(tài)的實(shí)例,唯一和最好的辦法是在Action類中,僅僅在Action類的execute()方法中使用局部變量,對于每個(gè)調(diào)用execute()方法的線程,JVM會(huì)在每個(gè)線程的堆棧中創(chuàng)建局部變量,因此每個(gè)線程擁有獨(dú)立的局部變量,不會(huì)被其他線程共享.當(dāng)線程執(zhí)行完execute()方法后,它的局部變量就會(huì)被銷毀.
如果Action類的實(shí)例變量是必須的話,需要采用JAVA同步機(jī)制(synchronized)對訪問共享資源的代碼塊進(jìn)行同步
三、Struts的幾種Action
Struts提供了一些現(xiàn)成的Action類,直接使用可以大大節(jié)省時(shí)間,如下
ForwardAction
可以轉(zhuǎn)發(fā)到其他web組件,僅僅提供一個(gè)轉(zhuǎn)發(fā)功能,不作處理。
IncludeAction
包含其他web組件。
DiapatchAction
通常一個(gè)Action只完成一個(gè)操作,用這個(gè)Action可以完成一組相關(guān)的操作。
LookupDispatchAction
他是DiapatchAction的子類,也可以定義多個(gè)方法,但主要用于一個(gè)表單里有多個(gè)按鈕,而這些按鈕又有一個(gè)共同的名字的場合。
SwitchAction
用于子模塊之間的切換。
四.ActionForward類
Action類的excute()方法返回一個(gè)ActionForward對象,它代表了web資源的邏輯抽象,這里的web資源可以是jsp頁面、Java servlet、或Action。
從excute返回ActionForward可以有兩種方法。
1) 動(dòng)態(tài)創(chuàng)建一個(gè)ActionForward實(shí)例
return new ActionForward(”Failure”,”login.jsp”,true);
2) 調(diào)用ActionMappin實(shí)例的findForward方法
這個(gè)方法先從action級(jí)別找,然后在<global-forwards />級(jí)別找
return mapping.findForward(“Failure”);
1) 調(diào)用processMultipart()方法
如果HTTP請求方式為post,并且contentType為”multipart/form-data”開頭,標(biāo)準(zhǔn)的HttpServletRequest對象將被重新包裝,以方便處理”multipart”類型的HTTP請求.如果請求方式為get,或正congtentType屬性不是”mulitipart”,就直接返回原始的HttpServletRequest對象.
2) 調(diào)用processPath()方法
獲得請求的URI的路徑,這一信息可用于選擇合適的Struts Action組件.
3) 調(diào)用processLocale方法
當(dāng)ControllerConfig對象的locale屬性為true,將讀取用戶請求中包含的Locale信息,然后把Locale實(shí)例保存在session范圍內(nèi).
4) 調(diào)用processContendType(contentType)方法
讀取ControllerConfig對象的conttentType屬性,然后調(diào)用response.setContentType(contentType)方法,設(shè)置響應(yīng)結(jié)果的文檔類型和字符編碼.
processContent()方法如下
5) 調(diào)用processNoCache()方法
讀取ControllerConfig對象的nocache屬性,如果nocache屬性為true,在響應(yīng)結(jié)果中將加入特定的頭參數(shù):Pragma,Cache-Control和Expires,
防止頁面被存儲(chǔ)在客戶的瀏覽器的緩存中,processNoCache方法的代碼如下:
6)調(diào)用processPreprocess()方法
該方法不執(zhí)行任何操作.直接返回true.子類可以覆蓋這個(gè)方法.
執(zhí)行客戶化的預(yù)處理請求操作.
7)調(diào)用processMapping()方法
尋找和用戶請求的URI匹配的ActionMapping,如果不存在這樣的ActionMapping,則向用戶返回恰當(dāng)?shù)腻e(cuò)誤信息.
8)調(diào)用processRoles()方法
先判斷是否為Action配置了安全角色,如果配置了安全角色,就調(diào)用isUserInRole()方法判斷當(dāng)前用戶是否具備必需的角色,如果不具備,就結(jié)束請求處理流程.,向用戶返回恰當(dāng)?shù)腻e(cuò)誤消息.
9)調(diào)用processActionForm()方法
先判斷是否為ActionMapping配置了ActionForm,如果配置了ActionForm,就先從ActionForm的存在范圍內(nèi)(request或session)尋找改ActionForm實(shí)例,如果不存在,就創(chuàng)建一個(gè)實(shí)例,接下來把它保存在合適的范圍內(nèi),保存時(shí)使用的屬性key為ActionMapping的name屬性。
10)調(diào)用processPopulate()方法
如果為ActionMapping配置了ActionForm,就先調(diào)用ActionForm的reset()方法,再把請求中的表單數(shù)據(jù)組裝到ActionForm中。
11)調(diào)用processValidate()方法
如果為ActionMapping配置了ActionForm,并且ActionMapping的validate屬性為true,就調(diào)用ActionForm的validate()方法,如果validate方法返回的ActionErrors對象中包含ActionMessage對象,說明表單驗(yàn)證失敗。就把ActionErrors對象放在request范圍內(nèi),再把請求轉(zhuǎn)發(fā)到ActionMapping的input屬性指定的Web組件。如果ActionForm的validate方法執(zhí)行表單驗(yàn)證成功,就繼續(xù)執(zhí)行下面的處理流程。
12)調(diào)用processForward()方法
判斷是否在ActionMapping中配置了forward屬性。如果配置了這個(gè)屬性,就調(diào)用RequestDispatcher的forward方法,請求處理流程結(jié)束。否則進(jìn)行下一步。
13)調(diào)用processInclude()方法
判斷是否在ActionMapping中配置了include屬性。如果配置了這個(gè)屬性,就調(diào)用RequestDispatcher的include方法,請求處理流程結(jié)束。否則進(jìn)行下一步。
14)調(diào)用processActionCreate()方法
先判斷是否在Action緩存中存在這個(gè)Action實(shí)例,如果沒有就新建一個(gè)Action實(shí)例,把它放在Action緩存中。可以看出Action也是只有一個(gè)實(shí)例在運(yùn)行的。
15)調(diào)用processActionPerform
該方法調(diào)用Action實(shí)例的execute方法,該方法位于try/catch中,以及捕獲異常。processActionPerform()方放代碼如下。
16)調(diào)用processActionForward方法
把你的Action的excute方法返回的ActionFoward對象作為參數(shù)傳給它,processActionForward對象包的請求轉(zhuǎn)發(fā)信息來執(zhí)行請求轉(zhuǎn)發(fā)或重定向。
在RequestProcessor類的process方法中,會(huì)訪問ControllerConfig、ActionMappig和ActionForward實(shí)力的屬性,ControllerConfig類和struts配置文件的<controlle>r元素對應(yīng),ActionMapping類和<action>元素對應(yīng),ActionForward和<forward>元素對應(yīng),process方法通過訪問這三個(gè)類實(shí)例的屬性來獲得相關(guān)的配置信息。
寫了這么多,RequestProcessor干得事夠多的吧。
二.?dāng)U展RequestProcessor類
如果想修改RequestProcessor的一些默認(rèn)功能,改易覆蓋RequestProcessor基類中的相關(guān)方法.
在struts配置文件中,<controller>元素的processorClass屬性用于配置你自己的RequestProcessor類
將各個(gè)子模塊應(yīng)用(除了默認(rèn)的)的前綴存到一個(gè)字符數(shù)組中,并放到servletcontext中,對于默認(rèn)的子應(yīng)用模塊,在appclication范圍內(nèi)存放他的MoudleConfig實(shí)例的key為“org.apache.struts.action.MODULE”,其他模塊如/account,存放的key為org.apache.struts.action.MODULE/account,消息,數(shù)據(jù)源和插件等部分存在servletcontext的key和上述方法類似,不在說明.
二.ActionServlet的process方法
當(dāng)ActionServlet接受到HTTP請求后,在doget()或doPost()方法中都會(huì)調(diào)用process()方法來處理請求.
public void doPost(HttpServletRequest request,
下面是process方法,它看上去并不復(fù)雜,但他調(diào)用的其他方法比較復(fù)雜.
protected void process(HttpServletRequest request, HttpServletResponse response)
三. 擴(kuò)展ActionServlet類
從Struts1.1開始,為減輕ActionServlet的負(fù)擔(dān),多數(shù)功能已經(jīng)移到RequestProcessor類中,所以基本不用擴(kuò)展ActionServlet類
如果需要?jiǎng)?chuàng)建自己的ActionServlet,則可以創(chuàng)建一個(gè)它的子類.覆蓋init()方法(或其他方法),可以寫一些自己的操作,但要先調(diào)用super.init();
定義如下的類:
擴(kuò)展完類后,還應(yīng)該在web.xml文件中如下配置: