文章目錄
一、Struts2 簡介
(1)Struts2是一個基於MVC設計模式的Web應用框架,Struts2現在屬於Apache軟件基金會,是旗下的一款開源的框架,Apache最早開發了一款Struts框架,在行業內流行了很長一段時間。其後由另外一個組織OpenSymphony開發了一款同類型框架叫做webwork,由於webwork對於web項目的表現層提供了更多的支持(例如FreeMarker),業內慢慢的將目光投向了webwork,並廣泛的使用webwork進行開發,後來Apache收購了webwork,在webwork的基礎上融入了Struts的優點形成了我們現在廣泛應用的框架Struts2。
(2)Struts2對於web開發的整個過程中需要進行的亂碼處理、參數獲取、異常處理、視圖層渲染,AJAX、文件上傳、文件下載等進行了封裝,大大的減少web項目的開發週期。而且這種封裝採用的是可拔插的設計方式(Struts2攔截器),可以根據自己的業務需求靈活的集成。在其後又提供了基於註解的配置方式和完全省去繁瑣配置的約定大於配置的開發方式,漸漸的被大衆所接受,成爲了JAVA程序員在MVC框架中的必學框架,直到現在依然有大量的企業在使用Struts2進行開發。
二、Struts2 開發示例
1、Struts2 開發示例步驟
(1)在Struts2的官網下載Struts2的開發包,截止目前爲止Struts2官網推薦使用的最新版本是2.5.20,以下是下載地址:http://mirrors.tuna.tsinghua.edu.cn/apache/struts/2.5.20/struts-2.5.20-all.zip
(2)解壓開發包,目錄如下
- apps:示例程序
- docs:開發文檔
- lib:Struts2的包以及一部分Struts2的依賴包
- src:源碼
(3)在Eclipse中新建web項目
在web項目的web-inf/lib文件夾中導入以下必要的開發包
(4)在web.xml中加載Struts2的核心控制器,Struts2的核心控制器是一個Filter,該Filter是整個Struts2中最重要的組件,它負責了請求分發,結果響應,以及加載各種類型的攔截器來完成各項工作。在定義Filter過濾的地址規則時,可以直接攔截/*,Struts2會自動判斷請求類型並對靜態資源放行(Struts2默認無後綴和.action後綴纔會進行請求分發,否則直接放行)。
配置過程如下:
<filter>
<filter-name>filter</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
(5)新建業務控制器類 TestAction 並繼承 ActionSupport 類。
public class TestAction extends ActionSupport{
public String test() {
System.out.println("又要打印我");
return "success";
}
}
(6)在src目錄下新建 struts.xml 文件,該文件用於進行請求地址與Action的映射,以及邏輯視圖與物理視圖的映射,注意該文件只能寫在src目錄之下,並且文件名稱區分大小寫。配置方式如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<package name="default" namespace="/" extends="struts-default">
<action name="login" class="struts.action.RegistAction" method="regist">
<result name="success">/success.html</result>
</action>
</package>
</struts>
標籤說明:
- struts:struts.xml文件的根目錄
- package: 邏輯層面的包,在一個包下可以配置多個 action 請求映射信息。
- name 屬性表示該包的名稱
- namespace 表示該包下的所有 action 請求的根路徑
- extends 表示當前包所繼承的另外一個包
- struts-default 是struts2默認定義的一個包,該包位於 struts 核心 jar 包的 struts-default.xml 文件中,struts-default這個包中定義了,常規web項目中所需要引用的一系列攔截器,例如:參數攔截器、 上下文攔截器、國際化攔截器、參數校驗攔截器、文件上傳與下載攔截器等等。
- action:用於進行請求地址映射的標籤
- name屬性用於描述請求地址名稱前綴
- class屬性表示該請求需要執行的業務控制器類
- method表示該請求要執行的方法名稱。
- result:用於進行邏輯視圖與物理視圖的映射
- name屬性表示邏輯視圖名稱 name 屬性默認success,result 標籤之間的內容表示該邏輯視圖響應的物理視圖地址。(默認用轉發的方式響應)
(7)在項目中新建 index.html 和 success.html,在 index.html 中通過表單請求、超鏈接發送test或者 test.action,請求都可以成功的執行到 TestAction 業務控制器之下的 execute 方法。
① index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="test.action">點我</a>
</body>
</html>
② success.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
測試成功
</body>
</html>
- 注意:因爲 TestAction 繼承的父類 ActionSupport 類中,在該類中擁有一個 execute 方法,當在 action 標籤中沒有明確的指定執行業務控制器的那個方法時,會默認執行 execute 方法,TestAction 中沒有 execute 方法,所以自然會執行父類中的 execute 方法。
- 並且父類的 execute 方法默認返回值就是 success,在該 action 映射信息中,success 映射的地址是 success.html(result 標籤之間的內容),所以最終頁面成功的響應到了success.html。
2、Struts2 的執行過程
下圖是 struts2 在開發文檔中提供的一張 Struts2 運行流程圖
分析
(1)瀏覽器發送請求,所有的請求通過一系列過濾器以及 Struts2 的核心控制器,進入 Filter,執行 Filter 中的 doFilter 方法。
(2)執行 ActionMapper 判斷當前請求是否需要是業務請求還是靜態資源請求,如果是靜態資源請求則執行響應靜態資源,如果是業務請求則需要執行對應的業務控制器 Action。
(3)執行 Action之前,首先 Struts2 會去讀取 struts.xml 文件,判斷在 struts.xml 文件中是否有映射信息,如果沒有該請求地址的映射信息則會拋出異常,如果找到了該映射信息,則會創建 Action 對象、攔截器鏈對象,以及該映射信息中業務控制器類的代理對象 。
(4)代理對象創建完成以後,會先根據 struts.xml 中的配置執行對應的攔截器,默認情況下會執行包括參數攔截器、上下文攔截器、國際化攔截器、參數校驗攔截器等等在內的多個攔截器,用於參數獲取、作用域注入等等相關的工作。
(5)執行完所有的攔截器以後,纔會去執行最終的業務控制器Action。
(6)根據業務控制器 Action 中返回的值得到對應邏輯視圖信息,然後響應最終的物理視圖信息至瀏覽器。
三、在 Action 中接收請求參數
接收客戶端傳遞的參數在web項目中,是一個必不可少而又相當繁瑣的一個過程,Struts2使用攔截器完成了參數的自動獲取和自動注入功能以及參數自動轉型的功能,我們可以很簡單獲取到客戶端傳遞到服務器的數據。
1、單個或者零散的參數
(1)單個參數或者零散的參數,無論是表單提交、地址欄傳參還是ajax傳參,只需要根據參數名稱在Action中定義對應類型的成員變量,併爲變量提供get和set方法,Struts2在獲取到參數以後會自動根據Action中定義的成員變量類型轉換數據類型,並將參數注入到Action的成員變量中。
(2)Demo
① 表單請求
<form action="login.action" method="post">
<input placeholder="請輸入賬號" name="name" type="text"><br>
<input placeholder="請輸入密碼" name="password" type="password"><br>
<input placeholder="請輸入年齡" name="age" type="text"><br>
<input name="date" type="date"><br>
<input type="submit" >
</form>
② RegistAction 類:在Action中就需要定義成員變量,並提供get和set方法
public class RegistAction extends ActionSupport{
private String name;
private String password;
private int age;
private Date date;
//省略get、set方法
public String regist() {
System.out.println(userRegist);
return "success";
}
}
接下來就可以在業務控制器對應的方法中直接使用這兩個參數。
注意:Struts2在進行參數的類型轉換時,如果要將參數類型轉爲日期類型,必須要保證客戶端傳入的字符 串日期是標準的yyyy-MM-dd的格式,例如:1999-01-05
2、將參數封裝爲對應的實體類對象
(1)表單提交、地址欄請求、Ajax中提交到服務器的參數如果比較多,用單個的參數接收方式需要定義很多的成員變量不利於使用,我們可以使用一個實體類對象對多個參數進行統一的接收。
(2)Demo
① 表單請求
<form action="login.action" method="post">
<input placeholder="請輸入賬號" name="userRegist.name" type="text"><br>
<input placeholder="請輸入密碼" name="userRegist.password" type="password"><br>
<input placeholder="請輸入年齡" name="userRegist.age" type="text"><br>
<input name="userRegist.date" type="date"><br>
<input type="submit" >
</form>
在該表單中的name屬性值 users.username 和 users.password 時struts2定義的一種參數傳輸規則,該規則的含義是,name=”users.username” 的參數會保存到Action中名字爲users對象的username屬性中,name=”users.password” 的參數會保存到Action中名字爲users對象的password屬性中。那麼爲了在Action中爲了接收這些參數,就需要定義一個實體類的對象users,提供get和set方法,並且users的類中必須包含username屬性和password屬性。
② RegistAction 類
public class RegistAction extends ActionSupport{
private UserRegist userRegist = new UserRegist();
public UserRegist getUserRegist() {
return userRegist;
}
public void setUserRegist(UserRegist userRegist) {
this.userRegist = userRegist;
}
public String regist() {
System.out.println(userRegist);
return "success";
}
}
③ UserRegist 實體類
public class UserRegist {
private String name;
private String password;
private int age;
private Date date;
//省略get、set方法
@Override
public String toString() {
return "UserRegist [name=" + name + ", password=" + password + ", age="
+ age + ", date=" + date + "]";
}
}
3、使用模型驅動的方式獲取參數
(1)要將多個參數封裝爲一個對象,除了採用第二種方式之外,還可以採用模型驅動的方式來完成,前端網頁表單中的寫法保持不變。
(2)Demo
① 表單請求
<form action="login.action" method="post">
<input placeholder="請輸入賬號" name="name" type="text"><br>
<input placeholder="請輸入密碼" name="password" type="password"><br>
<input placeholder="請輸入年齡" name="age" type="text"><br>
<input name="date" type="date"><br>
<input type="submit" >
</form>
在 Action 中實現 ModelDriven 接口,同時定義接收的參數類型作爲該接口的泛型。然後在 Action中實例化一個實體類對象,並重寫接口的 getModel 方法,在方法中返回實體類對象。
② RegistAction 類
public class RegistAction extends ActionSupport implements ModelDriven<UserRegist>{
private UserRegist userRegist = new UserRegist();
@Override
public UserRegist getModel() {
return userRegist;
}
public String regist() {
System.out.println(userRegist);
return "success";
}
}
注意:在 Action 中定義的成員變量,不光可以用於接收客戶端傳遞的參數,同時在 Action 響應網頁時如果採用的轉發的方式,那麼 Action 作用域中的成員變量中提供了 get 方法的屬性還會保存到 request 作用域中,這種設計方式是 Struts2 將數據保存到 request 作用域的主要方式,而且利用這個特性可以很便捷的實現查詢條件的回顯。
四、在Action中使用三大作用域
1、在 Action 中有時需要使用 Servlet 中的三大作用域,例如:登陸成功需要將查詢到的用戶信息保存到 HttpSession對象中,那麼就需要在 Action 中獲取 HttpSession 對象。
在Action中獲取三大作用域對象的方式有三種:
(1)解耦和的方式
ActionContext context = ActionContext.getContext();
Map request = (Map)context.get("request");
Map session = context.getSession();
Map application = context.getApplication();
解耦和的方式並沒有直接操作Servlet中的request、session和application,Struts2返回給我們的只是一個鍵值對,我們向該鍵值對中新增數據,最終Struts2會將鍵值對中的數據保存到三大作用域中。
(2)耦合的方式
HttpServletRequest request=ServletActionContext.getRequest();
ServletContext application=ServletActionContext.getServletContext();
HttpSession session=request.getSession();
耦合的方式直接操作三大作用域對象
(3)實現接口的解耦合方式
通過實現對應的接口,重寫set方法,set方法中的參數就是Struts2提供的解耦方式的三大作用域對象。