版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第6章Struts2類(lèi)型轉(zhuǎn)換與數(shù)據(jù)驗(yàn)證6.1注冊(cè)功能的初步實(shí)現(xiàn)6.2Struts2的數(shù)據(jù)類(lèi)型轉(zhuǎn)換6.3Struts2的數(shù)據(jù)驗(yàn)證
6.1注冊(cè)功能的初步實(shí)現(xiàn)
1.注冊(cè)頁(yè)面和提交成功頁(yè)面
以下Struts2標(biāo)簽實(shí)現(xiàn)注冊(cè)表單提交和顯示功能。注冊(cè)信息包括六個(gè)表單域:用戶(hù)名(username)、密碼(password)、重復(fù)密碼(repassword)、年齡(age)、出生年月(birthday)、電子郵件字段(email)。新建register.jsp文件,注意文件的放置目錄為ch05/WebRoot。代碼如下:
<%@pagelanguage="java"import="java.util.*"
pageEncoding="GB2312"%>
<%@taglibprefix="s"uri="/struts-tags"%>
…
<body>
<s:formaction="registerAction">
<s:textfieldname="username"
label="username"></s:textfield><s:passwordname="password"label="password"></s:password>
<s:passwordname="repassword"label="repassword"></s:password>
<s:textfieldname="age"label="age"></s:textfield>
<s:textfieldname="birthday"label="birthday"></s:textfield>
<s:textfieldname="email"label="email"></s:textfield>
<s:submitname="submit"></s:submit>
</s:form>
</body>新建registerok.jsp,代碼如下
<%@pagelanguage="java"import="java.util.*"pageEncoding="GB2312"%>
<%@taglibprefix="s"uri="/struts-tags"%>
…
<body>
username:<s:propertyvalue="username"/><br/>
password:<s:propertyvalue="password"/><br/>
age:<s:propertyvalue="age"/><br/>
birthday:<s:propertyvalue="birthday"/><br/>
email:<s:propertyvalue="email"/><br/>
</body>以上兩個(gè)文件的運(yùn)行界面分別如圖6-1和圖6-2所示。由于尚未配置Struts2控制器,注冊(cè)響應(yīng)界面無(wú)值傳入,所以運(yùn)行界面如圖6-2所示。
圖6-1注冊(cè)表單頁(yè)面圖6-2注冊(cè)響應(yīng)頁(yè)面
2.?RegisterAction控制器類(lèi)的完成
【步驟1】建立控制器類(lèi)com.action.RegisterAction.java。
在ch05工程的src目錄下,右鍵單擊【New】的【Class】子菜單,在打開(kāi)的如圖6-3所示的頁(yè)面中填寫(xiě)相關(guān)信息,新建com.action包中的Action文件RegisterAction.java,并繼承ActionSupport類(lèi)。圖6-3新建控制器類(lèi)
【步驟2】完成RegisterAction.java代碼。
在新建的RegisterAction.java文件中完成如下代碼:
packagecom.action;
importjava.util.Date;
importcom.opensymphony.xwork2.ActionSupport;
publicclassRegisterActionextendsActionSupport{
privateStringusername;
privateStringpassword;
privateStringrepassword;
privateintage;
privateDatebirthday;
privateStringemail;
publicStringgetUsername(){
returnusername;}
publicvoidsetUsername(Stringusername){
this.username=username;}
publicStringgetPassword(){
returnpassword;}
publicvoidsetPassword(Stringpassword){
this.password=password;}
publicStringgetRepassword(){
returnrepassword;}
publicvoidsetRepassword(Stringrepassword){
this.repassword=repassword;}
publicintgetAge(){
returnage;}
publicvoidsetAge(intage){
this.age=age;}
publicDategetBirthday(){
returnbirthday;}
publicvoidsetBirthday(Datebirthday){
this.birthday=birthday;}
publicStringgetEmail(){
returnemail;}
publicvoidsetEmail(Stringemail){
this.email=email;}
publicStringexecute()throwsException{
returnSUCCESS;
}
}
3.?struts.xml的配置
打開(kāi)第5章建立的struts.xml文件,在package標(biāo)簽中添加以下代碼:
<actionname="registerAction"
class="com.action.RegisterAction">
<resultname="input">/register.jsp</result>
<resultname="success">/registerok.jsp</result>
</action>
4.運(yùn)行結(jié)果
完成配置后可以運(yùn)行本項(xiàng)目。部署好后,啟動(dòng)服務(wù)器,在IE中輸入地址http://localhost/ch05/register.jsp,將顯示如圖6-4所示的界面,填好信息后點(diǎn)擊【Submit】按鈕,即可進(jìn)入圖6-5所示的界面。注意,此時(shí)地址欄的名字為http://localhost/ch05/registerAction.action,但界面內(nèi)容卻是registerok.jsp,說(shuō)明struts.xml配置成功。圖6-4運(yùn)行輸入界面圖6-5提交轉(zhuǎn)入頁(yè)面6.2Struts2的數(shù)據(jù)類(lèi)型轉(zhuǎn)換
6.2.1Struts2中數(shù)據(jù)類(lèi)型轉(zhuǎn)換的處理
1.內(nèi)置的類(lèi)型轉(zhuǎn)換器
Struts2內(nèi)置的類(lèi)型轉(zhuǎn)換器支持大多數(shù)常用數(shù)據(jù)類(lèi)型的轉(zhuǎn)換,因此,這些類(lèi)型在開(kāi)發(fā)過(guò)程中不用處理類(lèi)型轉(zhuǎn)換。如6.1節(jié)中RegisterAction.java中的age和birthday都不是String類(lèi)型,但系統(tǒng)都會(huì)對(duì)它們自動(dòng)轉(zhuǎn)換類(lèi)型。
Struts2內(nèi)置的類(lèi)型轉(zhuǎn)換器可以處理以下類(lèi)型:
●布爾型:boolean/Boolean;
●字符型:char/Character;
●數(shù)值型:int/Integer、long/Long、float/Float、double/Double;
●日期型:Date,采用用戶(hù)請(qǐng)求所在Locale的SHORT格式處理;
●數(shù)組:array,按具體數(shù)組元素轉(zhuǎn)換;
●集合:collection,默認(rèn)集合元素為String類(lèi)型,把所有字符串封裝在ArrayList中。
2.?OGNL機(jī)制
Struts2借助OGNL表達(dá)式的支持,允許將參數(shù)轉(zhuǎn)換成復(fù)合類(lèi)型對(duì)象。
舉例,把6.1節(jié)的注冊(cè)代碼重寫(xiě)如下:
【步驟1】視圖界面。
register1.jsp代碼:
<%@pagelanguage="java"import="java.util.*"
pageEncoding="GB2312"%>
<%@taglibprefix="s"uri="/struts-tags"%>
……<body>
<s:formaction="registerAction1">
<s:textfieldname="user.username"label="username"></s:textfield>
<s:passwordname="user.password"label="password"></s:password>
<s:passwordname="user.repassword"label="repassword"></s:password>
<s:textfieldname="user.age"label="age"></s:textfield>
<s:textfieldname="user.birthday"label="birthday"></s:textfield><s:textfieldname="user.email"label="email"></s:textfield>
<s:submitname="submit"></s:submit>
</s:form>
</body>
registerok1.jsp代碼:
<%@pagelanguage="java"import="java.util.*"pageEncoding="GB2312"%>
<%@taglibprefix="s"uri="/struts-tags"%>
……
<body>
username:<s:propertyvalue="user.username"
/><br/>
password:<s:propertyvalue="user.password"/><br/>
age:<s:propertyvalue="user.age”/><br/>
birthday:<s:propertyvalue="user.birthday"/><br/>
email:<s:propertyvalue="user.email"/><br/>
</body>
【步驟2】完成action。
com.bean.User.java代碼:
packagecom.bean;
importjava.util.Date;
publicclassUser{
privateStringusername;
privateStringpassword;
privateStringrepassword;
privateintage;
privateDatebirthday;
privateStringemail;
//省略get/set方法
}
com.action.RegisterAction1.java代碼:
packagecom.action;
importcom.bean.User;
importcom.opensymphony.xwork2.ActionSupport;
publicclassRegisterAction1extendsActionSupport{
privateUseruser;
publicUsergetUser(){
returnuser;}
publicvoidsetUser(Useruser){
this.user=user;}
publicStringexecute()throwsException{
returnSUCCESS;
}
}
【步驟3】struts.xml配置。
增加如下代碼:
<actionname="registerAction1"
class="com.action.RegisterAction1">
<resultname="input">/register1.jsp</result>
<resultname="success">/registerok1.jsp</result>
</action>在以上示例中,把所有注冊(cè)屬性都封裝到了User.java類(lèi)中,而在RegisterAction1.java中把User對(duì)象類(lèi)型作為屬性類(lèi)型。對(duì)于這樣的對(duì)象類(lèi)型轉(zhuǎn)換,Struts2提供的OGNL表達(dá)式允許開(kāi)發(fā)者無(wú)需任何特殊處理就可以轉(zhuǎn)換,只要像register1.jsp和registerok1.jsp代碼中的黑體部分那樣,在定義表單域時(shí)使用合法的OGNL表達(dá)式即可,如、user.age。
3.集合的轉(zhuǎn)換
為了讓Struts2了解集合屬性中元素的類(lèi)型,有以下兩種方式可以使用:
●使用泛型技術(shù)來(lái)直接指定集合元素類(lèi)型(推薦使用);
●通過(guò)Action的局部類(lèi)型轉(zhuǎn)換文件(詳見(jiàn)6.2.2節(jié))指定集合元素類(lèi)型。
這部分內(nèi)容將在下節(jié)詳述,可以將email改變?yōu)閾碛卸鄠€(gè)值的集合的處理。6.2.2自定義的類(lèi)型轉(zhuǎn)換器
如果內(nèi)置的類(lèi)型轉(zhuǎn)換器不能滿(mǎn)足用戶(hù)的Web應(yīng)用需求,那么Struts2也提供了自己開(kāi)發(fā)類(lèi)型轉(zhuǎn)換器的方法。而要?jiǎng)?chuàng)建一個(gè)類(lèi)型轉(zhuǎn)換器,則需實(shí)現(xiàn)ognl.TypeConverter接口,但該接口中的方法convertValue()太復(fù)雜。
org.apache.struts2.util.StrutsTypeConverter抽象類(lèi)中提供了兩個(gè)抽象方法用于字符串和其他類(lèi)型的相互轉(zhuǎn)換。這兩個(gè)方法如下:●?convertFromString(Maparg0,String[]arg1,Classarg2):從字符串轉(zhuǎn)換為指定對(duì)象類(lèi)型,即把客戶(hù)端獲得的字符串?dāng)?shù)據(jù)轉(zhuǎn)化成服務(wù)器需要的數(shù)據(jù)類(lèi)型。arg0表示action上下文的Map對(duì)象;arg1是要轉(zhuǎn)換的字符串值;arg2是要轉(zhuǎn)換的目標(biāo)類(lèi)型。
●?convertToString(Maparg0,Objectarg1):將指定對(duì)象轉(zhuǎn)換為字符串,即把服務(wù)器處理好的實(shí)際結(jié)果數(shù)據(jù)類(lèi)型轉(zhuǎn)換成客戶(hù)端輸出顯示的字符串?dāng)?shù)據(jù)。arg0表示action上下文的Map對(duì)象;arg1是要轉(zhuǎn)換的對(duì)象。下面我們對(duì)注冊(cè)的action屬性進(jìn)行重新設(shè)置,改變的要求如下:
(1)?birthday屬性:輸入的字符串提交后轉(zhuǎn)換為"yyyy-MM-dd"的日期格式;
(2)?email屬性:可以輸入以分號(hào)(;)隔開(kāi)的多個(gè)email值,用List集合來(lái)保存,輸出顯示[第1個(gè)Email為:aa@163.com,第2個(gè)Email為:bb@163.com,第3個(gè)Email為:cc@163.com]等不定個(gè)數(shù)的email值格式。
【步驟1】修改com.action.RegisterAction.java類(lèi)。
由于email要修改為L(zhǎng)ist集合保存的多個(gè)值,因此要在RegisterAction.java中把原來(lái)的代碼:
privateStringemail;
publicStringgetEmail(){
returnemail;
}
publicvoidsetEmail(Stringemail){
this.email=email;
}修改為如下代碼來(lái)滿(mǎn)足需求:
privateList<String>email;
publicList<String>getEmail(){
returnemail;
}
publicvoidsetEmail(List<String>email){
this.email=email;
}
【步驟2】編寫(xiě)日期類(lèi)型轉(zhuǎn)換器。
要滿(mǎn)足顯示"yyyy-MM-dd"日期格式,需編寫(xiě)日期類(lèi)型轉(zhuǎn)換器com.converter.DateConverter.java,代碼如下:
packagecom.converter;
importjava.text.ParseException;
importjava.text.SimpleDateFormat;
importjava.util.Map;
importorg.apache.struts2.util.StrutsTypeConverter;
import
com.opensymphony.xwork2.util.TypeConversionException;
publicclassDateConverterextendsStrutsTypeConverter{
privatestaticSimpleDateFormatsf=newSimpleDateFormat("yyyy-MM-dd");
//客戶(hù)端到服務(wù)器端
publicObjectconvertFromString(Maparg0,String[]arg1,Classarg2)
{try
{//將取得的客戶(hù)端輸入數(shù)據(jù)放入str;
String[]str=(String[])arg1;
//使用“yyyy-MM-dd”日期格式解析字符串值,返回Date對(duì)象
returnsf.parse(str[0]);
}
catch(ParseExceptione)
{thrownewTypeConversionException(
e.getMessage()+"["+arg1+"-class:"+arg2+"]");
}
}
//服務(wù)器端到客戶(hù)端
publicStringconvertToString(Maparg0,Objectarg1)
{
//使用"yyyy-MM-dd"日期格式格式化Date對(duì)象,
返回字符串
returnsf.format(arg1);
}
}
【步驟3】編寫(xiě)email類(lèi)型轉(zhuǎn)換器。
email屬性的變化較大,請(qǐng)讀者注意此轉(zhuǎn)換器的代碼中對(duì)集合的處理部分的代碼。email類(lèi)型轉(zhuǎn)換器com.converter.EmailConverter.java的代碼如下:
packagecom.converter;
importjava.util.ArrayList;
importjava.util.List;
importjava.util.Map;
importorg.apache.struts2.util.StrutsTypeConverter;
publicclassEmailConverterextendsStrutsTypeConverter{
//客戶(hù)端到服務(wù)器端
publicObjectconvertFromString(Maparg0,String[]arg1,Classarg2){
List<String>list=newArrayList<String>();
String[]str=(String[])arg1;
//分隔分號(hào)中的數(shù)據(jù)存入數(shù)組paramValues;
String[]paramValues=str[0].split(";");
//遍歷數(shù)組paramValues,把數(shù)字元素存入集合list
for(Stringparam:paramValues){
list.add(param);
}
returnlist;
}
//服務(wù)器端到客戶(hù)端
publicStringconvertToString(Maparg0,Objectarg1){
//取出處理后的數(shù)據(jù),轉(zhuǎn)化為集合類(lèi)型;
List<String>emails=(List<String>)arg1;
Stringresult="[";
inti=0;
//遍歷集合設(shè)置輸出字符串內(nèi)容
for(Stringemail:emails){
i++;
result+="第"+i+"個(gè)Email為:"+email+",";
}
//把最后一個(gè)逗號(hào)去掉
result=result.substring(0,result.length()-1);
result+="]";
returnresult;
}
}
【步驟4】注冊(cè)類(lèi)型轉(zhuǎn)換器。
僅僅為該應(yīng)用提供類(lèi)型轉(zhuǎn)換器還不夠,因?yàn)镾truts2依然不知道何時(shí)使用這些類(lèi)型轉(zhuǎn)換器,因此要對(duì)寫(xiě)好的類(lèi)型轉(zhuǎn)換器進(jìn)行注冊(cè),讓Struts2框架知道它們的存在。
Struts2支持以下三種注冊(cè)類(lèi)型轉(zhuǎn)換器的方式:
●局部類(lèi)型轉(zhuǎn)換器;
●全部類(lèi)型轉(zhuǎn)換器;
●使用Struts2提供的類(lèi)型轉(zhuǎn)換注解來(lái)配置。
(1)應(yīng)用于局部的類(lèi)型轉(zhuǎn)換器。
要指定局部范圍的類(lèi)型轉(zhuǎn)換器,需要建立屬性文件RegisterAperties。此文件名中后半部分(-perties)名字固定,前半部分(RegisterAction)為屬性文件中所定義的屬性所在的Action文件名。
選中com.action包,用右鍵【New】選中【File】,在打開(kāi)的如圖6-6所示的頁(yè)面中輸入文件名RegisterAperties,點(diǎn)擊【Finish】按鈕。圖6-6新建屬性文件在新建屬性文件的【Source】視圖中輸入以下代碼,可完成局部轉(zhuǎn)換器的注冊(cè)。
birthday=com.converter.DateConverter
email=com.converter.EmailConverter
從代碼中可以歸納出局部屬性文件的兩個(gè)特點(diǎn):
●每個(gè)屬性定義遵循的格式為:要轉(zhuǎn)換的類(lèi)屬性名=類(lèi)型轉(zhuǎn)換器的類(lèi)文件全稱(chēng);
●定義多個(gè)要轉(zhuǎn)換的屬性時(shí),只需分行定義,不能用標(biāo)點(diǎn)隔開(kāi)。分析整個(gè)轉(zhuǎn)換過(guò)程:從register.jsp提交到RegisterAction.java,當(dāng)遇到setBirthday()方法時(shí),系統(tǒng)到對(duì)應(yīng)的屬性文件RegisterAperties中檢查有無(wú)對(duì)此屬性進(jìn)行類(lèi)型轉(zhuǎn)換,如果有,則執(zhí)行屬性文件中對(duì)應(yīng)屬性轉(zhuǎn)換的類(lèi)DateConverter.java,然后檢查轉(zhuǎn)換的方向,是客戶(hù)端到服務(wù)器端還是服務(wù)器端到客戶(hù)端,此處是字符串到Date類(lèi)的轉(zhuǎn)換,即選擇convertFromString()方法,把處理后的結(jié)果返回Date類(lèi)值賦給setBirthday()中的birthday。這樣便完成了注冊(cè)提交數(shù)據(jù)的轉(zhuǎn)換過(guò)程。
(2)應(yīng)用于全局的類(lèi)型轉(zhuǎn)換器。
注冊(cè)全局類(lèi)型轉(zhuǎn)換器,可以使得注冊(cè)的類(lèi)型在所有的Action執(zhí)行時(shí)都起作用。
全局類(lèi)型轉(zhuǎn)換注冊(cè)文件應(yīng)該放在WEB-INF/classes文件夾根目錄中,和struts.xml在同一目錄,其文件名是perties,此文件名不可更改。由于也是.properties文件,其創(chuàng)建方式見(jiàn)圖6-6,把文件放在ch05/src根目錄,配置代碼如下:
java.util.Date=com.converter.DateConverter由于email屬性的轉(zhuǎn)換器具有特殊性,因此不在全局文件中配置。注意,此時(shí)要把局部文件中birthday配置注釋掉,否則全局轉(zhuǎn)換器不起作用,因?yàn)榫植孔?cè)文件會(huì)覆蓋全局文件中相同的內(nèi)容。
屬性文件的注釋方式就是在語(yǔ)句前加井(#)號(hào),代碼
如下:
#birthday=com.converter.DateConverter
【步驟5】運(yùn)行結(jié)果。
通過(guò)以上4個(gè)步驟的處理,基本完成了本實(shí)例對(duì)birthday和email的需求。注意,本實(shí)例是在6.1節(jié)實(shí)例的基礎(chǔ)上做的修改,已有的文件不重復(fù)講述。重啟Tomcat,運(yùn)行工程路徑http://localhost/ch05/register.jsp,如圖6-7所示,提交結(jié)果如圖6-8所示。圖6-7提交輸入頁(yè)面圖6-8提交轉(zhuǎn)換頁(yè)面6.2.3類(lèi)型轉(zhuǎn)換錯(cuò)誤的處理
圖6-7中輸入的數(shù)據(jù)都是人為的,難免會(huì)發(fā)生輸入格式不正確的情況,如在age中輸入abc,在birthday中輸入2001/1/1,在email中輸入aa@163.com,bb@163.com等。圖6-9顯示了進(jìn)行以上輸入后的執(zhí)行界面。圖6-9類(lèi)型轉(zhuǎn)換錯(cuò)誤提示頁(yè)面1
1.類(lèi)型轉(zhuǎn)換的錯(cuò)誤提示
從圖6-9看到,age和birthday由于數(shù)據(jù)類(lèi)型錯(cuò)誤而出現(xiàn)“Invalidfieldvalueforfield‘a(chǎn)ge’”的提示,email雖然轉(zhuǎn)換了但并不是我們想要的結(jié)果。在這里涉及了兩方面的處理:數(shù)據(jù)校驗(yàn)(email)和類(lèi)型轉(zhuǎn)換(age)。就像email的錯(cuò)誤那樣,輸入的數(shù)據(jù)可以進(jìn)行有效轉(zhuǎn)換,但轉(zhuǎn)換的結(jié)果依然是非法數(shù)據(jù)。所以,數(shù)據(jù)驗(yàn)證的前提還是類(lèi)型轉(zhuǎn)換,只有轉(zhuǎn)換為正確的數(shù)據(jù)才能對(duì)此數(shù)據(jù)進(jìn)行處理驗(yàn)證。圖中,age、birthday的類(lèi)型轉(zhuǎn)換錯(cuò)誤我們并沒(méi)有定義過(guò),那么它們的錯(cuò)誤提示來(lái)自哪里?當(dāng)發(fā)生類(lèi)型轉(zhuǎn)換錯(cuò)誤時(shí),Struts2會(huì)調(diào)用conversionError的攔截器,這在defaultStack默認(rèn)攔截器棧中定義。處于struts-default.xml文件中的相關(guān)代碼如下(具體見(jiàn)6.4節(jié)):
<interceptor-stackname=“defaultStack”>
……
<!--處理類(lèi)型轉(zhuǎn)換攔截器-->
<interceptor-refname="conversionError"/>
<!--處理數(shù)據(jù)校驗(yàn)攔截器-->
<interceptor-refname="validation">
<param
name="excludeMethods">
input,back,cancel,browse</param>
</interceptor-ref>
……
</interceptor-stack>然后將對(duì)應(yīng)錯(cuò)誤封裝成表單域錯(cuò)誤(FieldError),并將這些錯(cuò)誤信息放入ActionContext中,然后系統(tǒng)會(huì)跳轉(zhuǎn)到名為input的邏輯視圖中。
因此歸納提示用戶(hù)類(lèi)型轉(zhuǎn)換錯(cuò)誤有三個(gè)必要條件:
●引用defaultStack攔截器棧(一般action配置中默認(rèn)配置,特殊情況請(qǐng)見(jiàn)6.4節(jié));
●讓Action類(lèi)繼承ActionSupport類(lèi);
●為Action配置添加input映射。
2.錯(cuò)誤提示的位置
在圖6-9中,對(duì)于age和birthday的錯(cuò)誤提示分別在它們所在的表單組件的上方,而且表單中還會(huì)保留錯(cuò)誤的輸入內(nèi)容,這些都是Struts2中表單標(biāo)簽自帶的功能,可以自動(dòng)輸出與其關(guān)聯(lián)的錯(cuò)誤信息,通過(guò)字段名來(lái)關(guān)聯(lián)。
如果我們想改變信息提示的位置,讓它們更醒目一些,該怎么做?主要是對(duì)fielderror標(biāo)簽和表單主題進(jìn)行處理。前面已經(jīng)提到錯(cuò)誤內(nèi)容被封裝成表單域錯(cuò)誤(FieldError),那么可以使用fielderror標(biāo)簽來(lái)訪(fǎng)問(wèn)錯(cuò)誤,修改register.jsp頁(yè)面,添加代碼在body標(biāo)簽的第一句如下:
<s:fielderrorcssStyle="color:red"/>
則重新運(yùn)行錯(cuò)誤的類(lèi)型輸入提交,所有的錯(cuò)誤提示將集中顯示在頁(yè)頭,而且用紅色標(biāo)注,一目了然,如圖6-10所示。圖6-10類(lèi)型轉(zhuǎn)換錯(cuò)誤提示頁(yè)面2但是圖6-10中仍然有明顯的缺陷,就是表單域中的提示還在,這是因?yàn)檫@里的表單使用了xhtml主題的表單標(biāo)簽。我們可以再做以下修改,使得錯(cuò)誤提示頁(yè)面顯示為圖6-11
所示。圖6-11類(lèi)型轉(zhuǎn)換錯(cuò)誤提示頁(yè)面3
【步驟1】新建提交頁(yè)面。
要完成以上轉(zhuǎn)變,需在實(shí)例中做如下修改,新建register_simple.jsp來(lái)完成原來(lái)register.jsp的頁(yè)面,代碼如下:
<%@pagelanguage="java"import="java.util.*"
pageEncoding="gb2312"%>
<%@taglibprefix="s"uri="/struts-tags"%>
<body>
<s:formaction="simpleRegisterAction.action"
theme="simple">
<tablewidth="70%"border="1">
<tr><td>username</td>
<td><s:textfieldname="username"
label="username"></s:textfield></td>
<td><s:fielderrorcssStyle="color:red">
<s:param>username</s:param>
</s:fielderror>
</td></tr>
<tr><td>password</td>
<td><s:passwordname="password"
label="password"></s:password></td>
<td><s:fielderrorcssStyle="color:red">
<s:param>password</s:param>
</s:fielderror>
</td></tr>
<tr><td>re-password</td>
<td><s:passwordname="repassword"
label="repassword"></s:password></td>
<td><s:fielderrorcssStyle="color:red">
<s:param>repassword</s:param>
</s:fielderror>
</td></tr>
<tr><td>age</td>
<td><s:textfieldname="age"label=“age”>
</s:textfield></td>
<td><s:fielderrorcssStyle="
color:red"
>
<s:param>age</s:param>
</s:fielderror>
</td></tr>
<tr><td>birthday</td>
<td><s:textfieldname=“birthday”label="birthday">
</s:textfield></td>
<td><s:fielderrorcssStyle="color:red">
<s:param>birthday</s:param>
</s:fielderror>
</td></tr>
<tr><td>email</td>
<td><s:textfieldname"email"
label="email">
</s:textfield></td>
<td><s:fielderrorcssStyle="color:red">
<s:param>email</s:param>
</s:fielderror>
</td></tr>
<tr><td><s:submitvalue="submit"></s:submit></td>
<td><s:resetvalue="reset"></s:reset></td>
</tr></table></s:form>
</body>
【步驟2】修改Action文件。
為了6.3節(jié)和6.4節(jié)中的一些應(yīng)用,我們?cè)赗egisterAction.java中增加一個(gè)與execute方法結(jié)構(gòu)一樣的方法simple(),代碼如下:
publicStringsimple()throwsException{
System.out.println("abcexecute...");
returnSUCCESS;
}
【步驟3】配置struts.xml。
在struts.xml中對(duì)simpleRegisterAction.action進(jìn)行配置,代碼如下:
<actionname="simpleRegisterAction"
class="com.action.RegisterAction”method="simple"
>
<resultname="input">/register_simple.jsp</result>
<resultname="success">/registerok.jsp</result>
3.錯(cuò)誤提示內(nèi)容
在默認(rèn)的情況下,所有的轉(zhuǎn)換錯(cuò)誤都使用通用的i18n消息鍵來(lái)報(bào)告錯(cuò)誤,我們可以改變這些消息鍵來(lái)達(dá)到目的。一般的做法如下:
【步驟1】定義全局屬性文件名。
在struts.xml文件中已經(jīng)定義了語(yǔ)句,如果沒(méi)有,請(qǐng)加上:
<constantname="struts.custom.i18n.resources"
value="message"></constant>其中:constant標(biāo)簽表示在所有框架中使用的常量,這些常量會(huì)替代struts中內(nèi)置的相應(yīng)常量;name是常量名;struts.custom.i18n.resources是struts中國(guó)際化的資源文件,用來(lái)定義自動(dòng)產(chǎn)生的信息;value屬性定義資源文件的名字,此處表示對(duì)應(yīng)的文件是建立在WEB-INF/classes根目錄下的perties文件。
【步驟2】完善全局屬性文件。
錯(cuò)誤提示屬性文件的編寫(xiě)內(nèi)容可以針對(duì)所有的屬性,也可以針對(duì)個(gè)別屬性,一般建議在全局屬性文件中定義的內(nèi)容是針對(duì)所有的屬性。如果在perties文件中輸入代碼,那么任何錯(cuò)誤都將提示“屬性名invalid”:
xwork.default.invalid.fieldvalue={0}invalid
在輸出類(lèi)型錯(cuò)誤消息時(shí),占位符{0}將自動(dòng)被字段名所代替,如圖6-12所示。圖6-12類(lèi)型轉(zhuǎn)換錯(cuò)誤提示頁(yè)面3
【步驟3】完善局部屬性文件。
我們還可以通過(guò)建立局部屬性文件來(lái)處理特定字段的特殊提示。Struts2規(guī)定局部屬性文件名與驗(yàn)證的Action名相同,如此處應(yīng)命名為RegisterAperties,并且此局部屬性文件必須建立在與驗(yàn)證的Action同一目錄下,即建立在com.action包中。代碼如下:
invalid.fieldvalue.birthday=birthdaysformatisyyyy-MM-DD!左邊為invalid.fieldvalue.+錯(cuò)誤屬性字段名,右邊為顯示的內(nèi)容,因此運(yùn)行后的界面如圖6-13所示。圖6-13類(lèi)型轉(zhuǎn)換錯(cuò)誤提示頁(yè)面4
6.3Struts2的數(shù)據(jù)驗(yàn)證
對(duì)用戶(hù)輸入數(shù)據(jù)進(jìn)行驗(yàn)證包括客戶(hù)端驗(yàn)證和服務(wù)器端驗(yàn)證??蛻?hù)端驗(yàn)證主要通過(guò)JavaScript腳本代碼來(lái)實(shí)現(xiàn)有效的數(shù)據(jù)格式,為服務(wù)器端過(guò)濾數(shù)據(jù);而服務(wù)器端驗(yàn)證除了可以再次驗(yàn)證數(shù)據(jù)格式外,還可以進(jìn)行數(shù)據(jù)邏輯的驗(yàn)證,如年齡是否符合規(guī)定等。那么讀者會(huì)提出疑問(wèn),數(shù)據(jù)格式到底是在客戶(hù)端還是服務(wù)器端驗(yàn)證,還是二者皆要?一般構(gòu)建Web應(yīng)用時(shí)通常要先在客戶(hù)端進(jìn)行表單數(shù)據(jù)格式驗(yàn)證,減少服務(wù)器負(fù)載。但是由于JavaScript腳本可以在客戶(hù)端被屏蔽掉,或有高手可以直接通過(guò)Socket通信來(lái)向服務(wù)器端直接傳送非法數(shù)據(jù)攻擊系統(tǒng),因此最好在服務(wù)器端進(jìn)行重復(fù)數(shù)據(jù)有效性驗(yàn)證。對(duì)于服務(wù)器端驗(yàn)證,Struts2提供了三種方式:
●使用Action中的validate()方法驗(yàn)證數(shù)據(jù);
●使用驗(yàn)證框架;
●使用驗(yàn)證注解。6.3.1編寫(xiě)Java代碼并驗(yàn)證
ActionSupport抽象類(lèi)中提供了一個(gè)validate()方法來(lái)存放校驗(yàn)代碼,只有通過(guò)了validate()中的驗(yàn)證,Action才會(huì)執(zhí)行execute()方法。
1.?Field錯(cuò)誤信息
【步驟1】修改Action文件。
對(duì)LoginAction.java的修改主要是修改繼承類(lèi)和增加validate()方法,代碼如下:
publicclassLoginActionextendsActionSupport{
……//省略不修改部分
publicvoidvalidate(){
if(null==username||username.trim().length()==0){
this.addFieldError("username","usernamemustnotbenull!");
}
if(username.length()<6||username.length()>10){
this.addFieldError("username","usernameinvalid");
}
if(null==password||password.trim().length()==0){
this.addFieldError("password","passwordmustnotbenull!");
}
if(password.length()<6||password.length()>10){
this.addFieldError("password","passwordinvalid");
}
}
addFieldError(參數(shù)1,參數(shù)2)方法中的參數(shù)1表示放入
域(Field)錯(cuò)誤中的對(duì)應(yīng)屬性的名字,參數(shù)2表示提示的錯(cuò)誤信息。此文件其實(shí)可以不修改,為了給用戶(hù)一個(gè)必填的提示,在表單組件中增加required屬性值為true,則在表單顯示頁(yè)面中該組件會(huì)標(biāo)注星號(hào)(*),代碼如下:
<body>
<s:fielderrorcssStyle="color:red"/>
<s:formaction="loginAction"
>
<s:textfieldname="username"label=“username"required="true"
></s:textfield>
<s:passwordname="password"label="password"required="true"
></s:password>
<s:submitname="submit"></s:submit>
</s:form>
</body>
【步驟3】運(yùn)行結(jié)果。
重啟服務(wù)器,輸入U(xiǎn)RL進(jìn)行訪(fǎng)問(wèn),如圖6-14所示,不填表單數(shù)據(jù)直接提交的顯示頁(yè)面為圖6-15。
在圖6-15中,錯(cuò)誤信息不只在fielderror標(biāo)簽中顯示,而且還在表單組件上方顯示,這顯然沒(méi)有必要。如何讓表單組件上方不顯示錯(cuò)誤提示呢?圖6-14星號(hào)登錄頁(yè)面
圖6-15提交驗(yàn)證頁(yè)面
2.?Action錯(cuò)誤信息
為了使錯(cuò)誤提示不重復(fù),下面舉例來(lái)完善程序。
【步驟1】修改Action文件。
對(duì)LoginAction.java的修改主要是把錯(cuò)誤放入Action級(jí)別的錯(cuò)誤信息中,代碼如下:
publicvoidvalidate(){
if(null==username||username.trim().length()==0){
this.addActionError("usernamemustnotbenull!");
}elseif(username.length()<6||username.length()>10){
this.addActionError("usernameinvalid");
}
if(null==password||password.trim().length()==0){
this.addActionError("passwordmustnotbenull!");
}elseif(password.length()<6||password.length()>10){
this.addActionError(“passwordinvalid”);
}
}
addActionError(參數(shù)1)方法中的參數(shù)1表示提示的錯(cuò)誤
信息。
【步驟2】修改login.jsp文件。
此文件只需把原來(lái)顯示fielderror的標(biāo)簽改為actionerro標(biāo)簽即可,代碼如下:
<s:actionerrorcssStyle=“color:red”/>
【步驟3】運(yùn)行結(jié)果。
重啟服務(wù)器,輸入U(xiǎn)RL進(jìn)行訪(fǎng)問(wèn),不填表單數(shù)據(jù)直接提交的顯示頁(yè)面如圖6-16所示。圖6-16Action級(jí)別的錯(cuò)誤提示
3.?validate()方法和validateXxx()方法
由于Struts2的Action類(lèi)里可以包含多個(gè)處理邏輯,就是定義了多個(gè)與execute()方法結(jié)構(gòu)相同的邏輯方法,而并不是每個(gè)邏輯方法都需要輸入校驗(yàn),如添加數(shù)據(jù)一般要輸入驗(yàn)證,但刪除數(shù)據(jù)就沒(méi)必要。按照編程習(xí)慣,對(duì)于同一個(gè)數(shù)據(jù)表的操作CRUD一般都放在一個(gè)Action中,如果僅定義validate()方法顯然不能滿(mǎn)足需求,因?yàn)関alidate()方法無(wú)法知道需要校驗(yàn)?zāi)膫€(gè)處理邏輯。
Struts2的Action還允許提供一個(gè)validateXxx()方法來(lái)實(shí)現(xiàn)校驗(yàn)指定處理邏輯的功能。
【步驟1】修改Action文件。
對(duì)LoginAction.java的修改主要是增加validateLogin()方法,只判斷空值,而且提示信息有別于validate()中的定義。代碼如下:
publicvoidvalidateLogin(){
if(null==username||username.trim().length()==0){
this.addActionError("usernameisnull!");
}
if(null==password||password.trim().length()==0){
this.addActionError("passwordisnull!");
}
}
【步驟2】修改login.jsp文件。
此文件表單用于將提交Action改成isUMAction.action,因?yàn)樵趕truts.xml中配置好此action請(qǐng)求后,可執(zhí)行l(wèi)ogin()邏輯方法。代碼如下:
<body>
<s:actionerrorcssStyle="color:red"/>
<s:formaction="isUMAction">
<s:textfieldname="username"label="username"
required="true"></s:textfield>
<s:passwordname="password"label=“password"required="true"></s:password>
<s:submitname="submit"></s:submit>
</s:form>
</body>
【步驟3】運(yùn)行結(jié)果。
重啟服務(wù)器,輸入U(xiǎn)RL進(jìn)行訪(fǎng)問(wèn),不填表單數(shù)據(jù)直接提交的顯示頁(yè)面如圖6-17所示。圖6-17validatXxx()錯(cuò)誤提示1因此,在程序中把validate()方法名字改為validateExecute(),則空值錯(cuò)誤提示就只有頭兩行的提示,如圖6-18所示。圖6-18validatXxx()錯(cuò)誤提示26.3.2使用驗(yàn)證框架
1.在注冊(cè)程序中使用驗(yàn)證框架
校驗(yàn)規(guī)則針對(duì)register.jsp的每個(gè)表單域應(yīng)滿(mǎn)足的規(guī)則為:
●?username:字符串,不為空,長(zhǎng)度為6~10位;
●?password和repassword:字符串,不為空,長(zhǎng)度為6~10位,并且二者相等。
●?age:必填,1~150的整數(shù);
●?birthday:必填,1990-01-01到2010-01-01之間的日期型。
【步驟1】建立校驗(yàn)文件。
在com.action包中新建文件RegisterAction-validation.xml,進(jìn)行校驗(yàn)規(guī)則配置,其代碼如下:
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEvalidatorsPUBLIC"-//OpenSymphony
Group//XWorkValidator1.0.2//EN"
"/xwork/xwork-validator-1.0.2.dtd">
<validators>
<fieldname="username">①<!--必填字符串校驗(yàn)器
-->
<field-validatortype=“requiredstring”>
<!--可省,默認(rèn)為true
<paramname=“trim”>true</param>
-->
<message>usernameshouldnotbeblank!</message>
</field-validator>③
<!--字符串長(zhǎng)度校驗(yàn)器
-->
<field-validatortype="stringlength">
<paramname="minLength">6</param>
<paramname="maxLength">10</param>
<message>
usernameshouldbebetween${minLength}and
${maxLength}
</message>
</field-validator>
</field>
<fieldname="password">
<field-validatortype="requiredstring">
<message>passwordshouldnotbeblank!</message>
</field-validator>④
<!--正則表達(dá)式校驗(yàn)器
-->
<field-validatortype="regex">
<param
name="expression">
<![CDATA[(\w{6,10})]]></param>
<message>
passwordshouldbebetween6and10!
</message>
</field-validator>
</field>
<fieldname="repassword">
<field-validatortype="requiredstring">
<message>repasswordshouldnotbeblank!</message>
</field-validator>
<field-validatortype="stringlength">
<paramname="minLength">6</param>
<paramname="maxLength">10</param>
<message>
repasswordshouldbebetween${minLength}and
${maxLength}
</message>
</field-validator>⑤
<!--字段表達(dá)式校驗(yàn)器
-->
<field-validatortype="fieldexpression">
<param
name="expression">
repassword==password</param>
<message>repasswordshouldbethesamewith
pass!</message>
</field-validator>
</field>
<fieldname="age">⑥
<!--整數(shù)校驗(yàn)器
-->
<field-validatortype="int">
<paramname="min">1</param>
<paramname="max">150</param>
<message>ageshouldbebetween${min}and
${max}</message>
</field-validator>
</field>
<fieldname="birthday">②
<!--必填校驗(yàn)器
-->
<field-validatortype="required">
<message>birthdayshouldnotbeblank!</message>
</field-validator>⑦
<!--日期校驗(yàn)器
-->
<field-validatortype="date">
<paramname="min">1900-01-01</param>
<paramname="max">2010-01-01</param>
<message>
birthdayshouldbebetween${min}and${max}!
</message>
</field-validator>
</field>
</validators>
【步驟2】運(yùn)行程序。
重啟Tomcat,運(yùn)行http://localhost/ch05/register.jsp,不對(duì)任何表單組件執(zhí)行輸入操作,點(diǎn)擊提交后,將出現(xiàn)如圖6-19所示的提示。圖6-19驗(yàn)證框架空值提示1再次運(yùn)行http://localhost/ch05/register.jsp,在圖6-20中輸入相關(guān)內(nèi)容,其中密碼輸入兩次不同,age不是整型,birthday不在指定范圍內(nèi),點(diǎn)擊提交后,將出現(xiàn)如圖6-21所示的提示。圖6-20注冊(cè)輸入頁(yè)面
圖6-21驗(yàn)證框架錯(cuò)誤輸入值提示
2.驗(yàn)證文件的取名和保存位置
從以上實(shí)例大部分讀者可以猜出,此驗(yàn)證文件必須放在與所要驗(yàn)證的Action文件的同一目錄下,并且文件名為ActionName-validation.xml,其中ActionName為Action的文件名,-validation.xml為固定寫(xiě)法。所以實(shí)例中的驗(yàn)證文件為com.action.RegisterAction-validation.xml。但我們知道,在一個(gè)Action中有多個(gè)負(fù)責(zé)執(zhí)行邏輯操作的方法,對(duì)于不同的邏輯操作要使用不同的配置文件,其處理方式為:同樣在要處理的Action文件的相同目錄中建立文件ActionName-ActionAliasName-validation.xml,其中ActionName為Action的文件名,ActionAliasName為邏輯方法名,-validation.xml為固定寫(xiě)法。所以如果要對(duì)RegisterAction.java文件中的simple()方法建立驗(yàn)證文件,則應(yīng)取名為com.action.RegisterAction-simple-validation.xml。接下來(lái)我們用Struts2提供的另一種校驗(yàn)規(guī)則來(lái)實(shí)現(xiàn)com.action.RegisterAction-login-validation.xml,僅定義用戶(hù)名不為空和長(zhǎng)度6~10位的驗(yàn)證,完成的代碼如下:
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEvalidatorsPUBLIC"-//OpenSymphony
Group//XWorkValidator1.0.2//EN"
"/xwork/xwork-
validator-1.0.2.dtd">
<validators>
<validatortype="requiredstring">
<paramname="fieldName">username</param>
<message>simpleusernameshouldnotbe
blank!</message>
</validator>
<validatortype="stringlength">
<paramname="fieldName">username</param>
<paramname="minLength">6</param>
<paramname="maxLength">10</param>
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025版二手車(chē)買(mǎi)賣(mài)與車(chē)輛保險(xiǎn)代理合同4篇
- 2025年度面包磚施工進(jìn)度管理合同4篇
- 2025版住宅小區(qū)消防水源及供水系統(tǒng)改造合同范本3篇
- 2024版汽車(chē)銷(xiāo)售合同:汽車(chē)銷(xiāo)售公司向客戶(hù)銷(xiāo)售汽車(chē)及相關(guān)權(quán)益規(guī)定
- 2025年度純凈水瓶裝水環(huán)保材料研發(fā)與應(yīng)用合同4篇
- 二零二五年裝配式建筑技術(shù)工程師聘用合同范本大全3篇
- 2025年度交通事故現(xiàn)場(chǎng)勘查及鑒定服務(wù)合同4篇
- 2025年度新能源汽車(chē)補(bǔ)貼借款合同樣本4篇
- 二零二四年企業(yè)信息化規(guī)劃與實(shí)施合同3篇
- 2025彩鋼瓦材料采購(gòu)合同書(shū)(含環(huán)保檢測(cè))3篇
- 2025-2030年中國(guó)陶瓷電容器行業(yè)運(yùn)營(yíng)狀況與發(fā)展前景分析報(bào)告
- 二零二五年倉(cāng)儲(chǔ)配送中心物業(yè)管理與優(yōu)化升級(jí)合同3篇
- 2025屆廈門(mén)高三1月質(zhì)檢期末聯(lián)考數(shù)學(xué)答案
- 音樂(lè)作品錄制許可
- 拉薩市2025屆高三第一次聯(lián)考(一模)英語(yǔ)試卷(含答案解析)
- 開(kāi)題報(bào)告:AIGC背景下大學(xué)英語(yǔ)教學(xué)設(shè)計(jì)重構(gòu)研究
- 師德標(biāo)兵先進(jìn)事跡材料師德標(biāo)兵個(gè)人主要事跡
- 連鎖商務(wù)酒店述職報(bào)告
- 《實(shí)踐論》(原文)毛澤東
- 南潯至臨安公路(南潯至練市段)公路工程環(huán)境影響報(bào)告
- 初中數(shù)學(xué)校本教材(完整版)
評(píng)論
0/150
提交評(píng)論