10.2.2 常用的用戶輸入驗證實現方式
10.2.1中雖然實現了用戶登陸功能的,用戶輸入驗證。但是這種方式卻很少被使用。本節中介紹實際應用中較爲常見的編碼方式。代碼實現進需要修改Action類,其餘文件的內容無需修改。
代碼10-1中登陸案例代碼編寫中將用戶輸入驗證的代碼實現放到execute方法中,這種方法雖然容易被讀者理解。但是從代碼設計角度來看存在execute方法過於臃腫、不利於代碼的重用等問題。更爲常見的代碼實現方式,則是重寫ActionSupport類中的validate方法,在該方法中完成用戶輸入驗證。具體代碼如下所示:
packagecom.study.erp.action;
importcom.opensymphony.xwork2.ActionSupport;
public class LoginAction extendsActionSupport{
private String username;
private String password;
//此處省略屬性對應的get和set方法
….
@Override
public void validate() {
if(username == null || username.trim().equals("")){
addFieldError("username", "用戶名不能爲空.");
}
if(password == null || password.trim().equals("")){
addFieldError("password", "密碼不能爲空.");
}else if(password.length()<6 || password.length()>12){
addFieldError("password", "密碼長度應在6到12位之間.");
}
}
public String execute(){
return "success";
}
}
代碼10-4用戶登陸功能LoginAction
比較上述10-4代碼和10-1代碼讀者可以發現,10-4的內容更加簡潔。當進行用戶輸入驗證時,該驗證代碼編寫到validate方法。該方法中如果發現用戶輸入錯誤時,將錯誤信息添加到框架FieldError中即可。在進行完所有的用戶輸入驗證後,無需用戶編碼實現頁面的跳轉。框架會驗證用戶輸入驗證是否正確,如果正確會繼續執行execute方法,如果錯誤會跳轉到該Action對應的名爲input的結果視圖中。
本節案例中的代碼實現,是Struts框架下基於編碼方式實現用戶輸入驗證所提倡的方式。讀者在編寫時常見的錯誤是沒有在配置文件中配置名爲input的結果視圖,其配置文件的代碼爲:<result name="input">/xxx.jsp</result>。
10.2.3 多方法Action的用戶輸入驗證實現方式
在學習第二章Action的編寫和配置時,我們已經瞭解到Struts2的Action類中可以包含多個方法,每個方法用來完成不同的邏輯操作。例如,我們可以利用同一個Action來完成一組邏輯相關的操作:用戶登陸、用戶註冊、用戶信息修改和用戶信息刪除。代碼實現時需要在一個Action類中需要包括4個方法,但是對於這4個方法來說用戶輸入校驗的規則也是不同的,如果再使用10.2.2所講的validate方法來實現用戶輸入驗證,很難實現預期的效果。
Struts2框架對於這類情況也提供了相應的解決方案。當Action中包括多個邏輯操作方法時,爲完成用戶輸入驗證Action類的編碼須實現Validateable接口(ActionSupport類已經實現了Validateable接口)並編寫validateXxx方法,Xxx即對應Action邏輯操作方法的名字。Struts2框架利用了反射機制在對應的邏輯操作方法執行之前調用相應的validateXxx方法。
爲了讓讀者更容易讀懂本節中的代碼,本案例中僅實現了用戶註冊和用戶登陸功能的用戶輸入校驗。用戶登陸的用戶輸入驗證規則不變,用戶註冊功能的用戶輸入驗證規則包括:用戶名不能爲空、密碼不能爲空、密碼長度必須在6到12位之間、年齡的輸入範圍必須在0-100之間,郵箱必須包括@字符。
用戶登陸功能圖示與圖10-1,10-2,10-3一致,以下爲用戶註冊功能截圖:
(1) 當在頁面上只輸入年齡-11,郵箱爲11時
圖10-3 用戶註冊功驗證錯誤1
(2) 當在頁面上輸入用戶名爲11,密碼爲11,年齡爲-11,郵箱爲11時:
圖10-4 用戶註冊功驗證錯誤2
圖10-5 用戶註冊功驗證成功
以下爲【用戶登陸功能】、【用戶註冊功能】實現的代碼結構:
圖10-6 用戶登陸、用戶註冊功驗證代碼結構
編寫該功能時用戶需要編寫和創建的文件:
文件名
|
說明
|
備註
|
Login.jsp
|
用戶登陸頁面
|
視圖
|
LoginSuccess.jsp
|
用戶登陸成功頁面
|
視圖
|
Regist.jsp
|
用戶註冊頁面
|
視圖
|
RegistSuccess.jsp
|
用戶註冊成功頁面
|
視圖
|
UserAction
|
Action類
|
控制器
|
struts.xml
|
Struts2框架的配置文件
|
配置文件
|
web.xml
|
項目的部署描述文件
|
配置文件
|
由於篇幅的關係,以下僅列出UserAction類,Regist.jsp和struts.xml文件的部分代碼。其它代碼參考光盤中Unit10文件夾下03的項目代碼。
UserAction類包含兩個邏輯,因此包含了兩個邏輯方法分別是login和regist。login方法用於實現用戶登陸功能,對應的用戶輸入校驗方法爲validateLogin方法;regist方法用於實現用戶註冊功能,對應的用戶輸入校驗方法爲validateRegist方法。具體代碼如下所示:
packagecom.study.erp.action;
importcom.opensymphony.xwork2.ActionSupport;
public class UserActionextends ActionSupport{
private String username;
private String password;
private int age;
private String email;
//此處省略屬性對應的get和set方法
….
//用戶登陸功能對應的用戶輸入校驗方法
public void validateLogin() {
if(username == null || username.trim().equals("")){
addFieldError("username","用戶名不能爲空.");
}
if(password == null || password.trim().equals("")){
addFieldError("password", "密碼不能爲空.");
}else if(password.length()<6 || password.length()>12){
addFieldError("password", "密碼長度應在6到12位之間.");
}
}
//用戶註冊功能對應的用戶輸入校驗方法
public void validateRegist() {
if(username == null || username.trim().equals("")){
addFieldError("username", "用戶名不能爲空.");
}
if(password == null || password.trim().equals("")){
addFieldError("password", "密碼不能爲空.");
}else if(password.length()<6 || password.length()>12){
addFieldError("password", "密碼長度應在6到12位之間.");
}
if(age <0 || age>100){
addFieldError("age", "年齡不符合要求.");
}
if(email.indexOf("@") == -1){
addFieldError("email", "Email格式不符合要求.");
}
}
public String login(){
return "success";
}
public String regist(){
return "success";
}
}
以上代碼中用戶輸入校驗方法名編寫時務必注意: 1.爲validateXxx方法,方法名Xxx爲對應的邏輯方法方法名,首字母大寫。2.
方法的權限爲public,方法沒有參數,返回值爲void類型。
struts.xml文件中當前的Action類對應的每個action配置都需要包含名爲“input”的結果視圖,具體的配置信息如下所示:
<?xml version="1.0"encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTDStruts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="default"namespace="/" extends="struts-default">
<action name="login"class="com.study.erp.action.UserAction" method="login">
<result name="input">/Login.jsp</result>
<result name="success">/LoginSuccess.jsp</result>
</action>
<action name="regist"class="com.study.erp.action.UserAction" method="regist">
<result name="input">/Regist.jsp</result>
<result name="success">/RegistSuccess.jsp</result>
</action>
</package>
</struts>
用戶註冊視圖Regist.jsp代碼如下所示:
<%@ pagelanguage="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ tagliburi="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>用戶註冊頁面</title>
</head>
<body>
<h1>用戶註冊</h1>
<hr>
<s:form action="regist.action">
<s:textfield name="username" label="用戶名"></s:textfield>
<s:password name="password" label="密碼"></s:password>
<s:textfield name="age" label="年齡"></s:textfield>
<s:textfield name="email" label="電子郵件:"></s:textfield>
<s:submit name="login" value="註冊"/>
</s:form>
</body>
</html>
以上爲實現登陸和註冊功能的主要代碼,我們仔細分析發現validateLogin()和validateRegist()代碼中部分代碼是重複的,但是上面的代碼中由於用戶輸入驗證對應的方法是不同的,所以代碼出現了重複的現象,雖然我們可以單獨把這段重複的代碼單獨寫到一個方法中,然後在這兩個用戶輸入驗證方法中進行調用以進行改進。
Struts2框架的validate方法是由DefaultWorkFlowInterceptor攔截器調用的。該攔截器包含在defaultStack攔截器棧中。因此,只要使用默認的攔截器棧該攔截器都回被運行,從而validate方法會被調用。換句話說,默認情況下當前Action的所有邏輯方法執行之前都會執行validate方法。如果validate方法和validateXxx方法同時存在,它們的執行順序是先執行validateXxx方法,再執行validate方法。針對於Struts框架中本例中的Action類可以做如下優化:
packagecom.study.erp.action;
importcom.opensymphony.xwork2.ActionSupport;
public class UserActionextends ActionSupport{
private String username;
private String password;
private int age;
private String email;
//此處省略屬性對應的get和set方法
….
//用戶登陸功能對應的用戶輸入校驗方法,此時本方法可以省略不寫
public void validateLogin() {
}
//用戶註冊功能對應的用戶輸入校驗方法
public void validateRegist() {
if(age <0 || age>100){
addFieldError("age", "年齡不符合要求.");
}
if(email.indexOf("@") == -1){
addFieldError("email", "Email格式不符合要求.");
}
}
//用戶輸入驗證方法
public void validate(){
if(username == null || username.trim().equals("")){
addFieldError("username", "用戶名不能爲空.");
}
if(password == null || password.trim().equals("")){
addFieldError("password", "密碼不能爲空.");
}else if(password.length()<6 || password.length()>12){
addFieldError("password", "密碼長度應在6到12位之間.");
}
}
public String login(){
return "success";
}
public String regist(){
return "success";
}
}
如果某action中包含了多個邏輯方法,其中絕大部分方法都有相同的驗證規則,只有個別方法不需要該驗證規則時。可以使用DefaultWorkFlowInterceptor攔截器的excludeMethods參數,指定被排除的方法。如果被排除的方法超過1個,方法名中間使用逗號進行間隔。
例如UserAction類中包含了3個方法:用戶登陸login方法,用戶註冊regist方法,用戶信息刪除的delete方法。而用戶信息刪除不需要執行validate方法用戶名和用戶密碼的驗證規則。具體的實現方法可以包括以下兩種,比較而言第二種方法更容易理解也更加簡單。
1.重新設定默認的攔截器棧,在該攔截器棧中將delete方法排除掉。對應的struts.xml文件的內容如下所示:
<struts>
<package name="default"namespace="/" extends="struts-default">
<interceptors>
<interceptor-stackname="mydefaultStack">
<interceptor-refname="defaultStack">
<paramname="workflow.excludeMethods">delete</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<default-interceptor-refname="mydefaultStack"></default-interceptor-ref>
<action name="login"class="com.study.erp.action.UserAction" method="login">
<result name="input">/Login.jsp</result>
<result name="success">/LoginSuccess.jsp</result>
</action>
<action name="regist"class="com.study.erp.action.UserAction" method="regist">
<result name="input">/Regist.jsp</result>
<result name="success">/RegistSuccess.jsp</result>
</action>
<action name="delete"class="com.study.erp.action.UserAction" method="delete">
<result name="success">/DeleteSuccess.jsp</result>
</action>
</package>
</struts>
2.只在刪除用戶信息對應的action配置信息中將delete方法從攔截器中刪除掉。對應的配置文件內容
<?xml version="1.0"encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTDStruts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="default"namespace="/" extends="struts-default">
<action name="login"class="com.study.erp.action.UserAction" method="login">
<result name="input">/Login.jsp</result>
<result name="success">/LoginSuccess.jsp</result>
</action>
<action name="regist"class="com.study.erp.action.UserAction" method="regist">
<result name="input">/Regist.jsp</result>
<result name="success">/RegistSuccess.jsp</result>
</action>
<action name="delete"class="com.study.erp.action.UserAction"
method="delete">
<result name="success">/DeleteSuccess.jsp</result>
<interceptor-ref name="defaultStack">
<paramname="workflow.excludeMethods">delete</param>
</interceptor-ref>
</action>
</package>
</struts>