Struts2輸入校驗之validate輸入校驗方式
一.在Web系統專案中有大量的檢視頁面需要使用者自行輸入很多資料。這些資料的型別有很多種。為了防止某些客戶的惡意輸入以及對Web專案的惡意破壞,必須引入輸入校驗,像Windows作業系統的防火牆一樣把一些垃圾資料過濾掉,擋在Web系統之外。接下來就來介紹一下validate輸入校驗方式:
1.validate方法進行輸入校驗:這裡直接附上一個簡單的使用者註冊功能具體介紹利用validate方法對數字、字串、日期等型別資料進行輸入校驗方式介紹:
(1).首先,新建一個Struts2專案InputValidate,專案結構圖如下:
(2).新建一個註冊頁面,register.jsp頁面,用於輸入校驗的輸入資料,程式碼如下:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ taglib uri="/struts-tags" prefix="s"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'register.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <s:form action="register" namespace="/"> <s:textfield name="username" label="使用者名稱"></s:textfield> <s:password name="password" label="密碼"></s:password> <s:password name="password1" label="密碼確認"></s:password> <s:textfield name="birthday" label="生日"></s:textfield> <s:textfield name="mobile" label="手機號碼"></s:textfield> <s:textfield name="age" label="年齡"></s:textfield> <s:submit value="註冊"></s:submit> </s:form> </body> </html>
(3).新建一個Action類,RegisterAction類,程式碼如下:
package com.gk.action; import java.util.Date; import com.opensymphony.xwork2.ActionSupport; public class RegisterAction extends ActionSupport { private String username; private String password; private String password1; private Date birthday; private String mobile; private int age; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPassword1() { return password1; } public void setPassword1(String password1) { this.password1 = password1; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String execute() { return SUCCESS; } public void validate() { if (getUsername() == null || getUsername().trim().equals("")) { addFieldError("username", "請輸入使用者名稱"); } if (getPassword() == null || getPassword().trim().equals("")) { addFieldError("password", "請輸入密碼"); } if (getPassword1() == null || getPassword1().trim().equals("")) { addFieldError("password1", "請輸入確認密碼"); } if (!getPassword().equals(getPassword1())) { addFieldError("password", "密碼和輸入密碼不一致"); } if (getBirthday() == null) { addFieldError("birthday", "請輸入生日日期"); } else if (getBirthday().after(new Date())) { addFieldError("birthday", "請不要輸入未來日期"); } if (getMobile().length() != 11) { addFieldError("mobile", "請輸入正確的手機號碼"); } if (getAge() < 1 || getAge() > 120) { addFieldError("age", "請輸入正確年齡"); } } }
(4).接著配置一下struts.xml檔案,成功跳轉success.jsp頁面,程式碼如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
<constant name="struts.devMode" value="true"></constant>
<package name="input" namespace="/" extends="struts-default">
<action name="register" class="com.gk.action.RegisterAction">
<result name="success">/success.jsp</result>
<result name="input">/register.jsp</result>
</action>
</package>
</struts>
(5).接下來附上success.jsp的程式碼,用來輸出註冊成功後的資訊:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'success.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
使用者名稱為:
<s:property value="username" />
<br /> 密碼為:
<s:property value="password1" />
<br /> 生日為:
<s:property value="birthday" />
<br /> 手機號碼為:
<s:property value="mobile" />
<br /> 年齡為:
<s:property value="age" />
</body>
</html>
不輸入任何資料,點選註冊按鈕,如下圖所示:
輸入密碼不一致時和生日日期不合法時,如下圖所示:
(7).對以上程式碼進行解釋:
— Struts2對輸入校驗這方面採用的最基本的方法是在每個Action裡繼承ActionSupport類,並且重寫它的輸入校驗方法validate()。上述例子中的RegisterAction程式碼中顯示,根據頁面上輸入的各種校驗將所有不符合輸入校驗規則的錯誤資訊都由ActionSupport類中另一方法addFieldError方法將錯誤資訊加入到表單錯誤資訊,並且在輸入資料的頁面顯示,而不會再由Action導航到註冊成功頁面。struts.xml也定義了一個名字為"input"的result,它表明將所有輸入失敗的錯誤資訊導航到一個特定頁面。上述例子將這個特定頁面定義為資料輸入的頁面。
— 再次閱讀RegisterAction程式碼,可以發現在validate方法裡編寫了很多if語句,每一個if語句中都針對表單中某一欄位進行輸入校驗。如果發現不符合輸入校驗規則都呼叫addFieldError方法。該方法中有兩個引數,第一個引數都是表單中欄位名,這裡所有的名字和輸入資料的頁面中每一個欄位的name屬性中內容相同。否則Struts2是找不到具體錯誤資訊是針對哪一個欄位。這些內容就是在輸入校驗失敗時候顯示在之前所說的特定頁面中的。
— validate方法中的各個if語句判斷了表單中各個欄位的輸入資料是否符合輸入校驗的規則,這些規則也是開發人員根據特定業務邏輯定義的。比如其中資料是否輸入,輸入的生日資訊是否在當前日期之前等等。這裡又可以發現並沒有對這些欄位進行型別轉換,但在Action中某些欄位型別都已經變成Java的一些基本型別。比如生日欄位,頁面上輸入時候是字串,在Action中已經變成Java中的Date型別。頁面上輸入的資料已經都由字串型別轉換成Action中指定的Java型別。
— 而輸入生日時因為Struts2通過內建的型別轉換器進行型別轉換,轉換失敗所以提示Invalid field value for field “birthday”資訊。
2.validateXXX方法進行輸入校驗:這裡我們將上面那個InputValidate專案裡的一些程式碼進行修改,看下如何利用validateXXX方法對Action中某一特定的方法進行校驗。
(1).首先,修改InputValidate專案的register.jsp頁面,只是表單的action屬性改為register!register.action,即動態呼叫action,修改後如下:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'register.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body><s:fielderror></s:fielderror>
<s:form action="register!register.action" namespace="/">
<s:textfield name="username" label="使用者名稱"></s:textfield>
<s:password name="password" label="密碼"></s:password>
<s:password name="password1" label="密碼確認"></s:password>
<s:textfield name="birthday" label="生日"></s:textfield>
<s:textfield name="mobile" label="手機號碼"></s:textfield>
<s:textfield name="age" label="年齡"></s:textfield>
<s:submit value="註冊"></s:submit>
</s:form>
</body>
</html>
(2).接著修改一下RegisterAction這個類,裡面寫了一個方法register和validateRegister方法,其中手機號碼那裡使用了正則表示式來驗證手機號的正確性,修改後程式碼如下:
package com.gk.action;
import java.util.Date;
import com.opensymphony.xwork2.ActionSupport;
public class RegisterAction extends ActionSupport {
private String username;
private String password;
private String password1;
private Date birthday;
private String mobile;
private int age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword1() {
return password1;
}
public void setPassword1(String password1) {
this.password1 = password1;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String register() {
return SUCCESS;
}
public void validateRegister() {
if (getUsername() == null || getUsername().trim().equals("")) {
addFieldError("username", "請輸入使用者名稱");
}
if (getPassword() == null || getPassword().trim().equals("")) {
addFieldError("password", "請輸入密碼");
}
if (getPassword1() == null || getPassword1().trim().equals("")) {
addFieldError("password1", "請輸入確認密碼");
}
if (!getPassword().equals(getPassword1())) {
addFieldError("password", "密碼和輸入密碼不一致");
}
if (getBirthday() == null) {
addFieldError("birthday", "請輸入生日日期");
} else if (getBirthday().after(new Date())) {
addFieldError("birthday", "請不要輸入未來日期");
}
if (getMobile().isEmpty()) {
addFieldError("mobile", "手機號碼不為空");
} else if (!getMobile().matches("\\d*")) {
addFieldError("mobile", "手機號碼錯誤");
} else if (getMobile().length() != 11) {
addFieldError("mobile", "請輸入正確的手機號碼");
}
if (getAge() < 1 || getAge() > 120) {
addFieldError("age", "請輸入正確年齡");
}
}
}
(3).其它保持不變,重新部署此專案和開啟伺服器後,不輸入任何資料,點選註冊按鈕,其位址列發生變化,如下圖:
密碼輸入不一致和生日型別轉換失敗,手機號碼不正確的話,如下圖所示:
(4).對以上程式碼解釋:
— Struts2中除了validate方法之外它還有1種validateXXX方法針對Action中某一特定方法進行該方法的各種欄位的輸入校驗。其中XXX就是該特定方法名。在本示例中定義了一個register方法,該方法和上一小節中的execute方法類似只是一個簡單的導航。但是在該registerAction中就沒有了validate方法,取而代之的是validateRegister方法。
注意:如果使用validateRegister方法,那最好不要再使用validate方法。雖然和上一小節示例程式碼比較這兩個方法裡的內容是完全一摸一樣的,但是validate方法是對所有Action中方法的輸入校驗都進行校驗,validateRegister方法只對register方法進行校驗。因此兩者不能重複使用,都使用會造成兩個方法都進行了校驗的結果。執行順序是先validateRegister後validate。如果validateRegister方法有特殊的輸入校驗則就會被validate方法“覆蓋”,因此達不到預期的輸入校驗目的。
— validateRegister方法中各個if語句定義和上一小節的validate方法內容相同。這裡只是作為示例所以兩個方法中的內容相同,其實可以和上一小節中的validate方法的內容不相同,用來進行register方法中特定的表單欄位輸入校驗。
— 在資料輸入的檢視介面又增加了Struts2的標籤fielderror。在表單頭部也有出錯資訊顯示。這其實和Struts2的校驗順序有關。
在之前說明validateRegister方法和validate方法時候也記述了兩者的執行校驗順序是先validateRegister後validate。其實在檢視介面進行表單提交後。輸入校驗順序是以如下的順序:
查詢Action中是否有validateXXX方法。如果有則執行該方法。將校驗產生的錯誤資訊放置到ActionContext物件中。
查詢Action中是否有validate方法。如果有則執行該方法。將校驗產生的錯誤資訊放置到ActionContext物件中。
查詢檢視介面是否有fielderror標籤定義。如果有則返回到result為“input”的檢視。同時ActionContext物件中有關的輸入校驗的錯誤資訊也顯示在該檢視中。
Struts2的輸入校驗順序就是按照如上說明來先後執行的,這也更好的說明了validateRegister方法和validate方法並存在Action時候輸入校驗是如何進行的。