比较全的Struts介绍04
第6部分
本文我們來討論一下Struts中的輸入校驗問題。我們知道,信息系統(tǒng)有垃圾進垃圾出的特點,為了避免垃圾數(shù)據(jù)的輸入,對輸入進行校驗是任何信息系統(tǒng)都要面對的問題。在傳統(tǒng)的編程實踐中,我們往往在需要進行校驗的地方分別對它們進行校驗,而實際上需要校驗的東西大多都很類似,如必需的字段、日期、范圍等等。因此,應(yīng)用程序中往往到處充斥著這樣一些顯得冗余的代碼。而與此形成鮮明對照的是Struts采用Validator框架(Validator框架現(xiàn)在是Jakarta Commons項目的一部分)來解決校驗問題,它將校驗規(guī)則代碼集中到外部的且對具體的應(yīng)用程序中立的.xml文件中,這樣,就將那些到處出現(xiàn)的校驗邏輯從應(yīng)用程序中分離出來,任何一個Struts應(yīng)用都可以使用這個文件,同時還為校驗規(guī)則的擴展提供了便利。更難能可貴的是由于Validator框架將校驗中要用到的一些消息等信息與資源綁定有機結(jié)合在一起,使得校驗部分的國際化編程變得十分的便捷和自然。
???? Validator框架大致有如下幾個主要組件:
????Validators:是Validator框架調(diào)用的一個Java類,它處理那些基本的通用的校驗,包括required、mask(匹配正則表達式)、最小長度、最大長度、范圍、日期等
????.xml配置文件:主要包括兩個配置文件,一個是validator-rules.xml,另一個是validation.xml。前者的內(nèi)容主要包含一些校驗規(guī)則,后者則包含需要校驗的一些form及其組件的集合。
????資源綁定:提供(本地化)標簽和消息,缺省地共享struts的資源綁定。即校驗所用到的一些標簽與消息都寫在ApplicationResources.properity文件中。
????Jsp tag:為給定的form或者action path生成JavaScript validations。
????ValidatorForm:它是ActionForm的一個子類。
???? 為了對Validator框架有一個比較直觀的認識,我們還是以前面的登陸例子的輸入來示范一下Validator框架的使用過程:
???? 首先,找一個validator-rules.xml文件放在mystruts/WEB-INF目錄下,下面是該文件中涉及到的required驗證部分代碼的清單:
| <validator name="required" <!--①-->classname="org.apache.struts.validator.FieldChecks"method="validateRequired"methodParams="java.lang.Object,org.apache.commons.validator.ValidatorAction,org.apache.commons.validator.Field,org.apache.struts.action.ActionErrors, javax.servlet.http.HttpServletRequest" <!--②-->msg="errors.required"> <!--③--><javascript><![CDATA[function validateRequired(form) {var isValid = true;var focusField = null;var i = 0;var fields = new Array();oRequired = new required();for (x in oRequired) {var field = form[oRequired[x][0]];if (field.type == 'text' ||field.type == 'textarea' ||field.type == 'file' ||field.type == 'select-one' ||field.type == 'radio' ||field.type == 'password') {var value = '';// get field's valueif (field.type == "select-one") {var si = field.selectedIndex;if (si >= 0) {value = field.options[si].value;}} else {value = field.value;}if (trim(value).length == 0) {if (i == 0) {focusField = field;}fields[i++] = oRequired[x][1];isValid = false;}}}if (fields.length > 0) {focusField.focus();alert(fields.join('/n'));}return isValid;}// Trim whitespace from left and right sides of s.function trim(s) {return s.replace( /^/s*/, "" ).replace( //s*$/, "" );}]]></javascript></validator> |
???? ① 節(jié)的代碼是引用一個服務(wù)器邊的驗證器,其對應(yīng)的代碼清單如下:
| public static boolean validateRequired(Object bean,ValidatorAction va, Field field,ActionErrors errors,HttpServletRequest request) {String value = null;if (isString(bean)) {value = (String) bean;} else {value = ValidatorUtil.getValueAsString(bean, field.getProperty());}if (GenericValidator.isBlankOrNull(value)) {errors.add(field.getKey(), Resources.getActionError(request, va, field));return false;} else {return true;} } |
???? ② 節(jié)是驗證失敗后的出錯信息,要將對應(yīng)這些鍵值的信息寫入到ApplicationResources.properity文件中,常見的錯誤信息如下:
| # Standard error messages for validator framework checks errors.required={0} is required. errors.minlength={0} can not be less than {1} characters. errors.maxlength={0} can not be greater than {1} characters. errors.invalid={0} is invalid. errors.byte={0} must be a byte. errors.short={0} must be a short. errors.integer={0} must be an integer. errors.long={0} must be a long. errors.float={0} must be a float. errors.double={0} must be a double. errors.date={0} is not a date. errors.range={0} is not in the range {1} through {2}. errors.creditcard={0} is an invalid credit card number. errors.email={0} is an invalid e-mail address. |
???? ③ 節(jié)的代碼用于客戶邊的JavaScript驗證
其次,在validation.xml文件中配置要驗證的form極其相應(yīng)的字段,下面是該文件中的代碼:
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation //DTD Commons Validator Rules Configuration 1.0//EN" "http://jakarta.apache.org/commons/dtds/validator_1_0.dtd"> <form-validation> <formset> <form name="userInfoForm"> <field property="username" depends="required,mask,minlength,maxlength"> <arg0 key="logon.jsp.prompt.username" resource="true"/> <arg1 name="minlength" key="${var:minlength}" resource="false"/> <arg1 name="maxlength" key="${var:maxlength}" resource="false"/> <var> <var-name>mask</var-name> <var-value>^/w</var-value> </var> <var> <var-name>minlength</var-name> <var-value>2</var-value> </var> <var> <var-name>maxlength</var-name> <var-value>16</var-value> </var> </field> <field property="password" depends="required,minlength,maxlength"> <arg0 key="logon.jsp.prompt.password" resource="true"/> <arg1 name="minlength" key="${var:minlength}" resource="false"/> <arg1 name="maxlength" key="${var:maxlength}" resource="false"/> <var> <var-name>minlength</var-name> <var-value>2</var-value> </var> <var> <var-name>maxlength</var-name> <var-value>16</var-value> </var> </field> </form> </formset> </form-validation> |
???? 這里要注意的是:該文中的 和 中的鍵值都是取自資源綁定中的。前面還講到了出錯信息也是寫入ApplicationResources.properity文件中,因此,這就為國際化提供了一個很好的基礎(chǔ)。
???? 再次,為了使服務(wù)器邊的驗證能夠進行,將用到的formBean從ActionForm的子類改為ValidatorForm的子類,即:
???? 將public class UserInfoForm extends ActionForm改為:public class UserInfoForm extends ValidatorForm
???? 到此,進行服務(wù)器邊的驗證工作已經(jīng)一切準備得差不多了,此時,只要完成最后步驟就可以實驗服務(wù)器邊的驗證了。但大多數(shù)情況下,人們總希望把這些基本的簡單驗證放在客戶邊進行。
???? 為了能進行客戶邊的驗證,我們還要對logon.jsp文件做適當(dāng)?shù)男薷摹?
???? 將
| <html:form action="/logonAction.do" focus="username"> |
改為
????
| <html:form action="/logonAction.do" focus="username" οnsubmit="return validateUserInfoForm(this)"> |
???? 在標簽后加上:
????
| <html:javascript dynamicJavascript="true" staticJavascript="true" formName="userInfoForm"/> |
???? 最后,對struts的配置文件struts-config.xml作適當(dāng)?shù)男薷?#xff1a;
???? 1、將
| <action input="/logon.jsp" name="userInfoForm"path="/logonAction" scope="session" type="action.LogonAction" validate="false" > |
改為
| <action input="/logon.jsp" name="userInfoForm" path="/logonAction" scope="session" type="action.LogonAction" validate="true" > |
其作用是要求進行校驗
???? 2、將下列代碼放在struts-config.xml文件中的標簽前。其作用是將用于校驗的各個組件結(jié)合在一起。
| <plug-in className="org.apache.struts.validator.ValidatorPlugIn"><set-property property="pathnames"value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml" /> </plug-in> |
???? 到此為止,我們的一切工作準備就緒,您可以享受自己的勞動成果了,試著輸入各種組合的用戶名和口令,看看它們的驗證效果。仔細體會你會發(fā)現(xiàn),服務(wù)器邊的驗證要更全面一些,比如對password的字符長度的驗證。
????參考文獻:
《Struts in Action》Ted Husted Cedric Dumoulin George Franciscus David Winterfeldt著
《Programming Jakarta Struts》Chuck Cavaness著
第7部分
上一篇文章中介紹校驗時提到客戶邊的校驗用到了JavaScript,實際上用Struts配合JavaScript還可以實現(xiàn)許多有用的功能,比如,級聯(lián)下拉菜單的實現(xiàn)就是一個典型的例子:
本例假設(shè)要實現(xiàn)的是一個文章發(fā)布系統(tǒng),我們要發(fā)布的文章分為新聞類和技術(shù)類,其中新聞類又分為時事新聞和行業(yè)動態(tài);技術(shù)類又分為操作系統(tǒng)、數(shù)據(jù)庫、和編程語言等,為了便于添加新的條目,所有這些都保存在數(shù)據(jù)庫表中。
為此,我們建立一個名為articleClass的表和一個名為articleSubClass的表。
| articleClass表的結(jié)構(gòu)如下: articleClassID字段:char類型,長度為2,主鍵 articleClassName字段:varchar類型,長度為20 articleSubClass表的結(jié)構(gòu)如下: articleClassID字段:char類型,長度為2 articleSubClassID字段:char類型,長度為2與articleClassID一起構(gòu)成主鍵 articleSubClassName字段:varchar類型,長度為20 |
表建好后,在articleClass表中錄入如下數(shù)據(jù):如,01、新聞類;02、技術(shù)類
在articleSubClass表中錄入:01、01、時事新聞;01、02、行業(yè)動態(tài);02、01、操作系統(tǒng)等記錄。到這里,數(shù)據(jù)庫方面的準備工作就已做好。
有了前面做登錄例子的基礎(chǔ),理解下面要進行的工作就沒有什么難點了,我們現(xiàn)在的工作也在原來mystruts項目中進行。首先,建立需要用到的formbean即ArticleClassForm,其代碼如下:
| package entity; import org.apache.struts.action.*; import javax.servlet.http.*; import java.util.Collection;public class ArticleClassForm extends ActionForm {//為select的option做準備private Collection beanCollection;private String singleSelect = "";private String[] beanCollectionSelect = { "" };private String articleClassID;private String articleClassName;private String subI;//子類所在行數(shù)private String subJ;//子類所在列數(shù)private String articleSubClassID;private String articleSubClassName;public Collection getBeanCollection(){return beanCollection;}public void setBeanCollection(Collection beanCollection){this.beanCollection=beanCollection;}public String getSingleSelect() {return (this.singleSelect);}public void setSingleSelect(String singleSelect) {this.singleSelect = singleSelect;}public String[] getBeanCollectionSelect() {return (this.beanCollectionSelect);}public void setBeanCollectionSelect(String beanCollectionSelect[]) {this.beanCollectionSelect = beanCollectionSelect;}public String getArticleClassID() {return articleClassID;}public void setArticleClassID(String articleClassID) {this.articleClassID = articleClassID;}public String getArticleClassName() {return articleClassName;}public void setArticleClassName(String articleClassName) {this.articleClassName = articleClassName;}public String getSubI() {return subI;}public void setSubI(String subI) {this.subI = subI;}public String getSubJ() {return subJ;}public void setSubJ(String subJ) {this.subJ = subJ;}public String getArticleSubClassID() {return articleSubClassID;}public void setArticleSubClassID(String articleSubClassID) {this.articleSubClassID = articleSubClassID;}public String getArticleSubClassName() {return articleSubClassName;}public void setArticleSubClassName(String articleSubClassName) {this.articleSubClassName = articleSubClassName;} } |
將它放在包entity中。其次,我們的系統(tǒng)要訪問數(shù)據(jù)庫,因此也要建立相應(yīng)的數(shù)據(jù)庫訪問對象ArticleClassDao,其代碼如下:
| package db;import entity.ArticleClassForm; import db.*; import java.sql.*;import java.util.Collection; import java.util.ArrayList; import org.apache.struts.util.LabelValueBean; public class ArticleClassDao {private Connection con;public ArticleClassDao(Connection con) {this.con=con;}public Collection findInUseForSelect(){PreparedStatement ps=null;ResultSet rs=null;ArrayList list=new ArrayList();String sql="select * from articleClass order by articleClassID";try{if(con.isClosed()){throw new IllegalStateException("error.unexpected");}ps=con.prepareStatement(sql);rs=ps.executeQuery();while(rs.next()){String value=rs.getString("articleClassID");String label=rs.getString("articleClassName");list.add(new LabelValueBean(label,value));}return list;}catch(SQLException e){e.printStackTrace();throw new RuntimeException("error.unexpected");}finally{try{if(ps!=null)ps.close();if(rs!=null)rs.close();}catch(SQLException e){e.printStackTrace();throw new RuntimeException("error.unexpected");}}}public Collection findInUseForSubSelect(){PreparedStatement ps=null;ResultSet rs=null;PreparedStatement psSub=null;ResultSet rsSub=null;int i=0;//大類記數(shù)器int j=0;//小類記數(shù)器String classID="";String subClassID="";String subClassName="";ArrayList list=new ArrayList();ArticleClassForm articleClassForm;String sql="select * from articleClass order by articleClassID";try{if(con.isClosed()){throw new IllegalStateException("error.unexpected");}ps=con.prepareStatement(sql);rs=ps.executeQuery();while(rs.next()){i++;classID=rs.getString("articleClassID");String sqlSub="select * from articleSubClass where articleClassID=? order by articleSubClassID";psSub=con.prepareStatement(sqlSub);psSub.setString(1,classID);rsSub=psSub.executeQuery();articleClassForm=new ArticleClassForm();articleClassForm.setSubI(""+i);articleClassForm.setSubJ(""+j);articleClassForm.setArticleSubClassID("請輸入一個小類");articleClassForm.setArticleSubClassName("請輸入一個小類");list.add(articleClassForm);while(rsSub.next()){subClassID=rsSub.getString("articleSubClassID");subClassName=rsSub.getString("articleSubClassName");j++;//optionStr="articleSubClassGroup[" + i + "][" + j + "]= new Option('"+ subClassName +"','"+ subClassID+ "')";articleClassForm=new ArticleClassForm();articleClassForm.setSubI(""+i);articleClassForm.setSubJ(""+j);articleClassForm.setArticleSubClassID(subClassID);articleClassForm.setArticleSubClassName(subClassName);list.add(articleClassForm);}j=0;}return list;}catch(SQLException e){e.printStackTrace();throw new RuntimeException("error.unexpected");}finally{try{if(ps!=null)ps.close();if(rs!=null)rs.close();}catch(SQLException e){e.printStackTrace();throw new RuntimeException("error.unexpected");}}} } |
將它保存在db目錄中。它們的目的是將文章的類和子類信息從數(shù)據(jù)庫表中讀出,以一定的格式保存在集合對象中以供頁面顯示。
再次,我們要建立相應(yīng)的jsp文件,文件名為selectArticleClass.jsp,代碼如下:
| <%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %> <html> <head> <title> 選擇文件類別 </title> </head> <body bgcolor="#ffffff"> <h3> 選擇文件所屬類型 </h3> <html:errors/> <table width="500" border="0" cellspacing="0" cellpadding="0"><tr><td><html:form name="articleClassForm" type="entity.ArticleClassForm"action="selectArticleClassAction.do"><table width="500" border="0" cellspacing="0" cellpadding="0"><tr><td align="right">文章大類*</td><td><html:select property="articleClassID" styleClass="word"οnchange="articleClassFormredirect(this.options.selectedIndex)"><html:option value="">請選擇一個大類</html:option><html:optionsCollection name="articleClassForm" property="beanCollection" styleClass="word"/></html:select></td></tr><tr><td align="right">文章小類*</td><td><select name="articleSubClassID" Class="word" ><option value="">請選擇一個小類</option></select><SCRIPT language=JavaScript><!--var articleSubClassGroups=document.articleClassForm.articleClassID.options.lengthvar articleSubClassGroup=new Array(articleSubClassGroups)for (i=0; i<articleSubClassGroups; i++)articleSubClassGroup[i]=new Array()<logic:iterate name="articleSubClassList" id="articleClassForm"scope="request" type="entity.ArticleClassForm">articleSubClassGroup[<bean:write name="articleClassForm"property="subI"/>][<bean:write name="articleClassForm"property="subJ"/>]=new Option("<bean:write name="articleClassForm"property="articleSubClassName"/>","<bean:write name="articleClassForm"property="articleSubClassID"/>")</logic:iterate>var articleSubClassTemp=document.articleClassForm.articleSubClassIDfunction articleClassFormredirect(x){for (m=articleSubClassTemp.options.length-1;m>0;m--)articleSubClassTemp.options[m]=nullfor (i=0;i<articleSubClassGroup[x].length;i++){articleSubClassTemp.options[i]=newOption(articleSubClassGroup[x][i].text,articleSubClassGroup[x][i].value)}articleSubClassTemp.options[0].selected=true}//--></SCRIPT></td></tr></table></html:form></td></tr> </table> </body> </html> |
這里值得重點關(guān)注的是其中的JavaScript代碼,有興趣的可以仔細分析一下它們是怎樣配合集合中的元素來實現(xiàn)級聯(lián)選擇的。
最后,為了例子的完整。我們將涉及到action代碼和必要的配置代碼在下面列出:其中,action的文件名為SelectArticleClassAction.java,代碼如下:
| package action; import entity.*; import org.apache.struts.action.*; import javax.servlet.http.*; import javax.sql.DataSource; import java.sql.Connection; import db.ArticleClassDao; import java.util.Collection; import java.sql.SQLException; public class SelectArticleClassAction extends Action {public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm,HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {/**@todo: complete the business logic here, this is just a skeleton.*/ArticleClassForm articleClassForm = (ArticleClassForm) actionForm;DataSource dataSource;Connection cnn=null;ActionErrors errors=new ActionErrors();try{dataSource = getDataSource(httpServletRequest,"A");cnn = dataSource.getConnection();ArticleClassDao articleClassDao=new ArticleClassDao(cnn);Collection col=articleClassDao.findInUseForSelect();articleClassForm.setBeanCollection(col);httpServletRequest.setAttribute("articleClassList",col);//處理子類選項Collection subCol=articleClassDao.findInUseForSubSelect();httpServletRequest.setAttribute("articleSubClassList",subCol);return actionMapping.findForward("success");}catch(Throwable e){e.printStackTrace();//throw new RuntimeException("未能與數(shù)據(jù)庫連接");ActionError error=new ActionError(e.getMessage());errors.add(ActionErrors.GLOBAL_ERROR,error);}finally{try{if(cnn!=null)cnn.close();}catch(SQLException e){throw new RuntimeException(e.getMessage());}}saveErrors(httpServletRequest,errors);return actionMapping.findForward("fail");} } |
將其保存在action目錄中。
在struts-config.xml文件中做如下配置:
在
| <form-beans> |
| <form-bean name="articleClassForm" type="entity.ArticleClassForm" /> |
在
| ><action-mappings> |
| <action name="articleClassForm" path="/selectArticleClassAction" scope="session"type="action.SelectArticleClassAction" validate="false"> <forward name="success" path="/selectArticleClass.jsp" /> <forward name="fail" path="/genericError.jsp" /> </action> |
為了對應(yīng)配置中的
| <forward name="fail" path="/genericError.jsp" /> |
| <%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <html> <head> <title> genericError </title> <link href="css/mycss.css" rel="stylesheet" type="text/css"> </head> <body bgcolor="#ffffff"> <html:errors/> </body> </html> |
現(xiàn)在一切就緒,可以編譯執(zhí)行了。在瀏覽器中輸入:http://127.0.0.1:8080/mystruts/selectArticleClassAction.do就可以看到該例子的運行結(jié)果了。(T111)
本文作者:張永美 羅會波 湖北省當(dāng)陽市國稅局 可通過lhbf@sina.com與他們聯(lián)系
總結(jié)
以上是生活随笔為你收集整理的比较全的Struts介绍04的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ECharts学习--调色盘
- 下一篇: Java脚本数组复制