Struts2 类型转换和数据校验
學習內容
?Struts 2類型轉換
?Struts 2數據校驗
能力目標
?熟悉Struts 2自帶類型轉換器
?能自定義類型轉換器
?自定義輸入校驗功能
?熟悉Struts 2內置校驗器
本章簡介
Struts 2提供了功能強大的類型轉換器來處理表現層數據,開發者可以利用Struts 2的類型轉換機制來完成任意的類型轉換。在應用開發中,對用戶的輸入進行校驗是經常遇到的業務,Struts 2提供了多種方式供開發者對客戶輸入的數據進行校驗,非常得方便靈活。
本章將深入學習Struts 2的類型轉換器和數據校驗,并學習自定義類型轉換器和數據校驗的多種方式。
核心技能部分
8.1?Struts 2主題和模板
上一章我們學習了Struts 2中常用的標簽,其實Struts 2的UI標簽都是基于主題和模板的,模板是一個UI標簽的外在表現形式。如果我們為所有的UI標簽提供了樣式和視覺效果相似的模板,那么這一系列的模板就形成了一個主題。
主題和模板是UI標簽的核心,我們通過下面的例子來說明三者之間的關系。
下面是用Struts 2的表單標簽組成的一個登錄表單,代碼如下所示:
<%@ page language="java" ?pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>用戶登錄</title>
</head>
<body>
<h3>用戶登錄</h3>
<s:form action="checkLogin" namespace="/user">
<s:textfield name="loginname" label="登錄名稱"></s:textfield>
<s:password name="pwd" label="登錄密碼"></s:password>
<s:submit value="登錄"></s:submit>
</s:form>
</body>
</html>
該頁面的運行效果如圖8.1.1所示。
?
圖8.1.1 登錄頁面
現在打開本頁面的源文件來看看由Struts 2表單標簽生成的HTML代碼:
<html>
<head>
<title>用戶登錄</title>
</head>
<body>
<h3>用戶登錄</h3>
<form id="checkLogin" name="checkLogin" οnsubmit="return true;"
action="/firstStruts 2/user/checkLogin.action" method="post">
<table class="wwFormTable">
<tr>
<td class="tdLabel">
<label for="checkLogin_loginname" class="label">登錄名稱:</label></td>
<td>
<input type="text" name="loginname" value=""
?id="checkLogin_loginname"/></td>
</tr>
<tr>
<td class="tdLabel">
<label for="checkLogin_pwd" class="label">登錄密碼:</label></td>
<td><input type="password" name="pwd" id="checkLogin_pwd"/></td>
</tr>
<tr>
<td colspan="2">
<div align="right"><input type="submit" id="checkLogin_0" value="登錄"/>
</div></td>
</tr>
</table></form>
</body>
</html>
通過上述代碼可以看到Struts 2的表單標簽在生成HTML代碼時額外多出來了很多其他的代碼,我們在JSP頁面中使用Struts 2表單標簽時并沒有使用table表格進行頁面布局,但生成的HTML卻自動使用table表格進行了布局,這就是模板在起作用。不同的模板會產生不同的表現形式,Struts2的UI標簽默認采用table進行頁面布局。
模板是UI標簽的外在表現形式(也就是Struts2標簽解釋成HTML標簽的方式),每個標簽都有一個或多個模板,把樣式和視覺效果相似的模板放在一起就組成了一個主題。
Struts 2默認提供了四種主題,分別是simple、xhtml、css_xhtml和Ajax。
??simple主題:這是最簡單的主題,是底層的結構。使用該主題時,每個UI標簽只生成一個HTML元素,不會額外生成其他的內容。
??xhtml主題:這是Struts 2的默認主題,它對simple主題進行了擴展,在simple主題的基礎上增加了一些特性,該主題為UI標簽使用標準的兩列表格進行布局,并且能自動生成JavaScript客戶端校驗和自動輸出校驗錯誤提示信息。
??css_xhtml主題:該主題是對xhtml主題的擴展,在xhtml主題的基礎上加入了CSS樣式控制。
??Ajax主題:該主題是對xhtml主題的擴展,在xhtml主題的基礎上為UI標簽提供了額外的Ajax支持。例如,支持Ajax方式的客戶端校驗,支持表單異步提交等。
下面介紹如何使用這四種主題,設置主題是通過theme屬性來實現的,主要有如下幾種方式:
??通過指定UI標簽的theme屬性來設置主題
??通過取得request會話范圍內的theme屬性值來設置主題
??通過取得session會話范圍內的theme屬性值來設置主題
??通過取得application會話范圍內的theme屬性值來設置主題
??通過在struts.properties或struts.xml文件中對struts.ui.theme進行指定來設置主題
值得注意的是,上述方式是有不同優先級的,排在最上面的方式會覆蓋后面的方式。一旦我們指定了主題,Struts 2就會根據主題來加載模板并最終影響頁面效果。一個頁面一般使用一個主題或模板,所以使用theme屬性設置頁面主題通常放在<s:head/>標簽中。
8.2?類型轉換器
在基于HTTP協議的Web應用程序中,用戶在客戶端瀏覽器輸入的數據都被當作字符串來接收和傳遞,例如表單中的姓名、生日、年齡等。當數據被傳遞到服務器端時就需要經過類型轉換才能使用。例如表單中的年齡數據,這個數據被當作字符串傳遞到了服務器端,服務器端程序需要把這個數據轉換成整數類型后才能使用。
而在傳統的JSP+Servlet+JavaBean模型中,為了進行類型轉換,開發者需要反復編寫內容類似的代碼。
String name=request.getParameter("name");
Date birthday=Date.valueOf(request.getParameter("birthday"));
int height=Integer.parseInt(request.getParameter("height"));
int weight=Integer.parseInt(request.getParameter("weight"));
幸運的是,Struts 2作為一個完善的、優秀的MVC框架,提供了豐富的類型轉換功能,它本身內置的類型轉換器可以自動完成數據類型轉換,開發者一般不需要實現自定義的類型轉換器。
8.2.1?Struts 2內置類型轉換器
Struts 2內置了一下常用的類型轉換器:
??簡單類型,例如int、boolean、double等,即Struts 2可以把客戶端的字符串數據自動轉換成int、boolean、double等數據格式。
??日期類型,Struts 2會采用當前區域(Locale)的短日期格式來轉換客戶端的字符串格式的日期數據。
??集合類型,例如Collection、List、Set等,Struts 2會將客戶端的字符串數據,request.getParameterValues()方法返回的字符串數據轉換成集合。
對于內置的類型轉換器,我們在前面的案例中已經在使用了,這里不再多述。在實際應用中,業務千變萬化,有的情況下Struts 2的內置類型轉換器依然不能滿足開發者的需求,但是Struts 2充分考慮到了擴展性,開發者完全可以自定義類型轉換器。
8.2.2?自定義類型轉換器
Struts 2中自定義的類型轉換器必須實現ognl.TypeConverter接口,但是為了開發方便,可以直接繼承org.apache.Struts2.util.StrutsTypeConverter抽象類,并且實現該類中的兩個方法。
??public Object convertFromString(Map context, String[] values, Class toClass)
??public String convertToString(Map context,Object obj)
當需要將字符串轉換成復合類型時,調用convertFromString方法;當需要將復合類型轉換成字符串時,會調用convertToString方法。
下面是這兩個方法的參數介紹。表8-1-1是convertFromString方法的參數介紹,表8-1-2是convertToString方法的參數介紹。
表8-1-1 convertFromString方法的參數介紹
參數 | 說明 |
Map ?context | 類型轉換器環境的上下文 |
String[] ?values | 需要轉換的請求參數字符串數組 |
Class ?toClass | 轉換后的目標類型 |
?
表8-1-2convertToString方法的參數介紹
參數 | 說明 |
Map ?context | 類型轉換器環境的上下文 |
Object obj | 需要轉換成字符串的實例對象 |
示例8.1
下面我們給出一個案例介紹自定義類型轉換器的使用步驟,用戶在表單中輸入生日,而服務器端在接受的時候需要轉換成Date類型,這個時候經常會出席類型轉換異常,為了解決這個問題,我們自定義一個類型轉換器。
(1)創建名字為DateConverter.java的類型轉換器,繼承StrutsTypeConverter類,參考代碼如下所示。
public class DateConverter extends StrutsTypeConverter {
private ?final DateFormat[] dfs = { ?// 支持轉換多種日期格式
new SimpleDateFormat("yyyy-MM-dd"),
new SimpleDateFormat("yyyy/MM/dd")
};
// 將指定格式字符串轉換為日期類型
public Object convertFromString(Map context, String[] values, Class toType) {
String dateStr = values[0];// 獲取日期的字符串
// 遍歷日期支持格式,進行轉換
for (int i=0;i<dfs.length;i++) {
try {
return dfs[i].parse(dateStr); ??//類型轉換
} catch (Exception e) {
continue;
}
}
//如果遍歷完畢后仍沒有轉換成功,拋出轉換異常。
throw new TypeConversionException();
}
//將日期轉換為指定格式字符串
public String convertToString(Map context, Object object) {
Date date = (Date) object;
// 輸出的格式是yyyy-MM-dd
return new SimpleDateFormat("yyyy-MM-dd").format(date);
}
}
在上述代碼中我們重寫了convertFromString和convertToString方法,本案例主要使用convertFromString方法,在該方法中實現了把客戶端傳過來的字符串類型的日期轉換成Date類型。
(2)注冊自定義類型轉換器
創建好自定義類型轉換器后,只有將它注冊在Web應用中,Struts 2框架才能正常使用該類型轉換器。方法是首先在Web工程的src根目錄下創建名字為xwork-conversion.properties的文件,然后在文件中編寫“目標數據類型=自定義類型轉換器”代碼,如下所示。
java.util.Date=com.zy.DateConverter
(3)?創建Action來測試自定義的類型轉換器,代碼如下所示。
public class DateAction extends ActionSupport {
private Date birthday;
public String execute() {
System.out.print(birthday);
return null;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
(4)?創建JSP視圖頁面讓用戶輸入自己的生日,參考代碼如下所示。
<body>
<s:form action="test.action" name="f" method="post">
<s:textfield label="請輸入生日" name="birthday"/>
(yyyy-mm-dd或yyyy/mm/dd)
<br/>
<s:submit value="提交"/>
</s:form>
</body>
運行效果如圖8.1.2所示。
?
圖8.1.2 運行效果
單擊【提交】按鈕后會在控制臺看到如圖8.1.3所示的結果。
?
圖8.1.3 運行結果
8.2.3?開發集合屬性的自定義類型攔截器
在實際應用開發中,經常會出現需要批量操作對象的情況。例如,產品信息的批量增加如圖8.1.4所示。
?
圖8.1.4產品信息的批量增加
在圖8.1.4中,可以再輸入產品信息后單擊“增加”按鈕來動態添加產品輸入項,如圖8.1.5所示.。
?
圖8.1.5動態添加產品輸入項
在圖8.1.5中,用戶只需要輸入多個以字符串表示的產品集合,然后單擊“批量增加“按鈕,就可以實現產品的批量增加。與前面示例的不同在于,此處轉換類型的時候不再轉換一個實例,而是轉換的集合。為了實現這種功能,必須開發集合屬性的自定義類型轉化器,實現產品批量增加的功能,步驟如下:
(1)?創建用于描述產品信息的實體類,命名為“product.java”。
public class Product {
private String id;//產品編號
private String name;//產品名稱
private double price;//產品價格
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}//getter setter方法省略。。。
?
?
(2)?創建自定義類型轉換器,命名為“productConvert.java“,該類繼承自StrutsTypeConverter抽象類。
//基于StrutsTypeConverter接口的類型轉換器
public class ProductConvert extends StrutsTypeConverter {
//實現將字符串轉換成復合類型的方法
@Override
public Object convertFromString(Map arg0, String[] arg1, Class arg2) {
List<Product> products = new ArrayList<Product>();
//循環arg1中的每個元素,每個元素代表用戶輸入的一個產品項
for (int i = 0; i < arg1.length; i++) {
//從arg1數組中獲取用戶輸入的產品信息并使用逗號就行分割
String[] productValues = arg1[i].split(",");
//從分割后的數組中獲取id的值
String id= productValues[0];
//從分割后的數組中獲取name的值
String name = productValues[1];
//從分割后的數組中獲取price的值
double price = Double.parseDouble(productValues[2]);
//創建Product實例
Product product = new Product();
//設置屬性
product.setId(id);
product.setName(name);
product.setPrice(price);
//添加至集合中
products.add(product);
}
//返回列表
return products;
}
?
//實現將復合類型轉換為字符串的方法
public String convertToString(Map arg0, Object arg1) {
// TODO Auto-generated method stub
return null;
}
?
}
(3)?注冊ProcductConvert自定義類型轉換器。在xwork-conversion.properties文件中加入用于注冊ProcductConvert全局類型轉換器的代碼。
java.util.List=com.zzzy.web.struts.convert.ProductConvert
(4)?創建action業務控制器,命名為“ProductAction.java”,用于測試ProcductConvert類型轉換器。
public class ProductAction extends ActionSupport {
//定義用于封裝請求參數的Product集合實例
private List<Product> products;
public String execute()throws Exception {
//獲取輸出對象
PrintWriter out = ServletActionContext.getResponse().getWriter();
//獲取使用productConvert類型轉化器轉換后的products列表對象
out.println("<h2>已成功轉換,正在插入下列產品......</h2>");
out.println("編號?????????名稱 單價</br>");
for (int i = 0; i < products.size(); i++) {
//獲取id
String id = products.get(i).getId();
//獲取name
String name = products.get(i).getName();
//獲取價格
double price = products.get(i).getPrice();
out.println(id+" ?"+name+" ??"+price+"</br>");
}
return null;
}
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
}
(5)?創建jsp頁面,命名為“product.jsp”,用于提供用戶批量增加產品的界面。
<script type="text/javascript">
//動態創建表格行和文本框
function insertRow(){
//獲取表格對象
var myTab = document.getElementById("tab");
//創建表格行
var newRow = myTab.insertRow(myTab.rows.length-1);
//為新增的表格動態生成文本框
newRow.insertCell().innerHTML="<input type='text' name='products'/>";
}
</script>
??</head>
??
??<body>
??? <form action="productaction.action" method="post">
??? <table id="tab">
??? <tr>
??? <td align="center" bgcolor="#FFFF66">增加產品信息</td>
??? </tr>
??? <tr>
??? <td>
??? <input type="text" name="products"/>
??? <input type="button" value="增加?" οnclick="insertRow();">
???
??? </td>
??? </tr>
??? <tr>
??? <td bgcolor="#FFFF66">
??? <input type="submit" value="批量添加">
??? </td>
??? </tr>
???
??? </table>
???
??? </form>
??</body>
</html>
運行product.jsp頁面,輸入產品數據,圖8.1.5所示,單擊“批量增加”按鈕,運行結果如圖8.1.6所示。
?
圖8.1.6批量增加產品的運行結果
8.3?輸入校驗
由于Web應用的開放性,所有的瀏覽者都可以自由的訪問,輸入的數據可能是五花八門,所以輸入校驗就成了所有Web應用必須面對的問題。對于異常的輸入,輕則導致系統暫時中斷,重則導致系統崩潰。因此只有進行嚴格輸入校驗,才能提高系統的健壯性,保證其正常運行。通常情況下,Web應用的輸入校驗有兩種,一種是客戶端的校驗,主要通過JavaScript實現,另一種是服務器端的校驗,本小節將介紹通過Struts 2進行服務器端校驗。
8.3.1?手工完成數據校驗
1.?重寫ActionSupport.validate()方法
根據前面的案例,我們會發現包含有用戶輸入數據的請求最終會轉交給Action進行處理,那么在execute方法中就可以對轉交過來的數據進行校驗,例如下面實現登錄的代碼。
public class LoginAction extends ActionSupport {
private int id;
private String name;
private String pwd;
public String execute() {
if(name==null||name.equals(“”)||pwd==null||pwd.equals(“”))
return INPUT;
else
{
AdminDao ad=new AdminDao();
if(ad.checkLogin(name, pwd))
{
ActionContext ac=ActionContext.getContext();
Map session=ac.getSession();
session.put("logname", name);
return SUCCESS;
}
else
return ERROR;
}
}
//省略getter和setter方法
}
我們在LoginAction類的execute方法中首先對封裝在name、pwd屬性中的數據進行了非空校驗,校驗通過后才執行下面的代碼。類似的,我們可以在Action類中的任何業務方法中進行數據校驗,但是在大多情況下我們并不這樣做,而是讓Action中的業務方法專司其職:調用業務組件、返回邏輯視圖。因為在設計程序時,每個方法應該盡量完成單一的任務,而不推薦兩個或兩個以上的功能在同一個方法中實現,否則就違反了“高內聚,低耦合”的設計原則,這樣會給系統的開發與維護帶來很大的麻煩,尤其一個大型系統更是如此。
ActionSupport類的validate()方法專門用來實現數據校驗,所以我們創建的Action通常繼承該類,同時重寫validate()方法來實現數據校驗。Struts 2框架會在調用Action的業務方法之前調用validate()完成數據校驗。
示例8.2
下面我們改進一下登錄案例,使用ActionSupport類的validate()方法實現登錄校驗。
public class LoginAction extends ActionSupport{
private String name;
private String pwd;
public void validate()
{
if(name==null||name.equals(""))
this.addFieldError("name", "登錄名稱必須填寫!");
if(pwd==null||pwd.equals(""))
this.addFieldError("pwd", "登錄密碼必須填寫!");
}
public String checkLogin()
{
return "success";
}
//省略getter和setter方法
}
我們在Action中重寫了ActionSupport類的validate()方法,在該方法中對登錄名稱(name)和登錄密碼(pwd)進行了非空校驗,并使用ActionSupport類的addFieldError方法設置了提示信息。該方法有兩個參數,第一個參數表示被校驗的屬性名,第二個參數是自定義提示信息,該提示信息會在JSP頁面中自動顯示。一旦調用了addFieldError()方法,則說明校驗失敗,Action就不會繼續執行業務方法。
當Struts 2在執行Action中的業務方法之前會先執行validate方法,如果沒有通過數據校驗,就會把錯誤提示信息記錄下來并返回“input”結果;如果通過校驗就會繼續執行Action中的業務方法。
下面是login.jsp頁面的參考代碼。
<body>
<s:form action="login.action" method="post" >
<h3>管理員登錄</h3>
<s:textfield name="name" label="登錄名稱"/>
<s:password name="pwd" label="登錄密碼"/>
<s:submit value="提交"/>
</s:form>
</body>
下面是struts.xml配置文件的參考代碼。
<struts>
<package name="admin" extends="struts-default">
<action name="login" class="com.zy.LoginAction" method="checkLogin">
<result name="success">/succ.jsp</result>
<result name="input">/login.jsp</result>
</action>
</package>
</struts>
當我們沒有輸入登錄名稱和登錄密碼時,addFieldError方法中的提示信息就會自動在login.jsp頁面中顯示出來,如圖8.1.7所示。
?
圖8.1.7 登錄校驗
2.?使用validateXxx()方法
Struts 2的Action里可以包含多個業務處理方法,每個方法處理的業務各不相同,所以校驗的數據也會各不相同,這時它們就無法共用一個validate()方法。
Struts 2框架允許在Action中提供一個validateXxx方法來專門校驗xxx這個業務處理方法,xxx是業務方法的名字,在validateXxx方法中業務方法名字的首字母變大寫。例如,在一個Action中有一個業務方法為regist,我們就可以使用validateRegist方法來校驗regist業務方法所需要的數據。
示例8.3
下面我們使用這種方式修改登錄案例,只需要修改一下Action的代碼即可。
public class LoginAction extends ActionSupport{
private String name;
private String pwd;
public void validateCheckLogin()
{
if(name==null||name.equals(""))
this.addFieldError("name", "登錄名稱必須填寫!");
if(pwd==null||pwd.equals(""))
this.addFieldError("pwd", "登錄密碼必須填寫!");
}
public String checkLogin()
{
return "success";
}
public void validateReg(){
//代碼省略
}
public String reg(){
//代碼省略
}
//省略getter和setter方法
}
修改過之后的運行效果和圖8.1.7一樣。
3.?Struts 2的校驗順序
通過上面的介紹我們可以了解到,在Struts 2框架下可以使用多種方式進行輸入校驗,這些校驗并不是無序的,而是按照一定的順序來執行的,順序如下:
(1)客戶端校驗,如果有的話。
(2)對請求的字符串參數進行類型轉換,并設置為對應的Action屬性值。
(4)調用Action中的validateXxx方法進行校驗。
(5)調用Action的validate方法進行校驗。
(6)完成上面的步驟之后,Struts 2框架開始檢查在以上過程中有沒有通過輸入校驗,如果沒有,則返回“input”邏輯視圖,如果通過,則執行Action中的業務方法。
(7)系統根據上一步驟返回的邏輯視圖名,跳轉到相對應的視圖頁面。
8.3.2?Struts 2內置校驗器
1.?校驗配置文件
我們前面學習了幾種進行輸入驗證的方式,例如重寫validate方法、使用validateXxx方法等,雖然這些方式都能完成數據校驗,但是缺點也非常明顯。首先,如果驗證規則多且復雜,那就需要編寫繁瑣的驗證代碼,直接導致Action類的臃腫。其次,實現驗證規則的代碼無法有效重用,例如很多數據都需要進行非空驗證,但是我們每次都有重復編寫類似的驗證代碼。
鑒于數據驗證的普遍性和重復性,Struts 2內置了很多校驗器,平時常用的驗證規則都已在這些內置校驗器中實現,例如非空驗證、長度驗證、電子郵箱驗證等。我們只需在外部配置文件中為某個屬性設置相應的校驗器即可。
下面我們使用內置校驗器優化登錄案例,驗證的內容包括登錄名和登錄密碼非空,登錄密碼的長度必須大于等于6。
在使用Struts2內置校驗器時,Action中就無需任何校驗代碼了,所以像validate、validateXxx方法就不再需要了,其他代碼保持不變,只需額外增加一個校驗配置文件即可。校驗配置文件必須和需要驗證的Action放在同一個包中,并且采用“Action的類名—validation.xml”方式命名,下面是我們為LoginAction.java所編寫的校驗配置文件LoginAction—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="name">
<field-validator type="requiredstring">
<message>登錄不能為空!</message>
</field-validator>
</field>
<field name="pwd">
<field-validator type="requiredstring">
<message>登錄密碼不能為空!</message>
</field-validator>
<field-validator type="stringlength">
<param name="minLength">6</param>
<message>密碼長度必須大于等于${minLength}</message>
</field-validator>
</field>
</validators>
運行效果與圖8.1.7一樣,下面我們重點介紹一下校驗配置文件。
??<validators>是根元素,所有的校驗配置代碼都必須寫在該元素內。
??<field>元素對應Action中需要校驗的屬性,name屬性值必須和Actin中的屬性名一致。
??<field-validator>元素用來設置使用哪個內置校驗器,上述代碼中的“requiredstring”和“stringlength”就是Struts 2內置校驗器的名字,“requiredstring”用來實現非空校驗,“stringlength”用來實現長度校驗。
??<message>元素用來設置自定義提示信息。
2.?內置校驗器的使用
在xwork-core-2.2.1.jar中可以找到一個名字是default.xml的文件,Struts 2內置的校驗器都來自這里,代碼如下所示。
<?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="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>
一個<validator>元素配置一個校驗器,name屬性設置校驗器的名字,class屬性設置校驗器的實現類。下面我們列舉一些常用內置校驗器的例子。
3.?非空校驗器
Struts 2內置了兩個非空校驗器:required和requiredstring,required用來校驗數據是否為null,可以校驗任何對象,而requiredstring只針對字符串類型的數據,可以參看上面的示例。
4.?長度校驗器
長度校驗器的名字為stringlength,它要求被校驗的字段必須滿足指定的長度范圍,否則就會校驗失敗,此校驗器常用的參數如下所示:
??maxLength:此參數指定字符串的最大長度,這是一個可選的參數,如果不指定這個參數,表示字符串的最大長度不限。
??minLength:此參數用來指定字符串的最小長度,這也是一個可選的參數,如果不指定,則表示最小長度不限。
??trim:如果其值為true,表示在校驗此字符串之前截掉字符串的前后空格,這也是一個可選的參數,并且默認值為true。
<validators>
<field name="pass">
<field-validator type="stringlength">
<param name="maxLength">10</param>
<param name="minLength">6</param>
<message>密碼長度應${minLength}到${maxLength}!</message>
</field-validator>
</field>
</validators>
<param>元素用來設置參數,同時我們可以使用OGNL取出參數的值。
5.?整數校驗器
整數校驗器的名字為int。此校驗器要求被校驗的整數在指定的整數范圍內,否則校驗失敗。此校驗器常用的參數如下所示:
??max:此參數指定最大整數值,這是一個可選的參數,如果不指定這個參數,表示最大整數值不限。
??min:此參數用來指定被校驗整數的最小值,這也是一個可選的參數,如果不指定,則表示最小值不限。
<field name="age">
<field-validator type="int">
<param name="min">18</param>
<param name="max">50</param>
<message>年齡必須為${min}到${max}的整數</message>
</field-validator>
</field>
6.?日期校驗器
日期校驗器的名字為date,此校驗器要求被校驗的日期值必須在指定的范圍內,否則校驗失敗。此校驗器常用的參數如下所示:
??max:此參數指定最大日期值,這是一個可選的參數,如果不指定這個參數,表示最大日期值不限。
??min:此參數用來指定被校驗日期的最小值,這也是一個可選的參數,如果不指定,則表示最小值不限。
<field name="birthday">
<field-validator type="date">
<param name="max">2000-01-01</param>
<param name="min">1900-01-01</param>
<message>生日必須為${min}到${max}</message>
</field-validator>
</field>
7.?表達式校驗器
表達式校驗器的名字為fieldexpression,它要求指定的字段必須滿足一個邏輯表達式,此校驗器常用的參數如下所示:
??expression:此參數指定一個邏輯表達式,最后返回一個Boolean值,當返回為true時校驗通過,否則校驗失敗。
<field name="pass">
<field-validator type="requiredstring">
<message>密碼不能為空!</message>
</field-validator>
<field name="rpass">
<field-validator type="fieldexpression">
<param name="expression"><![CDATA[(pass==rpass)]]></param>
<message>兩次輸入的密碼必須一致!</message>
</field-validator>
</field>
8.?郵箱地址校驗器
郵箱地址校驗器的名字為email,它要求指定的字段必須滿足郵箱地址的規則。使用該校驗器時不需要設置任何參數。
<validators>
<field name="youxiang">
<field-validator type="email">
<message>電子郵箱格式不正確!</message>
</field-validator>
</field>
</validators>
Struts 2內置的校驗器不止這么多,大家有興趣可以查閱相關資料。另外需要注意的是:在使用內置校驗器時,我們自定義的Action必須繼承ActionSupport類。
下面通過一個注冊案例,綜合演示一下內置校驗器的應用。
示例8.4
(1)?創建reg.jsp;
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib ?uri="/struts-tags" prefix="s"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
?
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
??<head>
????<base href="<%=basePath%>">
????
????<title>My JSP 'reg.jsp' starting page</title>
????
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0"> ???
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
?
??</head>
??
??<body>
??? <s:form action="useraction.action" >
??? <s:textfield label="用戶名" name="name" />
??? <s:password name="pwd" label="密碼"/>
??? <s:password name="rpwd" label="確認密碼"/>
??? <s:textfield label="郵箱" name="email"/>
??? <s:textfield label="年齡" name="age"/>
??? <s:textfield label="生日" name="birthday"/>
??? <s:submit value="注冊"/>
??? </s:form>
??</body>
</html>
(2)?創建UserAction.java。
public class UserAction extends ActionSupport {
?
private String name;
private String pwd;
private String rpwd;
private String email;
private int age;
private Date birthday;
public String execute() {
//代碼省略......
return SUCCESS;
}
//getter setter方法省略
}
(3)?在struts.xml中?配置action
<action name="useraction" class="com.zzzy.action.UserAction">
?<!-- 注意添加input配置?-->
? <result name="input">/reg.jsp</result>
? <result >/ssuc.jsp</result>
??</action>
(4)?在src目錄下創建UserAction-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="name">
????<field-validator type="requiredstring">
??????<message>用戶名不能為空!</message>
????</field-validator>
??</field>
??<field name="pwd">
????<field-validator type="requiredstring">
??????<message>密碼不能為空!</message>
????</field-validator>
???<field-validator type="stringlength">
<param name="maxLength">10</param>
<param name="minLength">6</param>
<message>密碼長度應${minLength}到${maxLength}!</message>
</field-validator>
?
??</field>
??
??<field name="rpwd">
<field-validator type="fieldexpression">
<param name="expression"><![CDATA[(pwd==rpwd)]]></param>
<message>兩次輸入的密碼必須一致!</message>
</field-validator>
</field>
??
??<field name="age">
<field-validator type="int">
<param name="min">18</param>
<param name="max">50</param>
<message>年齡必須為${min}到${max}的整數</message>
</field-validator>
</field>
??
??<field name="birthday">
<field-validator type="date">
<param name="max">2000-01-01</param>
<param name="min">1900-01-01</param>
<message>生日必須為${min}到${max}</message>
</field-validator>
</field>
?
??<field name="email">
<field-validator type="email">
<message>電子郵箱格式不正確!</message>
</field-validator>
</field>
??
</validators>
(5)?運行reg.jsp 提交后,內置校驗器如果校驗失敗,則轉向input,顯示出錯誤消息。結果如圖8.1.8所示。
?
圖8.1.8 校驗失敗
本章總結
??Struts 2主題和模板,Struts 2的UI標簽都是基于主題和模板的,模板是一個UI標簽的外在表現形式。如果我們為所有的UI標簽提供了樣式和視覺效果相似的模板,那么這一系列的模板就形成了一個主題。
(1)Struts 2默認提供了四種主題,分別是simple、xhtml、css_xhtml和Ajax。
(2)設置主題是通過theme屬性來實現的,可以通過指定UI標簽的theme屬性、取得request會話范圍內的theme屬性值、取得session會話范圍內的theme屬性值、取得application會話范圍內的theme屬性值、在struts.properties或struts.xml文件中對struts.ui.theme進行指定來設置主題。
??自定義類型轉換器
(1)Struts 2中自定義的類型轉換器必須實現ognl.TypeConverter接口,但是為了開發方便,可以直接繼承org.apache.Struts2.util.StrutsTypeConverter抽象類,并且實現該類中的兩個方法。
(2)注冊自定義類型轉換器,在Web工程的src根目錄下創建名字為xwork-conversion.properties的文件,然后在文件中編寫“目標數據類型=自定義類型轉換器”。
??輸入校驗
(1)手工完成數據校驗。
(2)Struts 2內置校驗器。
任務實訓部分
1:添加管理員的輸入驗證
訓練技能點
??重寫validate方法
需求說明
前面我們實現了添加管理員的案例,現在要求在添加管理員時進行輸入驗證,登錄名稱和登錄密碼要求非空,登錄密碼的長度要求必須在6-10之間,兩次輸入的密碼必須相同,請通過重寫validate方法實現。
實現步驟
(1)?把原來的登錄表單使用Struts 2標簽進行替換。
(2)?在原Action中重寫validate方法,參考代碼如下所示。
public void validate()
{
if(logName==null||logName.equals(""))
this.addFieldError("logName", "登錄名稱必須填寫");
if(logPwd1==null||logPwd1.equals(""))
this.addFieldError("logPwd1", "登錄密碼必須填寫");
if(logPwd1.length()<6||logPwd2.length()>10)
this.addFieldError("logPwd1", "密碼長度必須在6~10之間");
if(!logPwd1.equals(logPwd2))
this.addFieldError("logPwd2", "兩次輸入的密碼必須相同");
}
(3)?在struts中增加input結果。
2:添加學生的輸入驗證
訓練技能點
??使用Struts 2內置校驗器
需求說明
實現添加學生的案例,并要求在添加學生時對輸入進行驗證,學生姓名、學生生日非空,學生身高必須在120到200之間。
3:簡易計算器
訓練技能點
??自定義類型轉換器
需求說明
前面我們實現了一個計算器案例,但是現在我們要求頁面中只出現一個文本框,用戶可以在這個文本框中輸入兩個數字進行運算,兩個數字之間用逗號隔開,如圖8.3.1所示。要求使用自定義類型轉換器實現。
實現步驟
(1)?創建一個名字是Digit的類用來描述用逗號隔開的兩個數字,參考代碼如下所示。
public class Digit {
private double num1; ?//表示逗號前的數字
private double num2; ?//表示逗號后的數字
//省略getter和setter方法
}
(2)?創建Action類,參考代碼如下所示。
public class CalculatorAction {
private Digit num; ?//文本框中的數據要轉換成Digit類型
private double result;
public String jia()
{
result=num.getNum1()+num.getNum2();
return "result";
}
public String jian()
{
result=num.getNum1()-num.getNum2();
return "result";
}
public String cheng()
{
result=num.getNum1()*num.getNum2();
return "result";
}
public String chu()
{
result=num.getNum1()/num.getNum2();
return "result";
}
//省略getter和setter方法
}
(3)?下面是JSP頁面的參考代碼。
<body>
<form name="frm" method="post">
<table width="298" border="0" align="center">
<tr>
<td colspan="2" align="center">簡易計算器</td>
</tr>
<tr>
<td width="76" align="center">請輸入兩個數</td>
<td width="206"><input type="text" name="num"
?value="${num.num1},${num.num2}">中間用逗號隔開</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="button" ?value="+" οnclick="submitForm('jia')">
<input type="button" ?value="-" οnclick="submitForm('jian')">
<input type="button" ?value="*" οnclick="submitForm('cheng')">
<input type="button" ?value="/" οnclick="submitForm('chu')"></td>
</tr>
<tr>
<td align="center">結果</td>
<td><input type="text" name="result" readonly value="${result}"></td>
</tr>
</table>
</form>
</body>
<script>
function submitForm(op)
{
frm.action="cal_"+op+".action";
frm.submit();
}
</script>
(4)?創建自定義類型轉換器,實現文本框中的字符串轉換成Digit類型,參考代碼如下所示。
public class CalculatorConverter extends StrutsTypeConverter {
public Object convertFromString(Map context, String[] values, Class toClass) {
String[] nums=values[0].split(",");
Digit d=new Digit();
d.setNum1(Double.parseDouble(nums[0]));
d.setNum2(Double.parseDouble(nums[1]));
return d;
}
public String convertToString(Map context, Object o) {
return null;
}
}
?
圖8.3.1 運行效果
4:生日類型轉換器
訓練技能點
??自定義類型轉換器
需求說明
上面的實訓任務包含了一個生日文本框,現在要求該生日文本框支持用戶輸入“yyyy-mm-dd”和“yyyy/mm/dd”兩種格式,請使用自定義類型轉換器完成對生日的類型轉換。
鞏固練習
一、選擇題
1. 自定義的類型轉換器必須實現的接口是()。
A.?StrutsConvert
B.?StrutsTypeConvert
C.?TypeConvert
D.?Convert
2. 下面關于Struts 2主題說法錯誤的是()。
A.?Struts 2可以通過主題影響頁面效果
E.?Struts 2的默認主題是simple
F.?theme屬性可以設置主題
G.?主題只對Struts 2標簽起作用
3. 下面關于Struts 2類型轉換器說法錯誤的是()。
A. Struts 2內置了一些類型轉換器
B. Struts 2不支持自定義類型轉換器
C. 自定義的類型轉換器必須實現ognl.TypeConverter接口
D. 自定義的類型轉換器必須添加xwork-conversion.properties文件
4. 下面關于Struts 2輸入校驗說法錯誤的是()。
A. WEB應用通常需要服務器端校驗,根本不需要客戶端校驗
B. Struts 2內置了很多校驗器
C. 使用內置校驗器需要添加校驗配置文件
D. Struts 2具備自動生成客戶端校驗的功能
5. 下面關于Struts 2輸入校驗說法正確的是()。
A. Struts2校驗文件中不能使用正則表達式。
B. requiredstring用來實現非空校驗。
C. requiredString用來實現非空校驗。
D. 校驗文件的命名是隨意的。
?
?
二、上機練習
自己實現一個注冊功能,要求用戶填寫昵稱、登錄密碼和電子郵件并對這些輸入進行驗證,登錄密碼長度必須大于等于8,電子郵件必須符合規定,請使用Struts 2內置校驗器實現。
總結
以上是生活随笔為你收集整理的Struts2 类型转换和数据校验的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 高新面试系列 性格篇
- 下一篇: Struts 2常见应用