1. 程式人生 > >Struts2之Validator驗證框架的詳細介紹

Struts2之Validator驗證框架的詳細介紹

Struts2中提供了資料校驗驗證資料例如驗證郵件、數字等。驗證方式有3種:

一是通過validate()方法,

二是通過Xml,

三是使用註解方式。

一、初始化

首先定義一個User類

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

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()方法執行前執行,僅當資料校驗正確,才執行execute()方法, 如錯誤則將錯誤新增到fieldErrors域中,如果定義的Action中存在多個邏輯處理方法,且不同的處理邏輯需要不同的校驗規則,這種情況下validate()會對所有處理邏輯使用相同的校驗規則,為了實現不同的校驗邏輯,需要通過validateX()方法,其中X表示處理邏輯的方法名,如果有錯誤系統會返回result name="input"的頁面,所以需要在action中定義一個input的result。我昨天就困在這個地方好久。問了我大學同學才解決,為了這個validate()驗證昨晚一點多都沒睡,雖然SSH框架現在不流行,特別是前幾天struts2報了一個遠端bug,不過想著既然學java了,就係統的學一遍吧。

1.validate()方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

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();

}

}

struts.xml:

1

2

3

4

5

6

7

8

9

10

11

12

13

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC

"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"

<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()方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

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();

}

}

struts.xml:

1

2

3

4

5

6

7

8

9

10

11

12

13

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC

"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"

<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>

JSP:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

<%@ 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" >

<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包下建立驗證檔案XXX-validation.xml,注:當一個Action中有多個業務處理方法是,命名規則為:actionName-methodName-validation.xml,其中actionName為Action類名,methodName為Action中某個業務處理方法的方法名,並且檔案的搜尋順序與方式一種validate()和validateX()一樣。

這裡先註釋掉Action的驗證方法,然後新增一個xml驗證檔案,最後要在form中增加validate="true"

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE validators PUBLIC

"-//Apache Struts//XWork Validator 1.0.3//EN"

<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中定義了一些驗證器的陣列,用於存放驗證規則,定義如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

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

引數:

  1. fieldName:校驗欄位名
  2. trim:校驗時取出字串兩邊的空格,預設為true 
  3. message:校驗失敗時的訊息
  4. key:校驗失敗時返回i18n中指定名稱的訊息

RequiredFieldValidator —— 必填校驗器

校驗要求:指定欄位不能為null

引數:

  1. fieldName:校驗欄位名
  2. message:校驗失敗時的訊息
  3. key:校驗失敗時返回i18n中指定名稱的訊息

IntRangeFieldValidator —— 整數範圍校驗器

校驗要求:int、long、short欄位的整數值在指定的範圍內

引數:

  1. min:指定最小值,可選,沒有則不檢查最小值
  2. max:指定最大值,可選,沒有則不檢查最大值
  3. fieldName:校驗欄位名
  4. message:校驗失敗時的訊息
  5. key:校驗失敗時返回i18n中指定名稱的訊息

DateRangeFieldValidator —— 日期範圍校驗器

校驗要求:日期在指定的範圍內   

引數:

  1. min:指定最小值,可選,沒有則不檢查最小值
  2. max:指定最大值,可選,沒有則不檢查最大值 
  3. fieldName:校驗欄位名
  4. message:校驗失敗時的訊息
  5. key:校驗失敗時返回i18n中指定名稱的訊息

EmailValidator —— Email地址校驗器

校驗要求:指定的欄位為Email地址

引數:

  1.  fieldName:校驗欄位名
  2. message:校驗失敗時的訊息
  3. key:校驗失敗時返回i18n中指定名稱的訊息

ExpressionValidator —— 表示式校驗器

校驗要求:指定的ONGL表示式返回true。

引數:

  1. expression:ONGL表示式   
  2. message:校驗失敗時的訊息
  3. key:校驗失敗時返回i18n中指定名稱的訊息

UrlValidator —— URL校驗器

校驗要求:校驗指定的欄位值是否為合法的URL

引數:

  1.  fieldName:校驗欄位名
  2. message:校驗失敗時的訊息
  3. key:校驗失敗時返回i18n中指定名稱的訊息

StringLengthFieldValidator —— 字串長度校驗器

校驗要求:字串長度在指定的範圍內

引數:

  1. minLength:指定最小長度,可選,沒有則不檢查最小長度
  2. maxLength:指定最大長度,可選,沒有則不檢查最大長度 
  3. trim:校驗時取出字串兩邊的空格,預設為true 
  4. fieldName:校驗欄位名
  5. message:校驗失敗時的訊息
  6. key:校驗失敗時返回i18n中指定名稱的訊息

ConversionErrorFieldValidator —— 轉換錯誤校驗器

校驗要求:校驗指定欄位是否發生型別轉換錯誤

引數:

  1.  fieldName:校驗欄位名
  2. message:校驗失敗時的訊息
  3. key:校驗失敗時返回i18n中指定名稱的訊息

VisitorFieldValidator —— Vistor校驗器

說明:普通校驗器只能校驗基本資料型別和字串型別,該校驗器可以校驗物件裡面的屬性。

引數:

  1. context:用於校驗的context
  2. appendPrefix: 校驗發生錯誤時是否在錯誤資訊中新增前最訊息
  3. fieldName:校驗欄位名
  4. message:校驗失敗時的訊息
  5. key:校驗失敗時返回i18n中指定名稱的訊息

RegexFieldValidator —— 正則表示式校驗器

校驗要求:指定欄位匹配指定的正則表示式

引數:

  1. expression:正則表示式
  2. fieldName:校驗欄位名
  3. message:校驗失敗時的訊息
  4. key:校驗失敗時返回i18n中指定名稱的訊息

ConditionalVisitorFieldValidator —— 帶條件的Vistor校驗器

驗證要求:在條件不滿足時,和Vistor校驗器功能一樣,條件滿足則不執行Vistor校驗

引數:

  1.  fieldName:校驗欄位名
  2. message:校驗失敗時的訊息
  3. key:校驗失敗時返回i18n中指定名稱的訊息

CustomValidator —— 自定義校驗器 

校驗器:自定義校驗器

舉例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

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對映中使用如下程式碼跳過校驗檢查

1

2

3

<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,不過都說在提問說不起作用,我懷疑是不是引數名有問題,報著試一試的態度用regexExpression試一試,沒想到還成功了。應該將上面用xml驗證name的地方改成這樣子。

1

2

3

4

5

6

<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>

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