從一個HTML表單到一個動做對象,類型轉換將是從字符串到非字符串.由於HTTP沒有"類型"的概念,因此一切表單輸入都將以請求參數的形式被髮送到服務器,而每一項表單輸入之多是一個String或一個String數組。在服務器端,必須先把這些String值轉換爲特定的數據類型,才能進行相應的處理。 html
把請求參數映射到動做屬性的工做由Parameters攔截器負責,它是defaultStack攔截器棧的一員。全部的請求參數都是String類型,但並不是全部的動做屬性都是String類型,因此每一種非String類型的動做屬性須要對相關的請求參數進行類型轉換。 java
Struts2在類型轉換失敗時會發生錯誤,具體如何處理取決於你的動做類是否實現了com.opensymphony.xwork2.ValidationAware接口。 程序員
注:若是你的動做類繼承自com.opensymphony.xwork2.ActionSupport,就至關於你間接實現了com.opensymphony.xwork2.ValidationAware接口。 正則表達式
conversionError攔截器負責添加與類型轉換有關的出錯消息和保存各請求參數的原始值,它是defaultStack中的一員。使用該攔截器的前提是你實現了com.opensymphony.xwork2.ValidationAware接口。 spring
若是你用來呈現這個字段的標籤使用的不是simple主題,有非法值的字段將致使一條有着如下格式的出錯消息: 數據庫
Invalid field value for field "fieldName". express
咱們能夠經過如下方式來改變該消息: apache
struts2內建的類型轉換器並不能解決全部的問題,那就須要本身建立類型轉換器。 編程
自定義的類型轉換器必須實現ognl.TypeConverter接口或對這個接口的某種具體實現作進一步擴展。 json
TypeConverter接口只有一個名爲convertValue的方法,它的方法簽名以下:
public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType);
參數:
context:將在其中進行類型轉換的OGNL上下文環境。
target:將在其中對有關屬性進行設置的目標對象。
member:將被設置的類成員的名字。
propertyName:將被設置的屬性的名字。
value:將被轉換的值。
toType:轉換結果的類型。
與自行實現TypeConverter接口相比,對該類擴展更容易一些,他是對TypeConverter金額接口的一種默認實現類,且他有簡單的方法簽名。
public Object convertValue(Map<String, Object> context, Object value, Class toType) {
return convertValue(value, toType);
}
public Object convertValue(Map<String, Object> context, Object target, Member member,
String propertyName, Object value, Class toType) {
return convertValue(context, value, toType);
}
在使用一個自定義的類型轉換器以前,必須先對它進行配置。這種配置能夠基於字段,也能夠基於類。
在動做類所在的包中建立ActionClass-conversion.properties的文件,其中的內容可能爲下所示:
fieldname=customConverter1
在WEB-INF/classes子目錄下建立一個conversion.properties文件,其中的內容可能爲下所示:
fullQualifieldClassName=customerConverter1
Strut2驗證能夠經過一個XML配置文件和註解的方式來實現,固然手工驗證(編碼驗證)也是支持的。同時也能夠經過XML和註解共同使用的方式實現聯合驗證。
Struts2的驗證是經過validation和workflow攔截器實現的,它們都屬於default interceptor stack。validation攔截器用於驗證並組織錯誤消息。workflow攔截器用於檢測是否包含錯誤消息,假若有,它將返回結果爲input所指向的頁面,並將錯誤消息和原先輸入的數據一同呈現給客戶。
若是您的程序中使用了默認的驗證(或者轉換器)而沒有提供爲input的結果,則將出現錯誤。
註解驗證從struts2.1版本開始就不建議使用了。
讓咱們一步一步作一個基礎驗證的示例
<body> <s:form action="helloValidation"> <s:textfield name="name" label="姓名"></s:textfield> <s:textfield name="age" label="年齡"></s:textfield> <s:textfield name="address" label="籍貫"></s:textfield> <s:submit value="提交"></s:submit> </s:form> </body> |
HelloAction.java |
package cn.wzhting;
import com.opensymphony.xwork2.ActionSupport;
public class HelloAction extends ActionSupport {
private static final long serialVersionUID = 117358005790515177L; private String name; private Integer age; private String address; public String getName() { return name; } public void setName(String name) { this.name = name; }
public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; }
} |
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> <validators> <field name="name"> <field-validator type="requiredstring"> <message>請輸入姓名</message> </field-validator> </field> <field name="age"> <field-validator type="int"> <param name="min">13</param> <param name="max">19</param> <message>年齡爲13~19週歲的才容許填寫</message> </field-validator> </field> </validators> |
… <action name="helloValidation" class="cn.wzhting.HelloAction"> <result name="success">/createConfirm.jsp</result> <result name="error">/error.jsp</result> <result name="input">/create.jsp</result> </action> … |
假如你沒有這樣設置,你將會獲得"No result defined for action *** and result input"的錯誤提示。
讓咱們一步一步作一個客戶端驗證的示例
步驟一:建立輸入表單
<head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Validation - Basic</title> <s:head/> </head> <body> <s:form action="helloValidation.action" validate="true"> <s:textfield name="name" label="姓名"></s:textfield> <s:textfield name="age" label="年齡"></s:textfield> <s:textfield name="address" label="籍貫"></s:textfield> <s:submit value="提交"></s:submit> </s:form> </body> |
注意:
步驟2、3、四通《基礎驗證 Basic Validation》一節,此處省略。
若是表單提交到的動做不在默認命名空間裏,在使用<s:form>時必須指定其namespace屬性。例如,helloValidation在命名空間/ns內,可能的struts.xml以下:
struts.xml |
… <package name="p1" extends="struts-default" namespace="/ns"> <action name="helloValidation" class="cn.wzhting.HelloAction"> <result name="success">/createConfirm.jsp</result> <result name="error">/error.jsp</result> <result name="input">/create.jsp</result> </action> </package> … |
輸入表單以下:
<head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Validation - Basic</title> <s:head/> </head> <body> <s:form action="helloValidation.action" validate="true" namespace="/ns"> <s:textfield name="name" label="姓名"></s:textfield> <s:textfield name="age" label="年齡"></s:textfield> <s:textfield name="address" label="籍貫"></s:textfield> <s:submit value="提交"></s:submit> </s:form> </body> |
看上去應該能正常運行,客戶端驗證將不能。struts必須準確的知道動做所在的命名空間(不是經過URL),所以正確的寫法以下:
create.jsp |
<head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Validation - Basic</title> <s:head/> </head> <body> <s:form action="/ns/helloValidation.action" validate="true"> <s:textfield name="name" label="姓名"></s:textfield> <s:textfield name="age" label="年齡"></s:textfield> <s:textfield name="address" label="籍貫"></s:textfield> <s:submit value="提交"></s:submit> </s:form> </body> |
struts2爲咱們共內置了16個驗證器,且所有是基於字段的驗證器。
用來驗證某個給定的字段的值不是null。注意,空字符串不是null。
(用法見後面的說明)
頁面:
<s:fielderror/>
<s:form action="validate">
<s:textfield name="userName" label="用戶名"></s:textfield>
<s:submit value="登陸"></s:submit>
</s:form>
動做類:
import com.opensymphony.xwork2.ActionSupport;
public class ValidationAction extends ActionSupport {
private static final long serialVersionUID = 6877330242746547448L;
private String userName;
private String password;
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;
}
}
<validators>
<field name="password">
<field-validator type="required">
<message>The password field is required!</message>
</field-validator>
</field>
</validators>
運行結果:
<validators>
<validator type="required">
<param name="fieldName">password</param>
<message>The password field is required!</message>
</validator>
</validators>
驗證給定的字段的值既不是null、也不是空白。
頁面:
<s:form action="validate">
<s:textfield name="userName" label="用戶名" required="true" requiredposition="left"></s:textfield>
<s:password name="password" label="密碼" required="true" requiredposition="left"></s:password>
<s:submit value="登陸"></s:submit>
</s:form>
動做類:
import com.opensymphony.xwork2.ActionSupport;
public class ValidationAction extends ActionSupport {
private static final long serialVersionUID = 6877330242746547448L;
private String userName;
private String password;
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;
}
}
驗證配置文件:
<validators>
<field name="userName">
<field-validator type="requiredstring">
<message>Please input the userName!</message>
</field-validator>
</field>
<field name="password">
<field-validator type="requiredstring">
<param name="trim">false</param>
<message>Please input the password!</message>
</field-validator>
</field>
</validators>
運行結果:
驗證配置文件的另一種寫法:
<validators>
<validator type="requiredstring">
<param name="fieldName">userName</param>
<message>Please input the userName!</message>
</validator>
<validator type="requiredstring">
<param name="fieldName">password</param>
<param name="trim">false</param>
<message>Please input the password!</message>
</validator>
</validators>
用來驗證某個字段的值是否能夠被轉換爲一個整數。若指定參數,還驗證是否在容許的範圍內。
參數名 |
類型 |
默認值 |
描述 |
fieldName |
String |
要驗證的字段名 |
|
min |
Integer |
容許的最小值。若沒有給出該參數則無限制 |
|
max |
Integer |
容許的最大值。若沒有給出該參數則無限制 |
頁面:
<s:form action="validate">
<s:textfield name="age" label="年齡"></s:textfield>
<s:submit value="登陸"></s:submit>
</s:form>
動做類:
private Integer age;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
驗證配置文件:
<validators>
<field name="age">
<field-validator type="int">
<param name="max">60</param>
<message>The age must be between ${min} and ${max}</message>
</field-validator>
</field>
</validators>
運行結果:
驗證配置文件的另一種寫法:
<validators>
<validator type="int">
<param name="fieldName">age</param>
<param name="min">18</param>
<param name="max">60</param>
<message>The age must be between ${min} and ${max}</message>
</validator>
</validators>
用來驗證某個字段的值是否能夠被轉換爲一個長整數。若指定參數,還驗證是否在容許的範圍內。
參數名 |
類型 |
默認值 |
描述 |
fieldName |
String |
要驗證的字段名 |
|
min |
Long |
容許的最小值。若沒有給出該參數則無限制 |
|
max |
Long |
容許的最大值。若沒有給出該參數則無限制 |
頁面:
動做類:
驗證配置文件:
運行結果:
用來驗證某個字段的值是否能夠被轉換爲一個短整數。若指定參數,還驗證是否在容許的範圍內。
參數名 |
類型 |
默認值 |
描述 |
fieldName |
String |
要驗證的字段名 |
|
min |
Short |
容許的最小值。若沒有給出該參數則無限制 |
|
max |
Short |
容許的最大值。若沒有給出該參數則無限制 |
頁面:
動做類:
驗證配置文件:
運行結果:
用來驗證某個字段的值是否能夠被轉換爲一個雙精度浮點數。若指定參數,還驗證是否在容許的範圍內。
類型 |
默認值 |
描述 |
|
fieldName |
String |
要驗證的字段名 |
|
minInclusive |
Double |
容許的最小值。若沒有給出該參數則無限制(含最小值) |
|
maxInclusive |
Double |
容許的最大值。若沒有給出該參數則無限制(含最大值) |
|
minExclusive |
Double |
容許的最小值。若沒有給出該參數則無限制(不含最小值) |
|
maxExclusive |
Double |
容許的最大值。若沒有給出該參數則無限制(不含最大值) |
<s:form action="validate">
<s:textfield name="percentage1" label="百分比1"></s:textfield>
<s:textfield name="percentage2" label="百分比2"></s:textfield>
<s:submit value="保存"></s:submit>
</s:form>
動做類:
private Double percentage1;
private Double percentage2;
public Double getPercentage1() {
return percentage1;
}
public void setPercentage1(Double percentage1) {
this.percentage1 = percentage1;
}
public Double getPercentage2() {
return percentage2;
}
public void setPercentage2(Double percentage2) {
this.percentage2 = percentage2;
}
驗證配置文件:
<validators>
<field name="percentage1">
<field-validator type="double">
<param name="minInclusive">20.1</param>
<param name="maxInclusive">50.1</param>
<message> The age must be between ${ minInclusive } and ${ maxInclusive }(含)</message>
</field-validator>
</field>
<field name="percentage2">
<field-validator type="double">
<param name="minExclusive">0.345</param>
<param name="maxExclusive">99.987</param>
<message> The age must be between ${ minExclusive } and ${ maxExclusive }(不含)</message>
</field-validator>
</field>
</validators>
運行結果:
<validators>
<validator type="double">
<param name="fieldName">percentage1</param>
<param name="minInclusive">20.1</param>
<param name="maxInclusive">50.1</param>
<message> The age must be between ${ minInclusive } and ${ maxInclusive }(含)</message>
</validator>
<validator type="double">
<param name="fieldName">percentage2</param>
<param name="minExclusive">0.345</param>
<param name="maxExclusive">99.987</param>
<message> The age must be between ${ minExclusive } and ${ maxExclusive }(不含)</message>
</validator>
</validators>
用來確保給定的日期字段的值落在一個給定的範圍內。
參數名 |
類型 |
默認值 |
描述 |
fieldName |
String |
要驗證的字段名 |
|
min |
java.util.Date |
容許的最小值。若沒有給出該參數則無限制(含最小值) |
|
max |
java.util.Date |
容許的最大值。若沒有給出該參數則無限制(含最大值) |
頁面:
<s:form action="validate">
<s:textfield name="birthday" label="出生日期"></s:textfield>
<s:submit value="保存"></s:submit>
</s:form>
動做類:
private Date birthday;
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
驗證配置文件:
<validators>
<field name="birthday">
<field-validator type="date">
<param name="min">2011-01-01</param>
<param name="max">2011-12-31</param>
<message>日期必須爲2011年</message>
</field-validator>
</field>
</validators>
運行結果:
驗證配置文件的另一種寫法:
<validators>
<validator type="date">
<param name="fieldName">birthday</param>
<param name="min">2011-01-01</param>
<param name="max">2011-12-31</param>
<message>日期必須爲2011年</message>
</validator>
</validators>
用於驗證是否知足一個OGNL表達式。這是一個非字段的驗證。只有給定的參數的返回值是true時才能驗證經過。驗證不經過時產生一個動做錯誤,所以要顯示該錯誤,須要使用<s:actionerror/>標籤。
頁面:
<s:actionerror/>
<s:form action="validate">
<s:textfield name="minNumber" label="最小值"></s:textfield>
<s:textfield name="maxNumber" label="最大值"></s:textfield>
<s:submit value="保存"></s:submit>
</s:form>
動做類:
private Integer minNumber;
private Integer maxNumber;
public Integer getMinNumber() {
return minNumber;
}
public void setMinNumber(Integer minNumber) {
this.minNumber = minNumber;
}
public Integer getMaxNumber() {
return maxNumber;
}
public void setMaxNumber(Integer maxNumber) {
this.maxNumber = maxNumber;
}
驗證配置文件:
<validators>
<validator type="expression">
<param name="expression">
maxNumber>minNumber
</param>
<message>最大值必須大於最小值</message>
</validator>
</validators>
運行結果:
該驗證器沒有字段形式的寫法。要進行字段驗證,請使用fieldexpression驗證器。
用於驗證某個字段是否知足一個OGNL表達式。這是一個基於字段的驗證。只有給定的參數的返回值是true時才能驗證經過。驗證不經過時產生一個字段錯誤。
參數名 |
類型 |
默認值 |
描述 |
fieldName |
String |
要驗證的字段名 |
|
expression |
String |
OGNL表達式,只有該表達式爲true才能驗證經過 |
頁面:
<s:form action="validate">
<s:textfield name="minNumber" label="最小值"></s:textfield>
<s:textfield name="maxNumber" label="最大值"></s:textfield>
<s:submit value="保存"></s:submit>
</s:form>
動做類:
private Integer minNumber;
private Integer maxNumber;
public Integer getMinNumber() {
return minNumber;
}
public void setMinNumber(Integer minNumber) {
this.minNumber = minNumber;
}
public Integer getMaxNumber() {
return maxNumber;
}
public void setMaxNumber(Integer maxNumber) {
this.maxNumber = maxNumber;
}
驗證配置文件:
<validators>
<field name="maxNumber">
<field-validator type="fieldexpression">
<param name="expression">
maxNumber>minNumber
</param>
<message>最大值必須大於最小值1</message>
</field-validator>
</field>
</validators>
運行結果:
驗證配置文件的另一種寫法:
<validators>
<validator type="fieldexpression">
<param name="fieldName">maxNumber</param>
<param name="expression">
maxNumber>minNumber
</param>
<message>最大值必須大於最小值</message>
</validator>
</validators>
用來驗證給定的字段是否符合一個Email的規範。它的正則表達式爲
\\b(^[_A-Za-z0-9-](\\.[_A-Za-z0-9-])*@([A-Za-z0-9-])+((\\.com)|(\\.net)|(\\.org)|(\\.info)|(\\.edu)|(\\.mil)|(\\.gov)|(\\.biz)|(\\.ws)|(\\.us)|(\\.tv)|(\\.cc)|(\\.aero)|(\\.arpa)|(\\.coop)|(\\.int)|(\\.jobs)|(\\.museum)|(\\.name)|(\\.pro)|(\\.travel)|(\\.nato)|(\\..{2,3})|(\\..{2,3}\\..{2,3}))$)\\b
頁面:
<s:form action="validate">
<s:textfield name="email" label="郵箱"></s:textfield>
<s:submit value="保存"></s:submit>
</s:form>
動做類:
private String email;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
驗證配置文件:
<validators>
<field name="email">
<field-validator type="email">
<message>請輸入正確的郵箱</message>
</field-validator>
</field>
</validators>
運行結果:
<validators>
<validator type="email">
<param name="fieldName">email</param>
<message>請輸入正確的郵箱</message>
</validator>
</validators>
用來驗證給定的字段值是不是一個合法的URL地址。
參數名 |
類型 |
默認值 |
描述 |
fieldName |
String |
要驗證的字段名 |
頁面:
<s:form action="validate">
<s:textfield name="url" label="我的主頁"></s:textfield>
<s:submit value="保存"></s:submit>
</s:form>
動做類:
private String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
驗證配置文件:
<validators>
<field name="url">
<field-validator type="url">
<message>請輸入正確的地址</message>
</field-validator>
</field>
</validators>
運行結果:
驗證配置文件的另一種寫法:
<validators>
<validator type="url">
<param name="fieldName">url</param>
<message>請輸入正確的地址</message>
</validator>
</validators>
該驗證程序能夠提升代碼的可重用性,你能夠利用它把同一個驗證程序配置文件用於多個動做。
頁面:
<s:form action="customer_save">
<s:textfield name="address.streetName" label="街道"></s:textfield>
<s:submit></s:submit>
</s:form>
動做類:
public class Customer extends ActionSupport {
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
public class Address {
private String streetName;
public String getStreetName() {
return streetName;
}
public void setStreetName(String streetName) {
this.streetName = streetName;
}
}
驗證配置文件:
Address-validation.xml
<validators>
<field name="streetName">
<field-validator type="requiredstring">
<message>請輸入正確街道地址</message>
</field-validator>
</field>
</validators>
Customer-validation.xml
<validators>
<field name="address">
<field-validator type="visitor">
<message>Address:</message>
</field-validator>
</field>
</validators>
運行結果:
頁面:
動做類:
驗證配置文件:
運行結果:
用來驗證一個非空的字段值是否是有足夠的長度。
頁面:
動做類:
驗證配置文件:
運行結果:
用來檢查給定字段是否與給定的正則表達式相匹配。正則表達式的詳細內容能夠參考JDK的java.util.regex.Pattern類。
參數名 |
類型 |
默認值 |
描述 |
fieldname |
String |
要驗證的字段名 |
|
expression |
String |
正則表達式。此參數是必須的 |
|
caseSensitive |
Boolean |
true |
是否區分大小寫的狀況 |
trim |
Boolean |
true |
驗證前是否要去掉前導和尾綴的空白字符 |
頁面:
<s:form action="validate">
<s:textfield name="userName" label="用戶名"></s:textfield>
<s:submit value="保存"></s:submit>
</s:form>
動做類:
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
驗證配置文件:
<validators>
<field name="userName">
<field-validator type="regex">
<param name="expression"><![CDATA[([aAbBcCdD][123][eEfFgG][456])]]></param>
<message> 用戶名必須符合規範</message>
</field-validator>
</field>
</validators>
運行結果:
驗證配置文件的另一種寫法:
<validators>
<validator type="regex">
<param name="fieldName">userName</param>
<param name="expression"><![CDATA[([aAbBcCdD][123][eEfFgG][456])]]></param>
<message> 用戶名必須符合規範</message>
</validator>
</validators>
頁面:
動做類:
驗證配置文件:
運行結果:
驗證的實現全是靠驗證器(validators)完成的,這些驗證器必須在ValidatorFactory(利用registerValidator方法)中進行註冊。自定義的驗證器能夠經過一種很簡單的方式註冊進去,那就是在構建路徑中(/WEB-INF/classes)中建立validators.xml文件,在該文件中聲明你要註冊的驗證器。
如下列出了struts2框架中默認的驗證器,自定義的驗證器的定義語法能夠參考如下內容。
com.opensymphony.xwork2.validator.validators.default.xml |
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator Config 1.0//EN" "http://www.opensymphony.com/xwork/xwork-validator-config-1.0.dtd">
<!-- START SNIPPET: validators-default --> <validators> <validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/> <validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/> <validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/> <validator name="long" class="com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator"/> <validator name="short" class="com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator"/> <validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/> <validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/> <validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/> <validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/> <validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/> <validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/> <validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/> <validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/> <validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/> <validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/> <validator name="conditionalvisitor" class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/> </validators> <!-- END SNIPPET: validators-default --> |
注意:
在struts2.0.7和以前的版本中,若是加入了自定義的驗證器,你必須同時還得擁有一份默認驗證器的拷貝,即在類路徑中的validators.xml的驗證器會覆蓋掉默認的驗證器。但以後的版本則避免了此問題。
用來檢查密碼強度的驗證程序。規則:至少包含一個數字、一個小寫字母和一個大寫字母。此外該驗證程序還能夠接受一個minLength參數,用戶能夠經過設置該參數來設置一個可接受的口令的最小長度。
一、編寫驗證器
package wiva.struts2.train.validator;
import com.opensymphony.xwork2.validator.ValidationException;
import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport;
public class StrongPasswordValidator extends FieldValidatorSupport {
private int minLength = -1;
public int getMinLength() {
return minLength;
}
public void setMinLength(int minLength) {
this.minLength = minLength;
}
public void validate(Object object) throws ValidationException {
String feildName = getFieldName();
String value = (String)getFieldValue(feildName, object);
if(value == null||value.length()==0){
addFieldError(feildName, object);
}else if((minLength>-1)&&(value.length()<minLength)){
addFieldError(feildName, object);
}else if(!isPasswordStrong(value)){
addFieldError(feildName, object);
}
}
private static final String GROUP1 = "abcdefghijklmnopqrstuvwxyz";
private static final String GROUP2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String GROUP3 = "0123456789";
protected boolean isPasswordStrong(String password) {
boolean ok1 = false;
boolean ok2 = false;
boolean ok3 = false;
int length = password.length();
for(int i=0;i<length;i++){
if(ok1&&ok2&&ok3)
break;
String character = password.substring(i,i+1);
if(GROUP1.contains(character)){
ok1 = true;
continue;
}
if(GROUP2.contains(character)){
ok2 = true;
continue;
}
if(GROUP3.contains(character)){
ok3 = true;
continue;
}
}
return ok1&&ok2&&ok3;
}
}
二、註冊驗證器(WEB-INF/classes/validators.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator Config 1.0//EN"
"http://www.opensymphony.com/xwork/xwork-validator-config-1.0.dtd">
<validators>
<validator name="strongpassword" class="wiva.struts2.train.validator.StrongPasswordValidator"></validator>
</validators>
三、使用(*Action-validation.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
<field name="password">
<field-validator type="strongpassword">
<param name="minLength">6</param>
<message>少包含一個數字、一個小寫字母和一個大寫字母且不能少於6個</message>
</field-validator>
</field>
</validators>
以前所使用和編寫的驗證程序都是聲明性的,先聲明,後使用。在某些場合,可能由於驗證規則過於複雜,用聲明性驗證會困難一些,於是須要爲它們編寫必要的驗證代碼,即須要進行"編程驗證"。
Struts2提供了一個com.opensymphony.xwork2.Validateable接口,能夠在本身的動做類內經過實現該接口以提供編程驗證的功能。
package com.opensymphony.xwork2;
public interface Validateable {
void validate();
}
若是動做類實現了該接口,Struts會調用它的validate方法,因此應把用來驗證用戶輸入的代碼編寫在這個方法內。ActionSupport實現了該接口,所以動做類繼承ActionSupport就不須要直接實現該接口了。
用戶註冊程序。若是用戶輸入的用戶名已經在數據庫中存在了,則要求用戶換另一個用戶名進行註冊。
動做類
package wiva.struts2.train.action;
import java.util.LinkedList;
import java.util.List;
import com.opensymphony.xwork2.ActionSupport;
public class UserRegAction extends ActionSupport {
/**
*
*/
private static final long serialVersionUID = 2227569782574386186L;
private String userName;
private String password;
private static List<String> userNames = new LinkedList<String>();
static{
//實際業務中,userNames中的內容應該從數據庫中查詢出來
userNames.add("admin");
userNames.add("wzhting");
}
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 void validate() {
if(userNames.contains(userName))
addFieldError("userName", "用戶名"+userName+"已經存在");
}
}
若針對某個動做方法單獨進行驗證,你須要編寫一個方法public void validate方法名().方法名的第一個字母大寫
<s:form action="addAction">
<s:textfield name="userName" label="用戶名"></s:textfield>
<s:submit value="添加"></s:submit>
</s:form>
<s:form action="editAction">
<s:textfield name="userName" label="用戶名"></s:textfield>
<s:submit value="修改"></s:submit>
</s:form>
動做類
package wiva.struts2.train.action;
import com.opensymphony.xwork2.ActionSupport;
public class ValidateAction extends ActionSupport {
private static final long serialVersionUID = -739143505400361615L;
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String add(){
return SUCCESS;
}
public String edit(){
return SUCCESS;
}
public void validateAdd() {
if(userName==null||userName.length()==0)
addFieldError("userName","請輸入用戶名");
}
}
struts2框架在如下方面支持國際化(i18n):
咱們能夠經過在標籤中使用getText方法、text標籤、i18n標籤等形式訪問資源文件。
<s:property value="getText('some.key')"/>
第一種:<s:text name="some,key"/>
若是some.key沒有找到,則顯示"some.key";若找到則顯示其對應的值。
第二種:<s:text name="some,key">
默認值
</s:text>
若是some.key沒有找到,則顯示"默認值";若找到則顯示其對應的值。
<s:i18n name="StudentAction">
<s:text name="student.name"></s:text>
</s:i18n>
<s:textfield name="name" key="student.name"></s:textfield>
編寫步驟
前提:上傳文件表單的enctype必須是multipart/form-data;method必須是post
屬性類型 |
屬性名 |
說明 |
java.io.File |
[inputName] |
表明要上傳的文件 |
java.lang.String |
[inputName]FileName |
表明要上傳的文件文件名 |
java.lang.String |
[inputName]ContentType |
表明要上傳的文件內容類型 |
注:適用於單文件上傳 |
3、File Upload攔截器
struts2應用程序裏,File Upload攔截器和Jakarta Commons FileUpload庫能夠幫助分析並負責上傳文件。它是defaultStack攔截器組的成員。
程序員通常會設置如下兩個File Upload攔截器的屬性:
maximumSize:上傳文件的最大長度(單位字節),默認值2MB.
allowedTypes:容許上傳得內容類型的清單,各種型之間以逗號分隔.
public class SingleFileUploadAction extends ActionSupport implements ServletContextAware{
private static final long serialVersionUID = -8952900773638870479L;
private File attachment;
private String attachmentFileName;
private String attachmentContentType;
private String description;
private ServletContext servletContext;
public String upload(){
if(attachment!=null){
String dataDir = servletContext.getRealPath("/WEB-INF/");
File saveFile = new File(dataDir,attachmentFileName);
boolean r = attachment.renameTo(saveFile);
return SUCCESS;
}else{
return INPUT;
}
}
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
public File getAttachment() {
return attachment;
}
public void setAttachment(File attachment) {
this.attachment = attachment;
}
public String getAttachmentFileName() {
return attachmentFileName;
}
public void setAttachmentFileName(String attachmentFileName) {
this.attachmentFileName = attachmentFileName;
}
public String getAttachmentContentType() {
return attachmentContentType;
}
public void setAttachmentContentType(String attachmentContentType) {
this.attachmentContentType = attachmentContentType;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
<struts>
<constant name="struts.devMode" value="true"></constant>
<package name="p1" extends="struts-default">
<action name="singleFileUploadInput">
<result>/SingleUpload.jsp</result>
</action>
<action name="singleFileUpload" class="cn.sdxhce.action.SingleFileUploadAction" method="upload">
<interceptor-ref name="fileUpload">
<param name="maximumSize">1048576</param>
</interceptor-ref>
<interceptor-ref name="basicStack"></interceptor-ref>
<result name="input">/SingleUpload.jsp</result>
<result>/SingleConfirm.jsp</result>
</action>
<action name="uploadAction" class="cn.sdxhce.action.FileUpload">
<result>/uploadResult.jsp</result>
<result name="input">/upload.jsp</result>
</action>
<action name="multipleUploadAction" class="cn.sdxhce.action.MultipleUploadAction" method="upload">
<result name="input">/multipleUpload.jsp</result>
<result>/multipleUploadResult.jsp</result>
</action>
</package>
</struts>
Struts自帶的攔截器有35個之多。例如:輸入驗證是由名爲validation攔截器處理的,若是禁用該攔截器,輸入驗證將中止工做;文件上傳如此簡單和順利,要感謝名爲fileUpload的攔截器。
Struts自帶的默認攔截器足以知足絕大多數的應用程序的須要,但早晚會遇到須要本身創建一個攔截器的時候,這就是自定義攔截器。
攔截器的使用必須先遵循先編寫攔截器、再定義後使用的原則。咱們所使用的默認攔截器其實都是Struts以前已經編寫好了的,而且在某個配置文件中進行了定義,這個文件即是存放在Struts的發行包中,具體位置爲struts2-core-*.jar(*爲版本號)中的struts-default.xml文件中。
<interceptors>
<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
<interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
<interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
<interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
<interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
<interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
<interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
<interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
<interceptor name="externalRef" class="com.opensymphony.xwork2.interceptor.ExternalReferencesInterceptor"/>
<interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
<interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
<interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
<interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
<interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
<interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
<interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
<interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
<interceptor name="sessionAutowiring" class="org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor"/>
<interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
<interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
<interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
<interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
<interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
<interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
<interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
<interceptor name="jsonValidation" class="org.apache.struts2.interceptor.validation.JSONValidationInterceptor" />
<interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
<interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />
<!-- Basic stack -->
<interceptor-stack name="basicStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
</interceptor-stack>
<!-- Sample validation and workflow stack -->
<interceptor-stack name="validationWorkflowStack">
<interceptor-ref name="basicStack"/>
<interceptor-ref name="validation"/>
<interceptor-ref name="workflow"/>
</interceptor-stack>
<!-- Sample JSON validation stack -->
<interceptor-stack name="jsonValidationWorkflowStack">
<interceptor-ref name="basicStack"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
<interceptor-ref name="jsonValidation"/>
<interceptor-ref name="workflow"/>
</interceptor-stack>
<!-- Sample file upload stack -->
<interceptor-stack name="fileUploadStack">
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>
<!-- Sample model-driven stack -->
<interceptor-stack name="modelDrivenStack">
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>
<!-- Sample action chaining stack -->
<interceptor-stack name="chainStack">
<interceptor-ref name="chain"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>
<!-- Sample i18n stack -->
<interceptor-stack name="i18nStack">
<interceptor-ref name="i18n"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>
<!-- An example of the paramsPrepareParams trick. This stack
is exactly the same as the defaultStack, except that it
includes one extra interceptor before the prepare interceptor:
the params interceptor.
This is useful for when you wish to apply parameters directly
to an object that you wish to load externally (such as a DAO
or database or service layer), but can't load that object
until at least the ID parameter has been loaded. By loading
the parameters twice, you can retrieve the object in the
prepare() method, allowing the second params interceptor to
apply the values on the object. -->
<interceptor-stack name="paramsPrepareParamsStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
<!-- A complete stack with all the common interceptors in place.
Generally, this stack should be the one you use, though it
may do more than you need. Also, the ordering can be
switched around (ex: if you wish to have your servlet-related
objects applied before prepare() is called, you'd need to move
servletConfig interceptor up.
This stack also excludes from the normal validation and workflow
the method names input, back, and cancel. These typically are
associated with requests that should not be validated.
-->
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
<!-- The completeStack is here for backwards compatibility for
applications that still refer to the defaultStack by the
old name -->
<interceptor-stack name="completeStack">
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
<!-- Sample execute and wait stack.
Note: execAndWait should always be the *last* interceptor. -->
<interceptor-stack name="executeAndWaitStack">
<interceptor-ref name="execAndWait">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="execAndWait">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="defaultStack"/>
從技術角度上講,每一個攔截器都是直接或間接地實現了com.opensymphony.xwork2.interceptor.Interceptor接口的java類,該接口的定義以下:
package com.opensymphony.xwork2.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import java.io.Serializable;
public interface Interceptor extends Serializable {
void destroy();
void init();
String intercept(ActionInvocation invocation) throws Exception;
}
方法說明:
Struts會依次調用程序員爲某個動做而註冊的每個攔截器的intercept方法。在每次調用該方法的時候,都會向它傳遞一個com.opensymphony.xwork2.ActionInvocation (接口)的實例。一個ActionInvocation對象表明一個給定動做的執行狀態,攔截器能夠從這個對象得到與該動做相關聯的Action對象和Result對象.在完成本身的任務後,攔截器將調用ActionInvocatio的invoke方法前進到動做處理流程的下一個環節.com.opensymphony.xwork2.interceptor.AbstractInterceptor類實現了Interceptor接口,併爲init和destroy方法分別提供了一個空白的實現.並不是全部的攔截器都須要對某些資源進行初始化和銷燬,所以咱們自定義的攔截器通常選擇繼承該類,以節省開發時間.
利用攔截器用於登錄用戶是否超時
public class SessionInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 6072772019059317328L;
public String intercept(ActionInvocation invocation) throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
Object o = session.getAttribute("user");
if(o==null)
return "sessionInvalided";
else
return invocation.invoke();
}
}
<struts>
<constant name="struts.devMode" value="true"></constant>
<package name="p1" extends="struts-default">
<interceptors>
<interceptor name="sessionCheck" class="cn.sdxhce.interceptor.SessionInterceptor"></interceptor>
</interceptors>
<global-results>
<result name="sessionInvalided">/sessionInvalid.jsp</result>
</global-results>
<action name="register" class="cn.sdxhce.action.StudentAction">
<interceptor-ref name="sessionCheck"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
<result>/result.jsp</result>
</action>
</package>
</struts>
/jfreechart-1.0.13.jar/jcommon-1.0.16.jar/struts2-jfreechart-plugin-2.1.8.1.jar
public class GetChartAction extends ActionSupport {
private static final long serialVersionUID = -7814290464584999876L;
private JFreeChart chart;
public JFreeChart getChart() {
return chart;
}
public String execute(){
ValueAxis xAxis = new NumberAxis("年度");
ValueAxis yAxis = new NumberAxis("產值");
XYSeries xySeries = new XYSeries("綠豆");
xySeries.add(0,300);
xySeries.add(1,200);
xySeries.add(2,400);
xySeries.add(3,500);
xySeries.add(4,600);
xySeries.add(5,500);
xySeries.add(6,800);
xySeries.add(7,1000);
xySeries.add(8,1100);
XYSeriesCollection xyDataset = new XYSeriesCollection(xySeries);
XYPlot xyPlot = new XYPlot(xyDataset,xAxis,yAxis,new StandardXYItemRenderer(StandardXYItemRenderer.SHAPES_AND_LINES));
chart = new JFreeChart(xyPlot);
return SUCCESS;
}
}
<package name="p2" extends="jfreechart-default">
<action name="chart" class="wiva.struts2.train.action.GetChartAction">
<result type="chart">
<param name="width">600</param>
<param name="height">400</param>
</result>
</action>
</package>
<body>
<s:url action="chart" var="url"></s:url>
<img src="<s:property value="url"/>" alt="hello" />
</body>