Struts2之Validator驗(yàn)證框架的詳細(xì)介紹
Struts2中提供了數(shù)據(jù)校驗(yàn)驗(yàn)證數(shù)據(jù)例如驗(yàn)證郵件、數(shù)字等。驗(yàn)證方式有3種:一是通過(guò)validate()方法,二是通過(guò)Xml,三是使用注解方式。
一、初始化
首先定義一個(gè)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()方法驗(yàn)證
可以在繼承了ActionSupport的Action中重寫(xiě)validate()來(lái)進(jìn)行驗(yàn)證。validate()方法在execute()方法執(zhí)行前執(zhí)行,僅當(dāng)數(shù)據(jù)校驗(yàn)正確,才執(zhí)行execute()方法, 如錯(cuò)誤則將錯(cuò)誤添加到fieldErrors域中,如果定義的Action中存在多個(gè)邏輯處理方法,且不同的處理邏輯需要不同的校驗(yàn)規(guī)則,這種情況下validate()會(huì)對(duì)所有處理邏輯使用相同的校驗(yàn)規(guī)則,為了實(shí)現(xiàn)不同的校驗(yàn)邏輯,需要通過(guò)validateX()方法,其中X表示處理邏輯的方法名,如果有錯(cuò)誤系統(tǒng)會(huì)返回result name="input"的頁(yè)面,所以需要在action中定義一個(gè)input的result。我昨天就困在這個(gè)地方好久。問(wèn)了我大學(xué)同學(xué)才解決,為了這個(gè)validate()驗(yàn)證昨晚一點(diǎn)多都沒(méi)睡,雖然SSH框架現(xiàn)在不流行,特別是前幾天struts2報(bào)了一個(gè)遠(yuǎn)程bug,不過(guò)想著既然學(xué)java了,就系統(tǒng)的學(xué)一遍吧。
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", "用戶名(字母開(kāi)頭 + 數(shù)字/字母/下劃線)"); } 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", "用戶名(字母開(kāi)頭 + 數(shù)字/字母/下劃線)"); } 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>注冊(cè)頁(yè)面</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="注冊(cè)"></struts:submit> </struts:form> </body> </html>
二、XML驗(yàn)證
使用validate方法校驗(yàn)時(shí),如果Web應(yīng)用中存在大量Action就需要多次重寫(xiě)validate方法,因此可以使用XWork的validator框架來(lái)對(duì)Struts2進(jìn)行數(shù)據(jù)校驗(yàn),減少代碼量。在action包下創(chuàng)建驗(yàn)證文件XXX-validation.xml,注:當(dāng)一個(gè)Action中有多個(gè)業(yè)務(wù)處理方法是,命名規(guī)則為:actionName-methodName-validation.xml,其中actionName為Action類名,methodName為Action中某個(gè)業(yè)務(wù)處理方法的方法名,并且文件的搜索順序與方式一種validate()和validateX()一樣。
這里先注釋掉Action的驗(yàn)證方法,然后新增一個(gè)xml驗(yàn)證文件,最后要在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 之間,且必須是字母或者數(shù)字</message> </field-validator> </field> <field name="user.email"> <field-validator type="email"> <message>你的電子郵件地址必須是一個(gè)有效的電郵地址</message> </field-validator> </field> <field name="user.age"> <field-validator type="int"> <param name="min">1</param> <param name="max">120</param> <message>年紀(jì)必須在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>
這里遺留了兩個(gè)問(wèn)題,一是錯(cuò)誤信息不是一次全部顯示出來(lái),如上面兩個(gè)圖先顯示兩個(gè)錯(cuò)誤提示,然后將顯示的修改正確之后又顯示其他的,這為什么不是全部顯示出來(lái)呢?二是在Xml中使用正則表達(dá)式驗(yàn)證怎么不起作用,這個(gè)也是個(gè)遺留的問(wèn)題,先把這兩個(gè)問(wèn)題放在這里,等以后再問(wèn)下其他人,如果哪位讀者知道原因也希望留言告訴博主,先謝過(guò)了。
三、注解
1.Validations Annotation的使用
Validations中定義了一些驗(yàn)證器的數(shù)組,用于存放驗(yàn)證規(guī)則,定義如下
public @interface Validations { //自定義校驗(yàn)器數(shù)組 public CustomValidator[] customValidators() default {}; //字段轉(zhuǎn)換錯(cuò)誤校驗(yàn)器數(shù)組 public ConversionErrorFieldValidator[] conversionErrorFields() default {}; //日期范圍校驗(yàn)器 public DateRangeFieldValidator[] dateRangeFields() default {}; //Email校驗(yàn)器 public EmailValidator[] emails() default {}; //字段表達(dá)式校驗(yàn)器 public FieldExpressionValidator[] fieldExpressions() default {}; //整數(shù)范圍校驗(yàn)器 public IntRangeFieldValidator[] intRangeFields() default {}; //必填字段校驗(yàn)器 public RequiredFieldValidator[] requiredFields() default {}; //必填字符串校驗(yàn)器 public RequiredStringValidator[] requiredStrings() default {}; //字符串長(zhǎng)度校驗(yàn)器 public StringLengthFieldValidator[] stringLengthFields() default {}; //URL校驗(yàn)器 public UrlValidator[] urls() default {}; //帶條件的Vistor校驗(yàn)器 public ConditionalVisitorFieldValidator[] conditionalVisitorFields() default {}; //Vistor校驗(yàn)器 public VisitorFieldValidator[] visitorFields() default {}; //正則表達(dá)式校驗(yàn)器 public RegexFieldValidator[] regexFields() default {}; //表達(dá)式校驗(yàn)器 public ExpressionValidator[] expressions() default {}; }
RequiredStringValidator —— 必填字符串校驗(yàn)器
校驗(yàn)要求:指定字段不能為null且字符串長(zhǎng)度大于0
參數(shù):
- fieldName:校驗(yàn)字段名
- trim:校驗(yàn)時(shí)取出字符串兩邊的空格,默認(rèn)為true
- message:校驗(yàn)失敗時(shí)的消息
- key:校驗(yàn)失敗時(shí)返回i18n中指定名稱的消息
RequiredFieldValidator —— 必填校驗(yàn)器
校驗(yàn)要求:指定字段不能為null
參數(shù):
- fieldName:校驗(yàn)字段名
- message:校驗(yàn)失敗時(shí)的消息
- key:校驗(yàn)失敗時(shí)返回i18n中指定名稱的消息
IntRangeFieldValidator —— 整數(shù)范圍校驗(yàn)器
校驗(yàn)要求:int、long、short字段的整數(shù)值在指定的范圍內(nèi)
參數(shù):
- min:指定最小值,可選,沒(méi)有則不檢查最小值
- max:指定最大值,可選,沒(méi)有則不檢查最大值
- fieldName:校驗(yàn)字段名
- message:校驗(yàn)失敗時(shí)的消息
- key:校驗(yàn)失敗時(shí)返回i18n中指定名稱的消息
DateRangeFieldValidator —— 日期范圍校驗(yàn)器
校驗(yàn)要求:日期在指定的范圍內(nèi)
參數(shù):
- min:指定最小值,可選,沒(méi)有則不檢查最小值
- max:指定最大值,可選,沒(méi)有則不檢查最大值
- fieldName:校驗(yàn)字段名
- message:校驗(yàn)失敗時(shí)的消息
- key:校驗(yàn)失敗時(shí)返回i18n中指定名稱的消息
EmailValidator —— Email地址校驗(yàn)器
校驗(yàn)要求:指定的字段為Email地址
參數(shù):
- fieldName:校驗(yàn)字段名
- message:校驗(yàn)失敗時(shí)的消息
- key:校驗(yàn)失敗時(shí)返回i18n中指定名稱的消息
ExpressionValidator —— 表達(dá)式校驗(yàn)器
校驗(yàn)要求:指定的ONGL表達(dá)式返回true。
參數(shù):
- expression:ONGL表達(dá)式
- message:校驗(yàn)失敗時(shí)的消息
- key:校驗(yàn)失敗時(shí)返回i18n中指定名稱的消息
UrlValidator —— URL校驗(yàn)器
校驗(yàn)要求:校驗(yàn)指定的字段值是否為合法的URL
參數(shù):
- fieldName:校驗(yàn)字段名
- message:校驗(yàn)失敗時(shí)的消息
- key:校驗(yàn)失敗時(shí)返回i18n中指定名稱的消息
StringLengthFieldValidator —— 字符串長(zhǎng)度校驗(yàn)器
校驗(yàn)要求:字符串長(zhǎng)度在指定的范圍內(nèi)
參數(shù):
- minLength:指定最小長(zhǎng)度,可選,沒(méi)有則不檢查最小長(zhǎng)度
- maxLength:指定最大長(zhǎng)度,可選,沒(méi)有則不檢查最大長(zhǎng)度
- trim:校驗(yàn)時(shí)取出字符串兩邊的空格,默認(rèn)為true
- fieldName:校驗(yàn)字段名
- message:校驗(yàn)失敗時(shí)的消息
- key:校驗(yàn)失敗時(shí)返回i18n中指定名稱的消息
ConversionErrorFieldValidator —— 轉(zhuǎn)換錯(cuò)誤校驗(yàn)器
校驗(yàn)要求:校驗(yàn)指定字段是否發(fā)生類型轉(zhuǎn)換錯(cuò)誤
參數(shù):
- fieldName:校驗(yàn)字段名
- message:校驗(yàn)失敗時(shí)的消息
- key:校驗(yàn)失敗時(shí)返回i18n中指定名稱的消息
VisitorFieldValidator —— Vistor校驗(yàn)器
說(shuō)明:普通校驗(yàn)器只能校驗(yàn)基本數(shù)據(jù)類型和字符串類型,該校驗(yàn)器可以校驗(yàn)對(duì)象里面的屬性。
參數(shù):
- context:用于校驗(yàn)的context
- appendPrefix: 校驗(yàn)發(fā)生錯(cuò)誤時(shí)是否在錯(cuò)誤信息中添加前最消息
- fieldName:校驗(yàn)字段名
- message:校驗(yàn)失敗時(shí)的消息
- key:校驗(yàn)失敗時(shí)返回i18n中指定名稱的消息
RegexFieldValidator —— 正則表達(dá)式校驗(yàn)器
校驗(yàn)要求:指定字段匹配指定的正則表達(dá)式
參數(shù):
- expression:正則表達(dá)式
- fieldName:校驗(yàn)字段名
- message:校驗(yàn)失敗時(shí)的消息
- key:校驗(yàn)失敗時(shí)返回i18n中指定名稱的消息
ConditionalVisitorFieldValidator —— 帶條件的Vistor校驗(yàn)器
驗(yàn)證要求:在條件不滿足時(shí),和Vistor校驗(yàn)器功能一樣,條件滿足則不執(zhí)行Vistor校驗(yàn)
參數(shù):
- fieldName:校驗(yàn)字段名
- message:校驗(yàn)失敗時(shí)的消息
- key:校驗(yàn)失敗時(shí)返回i18n中指定名稱的消息
CustomValidator —— 自定義校驗(yàn)器
校驗(yàn)器:自定義校驗(yàn)器
舉例:
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="郵件字段的格式不對(duì)")}, conversionErrorFields={@ConversionErrorFieldValidator(fieldName="user.age",message="年齡輸入的值轉(zhuǎn)換錯(cuò)誤")}, 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="用戶名(字母開(kāi)頭 + 數(shù)字/字母/下劃線)")} ) 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; } }
結(jié)論:
1.Action類中使用Validations Annotation定義驗(yàn)證。
2.Action中,可以在方法上、類上定義驗(yàn)證Annotations,所有的驗(yàn)證器都將同時(shí)作用在映射為Action的方法上。
3.Action中有多個(gè)方法被映射為Action時(shí),類上和方法上所有定義的驗(yàn)證Annotations都將作用在每個(gè)映射為Action的方法上。
4.Action中校驗(yàn)失敗時(shí),返回input邏輯視圖
5.可以使用@SkipValidation跳過(guò)所有的驗(yàn)證檢查,包括自身方法定義的校驗(yàn)器。
6.可以在Action映射中使用如下代碼跳過(guò)校驗(yàn)檢查
<interceptor-ref name="validation"> <param name="validateAnnotatedMethodOnly">true</param> </interceptor-ref>
遺留問(wèn)題修改:
上面遺留了一個(gè)問(wèn)題,在xml中來(lái)做驗(yàn)證時(shí)正則表達(dá)式不起作用,保存之后突然想到在注解中用下面的代碼來(lái)表示的
regexFields={@RegexFieldValidator(regexExpression="^[A-Za-z][A-Za-z1-9_-]+$",fieldName="user.name",message="用戶名(字母開(kāi)頭 + 數(shù)字/字母/下劃線)")}
看著參數(shù)名和xml中配置的不一樣,會(huì)不會(huì)是參數(shù)名錯(cuò)誤呢?因?yàn)槲以诰W(wǎng)上查的有的用regex或expression,不過(guò)都說(shuō)在提問(wèn)說(shuō)不起作用,我懷疑是不是參數(shù)名有問(wèn)題,報(bào)著試一試的態(tài)度用regexExpression試一試,沒(méi)想到還成功了。應(yīng)該將上面用xml驗(yàn)證name的地方改成這樣子。
<field name="user.name"> <field-validator type="regex"> <param name="regexExpression"><![CDATA[(\^[A-Za-z][A-Za-z1-9_-]+$)]]></param> <message>用戶名(字母開(kāi)頭 + 數(shù)字/字母/下劃線)</message> </field-validator> </field>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
spring batch 讀取多個(gè)文件數(shù)據(jù)導(dǎo)入數(shù)據(jù)庫(kù)示例
本篇文章主要介紹了spring batch 讀取多個(gè)文件數(shù)據(jù)導(dǎo)入數(shù)據(jù)庫(kù)示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03java關(guān)于list集合做刪除操作時(shí)的坑及解決
這篇文章主要介紹了java關(guān)于list集合做刪除操作時(shí)的坑及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11Java線程中斷及線程中斷的幾種使用場(chǎng)景小結(jié)
在并發(fā)編程中,合理使用線程中斷機(jī)制可以提高程序的魯棒性和可維護(hù)性,本文主要介紹了Java線程中斷及線程中斷的幾種使用場(chǎng)景小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01Java實(shí)現(xiàn)文件上傳的方法總結(jié)
這篇文章主要為大家介紹了三種Java實(shí)現(xiàn)文件上傳的方法,文中的示例代碼講解詳細(xì),對(duì)我們的學(xué)習(xí)或工作有一定的借鑒價(jià)值,感興趣的可以了解一下2023-04-04java 使用BigDecimal進(jìn)行貨幣金額計(jì)算的操作
這篇文章主要介紹了java 使用BigDecimal進(jìn)行貨幣金額計(jì)算的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02