Struts2之Validator驗證框架的詳細介紹
Struts2中提供了數據校驗驗證數據例如驗證郵件、數字等。驗證方式有3種:一是通過validate()方法,二是通過Xml,三是使用注解方式。
一、初始化
首先定義一個User類
package com.cyw.test;
import java.util.Date;
public class User {
private String name;
private int age;
private String email;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getBirthDay() {
return birthDay;
}
public void setBirthDay(Date birthDay) {
this.birthDay = birthDay;
}
private Date birthDay;
}
二、validate()方法驗證
可以在繼承了ActionSupport的Action中重寫validate()來進行驗證。validate()方法在execute()方法執(zhí)行前執(zhí)行,僅當數據校驗正確,才執(zhí)行execute()方法, 如錯誤則將錯誤添加到fieldErrors域中,如果定義的Action中存在多個邏輯處理方法,且不同的處理邏輯需要不同的校驗規(guī)則,這種情況下validate()會對所有處理邏輯使用相同的校驗規(guī)則,為了實現不同的校驗邏輯,需要通過validateX()方法,其中X表示處理邏輯的方法名,如果有錯誤系統(tǒng)會返回result name="input"的頁面,所以需要在action中定義一個input的result。我昨天就困在這個地方好久。問了我大學同學才解決,為了這個validate()驗證昨晚一點多都沒睡,雖然SSH框架現在不流行,特別是前幾天struts2報了一個遠程bug,不過想著既然學java了,就系統(tǒng)的學一遍吧。

1.validate()方法
package com.cyw.test;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.opensymphony.xwork2.ActionSupport;
public class ValidatorAction extends ActionSupport {
private User user;
private List<User>userList=new ArrayList<User>();
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
@Override
public String execute() throws Exception {
if(user==null || this.hasFieldErrors())
{
return "regist";
}
else
{
return "success";
}
}
public String addUser()
{
userList.add(user);
return "success";
}
private static final long serialVersionUID = 1L;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public void validate() {
if(user!=null)
{
if(!dataPass( user.getName(),"^[A-Za-z][A-Za-z1-9_-]+$"))
{
addFieldError("user.name", "用戶名(字母開頭 + 數字/字母/下劃線)");
}
if(!dataPass(String.format("%d", user.getAge()) ,"(?:[1-9][0-9]?|1[01][0-9]|120)"))
{
addFieldError("user.name", "年齡0-120之間");
}
Date startDate=strToDate("1900-01-01");
Date endDate=strToDate("2017-01-01");
if(user.getBirthDay().before(startDate) || user.getBirthDay().after(endDate) )
{
addFieldError("birthDay", "出生日期在1900-01-01至2017-01-01之間。");
}
if(!dataPass(user.getEmail(),"^[a-zA-Z_]{1,}[0-9]{0,}@(([a-zA-z0-9]-*){1,}\\.){1,3}[a-zA-z\\-]{1,}$"))
{
addFieldError("email", "郵箱格式不符合");
}
}
}
private Date strToDate(String strDate)
{
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
ParsePosition pos = new ParsePosition(0);
Date strtodate = formatter.parse(strDate, pos);
return strtodate;
}
private boolean dataPass(String str,String regEx)
{
Pattern pattern=Pattern.compile(regEx,Pattern.CASE_INSENSITIVE);
Matcher matcher =pattern.matcher(str);
return matcher.matches();
}
}<?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="regist" class="com.cyw.test.ValidatorAction"> <result name="regist">/register.jsp</result> <result name="success">/success.jsp</result> <result name="input">/register.jsp</result> </action> </package> </struts>

2.validateX()方法
package com.cyw.test;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.opensymphony.xwork2.ActionSupport;
public class ValidatorAction extends ActionSupport {
private User user;
private List<User>userList=new ArrayList<User>();
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
public String addUser()
{
if(user==null)
{
return "regist";
}
userList.add(user);
return "success";
}
private static final long serialVersionUID = 1L;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public void validateAddUser() {
if(user!=null)
{
if(!dataPass( user.getName(),"^[A-Za-z][A-Za-z1-9_-]+$"))
{
addFieldError("user.name", "用戶名(字母開頭 + 數字/字母/下劃線)");
}
if(!dataPass(String.format("%d", user.getAge()) ,"(?:[1-9][0-9]?|1[01][0-9]|120)"))
{
addFieldError("user.name", "年齡0-120之間");
}
Date startDate=strToDate("1900-01-01");
Date endDate=strToDate("2017-01-01");
if(user.getBirthDay().before(startDate) || user.getBirthDay().after(endDate) )
{
addFieldError("birthDay", "出生日期在1900-01-01至2017-01-01之間。");
}
if(!dataPass(user.getEmail(),"^[a-zA-Z_]{1,}[0-9]{0,}@(([a-zA-z0-9]-*){1,}\\.){1,3}[a-zA-z\\-]{1,}$"))
{
addFieldError("email", "郵箱格式不符合");
}
}
}
private Date strToDate(String strDate)
{
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
ParsePosition pos = new ParsePosition(0);
Date strtodate = formatter.parse(strDate, pos);
return strtodate;
}
private boolean dataPass(String str,String regEx)
{
Pattern pattern=Pattern.compile(regEx,Pattern.CASE_INSENSITIVE);
Matcher matcher =pattern.matcher(str);
return matcher.matches();
}
}
<?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="regist" class="com.cyw.test.ValidatorAction" method="addUser"> <result name="regist">/register.jsp</result> <result name="success">/success.jsp</result> <result name="input">/register.jsp</result> </action> </package> </struts>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="/struts-tags" prefix="struts" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>注冊頁面</title> </head> <body> <struts:fielderror key="name"></struts:fielderror> <struts:form action="regist" method="post"> <struts:textfield name="user.name" label="用戶名"></struts:textfield> <br/> <struts:textfield name="user.age" label="年齡"></struts:textfield> <br/> <struts:textfield name="user.birthDay" label="出生日期"></struts:textfield> <br/> <struts:textfield name="user.email" label="郵箱"></struts:textfield> <br/> <struts:submit value="注冊"></struts:submit> </struts:form> </body> </html>

二、XML驗證
使用validate方法校驗時,如果Web應用中存在大量Action就需要多次重寫validate方法,因此可以使用XWork的validator框架來對Struts2進行數據校驗,減少代碼量。在action包下創(chuàng)建驗證文件XXX-validation.xml,注:當一個Action中有多個業(yè)務處理方法是,命名規(guī)則為:actionName-methodName-validation.xml,其中actionName為Action類名,methodName為Action中某個業(yè)務處理方法的方法名,并且文件的搜索順序與方式一種validate()和validateX()一樣。
這里先注釋掉Action的驗證方法,然后新增一個xml驗證文件,最后要在form中增加validate="true"

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<field name="user。name">
<field-validator type="regex">
<param name="expression"><![CDATA[(\w{4,20})]]></param>
<message>用戶名必須在4到20 之間,且必須是字母或者數字</message>
</field-validator>
</field>
<field name="user.email">
<field-validator type="email">
<message>你的電子郵件地址必須是一個有效的電郵地址</message>
</field-validator>
</field>
<field name="user.age">
<field-validator type="int">
<param name="min">1</param>
<param name="max">120</param>
<message>年紀必須在1到120之間</message>
</field-validator>
</field>
<field name="user.birthDay" >
<field-validator type="date" short-circuit="true">
<param name="min">1900-01-01</param>
<param name="max">2050-02-21</param>
<message>生日在${min}到${max}之間</message>
</field-validator>
</field>
</validators>



這里遺留了兩個問題,一是錯誤信息不是一次全部顯示出來,如上面兩個圖先顯示兩個錯誤提示,然后將顯示的修改正確之后又顯示其他的,這為什么不是全部顯示出來呢?二是在Xml中使用正則表達式驗證怎么不起作用,這個也是個遺留的問題,先把這兩個問題放在這里,等以后再問下其他人,如果哪位讀者知道原因也希望留言告訴博主,先謝過了。

三、注解
1.Validations Annotation的使用
Validations中定義了一些驗證器的數組,用于存放驗證規(guī)則,定義如下
public @interface Validations {
//自定義校驗器數組
public CustomValidator[] customValidators() default {};
//字段轉換錯誤校驗器數組
public ConversionErrorFieldValidator[] conversionErrorFields() default {};
//日期范圍校驗器
public DateRangeFieldValidator[] dateRangeFields() default {};
//Email校驗器
public EmailValidator[] emails() default {};
//字段表達式校驗器
public FieldExpressionValidator[] fieldExpressions() default {};
//整數范圍校驗器
public IntRangeFieldValidator[] intRangeFields() default {};
//必填字段校驗器
public RequiredFieldValidator[] requiredFields() default {};
//必填字符串校驗器
public RequiredStringValidator[] requiredStrings() default {};
//字符串長度校驗器
public StringLengthFieldValidator[] stringLengthFields() default {};
//URL校驗器
public UrlValidator[] urls() default {};
//帶條件的Vistor校驗器
public ConditionalVisitorFieldValidator[] conditionalVisitorFields() default {};
//Vistor校驗器
public VisitorFieldValidator[] visitorFields() default {};
//正則表達式校驗器
public RegexFieldValidator[] regexFields() default {};
//表達式校驗器
public ExpressionValidator[] expressions() default {};
}
RequiredStringValidator —— 必填字符串校驗器
校驗要求:指定字段不能為null且字符串長度大于0
參數:
- fieldName:校驗字段名
- trim:校驗時取出字符串兩邊的空格,默認為true
- message:校驗失敗時的消息
- key:校驗失敗時返回i18n中指定名稱的消息
RequiredFieldValidator —— 必填校驗器
校驗要求:指定字段不能為null
參數:
- fieldName:校驗字段名
- message:校驗失敗時的消息
- key:校驗失敗時返回i18n中指定名稱的消息
IntRangeFieldValidator —— 整數范圍校驗器
校驗要求:int、long、short字段的整數值在指定的范圍內
參數:
- min:指定最小值,可選,沒有則不檢查最小值
- max:指定最大值,可選,沒有則不檢查最大值
- fieldName:校驗字段名
- message:校驗失敗時的消息
- key:校驗失敗時返回i18n中指定名稱的消息
DateRangeFieldValidator —— 日期范圍校驗器
校驗要求:日期在指定的范圍內
參數:
- min:指定最小值,可選,沒有則不檢查最小值
- max:指定最大值,可選,沒有則不檢查最大值
- fieldName:校驗字段名
- message:校驗失敗時的消息
- key:校驗失敗時返回i18n中指定名稱的消息
EmailValidator —— Email地址校驗器
校驗要求:指定的字段為Email地址
參數:
- fieldName:校驗字段名
- message:校驗失敗時的消息
- key:校驗失敗時返回i18n中指定名稱的消息
ExpressionValidator —— 表達式校驗器
校驗要求:指定的ONGL表達式返回true。
參數:
- expression:ONGL表達式
- message:校驗失敗時的消息
- key:校驗失敗時返回i18n中指定名稱的消息
UrlValidator —— URL校驗器
校驗要求:校驗指定的字段值是否為合法的URL
參數:
- fieldName:校驗字段名
- message:校驗失敗時的消息
- key:校驗失敗時返回i18n中指定名稱的消息
StringLengthFieldValidator —— 字符串長度校驗器
校驗要求:字符串長度在指定的范圍內
參數:
- minLength:指定最小長度,可選,沒有則不檢查最小長度
- maxLength:指定最大長度,可選,沒有則不檢查最大長度
- trim:校驗時取出字符串兩邊的空格,默認為true
- fieldName:校驗字段名
- message:校驗失敗時的消息
- key:校驗失敗時返回i18n中指定名稱的消息
ConversionErrorFieldValidator —— 轉換錯誤校驗器
校驗要求:校驗指定字段是否發(fā)生類型轉換錯誤
參數:
- fieldName:校驗字段名
- message:校驗失敗時的消息
- key:校驗失敗時返回i18n中指定名稱的消息
VisitorFieldValidator —— Vistor校驗器
說明:普通校驗器只能校驗基本數據類型和字符串類型,該校驗器可以校驗對象里面的屬性。
參數:
- context:用于校驗的context
- appendPrefix: 校驗發(fā)生錯誤時是否在錯誤信息中添加前最消息
- fieldName:校驗字段名
- message:校驗失敗時的消息
- key:校驗失敗時返回i18n中指定名稱的消息
RegexFieldValidator —— 正則表達式校驗器
校驗要求:指定字段匹配指定的正則表達式
參數:
- expression:正則表達式
- fieldName:校驗字段名
- message:校驗失敗時的消息
- key:校驗失敗時返回i18n中指定名稱的消息
ConditionalVisitorFieldValidator —— 帶條件的Vistor校驗器
驗證要求:在條件不滿足時,和Vistor校驗器功能一樣,條件滿足則不執(zhí)行Vistor校驗
參數:
- fieldName:校驗字段名
- message:校驗失敗時的消息
- key:校驗失敗時返回i18n中指定名稱的消息
CustomValidator —— 自定義校驗器
校驗器:自定義校驗器
舉例:
package com.cyw.test;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.validator.annotations.Validations;
import com.opensymphony.xwork2.validator.annotations.*;
public class ValidatorAction extends ActionSupport {
private User user;
private List<User>userList=new ArrayList<User>();
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
@Validations(
emails={@EmailValidator(fieldName="user.email",message="郵件字段的格式不對")},
conversionErrorFields={@ConversionErrorFieldValidator(fieldName="user.age",message="年齡輸入的值轉換錯誤")},
intRangeFields={@IntRangeFieldValidator(fieldName="user.age",min="0",max="120",message="年齡范圍為0到120")},
dateRangeFields={@DateRangeFieldValidator(fieldName="user.birthDay",min="1900-01-01",max="2017-03-30",message="日期輸入不正確")},
regexFields={@RegexFieldValidator(regexExpression="^[A-Za-z][A-Za-z1-9_-]+$",fieldName="user.name",message="用戶名(字母開頭 + 數字/字母/下劃線)")}
)
public String addUser()
{
if(user==null)
{
return "regist";
}
userList.add(user);
return "success";
}
private static final long serialVersionUID = 1L;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}

結論:
1.Action類中使用Validations Annotation定義驗證。
2.Action中,可以在方法上、類上定義驗證Annotations,所有的驗證器都將同時作用在映射為Action的方法上。
3.Action中有多個方法被映射為Action時,類上和方法上所有定義的驗證Annotations都將作用在每個映射為Action的方法上。
4.Action中校驗失敗時,返回input邏輯視圖
5.可以使用@SkipValidation跳過所有的驗證檢查,包括自身方法定義的校驗器。
6.可以在Action映射中使用如下代碼跳過校驗檢查
<interceptor-ref name="validation"> <param name="validateAnnotatedMethodOnly">true</param> </interceptor-ref>
遺留問題修改:
上面遺留了一個問題,在xml中來做驗證時正則表達式不起作用,保存之后突然想到在注解中用下面的代碼來表示的
regexFields={@RegexFieldValidator(regexExpression="^[A-Za-z][A-Za-z1-9_-]+$",fieldName="user.name",message="用戶名(字母開頭 + 數字/字母/下劃線)")}
看著參數名和xml中配置的不一樣,會不會是參數名錯誤呢?因為我在網上查的有的用regex或expression,不過都說在提問說不起作用,我懷疑是不是參數名有問題,報著試一試的態(tài)度用regexExpression試一試,沒想到還成功了。應該將上面用xml驗證name的地方改成這樣子。
<field name="user.name"> <field-validator type="regex"> <param name="regexExpression"><![CDATA[(\^[A-Za-z][A-Za-z1-9_-]+$)]]></param> <message>用戶名(字母開頭 + 數字/字母/下劃線)</message> </field-validator> </field>

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

