1. 輸入校驗章節目錄 輸入校驗概述 客戶端校驗 伺服器端校驗 手動編程校驗 重寫validate方法 重寫validateXxx()方法 輸入校驗流程 校驗框架校驗 Struts2 內置的校驗器 常用的內置校驗器的配置 客戶端校驗 伺服器端校驗 重寫validate方法 重寫validateXxx ...
1. 輸入校驗章節目錄
- 輸入校驗概述
- 客戶端校驗
- 伺服器端校驗
- 手動編程校驗
- 重寫validate方法
- 重寫validateXxx()方法
- 輸入校驗流程
- 校驗框架校驗
- Struts2 內置的校驗器
- 常用的內置校驗器的配置
2. 詳細內容
2.1 輸入校驗概述
輸入校驗分為客戶端校驗和伺服器端校驗,客戶端校驗主要是過濾正常用戶的誤操作,主要通過JavaScript代碼完成;伺服器端校驗是整個應用阻止非法數據的最後防線,主要通過在應用中編程實現。
2.1.1 客戶端校驗
大多數情況下,使用JavaScript進行客戶端校驗的步驟如下:
- 編寫校驗函數;
- 在提交表單的事件中調用校驗函數;
- 根據校驗函數來判斷是否進行表單提交;
下麵通過一個簡單的示例講解使用JavaScript進行客戶端校驗的方法,具體代碼如下所示:
<%-- Created by IntelliJ IDEA. User: mairr Date: 17-12-5 Time: 下午10:07 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page language = "java" import = "java.util.*" pageEncoding="utf-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <html> <head> <title>註冊界面</title> <script type="text/javascript" > // 去掉前後的空格 function deltrim(x) { while (x.length > 0 && x.charAt(0) == ' ') x = x.substring(1, x.length); while (x.length > 0 && x.charAt(x.length - 1) == ' ') x = x.substring(0, x.length - 1); return x; } // 非空驗證 function isNULL(elem,message){ var va = deltrim(elem.value); if(va == " ") { alert(message); elem.focus(); return false; } return true; } // 驗證帳號,帳號只能是小寫字母數字,並且只能以字母開頭 function validateId(){ var first = document.forms[0].id.value.charAt(0); var exp = /^[a-z0-9]+$/; if(isNULL(document.forms[0].id,"請輸入帳號")){ // 驗證非空 // 驗證首字元 if((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z')){} else{ alert("帳號首字元必須是字母!"); document.forms[0].id.focus(); return false; } if(!exp.test(document.forms[0].id.value)){ alert("帳號必須是字母或者數字!"); document.forms[0].id.focus(); return false; } return true; } else{ return false; } } // 驗證密碼,密碼要在8位以上,且需要有字母或者數字之外的字元 function validatepwd(){ var exp = /^[a-z0-9]+$/; if(isNULL(document.forms[0].pwd," 請輸入密碼")){ //驗證非空 if(document.forms[0].pwd.value.length <= 8){ alert("密碼大於8位"); document.forms[0].pwd.focus(); return false; }else{ if(exp.test(document.forms[0].pwd.value)){ alert("密碼要有字母和數字之外的字元!"); document.forms[0].pwd.focus(); return false; } } }else{ return false; } if(document.forms[0].pwd.value != document.forms[0].repwd.value) { alert("兩次密碼不一樣!"); document.forms[0].pwd.focus(); return false; } return true; } // 驗證郵箱,右邊為六位數子 function checkcode() { var exp = /^[0-9]+$/; if(isNULL(document.forms[0].ecode,"請輸入郵編")){ // 驗證非空 if(document.forms[0].ecode.value.length != 6){ alert("郵編為6位"); document.forms[0].ecode.focus(); return false; }else{ if(!exp.test(document.forms[0].ecode.value)){ alert("郵編為數字"); document.forms[0].ecode.focus(); return false; } } return true; }else{ return false; } } // 驗證E-mail的基本格式 function checkEmail(){ var exp = /^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/; if(isNULL(document.forms[0].email,"請輸入Email")){ // 驗證非空 if(!exp.test(document.forms[0].email.value)){ alert("Email格式錯誤"); document.forms[0].email.focus(); return false; } return true; }else{ return false; } } // 提交按鈕 function gogo(){ if(validateId() && validatepwd() && checkcode() && checkEmail()){ document.forms[0].submit(); return true; } return false; } </script> </head>
<body> <s:form action ="" theme="simple"> <table> <tr> <td>登錄帳號</td> <td><s:textfield name="id"/></td> </tr> <tr> <td>密碼</td> <td><s:password name="pwd"/></td> </tr> <tr> <td>確認密碼</td> <td><s:password name="repwd"/></td> </tr> <tr> <td>郵編</td> <td><s:textfield name = "ecode"/></td> </tr> <tr> <td>Mail</td> <td><s:textfield name = "email"/></td> </tr> <tr> <td><input type="button" value="提交" onclick="return gogo()" /></td> <td><s:reset value = "重置"/></td> </tr> </table> </s:form> </body>
</html>
上述的校驗過程中,建立了一個Struts2的項目(前面幾篇博文有介紹),JSP校驗頁面中運用了部分struts2的標簽。由上述JSP程式,執行結果有如下幾種情況:
(1) 頁面:
(2) 客戶端校驗結果:
客戶端校驗可以過濾用戶的錯誤操作,是第一道防線,一般使用JavaScript代碼實現。僅有客戶端校驗是不夠的。攻擊者可以繞過客戶端校驗直接進行非法輸入,這樣會引起系統的異常,為了確保數據的合法性,防止用戶通過非正常手段提交錯誤信息,所以必須加上伺服器驗證。
2.1.2 伺服器端校驗
伺服器對於系統的安全性、完整性、健壯性起到至關重要的作用。Struts2框架提供了一套驗證框架,通過驗證框架能夠非常簡單和快速地完成輸入校驗。
在伺服器端,對於輸入校驗Struts2提供了兩種實現方法:一是採用手工編寫代碼實現;另外一種是,給予XML配置方式的實現(校驗框架校驗)。接下來詳細介紹這兩種方法。
2.2 手動編程校驗
手動編程校驗主要是通過在類中編寫校驗邏輯代碼,有兩種方式i:一是在Action類中重寫validate()方法;二是在Action類中重寫validateXxx()方法。
2.2.1 重寫validate方法
validate()方法會校驗Action中所有與execute()方法簽名相同的方法。當某個數據校驗失敗時,在validate()方法中應該調用addFiledError()方法向系統fieldErrors添加校驗失敗信息。為了使用addFileError方法,Action類需要繼承ActionSupport。
如果系統的fieldErrors包含失敗信息,Struts2會將請求轉發到名為input的result。在input視圖中可以通過<s:fielderror/>標簽失敗信息。
下麵通過一個簡單示例講解如何重寫validate()方法進行輸入校驗。
(1) 創建一個JSP頁面login.jsp,要求驗證所有輸入項不能為空、密碼長度6~12位以及兩次密碼一樣(不運用javascript的客戶端校驗),具體代碼如下所示:
<%-- Created by IntelliJ IDEA. User: mairr Date: 17-12-6 Time: 下午9:39 To change this template use File | Settings | File Templates. --%> <%@ page language="java" import="java.util.*" pageEncoding="utf-8" %> <%@ taglib prefix="s" uri="/struts-tags" %> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <html> <head> <base href="<%=basePath%>"> </head> <body> <s:form action="login" theme="simple"> <table> <tr> <td>登陸帳號</td> <td><s:textfield name = "id"/></td> </tr> <tr> <td>密碼</td> <td><s:password name = "pwd"/></td> </tr> <tr> <td>確認密碼</td> <td><s:password name = "repwd"/></td> </tr> <tr> <td><s:submit value= "提交"/></td> <td><s:reset value = "重置"/></td> </tr> </table> <!--顯示this.addFieldError("id","id不能為空")的信息--> <s:fielderror fieldName="id"/> <!--顯示所有校驗失敗信息--> <s:fielderror/> </s:form> </body> </html>
(2) 創建Action類LoginAction.java,在該類中重寫validate()方法,具體代碼如下“
package action; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport { private String id; private String pwd; private String repwd; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } public String getRepwd() { return repwd; } public void setRepwd(String repwd) { this.repwd = repwd; } // 重寫validate方法,進行輸入校驗,該方法在execute方法之前執行 @Override public void validate() { if (id == null || id.trim().equals(" ")) { this.addFieldError("id", "id不能為空"); } if (pwd == null || pwd.trim().equals(" ")) { this.addFieldError("pwd", "密碼不能為空"); } else { if (pwd.length() < 6 || pwd.length() > 12) { this.addFieldError("pwdlength", "密碼的長度在6~12位之間"); } } if (!pwd.equals(repwd)) { this.addFieldError("pwdsame", "兩次密碼不一致"); } } // 實現登陸業務處理 @Override public String execute() { return SUCCESS; } }
(3) 配置Struts2的action,具體代碼如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN" "http://struts.apache.org/dtds/struts-2.5.dtd"> <struts> <package name="default" namespace="/" extends="struts-default"> <action name="login" class="action.LoginAction"> <result name="input">/login.jsp</result> </action> </package> </struts>
(4) web.xml配置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
(5) 運行login.jsp頁面,如果輸入非法信息則輸出校驗結果如下所示:
2.2.2 重寫validateXxx()方法
validateXxx()只會校驗Action中方法名為Xxx()的方法,其中Xxx的第一個字母要大寫。重寫validateXxx()方法進行輸入校驗與重寫validate()方法基本一樣,唯一不同的就是校驗的方法名不同。
將上面一個例子重寫為validateXxx()方法進行輸入校驗,則需要修改Action類和配置文件。
- 修改後的Action類的代碼如下:
package action; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport { private String id; private String pwd; private String repwd; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } public String getRepwd() { return repwd; } public void setRepwd(String repwd) { this.repwd = repwd; } // 重寫validateLogin方法,進行輸入校驗 public void validateLogin() { if (id == null || id.trim().equals(" ")) { this.addFieldError("id", "id不能為空"); } if (pwd == null || pwd.trim().equals(" ")) { this.addFieldError("pwd", "密碼不能為空"); } else { if (pwd.length() < 6 || pwd.length() > 12) { this.addFieldError("pwdlength", "密碼的長度在6~12位之間"); } } if (!pwd.equals(repwd)) { this.addFieldError("pwdsame", "兩次密碼不一致"); } } // 實現登陸業務處理 public String login() { return SUCCESS; } }
- 修改後的配置文件struts.xml如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN" "http://struts.apache.org/dtds/struts-2.5.dtd"> <struts> <package name="default" namespace="/" extends="struts-default"> <action name="login" class="action.LoginAction" method="login"> <result name="input">/login.jsp</result> </action> </package> </struts>
- 結果是一致的:
2.2.3 輸入校驗的流程
經過前面講解,可以知道,Struts2輸入校驗需要經過一下幾個步驟:
- 類型轉器對請求參數執行類型轉換,並且把轉換後的值賦給Action中的屬性。
- 如果在執行轉換過程中出現了異常,系統會把異常信息保存到ActionContext , conversionError攔截器將異常信息添加到fieldError里。不管類型轉換是否出現異常,都會進入步驟三;
- 系統通過反射技術先調用Action中的validateXxx()方法,Xxx為方法名字。
- 再調用Action中的validate()方法;
- 經過上面的4個步驟,如果系統中的fieldError存在錯誤信息(即存放錯誤信息的集合的size大於0),系統自動將請求轉發至名稱為input的視圖。如果系統中的fileError沒有任何錯誤信息,系統將執行Action中的處理方法。
2.3 校驗框架校驗
使用Struts2校驗框架的好處是將校驗邏輯放到配置文件中,實現校驗邏輯代碼與業務邏輯代碼的分離。使用基於校驗框架校驗方式實現輸入校驗時,Action也需要繼承ActionSupport,並且提供校驗文件。同樣框架校驗的方式也有2種:一是校驗Action中所有與execute方法簽名相同的方法;二是校驗Action中某個與execute方法簽名相同的方法。
2.3.1 Struts2內置的校驗器
Struts2框架提供的內置校驗器如下:(多看幾遍,還蠻重要的)
- required:必填校驗器,要求field的值不能為null;
- requiredstring:必填字元串校驗器,要求field的值不能為null,並且長度大於0,預設情況下會對字元串去掉前後空格;
- stringlength:字元串長度校驗器,要求field的值必須在指定的範圍內,否則校驗失敗;miniLength參數指定最小長度,maxLength參數指定最大長度,trim參數指定校驗field之前是否去掉字元串前後空格;
- regex:正則表達式校驗器,檢查被校驗的field是否匹配一個正則表達式。expression參數指定正則表達式, caseSensitive參數指定進行正則表達式匹配時,是否區分大小寫,預設值為true;
- int:整數校驗器,要求field的整數值必須在指定範圍內,mini指定最小值,max最大值;
- double:雙精度浮點數校驗器,要求field的雙進度浮點數必須在指定範圍內,mini指定最小值,max最大值;
- fieldexpression:欄位OGNL表達式校驗器,要求field滿足一個OGNL表達式,expression參數指定一個OGNL表達式,該邏輯表達式基於ValueStack進行求值,返回true時校驗通過,否則不通過。該校驗器只能用於<filed-validator>;
- email:郵件地址校驗器,要求如果field的值非空,則必須是合法的郵件地址;
- url:網址校驗器,要求如果field的值非空,則必須是合法的URL地址i;
- date:日期校驗器,要求field的日期值必須在指定的範圍內,mini指定最小值,max指定最大值;
- conversion:轉換校驗器,指定在類型轉換失敗時,提示錯誤信息;
- visitor:用於校驗Action中的複合屬性,指定一個校驗文件用於校驗複合中的屬性;
- expression:OGNL表達式表達式校驗,expression參數指定OGNL表達式,該邏輯表達式基於ValueStack進行求值,返回true時校驗通過,否則不通過,該校驗器不用在欄位校驗器的配置中,只能用於<validator>.
2.3.2 常用內置校驗器的配置
對於Struts2校驗框架來說,一般有兩種方式來配置校驗器:
- 使用<validator>
- 使用<field-validator>
當<validator>的子節點中配置了<param name="fieldName">用於指定某個屬性進行校驗時,則達到的效果與<field-validator>是一樣的。如下所示:(兩種配置方式是等效的)
<!--校驗user.id屬性時,用<validator>來配置--> <validator type="required"> <s:param name="fieldName">user.id</s:param> <message>用戶的ID不能為空!</message> </validator> <!--------方式二 -----> <field name="user.id"> <field-validator type ="required"> <message>用戶的ID不能為空!</message> </field-validator>
</field>
下麵簡單介紹幾種常用的內置校驗器的配置示例:
(1) required(必填校驗器)
<field-validator type ="required"> <message>用戶的ID不能為空!</message> </field-validator>
(2) requiredstring(必填字元串校驗器)
<field-validator type ="requiredstring"> <param name ="trim">true</param> <message>用戶的ID不能為空!</message> </field-validator>
(3) stringlength(字元串長度校驗器)
<field-validator type ="stringlength"> <param name = "maxlength">12</param> <param name = "minilength">6</param> <message>密碼必須在6~12位之間</message> </field-validator>
(4) email(郵件地址校驗器)
<field-validator type ="email"> <message>郵箱格式不正確</message> </field-validator>
(5) regex(正則表達式校驗器)
<field-validator type ="regex"> <param name="expression"><![CDATA[^1[3578]\d{9}$]]></param> <message>手機號格式不正確</message> </field-validator>
(6) int(整數校驗)
<param type ="int"> <param name="max">100</param> <param name="mini">0</param> <message>年齡必須在0~100之間</message> </field-validator>
(7) 欄位OGNL表達式校驗器
<param type ="int"> <param name="expression"><![CDATA[imagefile.length() <=0 ]]></param> <message>文件不能為空</message> </field-validator>
基於Struts2框架的校驗主要是以上內容,這是Struts2框架應用比較多的一個版塊,比較重要的內容!