本章要點html
— Struts 2的下載和安裝java
— 純手工建立一個Web應用程序員
— 純手工建立一個Struts 2應用web
— 實現Struts 2的Action數據庫
— 配置Struts 2的Actionapache
— 在Action中訪問HttpSession編程
— 在JSP中輸出Action的返回值數組
— 使用Struts 2的表單標籤瀏覽器
— 程序國際化初步服務器
— 數據校驗初步
前面已經簡要介紹了Struts 2的起源,以及Struts 2的兩個前身:Struts 1和WebWork,並詳細對比了Struts 2和Struts 1的差別,對比了Struts 2和WebWork的差別,並且指出:Struts 2是WebWork的升級,而不是Struts 1的升級。
雖然Struts 2提供了與Struts 1的兼容,但已經不是Struts 1的升級。對於已有Struts 1開發經驗的開發者而言,Struts 1的開發經驗對於Struts 2並無太大的幫助;相反,對於已經有WebWork開發經驗的開發者而言,WebWork的開發經驗對Struts 2的開發將有很好的借鑑意義。
下面將以一個Struts 2的HelloWorld應用爲例,介紹Strust 2 MVC框架如何攔截用戶請求,如何調用業務控制器處理用戶請求,並介紹Action處理結果和資源之間的映射關係。
本HelloWorld應用是一個簡單的應用:用戶進入一個登陸頁面,容許用戶輸入用戶名、密碼,若是用戶輸入的用戶名和密碼符合要求,則進入一個歡迎頁面;若是用戶輸入錯誤,則進入一個提示頁面。當用戶提交表單時,本應用會有基本的數據校驗。
2.1 下載和安裝Struts 2框架
下面咱們從下載、安裝Struts 2開始,慢慢開始體驗Struts 2 MVC框架的魅力。
筆者寫本書的時候,Struts 2已經發布了其產品化GA(General Availability)版,其實最新的產品化GA版是Struts 2.06,故本書的全部應用都是基於該版本的Struts 2。建議讀者下載Struts 2.06版,而不是下載最新的Beta版,若是Struts 2有最新的GA版,讀者也能夠下載更新的GA版,相信不會有太大差別。
下載和安裝DWR請按以下步驟進行。
登陸http://struts.apache.org/download.cgi#Struts206站點,下載Struts 2的最新GA版。在Struts 2.06下有以下幾個選項:
— Full Distribution:下載Struts 2的完整版。一般建議下載該選項。
— Example Applications:下載Struts 2的示例應用,這些示例應用對於學習Struts 2有很大的幫助,下載Struts 2的完整版時已經包含了該選項下所有應用。
— Blank Application only:僅下載Struts 2的空示例應用,這個空應用已經包含在Example Applications選項下。
— Essential Dependencies:僅僅下載Struts 2的核心庫,下載Struts 2的完整版時將包括該選項下的所有內容。
— Documentation:僅僅下載Struts 2的相關文檔,包含Struts 2的使用文檔、參考手冊和API文檔等。下載Struts 2的完整版時將包括該選項下的所有內容。
— Source:下載Struts 2的所有源代碼,下載Struts 2的完整版時將包括該選項下的所有內容。
— Alternative Java 4 JARs:下載可選的JDK 1.4的支持JAR。下載Struts 2的完整版時將包括該選項下的所有內容。
一般建議讀者下載第一個選項:下載Struts 2的完整版,將下載到的Zip文件解壓縮,該文件就是一個典型的Web結構,該文件夾包含以下文件結構:
— apps:該文件夾下包含了基於Struts 2的示例應用,這些示例應用對於學習者是很是有用的資料。
— docs:該文件夾下包含了Struts 2的相關文檔,包括Struts 2的快速入門、Struts 2的文檔,以及API文檔等內容。
— j4:該文件夾下包含了讓Struts 2支持JDK 1.4的JAR文件。
— lib:該文件夾下包含了Struts 2框架的核心類庫,以及Struts 2的第三方插件類庫。
— src:該文件夾下包含了Struts 2框架的所有源代碼。
將lib文件夾下的Struts2-core-2.0.6.jar、xwork-2.0.1.jar和ognl-2.6.11.jar等必需類庫複製到Web應用的WEB-INF/lib路徑下。固然,若是你的Web應用須要使用Struts 2的更多特性,則須要將更多的JAR文件複製到Web應用的WEB-INF/lib路徑下。若是須要在DOS或者Shell窗口下手動編譯Struts 2相關的程序,則還應該將Struts2-core-2.0.6.jar和xwork-2.0.1.jar添加到系統的CLASSPATH環境變量裏。
提示 大部分時候,使用Struts 2的Web應用並不須要利用到Struts 2的所有特性,所以沒有必要一次將該lib路徑下JAR文件所有複製到Web應用的WEB-INF/lib路徑下。
編輯Web應用的web.xml配置文件,配置Struts 2的核心Filter。下面是增長了Struts 2的核心Filter配置的web.xml配置文件的代碼:
<?xml version="1.0" encoding="GBK"?>
<!-- web-app是Web應用配置文件的根元素,指定Web應用的Schema信息 -->
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.
com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- 定義Struts 2的FilterDispatcher的Filter -->
<filter>
<!-- 定義核心Filter的名字 -->
<filter-name>struts2</filter-name>
<!-- 定義核心Filter的實現類 -->
<filter-class>org.apache.Struts2.dispatcher.FilterDispatcher
</ filter-class>
</filter>
<!-- FilterDispatcher用來初始化Struts 2而且處理全部的Web請求 -->
<filter-mapping>
<filter-name>Struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
通過上面3個步驟,咱們已經能夠在一個Web應用中使用Struts 2的基本功能了,下面將帶領讀者進入Struts 2 MVC框架的世界。
2.2 從用戶請求開始
Struts 2支持大部分視圖技術,固然也支持最傳統的JSP視圖技術,本應用將使用最基本的視圖技術:JSP技術。當用戶須要登陸本系統時,用戶須要一個簡單的表單提交頁面,這個表單提交頁面包含了兩個表單域:用戶名和密碼。
下面是一個最簡單的表單提交頁面,該頁面的表單內僅包含兩個表單域,甚至沒有任何動態內容,實際上,整個頁面徹底能夠是一個靜態HTML頁面。但考慮到須要在該頁面後面增長動態內容,所以依然將該頁面以jsp爲後綴保存。下面是用戶請求登陸的JSP頁面代碼:
<%@ page language="java" contentType="text/html; charset=GBK"%>
<html>
<head>
<title>登陸頁面</title>
</head>
<body>
<!-- 提交請求參數的表單 -->
<form action="Login.action" method="post">
<table align="center">
<caption><h3>用戶登陸</h3></caption>
<tr>
<!-- 用戶名的表單域 -->
<td>用戶名:<input type="text" name="username"/></td>
</tr>
<tr>
<!-- 密碼的表單域 -->
<td>密 碼:<input type="text" name="password"/></td>
</tr>
<tr align="center">
<td colspan="2"><input type="submit" value="登陸"/><input
type="reset" value="重填" /></td>
</tr>
</table>
</form>
</body>
</html>
正如前面介紹的,該頁面沒有包含任何的動態內容,徹底是一個靜態的HTML頁面。但咱們注意到該表單的action屬性:login.action,這個action屬性比較特殊,它不是一個普通的Servlet,也不是一個動態JSP頁面。可能讀者已經猜到了,當表單提交給login.action時,Struts 2的FilterDispatcher將自動起做用,將用戶請求轉發到對應的Struts 2 Action。
注意 Struts 2 Action默認攔截全部後綴爲.action的請求。所以,若是咱們須要將某個表單提交給Struts 2 Action處理,則應該將該表單的action屬性設置爲*.action的格式。
該頁面就是一個基本的HTML頁面,在瀏覽器中瀏覽該頁面,看到如圖2.1所示的界面。
整個頁面就是一個標準的HTML頁面,整個單獨的頁面尚未任何與用戶交互的能力。下面咱們開始動手建立一個Struts 2的Web應用。
2.3 建立Struts 2的Web應用
Struts 2的Web應用就是一個普通的Web應用,而後增長Struts 2功能,該應用就能夠充分利用Struts 2的MVC框架了。
2.3.1 建立Web應用
筆者一直相信:要想成爲一個優秀的程序員,應該從基本功練起,全部的代碼都應該用簡單的文本編輯器(包括EditPlus、UtraEdit等工具)完成。筆者常常見到一些有兩三年開發經驗的程序員,一旦離開了熟悉的IDE(集成開發環境,如Eclipse、JBuilder等),徹底不能動手寫任何代碼。而他們每每還振振有詞:誰會不用任何工具來開發?
實際上,真正優秀的程序員固然可使用IDE工具,但即便使用VI(UNIX下無格式編輯器)、記事本也同樣能夠完成很是優秀的項目。筆者對於IDE工具的態度是:可使用IDE工具,但毫不可依賴於IDE工具。學習階段,千萬不要使用IDE工具;開發階段,纔去使用IDE工具。
提醒 對於IDE工具,業內有一個說法:IDE工具會加快高手的開發效率,但會使初學者更白癡。
爲了讓讀者更加清楚Struts 2應用的核心,筆者下面將「徒手」創建一個Struts 2應用。
創建一個Web應用請按以下步驟進行。
在任意目錄新建一個文件夾,筆者將以該文件夾創建一個Web應用。
在第1步所建的文件夾內建一個WEB-INF文件夾。
進入Tomcat,或任何Web容器內,找到任何一個Web應用,將Web應用的WEB-INF下的web.xml文件複製到第2步所建的WEB-INF文件夾下。
修改複製的web.xml文件,將該文件修改爲只有一個根元素的XML文件,修改後的web.xml文件代碼以下:
<?xml version="1.0" encoding="GBK"?>
<!-- web-app是Web應用配置文件的根元素,指定Web應用的Schema信息 -->
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.
com/xml/ns/j2ee/web-app_2_4.xsd">
</web-app>
在第2步所建的WEB-INF路徑下,新建兩個文件夾:classes和lib,它們分別用於保存單個*.class文件和JAR文件。
通過上面步驟,已經創建了一個空Web應用。將該Web應用複製到Tomcat的webapps路徑下,該Web應用將能夠自動部署在Tomcat中。
將2.2節所定義的JSP頁面文件複製到第1步所建的文件夾下,該JSP頁面將成爲該Web應用的一個頁面。該Web將有以下文件結構:
Struts2qs
|-WEB-INF
| |-classes
| |-lib
| |-web.xml
|-login.jsp
上面的Struts2qs是Web應用所對應文件夾的名字,能夠更改;login.jsp是該Web應用下JSP頁面的名字,也能夠修改。其餘文件夾、配置文件都不能夠修改。
啓動Tomcat,在瀏覽器中瀏覽2.2節定義的JSP頁面,將看到如圖2.1所示的頁面。
2.3.2 增長Struts 2功能
爲了給Web應用增長Struts 2功能,只須要將Struts 2安裝到Web應用中便可。在Web應用中安裝Struts 2框架核心只須要通過以下三個步驟。
修改web.xml文件,在web.xml文件中配置Struts 2的核心Filter。
將Struts 2框架的類庫複製到Web應用的WEB-INF/lib路徑下。
在WEB-INF/classes下增長struts.xml配置文件。
下面是增長了Struts 2功能後Web應用的文件結構:
Struts2qs
|-WEB-INF
| |-classes(struts.xml)
| |-lib(commons-logging.jar,freemarker.jar,ognl.jar,struts2-core.jar,xwork.jar)
| |-web.xml
|-login.jsp
在上面的文件結構中,lib下Struts 2框架的類庫可能有版本後綴。例如commons-logging.jar,多是commons-logging-1.1.jar;struts2-core.jar多是struts2-core-2.0.6.jar。
修改後的web.xml文件在2.1節已經給出了,故此處再也不贅述。
此處須要給讀者指出的是,Struts 2的Web應用默認須要Java 5運行環境,須要Web容器支持Servlet API 2.4和JSP API 2.0。若是讀者須要使用更低版本的Java運行時環境,則須要使用Struts 2框架的JDK 1.4支持。爲了簡單起見,筆者建議讀者使用Java 5運行時環境,使用Tomcat 5.5或者更高版本。
注意 Struts 2應用默認須要Java 5運行時環境,須要支持Servlet API 2.4和JSP API 2.0的Web容器。
2.4 實現控制器
前面介紹MVC框架時,已經指出:MVC框架的核心就是控制器。當用戶經過2.2節的頁面提交用戶請求時,該請求須要提交給Struts 2的控制器處理。Struts 2的控制器根據處理結果,決定將哪一個頁面呈現給客戶端。
2.4.1 實現控制器類
Struts 2下的控制器再也不像Struts 1下的控制器,須要繼承一個Action父類,甚至能夠無需實現任何接口,Struts 2的控制器就是一個普通的POJO。
實際上,Struts 2的Action就是一個包含execute方法的普通Java類,該類裏包含的多個屬性用於封裝用戶的請求參數。下面是處理用戶請求的Action類的代碼:
//Struts 2的Action類就是一個普通的Java類
public class LoginAction
{
//下面是Action內用於封裝用戶請求參數的兩個屬性
private String username;
private String password;
//username屬性對應的getter方法
public String getUsername()
{
return username;
}
//username屬性對應的setter方法
public void setUsername(String username)
{
this.username = username;
}
//password屬性對應的getter方法
public String getPassword()
{
return password;
}
//password屬性對應的setter方法
public void setPassword(String password)
{
this.password = password;
}
//處理用戶請求的execute方法
public String execute() throws Exception
{
//當用戶請求參數的username等於scott,密碼請求參數爲tiger時,返回success
字符串
//不然返回error字符串
if (getUsername().equals("scott")
&& getPassword().equals("tiger") )
{
return "success";
}
else
{
return "error";
}
}
}
上面的Action類是一個再普通不過的Java類,該類裏定義了兩個屬性:username和password,併爲這兩個屬性提供了對應的setter和getter方法。除此以外,該Action類裏還包含了一個無參數的execute方法——這大概也是Action類與POJO惟一的差異。實際上,這個execute方法依然是一個很普通的方法,既沒有與Servlet API耦合,也沒有與Struts 2 API耦合。
提示 表面上看起來,該Action的兩個屬性只提供了對應的setter和getter方法,很難理解請求參數在何時賦值給該Action的屬性,事實上,由於Struts 2的攔截器機制,它們負責解析用戶的請求參數,並將請求參數賦值給Action對應的屬性。
2.4.2 配置Action
上面定義了Struts 2的Action,但該Action還未配置在Web應用中,還不能處理用戶請求。爲了讓該Action能處理用戶請求,還須要將該Action配置在struts.xml文件中。
前面已經介紹過了,struts.xml文件應該放在classes路徑下,該文件主要放置Struts 2的Action定義。定義Struts 2 Action時,除了須要指定該Action的實現類外,還須要定義Action處理結果和資源之間的映射關係。下面是該應用的struts.xml文件的代碼:
<?xml version="1.0" encoding="GBK"?>
<!-- 指定Struts 2配置文件的DTD信息 -->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<!-- struts是Struts 2配置文件的根元素 -->
<struts>
<!-- Struts 2的Action必須放在指定的包空間下定義 -->
<package name="strutsqs" extends="struts-default">
<!-- 定義login的Action,該Action的實現類爲lee.Action類 -->
<action name="Login" class="lee.LoginAction">
<!-- 定義處理結果和資源之間映射關係。 -->
<result name="error">/error.jsp</result>
<result name="success">/welcome.jsp</result>
</action>
</package>
</struts>
上面映射文件定義了name爲login的Action,即:該Action將負責處理向login.action URL請求的客戶端請求。該Action將調用自身的execute方法處理用戶請求,若是execute方法返回success字符串,請求將被轉發到/welcome.jsp頁面;若是execute方法返回error字符串,則請求被轉發到/error.jsp頁面。
2.4.3 增長視圖資源完成應用
通過上面步驟,這個最簡單的Struts 2應用幾乎能夠運行了,但還須要爲該Web應用增長兩個JSP文件,兩個JSP文件分別是error.jsp頁面和welcome.jsp頁面,將這兩個JSP頁面文件放在Web應用的根路徑下(與WEB-INF在同一個文件夾下)。
這兩個JSP頁面文件是更簡單的頁面,它們只是包含了簡單的提示信息。其中welcome.jsp頁面的代碼以下:
<%@ page language="java" contentType="text/html; charset=GBK"%>
<html>
<head>
<title>成功頁面</title>
</head>
<body>
您已經登陸!
</body>
</html>
上面的頁面就是一個普通的HTML頁面,登陸失敗後進入的error.jsp頁面也與此徹底相似。
在如圖2.1所示頁面的「用戶名」輸入框中輸入scott,在「密碼」輸入框中輸入tiger,頁面將進入welcome.jsp頁面,將看到如圖2.2所示的頁面。
對於上面的處理流程,能夠簡化爲以下的流程:用戶輸入兩個參數,即username和password,而後向login.action發送請求,該請求被FilterDispatcher轉發給LoginAction處理,若是LoginAction處理用戶請求返回success字符串,則返回給用戶welcome.jsp頁面;若是返回error字符串,則返回給用戶error.jsp頁面。
圖2.3顯示了上面應用的處理流程。
圖2.3 HelloWorld應用的處理流程
2.5 改進控制器
經過前面介紹,讀者已經能夠完成簡單的Struts 2的基本應用了,但還能夠進一步改進應用的Action類,例如該Action類能夠經過實現Action接口,利用該接口的優點。前面應用的Action類沒有與JavaBean交互,沒有將業務邏輯操做的結果顯示給客戶端。
2.5.1 實現Action接口
表面上看起來,實現Struts 2的Action接口沒有太大的好處,僅會污染該Action的實現類。事實上,實現Action接口能夠幫助開發者更好地實現Action類。下面首先看Action接口的定義:
public interface Action
{
//下面定義了5個字符串常量
public static final String SUCCESS = "success";
public static final String NONE = "none";
public static final String ERROR = "error";
public static final String INPUT = "input";
public static final String LOGIN = "login";
//定義處理用戶請求的execute抽象方法
public String execute() throws Exception;
}
在上面的Action代碼中,咱們發現該Action接口裏已經定義了5個標準字符串常量:SUCCESS、NONE、ERROR、INPUT和LOGIN,它們能夠簡化execute方法的返回值,並可使用execute方法的返回值標準化。例如對於處理成功,則返回SUCCESS常量,避免直接返回一個success字符串(程序中應該儘可能避免直接返回數字常量、字符串常量等)。
所以,藉助於上面的Action接口,咱們能夠將原來的Action類代碼修改成以下:
//實現Action接口來實現Struts 2的Action類
public class LoginAction implements Action
{
//下面是Action內用於封裝用戶請求參數的兩個屬性
private String username;
private String password;
//username屬性對應的getter方法
public String getUsername()
{
return username;
}
//username屬性對應的setter方法
public void setUsername(String username)
{
this.username = username;
}
//password屬性對應的getter方法
public String getPassword()
{
return password;
}
//password屬性對應的setter方法
public void setPassword(String password)
{
this.password = password;
}
//處理用戶請求的execute方法
public String execute() throws Exception
{
//當用戶請求參數的username等於scott,密碼請求參數爲tiger時,返回success
字符串
//不然返回error的字符串
if (getUsername().equals("scott")
&& getPassword().equals("tiger") )
{
return SUCCESS;
}
else
{
return ERROR;
}
}
}
對比前面Action和此處的Action實現類,咱們發現兩個Action類的代碼基本類似,除了後面的Action類實現了Action接口。由於實現了Action接口,故Action類的execute方法能夠返回Action接口裏的字符串常量。
2.5.2 跟蹤用戶狀態
前面的Action處理完用戶登陸後,僅僅執行了簡單的頁面轉發,並未跟蹤用戶狀態信息——一般,當一個用戶登陸成功後,須要將用戶的用戶名添加爲Session狀態信息。
爲了訪問HttpSession實例,Struts 2提供了一個ActionContext類,該類提供了一個getSession的方法,但該方法的返回值類型並非HttpSession,而是Map。這又是怎麼回事呢?實際上,這與Struts 2的設計哲學有關,Struts 2爲了簡化Action類的測試,將Action類與Servlet API徹底分離,所以getSession方法的返回值類型是Map,而不是HttpSession。
雖然ActionContext的getSession返回的不是HttpSession對象,但Struts 2的系列攔截器會負責該Session和HttpSession之間的轉換。
爲了能夠跟蹤用戶信息,咱們修改Action類的execute方法,在execute方法中經過ActionContext訪問Web應用的Session。修改後的execute方法代碼以下:
//處理用戶請求的execute方法
public String execute() throws Exception
{
//當用戶請求參數的username等於scott,密碼請求參數爲tiger時,返回success字符串
//不然返回error的字符串
if (getUsername().equals("scott")
&& getPassword().equals("tiger") )
{
//經過ActionContext對象訪問Web應用的Session
ActionContext.getContext().getSession().put("user" , getUsername());
return SUCCESS;
}
else
{
return ERROR;
}
}
上面的代碼僅提供了Action類的execute方法,該Action類的其餘部分與前面的Action類代碼徹底同樣。在上面的Action類經過ActionContext設置了一個Session屬性:user。爲了檢驗咱們設置的Session屬性是否成功,咱們修改welcome.jsp頁面,在welcome.jsp頁面中使用JSP 2.0表達式語法輸出Session中的user屬性。下面是修改後的welcome.jsp頁面代碼:
<%@ page language="java" contentType="text/html; charset=GBK"%>
<html>
<head>
<title>成功頁面</title>
</head>
<body>
歡迎,${sessionScope.user},您已經登陸!
</body>
</html>
上面的JSP頁面與前面的JSP頁面沒有太大改變,除了使用了JSP 2.0語法來輸出Session中的user屬性。關於JSP 2.0表達式的知識,請參看筆者所著的《輕量級J2EE企業應用實戰》一書的第2章。
在如圖2.1所示頁面的「用戶名」輸入框中輸入scott,在「密碼」輸入框中輸入tiger,而後單擊「登陸」按鈕,將看到如圖2.4所示的頁面。
在上面登陸成功的頁面中,已經輸出登陸所用的用戶名:scott,可見在Action經過ActionContext設置Session是成功的。
2.5.3 添加處理信息
到目前爲止,Action僅僅控制轉發用戶請求,JSP頁面並未得到Action的處理結果。對於大部分Web應用而言,用戶須要得到請求Action的處理結果,例如,在線購物系統須要查詢某個種類下的商品,則Action調用業務邏輯組件的業務邏輯方法獲得該種類下的所有商品,而JSP頁面則獲取該Action的處理結果,並將所有結果迭代輸出。
下面將爲應用增長一個Action,該Action負責獲取某個系列的所有書籍。爲了讓該Action能夠獲取這系列的書籍,咱們增長一個業務邏輯組件,它包含一個業務邏輯方法,該方法能夠獲取某個系列的所有書籍。
下面是系統所用的業務邏輯組件的代碼:
public class BookService
{
//以一個常量數組模擬了從持久存儲設備(數據庫)中取出的數據
private String[] books =
new String[]{
"Spring2.0寶典" ,
"輕量級J2EE企業應用實戰",
"基於J2EE的Ajax寶典",
"Struts,Spring,Hibernate整合開發"
};
//業務邏輯方法,該方法返回所有圖書
public String[] getLeeBooks()
{
return books;
}
}
上面的業務邏輯組件實際上就是MVC模式中的Model,它負責實現系統業務邏輯方法。理論上,業務邏輯組件實現業務邏輯方法時,必須依賴於底層的持久層組件,但此處的業務邏輯組件則只是返回一個靜態的字符串數組——由於這只是一種模擬。
注意 此處的業務邏輯組件只是模擬實現業務邏輯方法,並未真正調用持久層組件來獲取數據庫信息。
在系統中增長以下Action類,該Action類先判斷Session中user屬性是否存在,而且等於scott字符串——這要求查看圖書以前,用戶必須已經登陸本系統。若是用戶已經登陸本系統,則獲取系統中所有書籍,不然返回登陸頁面。
新增的Action類的代碼以下:
public class GetBooksAction implements Action
{
//該屬性並不用於封裝用戶請求參數,而用於封裝Action須要輸出到JSP頁面信息
private String[] books;
//books屬性的setter方法
public void setBooks(String[] books)
{
this.books = books;
}
//books屬性的getter方法
public String[] getBooks()
{
return books;
}
//處理用戶請求的execute方法
public String execute() throws Exception
{
//獲取Session中的user屬性
String user = (String)ActionContext.getContext().getSession().
get("user");
//若是user屬性不爲空,且該屬性值爲scott
if (user != null && user.equals("scott"))
{
//建立BookService實例
BookService bs = new BookService();
//將業務邏輯組件的返回值設置成該Action的屬性
setBooks(bs.getLeeBooks());
return SUCCESS;
}
else
{
return LOGIN;
}
}
}
經過上面的Action類,咱們發現Action類中的成員屬性,並不必定用於封裝用戶的請求參數,也多是封裝了Action須要傳入下一個JSP頁面中顯示的屬性。
提示 Action中的成員屬性,並必定用於封裝用戶的請求參數,也多是封裝了Action須要傳入下一個頁面顯示的值。實際上,這些值將被封裝在ValueStack對象中。
當咱們的控制器須要調用業務邏輯方法時,咱們直接建立了一個業務邏輯組件的實例,這並非一種好的作法,由於控制器不該該關心業務邏輯組件的實例化過程。比較成熟的作法能夠利用工廠模式來管理業務邏輯組件;固然,目前最流行的方式是利用依賴注入——這將在後面章節裏介紹。
注意 實際項目中不會在控制器中直接建立業務邏輯組件的實例,而是經過工廠模式管理業務邏輯組件實例,或者經過依賴注入將業務邏輯組件實例注入控制器組件。
該Action處理用戶請求時,無需得到用戶的任何請求參數。將該Action配置在struts.xml文件中,配置該Action的配置片斷以下:
<!-- 定義獲取系統中圖書的Action,對應實現類爲lee.GetBooksAction -->
<action name="GetBooks" class="lee.GetBooksAction">
<!-- 若是處理結果返回login,進入login.jsp頁面 -->
<result name="login">/login.jsp</result>
<!-- 若是處理結果返回success,進入showBook.jsp頁面 -->
<result name="success">/showBook.jsp</result>
</action>
當用戶向getBooks.action發送請求時,該請求將被轉發給lee.GetBooksAction處理。
2.5.4 輸出處理信息
若是用戶沒有登陸,直接向getBooks.action發送請求,該請求將被轉發到login.jsp頁面。若是用戶已經登陸,getBooks.action將從系統中加載到系統中的全部圖書,並將請求轉發給showBook.jsp頁面,所以showBook.jsp頁面必須負責輸出所有圖書。
下面筆者將以最原始的方式:JSP腳原本輸出所有圖書。
注意 在實際應用中,幾乎絕對不會使用筆者這種方式來輸出Action轉發給JSP輸出的信息,但筆者爲了讓讀者更清楚Struts 2標籤庫在底層所完成的動做,故此處使用JSP腳原本輸出所有圖書信息。
當Action設置了某個屬性值後,Struts 2將這些屬性值所有封裝在一個叫作struts.valueStack的請求屬性裏。
提示 讀者可能感到奇怪:筆者是如何知道Struts 2將這些屬性值封裝在struts.valueStack請求屬性裏的?這一方面與編程經驗有關,另外一方面能夠經過查看Struts 2的各類文檔,最重要的一點是能夠在showBook.jsp頁面中經過getAttributeNames方法分析請求中的所有屬性。
爲了在JSP頁面中輸出須要輸出的圖書信息,咱們能夠經過以下代碼來獲取包含所有輸出信息的ValueStack對象。
//獲取封裝輸出信息的ValueStack對象
request.getAttribute("struts.valueStack");
上面代碼返回一個ValueStack對象,該對象封裝了所有的輸出信息。該對象是 Struts 2使用的一個ValueStack對象,能夠經過OGNL表達式很是方便地訪問該對象封裝的信息。
從數據結構上來看,ValueStack有點相似於Map結構,但它比Map結構更增強大(由於它能夠根據表達式來查詢值)。Action全部的屬性都被封裝到了ValueStack對象中,Action中的屬性名能夠理解爲ValueStack中value的名字。
大體理解了ValueStack對象的結構後,咱們能夠經過以下代碼來獲取Action中設置的所有圖書信息。
//調用ValueStack的fineValue方法查看某個表達式的值
vs.findValue("books");
理解了上面關鍵的兩步,整個JSP頁面的代碼就比較容易瞭解了。下面是showBook.jsp頁面的代碼:
<%@ page language="java" contentType="text/html; charset=GBK">
<% @page import="java.util.*,com.opensymphony.xwork2.util.*"%>
<html>
<head>
<title>做者李剛的圖書</title>
</head>
<body>
<table border="1" width="360">
<caption>做者李剛的圖書</caption>
<%
//獲取封裝輸出信息的ValueStack對象
ValueStack vs = (ValueStack)request.getAttribute("struts.valueStack");
//調用ValueStack的fineValue方法獲取Action中的books屬性值
String[] books = (String[])vs.findValue("books");
//迭代輸出所有圖書信息
for (String book : books)
{
%>
<tr>
<td>書名:</td>
<td><%=book%></td>
</tr>
<%}%>
</table>
</body>
</html>
不能否認,上面JSP頁面的代碼是醜陋的,並且難以維護,由於裏面鑲嵌了大量的Java腳本。但它對於讀者理解Struts 2如何處理封裝在Action的ValueStack卻頗有幫助。
在瀏覽器中向getBooks.action發送請求,將看到如圖2.5所示的頁面。
經過上面頁面,咱們看到JSP頁面已經輸出了Struts 2控制器的返回信息。上面整個過程,已經徹底包括了Struts 2框架的3個部分:視圖、控制器和模型。
圖2.5 在JSP頁面中輸出Action的返回信息
2.6 改進視圖組件
經過前面的幾節的介紹,咱們已經明白了Struts 2 MVC框架的基本數據流,已經完成了Struts 2應用中模型、控制器、視圖3個組件的開發。但應用中的視圖組件:JSP頁面很是醜陋,特別是輸出Action返回信息的JSP頁面,使用了大量的Java腳原本控制輸出,下面將會使用Struts 2的標籤來改善整個應用視圖組件。
2.6.1 改善輸出頁面
爲了控制輸出Struts 2的ValueStack中封裝的值,Struts 2提供了大量的標籤。其中比較經常使用的標籤有:
— if:該標籤支持標籤體,若是if標籤裏判斷的表達式返回真,則輸出標籤體內容。
— else:該標籤不能獨立使用,它須要與if標籤結合使用,若是if標籤內判斷的表達式返回假,則輸出該標籤裏的標籤體。
— iterator:主要用於迭代輸出某個集合屬性的各個集合元素。
— property:該標籤用於輸出指定屬性值。
關於Struts 2標籤庫更深刻的使用,第10章還會深刻介紹,故此處再也不詳細講解。經過使用上面的幾個標籤,替換showBook.jsp頁面中的Java腳本,修改後的showBook.jsp頁面代碼以下:
<%@ page language="java" contentType="text/html; charset=GBK" %>
<!-- 導入Struts 2的標籤庫 -->
<%@taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>做者李剛的圖書</title>
</head>
<body>
<table border="1" width="360">
<caption>做者李剛的圖書</caption>
<!-- 迭代輸出ValueStack中的books對象,其中status是迭代的序號 -->
<s:iterator value="books" status="index">
<!-- 判斷序號是否爲奇數 -->
<s:if test="#index.odd == true">
<tr style="background-color:#cccccc">
</s:if>
<!-- 判斷迭代元素的序號是否不爲偶數 -->
<s:else>
<tr>
</s:else>
<td>書名:</td>
<td><s:property/></td>
</tr>
</s:iterator>
</table>
</body>
</html>
上面的JSP頁面使用了Struts 2的標籤庫,所以必須在JSP頁面的首部添加taglib指令,該taglib指令用於導入標籤庫。
提示 若是須要使用某個標籤庫中的標籤,則必須在頁面的開始導入該標籤庫。
頁面中使用Struts 2的iterator標籤迭代輸出ValueStack中的books數組,併爲每一個數組元素定義了一個序號:index。經過判斷序號是否爲奇數,若是行序號爲奇數,則輸出一個有背景色的表格行;不然輸出一個無背景色的表格行。
在瀏覽器中再次向getBooks.action發送請求(發送請求以前,必須先登陸本系統),將看到如圖2.6所示的界面。
圖2.6 使用Struts 2標籤改善後的輸出界面
上面頁面的輸出效果與圖2.5並無太大的不一樣,只是使用不一樣顏色來分隔了記錄行。這也得益於Struts 2標籤庫的簡潔。
關鍵在於2.5.4節中的JSP頁面代碼與本節頁面代碼的差別:前面JSP頁面使用了大量的Java腳本,讓整個頁面的代碼看起來很是凌亂,下降了可閱讀性、可維護性。但本頁面中僅使用Struts 2腳本控制輸出,徹底消除了頁面中的Java腳本,下降了該頁面的後期維護成本。
2.6.2 使用UI標籤簡化表單頁面
前面已經提到過,Struts 2的一個重要組件就是標籤庫。Struts 2標籤庫中不只提供了前面所示的基本控制、數據輸出等功能,還提供了很是豐富的UI組件,除了提供系列的主題相關標籤外,還提供了一系列的表單相關的標籤。
Struts 2爲經常使用表單域都提供了對應的標籤,下面是經常使用的表單域標籤。
— form:對應一個表單元素。
— checkbox:對應一個複選框元素。
— password:對應一個密碼輸入框。
— radio:對應一個單選框元素。
— reset:對應一個重設按鈕。
— select:對應一個下拉列表框。
— submit:對應一個提交按鈕。
— textarea:對應一個多行文本域。
— textfield:對應一個單行文本框。
關於這些界面相關的標籤,一樣將在第10章詳細介紹。下面將使用Struts 2的表單相關標籤簡化用戶登陸的login.jsp頁面,修改的login.jsp頁面的代碼以下:
<%@ page language="java" contentType="text/html; charset=GBK"%>
<%@taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>登陸頁面</title>
</head>
<body>
<!-- 使用form標籤生成表單元素 -->
<s:form action="Login">
<!-- 生成一個用戶名文本輸入框 -->
<s:textfield name="username" label="用戶名"/>
<!-- 生成一個密碼文本輸入框 -->
<s:textfield name="password" label="密 碼"/>
<!-- 生成一個提交按鈕 -->
<s:submit value="登陸"/>
</s:form>
</body>
</html>
將該頁面與前面的表單頁面進行對比,咱們發現該頁面的代碼簡潔多了。由於使用了Struts 2的表單標籤,定義表單頁面也更加迅速。在瀏覽器中瀏覽該頁面,看到如圖2.7所示的界面。
圖2.7 使用Struts 2表單標籤後的表單頁
固然,Struts 2的標籤還有許多功能,此處先不詳述,本書的第10章將會詳細介紹Struts 2標籤的用法。
2.7 完成程序國際化
由於一個企業應用常常須要面對多區域的用戶,所以,程序國際化是一個企業應用必須實現的功能。Struts 2提供了很好的程序國際化支持。
2.7.1 定義國際化資源文件
Struts 2的程序國際化支持創建在Java程序國際化的基礎之上,關於Java程序的國際化筆者將在第9章簡要介紹。此處不會詳細介紹,但咱們要明白一個概念:程序國際化的設計思想是很是簡單的,其主要思想是:程序界面中須要輸出國際化信息的地方,咱們不要在頁面中直接輸出信息,而是輸出一個key值,該key值在不一樣語言環境下對應不一樣的字符串。當程序須要顯示時,程序將根據不一樣的語言環境,加載該key對應該語言環境下的字符串——這樣就能夠完成程序的國際化。
圖2.8顯示了程序國際化的示意圖。
圖2.8 程序國際化示意圖
從圖2.8能夠看出,若是須要程序支持更多的語言環境,只須要增長更多語言資源文件便可。
爲了給本應用增長程序國際化支持(支持英文和中文),則應該提供兩份語言資源文件。下面是本應用所使用的中文語言環境下資源文件的代碼。
loginPage=登陸頁面
errorPage=錯誤頁面
succPage=成功頁面
failTip=對不起,您不能登陸!
succTip=歡迎,${0},您已經登陸!
viewLink=查看做者李剛已出版的圖書
bookPageTitle=做者李剛已出版的圖書
bookName=書名:
user=用戶名
pass=密 碼
login=登陸
由於該資源文件中包含了非西歐字符,所以必須使用native2ascii命令來處理該文件。將上面文件保存在WEB-INF/classes路徑下,文件名爲「messageResouce.properties」。保存該文件後,必須使用native2ascii命令來處理該文件,處理該文件的命令格式爲:
native2ascii messageResouce.properties messageResouce_zh_CN.properties
上面命令將包含非西歐字符的資源文件處理成標準的ASCII格式,處理完成後生成了一份新文件:messageResouce _zh_CN.properties文件。這個文件的文件名符合資源文件的命名格式,資源文件的文件名命名格式爲:
basename_語言代碼_國家代碼.properties
當請求來自簡體中文的語言環境時,系統將自動使用這種資源文件中的內容輸出。
注意 對於包含非西歐字符的資源文件,必定要使用native2assii命令來處理該文件,不然將看到一堆亂碼。
除此以外,還應該提供以下英文語言環境的資源文件。
loginPage=Login Page
errorPage=Error Page
succPage=Welcome Page
failTip=Sorry,You can't log in!
succTip=welcome,{0},you has logged in!
viewLink=View LiGang\'s Books
bookPageTitle=LiGang\'s Books
bookName=BookName:
user=User Name
pass=UserPass
login=Login
將上面資源文件保存在WEB-INF/classes路徑下,文件名爲「messageResouce_en_ US.properties」。當請求來自美國時,系統自動使用這份資源文件的內容輸出。
2.7.2 加載資源文件
Struts 2支持在JSP頁面中臨時加載資源文件,也支持經過全局屬性來加載資源文件。經過全局屬性加載資源文件更簡單,本應用使用全局屬性加載Struts 2國際化資源文件。
加載資源文件能夠經過struts.properties文件來定義,本應用的struts.properties文件僅有以下一行代碼:
//定義Struts 2的資源文件的baseName是messageResource
struts.custom.i18n.resources=messageResource
在struts.properties文件中增長上面的代碼定義後,代表該應用使用的資源文件的baseName爲「messageResouce」——這與咱們前面保存資源文件的baseName是一致的。
Struts 2默認加載WEB-INF/classes下的資源文件,在上一節中,咱們就是將資源文件保存在該路徑下的。若是將該資源文件保存在WEB-INF/classes的子目錄下,例如保存在WEB-INF/classes/lee路徑下,則須要修改struts.properties中的定義以下:
//定義Struts 2的資源文件的baseName是messageResource,且文件放在WEB-INF/
classes/lee路徑下
struts.custom.i18n.resources=lee.messageResource
2.7.3 輸出國際化信息
爲了讓程序能夠顯示國際化信息,則須要在JSP頁面中輸出key,而不是直接輸出字符串常量。
Struts 2提供了以下兩種方式來輸出國際化信息:
— <s:text name="messageKey"/>:使用s:text標籤來輸出國際化信息。
— <s:property value="%{getText("messageKey")}"/>:使用表達式方式輸出國際化信息。
所以,咱們再次修改表現層的JSP頁面,使用國際化標籤輸出國際化信息。修改後的showBook.jsp頁面代碼以下:
<%@ page language="java" contentType="text/html; charset=GBK"%>
<%@taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<!-- 使用s:text輸出國際化信息 -->
<title><s:text name="bookPageTitle"/></title>
</head>
<body>
<table border="1" width="360">
<!-- 使用s:text輸出國際化信息 -->
<caption><s:text name="bookPageTitle"/></caption>
<s:iterator value="books" status="index">
<s:if test="#index.odd == true">
<tr style="background-color:#cccccc">
</s:if>
<s:else>
<tr>
</s:else>
<td><s:text name="bookName"/></td>
<td><s:property/></td>
</tr>
</s:iterator>
</table>
</body>
</html>
咱們發現,上面的JSP頁面再也不包含任何直接字符串,而是所有經過<s:text name="..."/>來輸出國際化提示。
再次在瀏覽器瀏覽該頁面,將看到與圖2.7相同的界面。
從新設置瀏覽者所在的語言/區域選項,設置語言/區域選項請先進入「控制面板」,在控制面板中單擊「區域和語言選項」,進入如圖2.9所示的對話框。
若是咱們選擇「英語(美國)」選項,而後單擊「肯定」按鈕,將設置本地的語言環境爲美國英語。
再次向服務器請求login.jsp頁面,將看到如圖2.10所示的頁面。
圖2.9 設置語言/區域選項 圖2.10 程序國際化的效果
若是咱們使用FireFox瀏覽器來瀏覽該頁面時,發現依然顯示中文界面——這是由於FireFox的語言環境並不受Windows系統的控制。爲了讓FireFox也使用美國英語環境,單擊FireFox瀏覽器菜單欄中的「工具」菜單,選擇「選項」菜單項,將出現「選項」對話框,單擊「高級」按鈕,將看到如圖2.11所示的界面。
在如圖2.11所示的對話框中單擊「選擇」按鈕,將出現「語言和字符編碼」對話框,在該對話框下面的下拉列表框中選擇「英語/美國 [en-us]」選項,如圖2.12所示,而後單擊下拉框右邊的「添加」按鈕,將添加了「英語/美國」的語言環境。並在該對話框上面的列表框中選擇「英語/美國 [en-us]」,而後單擊「上移」按鈕,將該選項移至最上面,讓整個頁面優先使用英語/美國的環境。
圖2.11 設置FireFox的語言環境 圖2.12 設置FireFox的語言環境爲英語/美國
再次使用FireFox瀏覽器瀏覽login.jsp頁面,將看到該頁面變成了英文界面。
2.8 增長數據校驗
在上面應用中,即便瀏覽者輸入任何用戶名、密碼,系統也會處理用戶請求。在咱們整個HelloWorld應用中,這種空用戶名、空密碼的狀況不會引發太大的問題。但若是數據須要保存到數據庫,或者須要根據用戶輸入的用戶名、密碼查詢數據,這些空輸入可能引發異常。
爲了不用戶的輸入引發底層異常,一般咱們會在進行業務邏輯操做以前,先執行基本的數據校驗。
2.8.1 繼承ActionSupport
ActionSupport類是一個工具類,它已經實現了Action接口。除此以外,它還實現了Validateable接口,提供了數據校驗功能。經過繼承該ActionSupport類,能夠簡化Struts 2的Action開發。
在Validatable接口中定義了一個validate()方法,重寫該方法,若是校驗表單輸入域出現錯誤,則將錯誤添加到ActionSupport類的fieldErrors域中,而後經過OGNL表達式負責輸出。
爲了讓Struts 2增長輸入數據校驗的功能,改寫程序中的LoginAction,增長重寫validate方法。修改後的LoginAction類代碼以下:
//Struts 2的Action類就是一個普通的Java類
public class LoginAction
{
//下面是Action內用於封裝用戶請求參數的兩個屬性
private String username;
private String password;
//username屬性對應的getter方法
public String getUsername()
{
return username;
}
//username屬性對應的setter方法
public void setUsername(String username)
{
this.username = username;
}
//password屬性對應的getter方法
public String getPassword()
{
return password;
}
//password屬性對應的setter方法
public void setPassword(String password)
{
this.password = password;
}
//處理用戶請求的execute方法
public String execute() throws Exception
{
//當用戶請求參數的username等於scott,密碼請求參數爲tiger時,返回success
字符串
//不然返回error的字符串
if (getUsername().equals("scott")
&& getPassword().equals("tiger") )
{
return "success";
}
else
{
return "error";
}
}
//完成輸入校驗須要重寫的validate方法
public void validate()
{
//若是用戶名爲空,或者用戶名爲空字符串
if (getUsername() == null || getUsername().trim().equals(""))
{
//添加表單校驗錯誤
addFieldError("username", "user.required");
}
//當密碼爲空,或者密碼爲空字符串時,添加表單校驗錯誤
if (getPassword() == null || getPassword().trim().equals(""))
{
addFieldError("password", "pass.required");
}
}
}
上面的Action類重寫了validate方法,該方法會在執行系統的execute方法以前執行,若是執行該方法以後,Action類的fieldErrors中已經包含了數據校驗錯誤,請求將被轉發到input邏輯視圖處。
爲了在校驗失敗後,系統能將視圖轉入input處,必須在配置該Action時配置input屬性。下面是修改後login Action的配置片斷:
<!-- 定義login的Action -->
<action name="Login" class="lee.LoginAction">
<!-- 定義input的邏輯視圖名,對應login.jsp頁面 -->
<result name="input">/login.jsp</result>
<!-- 定義error的邏輯視圖名,對應error.jsp頁面 -->
<result name=" success ">/error.jsp</result>
<!-- 定義welcome的邏輯視圖名,對應welcome.jsp頁面 -->
<result name="success">/welcome.jsp</result>
</action>
對比上面的Action配置與前面的Action配置,咱們發現該Action配置片斷中增長了input邏輯視圖的配置,該邏輯視圖映射到login.jsp頁面。
前面已經提到:當用戶提交請求時,請求獲得execute方法處理以前,先會被validate方法處理,若是該方法處理結束後,Action的fieldErrors裏的校驗錯誤不爲空,請求將被轉發給input邏輯視圖。若是咱們不輸入用戶名、密碼而直接提交表單,將看到如圖2.13所示的界面。
圖2.13 輸入校驗的界面
看到這裏也許讀者以爲很是神奇:咱們僅僅在Action添加了數據校驗錯誤,並未在輸入頁面輸出這些校驗錯誤信息,但圖2.13所示的頁面,卻能夠看到頁面已經輸出了這些校驗信息——這是由於Struts 2的標籤,上面的JSP頁面中表單使用的並非HTML表單,而是用了<s:form .../>標籤,Struts 2的<s:form ... />標籤已經具有了輸出校驗錯誤的能力。
提示 Struts 2的<s:form .../>默認已經提供了輸出校驗錯誤的能力。
但上面的程序還存在一個問題:校驗信息的國際化。查看上面的Action類代碼發現:重寫validate方法時,若是發生校驗失敗的問題,校驗錯誤的提示信息是以硬編碼方式寫死了——這就失去了國際化的能力。
實際上,ActionSupport類已經提供了國際化信息的能力,它提供了一個getText(String key)方法,該方法用於從資源文件中獲取國際化信息。爲了讓校驗信息支持國際化,再次改寫Action裏的validate方法,改寫後的validate方法代碼以下:
//執行數據校驗的validate方法
public void validate()
{
//若是用戶名爲空,或者爲空字符串
if (getUsername() == null || getUsername().trim().equals(""))
{
//添加校驗錯誤提示,使用getText方法來使提示信息國際化
addFieldError("username", getText("user.required"));
}
if (getPassword() == null || getPassword().trim().equals(""))
{
addFieldError("password", getText("pass.required"));
}
}
在上面的validate方法中,添加校驗錯誤提示時,並非直接給出了錯誤提示的字符串,而是調用了getText方法來獲取錯誤提示。由於在Action中,使用getText方法來獲取了兩個國際化提示:user.required和pass.required,所以應該在國際化資源文件中添加這兩條提示信息。
提示 ActionSupport增長了讓提示信息國際化的能力,ActionSupport提供的getText方法能夠根據資源文件加載得到國際化提示信息。
此時,若是沒有任何輸出,直接提交登陸表單,將看到如圖2.14所示的界面。
圖2.14 國際化數據校驗的錯誤提示
2.8.2 使用Struts 2的校驗框架
上面的輸入校驗是經過重寫ActionSupport類的validate方法實現的,這種方法雖然不錯,但須要大量重寫的validate方法——畢竟,重複書寫相同的代碼不是一件吸引人的事情。
相似於Struts 1,Struts 2也容許經過定義配置文件來完成數據校驗。Struts 2的校驗框架其實是基於XWork的validator框架。
下面仍是使用原來的Action類(即不重寫validate方法),卻增長一個校驗配置文件,校驗配置文件經過使用Struts 2已有的校驗器,完成對錶單域的校驗。Struts 2提供了大量的數據校驗器,包括表單域校驗器和非表單域校驗器兩種。
本應用主要使用了requiredstring校驗器,該校驗器是一個必填校驗器——指定某個表單域必須輸入。
下面是校驗規則的定義文件:
<?xml version="1.0" encoding="GBK"?>
<!-- 指定校驗規則文件的DTD信息 -->
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator
1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<!-- 校驗規則定義文件的根元素 -->
<validators>
<!-- 校驗第一個表單域:username -->
<field name="username">
<!-- 該表單域必須填寫 -->
<field-validator type="requiredstring">
<!-- 若是校驗失敗,顯示user.required對應的信息 -->
<message key="user.required"/>
</field-validator>
</field>
<!-- 校驗第二個表單域:password -->
<field name="password">
<field-validator type="requiredstring">
<!-- 若是校驗失敗,顯示pass.required對應的信息 -->
<message key="pass.required"/>
</field-validator>
</field>
</validators>
定義完該校驗規則文件後,該文件的命名應該遵照以下規則:
ActionName-validation.xml:其中ActionName就是須要校驗的Action的類名。
所以上面的校驗規則文件應該命名爲「LoginAction-validation.xml」,且該文件應該與Action類的class文件位於同一個路徑下。所以,將上面的校驗規則文件放在WEB-INF/classes/lee路徑下便可。
固然,在struts.xml文件的Action定義中,同樣須要定義input的邏輯視圖名,將input邏輯視圖映射到login.jsp頁面。
若是不輸入用戶名、密碼而提交表單,將再次看到如圖2.14所示的界面。在這種校驗方式下,無需書寫校驗代碼,只須要經過配置文件指定校驗規則便可,所以提供了更好的可維護性。
2.9 本章小結
本章以一個HelloWorld應用爲例,簡要介紹了Struts 2 MVC框架的基本流程,從Action類基本流程控制講起,詳細介紹瞭如何開發一個Struts 2應用。本章的後面部分在基本Struts 2應用基礎上,介紹了一些Struts 2的深刻應用,包括在Action中訪問HttpSession狀態,將Action處理結果傳回JSP頁面顯示,本應用也綜合應用了Struts 2的標籤庫、數據校驗、程序國際化等經常使用功能。經過閱讀本章的內容,讀者應該對Struts 2框架有一個大體的掌握。