struct2 權威指南html
這一節經過一個詳細的實例來說解Struct2框架的應用java
1 下載和安裝Struts 2框架web
(1) 登陸http://struts.apache.org/download.cgi#Struts206站點,下載Struts 2的最新GA版。在Struts 2.06下有以下幾個選項:數據庫
— Full Distribution:下載Struts 2的完整版。一般建議下載該選項。apache
— Example Applications:下載Struts 2的示例應用,這些示例應用對於學習Struts 2有很大的幫助,下載Struts 2的完整版時已經包含了該選項下所有應用。數組
— Blank Application only:僅下載Struts 2的空示例應用,這個空應用已經包含在Example Applications選項下。session
— Essential Dependencies:僅僅下載Struts 2的核心庫,下載Struts 2的完整版時將包括該選項下的所有內容。app
— Documentation:僅僅下載Struts 2的相關文檔,包含Struts 2的使用文檔、參考手冊和API文檔等。下載Struts 2的完整版時將包括該選項下的所有內容。框架
— Source:下載Struts 2的所有源代碼,下載Struts 2的完整版時將包括該選項下的所有內容。webapp
— 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框架的所有源代碼。
(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環境變量裏。
(3)編輯Web應用的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>
2 建立一個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>
3. 建立WEB應用
創建一個Web應用請按以下步驟進行。
在任意目錄新建一個文件夾,筆者將以該文件夾創建一個Web應用。
(1)在第1步所建的文件夾內建一個WEB-INF文件夾。
(2)進入Tomcat,或任何Web容器內,找到任何一個Web應用,將Web應用的WEB-INF下的web.xml文件複製到第2步所建的WEB-INF文件夾下。
(3) 修改複製的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>
(4) 在第2步所建的WEB-INF路徑下,新建兩個文件夾:classes和lib,它們分別用於保存單個*.class文件和JAR文件。
(5)通過上面步驟,已經創建了一個空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頁面的名字,也能夠修改。其餘文件夾、配置文件都不能夠修改。
4. 增長Struct2的功能
爲了給Web應用增長Struts 2功能,只須要將Struts 2安裝到Web應用中便可。在Web應用中安裝Struts 2框架核心只須要通過以下三個步驟。
(1) 修改web.xml文件,在web.xml文件中配置Struts 2的核心Filter。
(2)將Struts 2框架的類庫複製到Web應用的WEB-INF/lib路徑下。
(3) 在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節已經給出了,故此處再也不贅述。
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";
}
}
}
4.2 配置Action
前面已經介紹過了,struts.xml文件應該放在classes路徑下,該文件主要放置Struts 2的Action定義。定義Struts 2 Action時,除了須要指定該Action的實現類外,還須要定義Action處理結果和資源之間的映射關係。下面是該應用的struts.xml文件的代碼:
-----------------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頁面。
咱們再增長兩個頁面 error.jsp和welcome.jsp也就完成了基本屬性的配置
第二部分 功能擴展:
5. 改進控制器
5.1 實現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接口裏的字符串常量。
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是成功的。
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處理。