Struts2核心技術 (一)
struts2
struts2發展歷史
經過很多年發展,Struts1已經成為了高度成熟的框架,但隨著時間的發展,Struts1的侷限性和缺點不斷的暴露出來。
現在Struts已經分化成了兩個框架
-第一個是在Struts1的基礎上,融合了另一個web框架Webwork的Struts2.Struts2實質上是以Webwork為核心的,和Struts1有很大區別。
-第二個是Shale,與原有Struts1關聯很少,使用了全新的設計思想。
MVC思想概述
java web動態程式設計技術,經歷了Model和Model2時代。
Model1時代:整個Web應用幾乎全部由jsp頁面組成,jsp頁面接收處理客戶端請求,對請求處理後直接做出響應,用少量的JavaBean來處理資料庫連線訪問等操作。Model1的侷限性非常明顯,jsp頁面同時擔任View和Controller兩種角色,將頁面表現和邏輯處理混雜在一起,程式碼重用性極低,增加了擴充套件和維護難度。
Model2時代:已經採用了MVC的設計。在Model 2架構中,Servlet作為Controller,負責接收使用者請求,只包含控制邏輯,然後呼叫後端來進行具體的邏輯處理。最後轉發到相應的jsp頁面負責顯示。
MVC由Model(模型),View(檢視),Controller(控制器)組成。
javaWeb中的三層架構
表現層:MVC,struts2框架其實是對錶現層的MVC作了優化
業務層:service
持久層:dao
Struts2環境的搭建
(1)下載Struts2
目錄結構
apps:該資料夾下包含了基於Struts2的示例應用
docs:包含了Struts2的相關文件
lib:包含了Struts2的核心類庫,以及Struts2的第三方類庫
src:包含了Struts框架的所有原始碼
(2)建立web專案,匯入struts2所需jar包,lib中有struts2的所有jar包,但是我們不需要那麼多。
我們只把必需的新增到專案即可。將apps目錄下struts2-blank.war壓縮包中的lib目錄下的jar包新增到我們專案中即可。這是struts2必需的jar包。
Struts2架構
struts使用攔截器作為增強處理,以使用者的邏輯控制器為目標,建立一個控制器代理,控制器代理回撥業務控制器的execute方法處理使用者請求,該方法的返回值決定struts2將怎樣的檢視資源呈現給使用者
struts2大致處理流程:
(1)瀏覽器傳送請求
(2)核心控制器根據請求決定是否呼叫相應的Action
(3)struts2內建的攔截器鏈會自動對請求進行一些操作
(4)回撥Action的execute方法,執行操作。
(5)Action會將處理結果存入stack Context中,並返回字串,核心控制器根據字串跳轉到指定的檢視資源。
(6)檢視資源會讀取Stack Context中的資訊,向瀏覽器生成響應資料。
Struts2入門案例
只需跟著做即可,先不必瞭解為何這樣做。
(1)編輯web應用的web.xml配置檔案,配置struts2的核心攔截器。
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(2)從使用者請求開始,我們實現一個登陸表單
這裡的action屬性比較特殊,不是普通的servlet。
當表單提交給login時,struts的攔截器會起作用,呼叫使用者開發的Action處理使用者請求
<body>
<form action="login" method="post">
使用者名稱:<input type="text" name="username"><br>
密 碼:<input type="password" name="password"><br>
<input type="submit" value="登入">
</form>
</body>
(3)實現控制器Action類處理使用者請求
我們已經指出,MVC框架的核心就是控制器,控制器處理具體使用者請求。
這個類實現Action介面,並實現介面的execute方法。
該類包含的多個屬性用於封裝使用者的請求引數。 我們可能現在很難理解,我們請求的引數是怎麼賦值給這個類的。
我們說過,在呼叫Action方法之前,struts2的內建攔截器會自動負責解析使用者請求引數,並賦值給Action相應的引數
public class LoginAction extends Action{
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;
}
//判斷使用者名稱和密碼是否相同
public String execute(){
if(getUsername().equals("cad")&&getPassword().equals("123456")){
return "success";
}else
{
return "error";
}
}
}
(4)配置Action
我們使用者傳送login請求,那麼如果根據login請求去呼叫相應的Action實現類呢?這就需要我們去配置Action。
配置struts.xml ,struts.xml應該放在src的classes路徑下
<?xml version="1.0" encoding="UTF-8"?> //直接複製
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts> //根元素
<package name="demo" extends="struts-default"> //包 name隨便取,extends照寫就ok
<action name="login" class="com.cad.struts2.LoginAction"> //action name為login,即為負責處理login的請求,action預設呼叫自身的execute方法處理請求
<result name="success">/welcome.jsp</result> //根據返回的字串轉發到相應頁面
<result name="error">/error.jsp</result>
</action>
</package>
</struts>
Struts2兩個重要組成部分
struts2核心就是核心控制器和業務控制器。
核心控制器StrutsPrepareAndExecuteFilter
StrutsPrepareAndExecuteFilter作為一個filter執行在web應用中,負責攔截所有使用者請求,該filter 會過濾使用者請求,然
後將請求都交給struts2框架處理。攔截器會預設攔截副檔名為.action的請求,什麼字尾名都不寫也可以。例如
hello.action或者hello都會進行攔截。xxx.jsp就不會進行攔截,直接放行。
(1)啟動Tomcat,tomcat載入web.xml檔案。同時載入和初始化核心過濾器,檢視struts2原始碼,發現核心過濾器的初始化方法中會載入struts.xml等struts2配置檔案。
(2)當用戶請求到達時,核心過濾器攔截使用者請求,將請求交給struts2框架來處理,即去匹配struts.xml的內容。
struts2框架獲取使用者請求後,根據請求的名字來決定呼叫哪個業務邏輯元件,例項化相應的類。例如,對於login請求,呼叫名為login的Action處理。
(3)struts2的所有Action都被定義在struts.xml檔案中,Action有name和class屬性,name決定了該Action處理哪個使用者請求,class決定了該Action的實現類。
(4)Struts2使用者處理使用者請求的Action例項,並不是使用者實現的業務控制器,而是Action代理,他會回撥使用者的處理方法,因為使用者實現的業務控制器沒有與Servlet API有任何關係,所以根本沒辦法進行獲取引數等請求處理,而struts2定義了一系列攔截器,會對請求引數解析,傳入到Action中,回撥execute方法。
我們每次請求都會例項化相應的類,所以不會出現執行緒不安全的情況。而Servlet為單例,會出現執行緒不安全。
業務控制器:
業務控制器就是使用者實現的Action類,Action類中通常包含一個execute方法,該方法返回一個字串,字串與struts.xml中的result的name相對應,跳轉到不同頁面。
struts2內部執行流程
(1)客戶端發出HTTP請求
(2)然後請求被核心過濾器StrutsPrepareAndExecuteFilter攔截
(3)核心過濾器將請求轉發到Action對映器,Action對映器負責識別當前的請求是否需要交由Struts2處理。
(4)Action對映器返回需要struts2處理的資訊,StrutsPrepareAndExecuteFilter會建立一個Action代理
(5)Action代理並不知道執行哪一個Action,它會向配置管理器詢問呼叫哪一個Action,配置管理器會從struts.xml讀取我們配置的Action資訊。
(6)Action代理建立相關請求的Action物件,呼叫相關的方法之前,struts2的一系列攔截器會幫我們做一些操作,例如獲取請求引數等。
(7)然後呼叫execute方法根據返回的字串去匹配相應的頁面,
(8)頁面可以獲取一些頁面模板,然後生成最終頁面,再倒序的執行攔截器的後續操作
(9)最後生成HTTP響應內容
Struts2配置檔案
Struts2核心配置檔案是struts.xml,該檔案主要負責管理業務控制器Action。
struts2有很多配置檔案,按照以下順序載入配置
(在伺服器開啟時,載入web.xml檔案,然後初始化核心過濾器,核心過濾器的init初始化方法中,
提供了載入配置檔案的方法。所以伺服器一啟動,這些配置檔案就已經載入到記憶體中了。 )
default.properties:該檔案儲存在struts2-core-2.3.32.jar中的org.apache.struts2包裡面
裡面儲存一些常量。
struts-default.xml :該檔案儲存在struts2-core-2.3.32.jar中
定義了一些struts2的基礎Bean和struts2內建支援的結果型別,還有struts2內建的攔截器(攔截器有很多,分為一系列的攔截器塊,我們預設使用defaultStack攔截器塊)
struts-plugin.xml :該檔案儲存在struts-xxx-2.3.32.jar等struts2外掛jar包中
我們整合spring等框架時,都需要這種外掛的jar包。
struts.xml:是web應用預設的自己的struts2配置檔案
struts.properties :是struts2的預設配置檔案
web.xml:web應用的配置檔案
如果多個檔案配置了同一個struts2常量,則後一個檔案中配置的常量值會覆蓋前面檔案中配置的常量值。
配置檔案中常用的常量
struts.i18n.encoding:該常量指定struts2應用預設使用的字符集。
struts.objectFactory.spring.autoWire:和spring框架整合有關。
struts.multipart.parser:指定檔案上傳用的元件。預設為jakarta(即common-fileupload上傳元件)
struts.multipart.saveDir:指定上傳檔案的臨時儲存路徑
struts.multipart.maxSize:指定上傳中整個請求所允許上傳的最大位元組數。
struts.action.extension:指定struts2需要處理的請求字尾。預設值為.action或者什麼都不寫
struts.serve.static.browserCache:設定瀏覽器是否快取靜態內容,當應用處於開發階段時,我們希望不快取,可設定為false
struts.enable.DynamicMethodInvocation:設定struts2是否支援動態方法呼叫,預設值為true
struts.devMode:設定struts2是否使用開發模式。如果設定為true,為開發模式,修改struts.xml配置檔案不需要重啟伺服器,會顯示更多更友好的錯誤提示。
struts.ui.theme:指定檢視主題。
struts.url.includeParams:指定struts2生成url時是否包含請求引數。有none,get和all三個值。分別對應不包含,僅包含get型別請求引數和包含全部請求引數。
struts.xml檔案中配置和修改常量
在struts.xml檔案中配置,使用<constant .../>配置常量。
name:常量名
value:常量值
<constant name="" value=""/>
例子:我們修改請求字尾為.abc
在struts.xml檔案中配置
<package name="demo" extends="struts-default">
<action name="hello" class="com.cad.struts2.Hello" method="sayHello">
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
//修改請求字尾為abc
<constant name="struts.action.extension" value="abc"></constant>
編寫jsp頁面
<body>
//使用預設請求字尾
<a href="${pageContext.request.contextPath }/hello.action">字尾為.action</a>
<a href="${pageContext.request.contextPath }/hello">沒有後綴</a>
<a href="${pageContext.request.contextPath }/hello.abc">字尾為.abc</a>
</body>
結果為前兩個都出現404
最後一個超連結訪問成功
在web.xml檔案中配置常量
//修改請求字尾為do
<init-param>
<param-name>struts.action.extension</param-name>
<param-value>do</param-value>
</init-param>
jsp頁面
<body>
<a href="${pageContext.request.contextPath }/hello.action">字尾為.action</a>
<a href="${pageContext.request.contextPath }/hello">沒有後綴</a>
<a href="${pageContext.request.contextPath }/hello.abc">字尾為.abc</a>
<a href="${pageContext.request.contextPath }/hello.do">字尾為.do</a>
</body>
前三個都請求失敗,最後.do結尾的請求成功。這也驗證了我們說的配置檔案的載入順序。
深入struts2配置檔案
Bean配置
struts2是一個高度可擴充套件的框架。框架的大部分核心元件,並不是硬編碼寫在程式碼中,而是以自己的IOC容器管理框架的核心元件。
struts2以可配置的方式來管理核心元件,從而允許開發者很方便的擴充套件該框架的核心元件,當開發者需要擴充套件,替換核心元件時,只需要提供自己元件的實現類,將其部署在struts2的IoC容器中即可。
struts-default.xml檔案中配置了大量的struts2框架的內建Bean。
我們在struts.xml中定義Bean時,通常有兩個作用
-建立該Bean的例項,將該例項作為struts2框架的核心元件使用。
-Bean包含的靜態方法需要注入一個值。可以很方便地允許不建立某個類的例項,卻可以接受框架常量。
這個部分只需要瞭解即可,百分之九十九的struts2應用都不用我們去定義核心元件和去配置Bean。
使用<bean />元素在struts.xml定義Bean
屬性:
class:必填屬性。指定了Bean例項的實現類
type:可選屬性,制定了Bean例項實現的struts2規範,該規範通過某個介面實現。
name:可選屬性。Bean例項的名字
scope:可選屬性。指定Bean例項的作用域
static:可選屬性。指定Bean是否使用靜態方法注入。
optional:可選屬性。指定該Bean是否是一個可選Bean。
例如
使用自定義的ObjectFactory,實現了ObjectFactory介面。實現類是MyObjectFactory
<bean type="com.opensymphony.xwork2.ObjectFactory" name="myfactory" class="com.my.MyObjectFactory"/>
瞭解即可,不需要深入。
package包配置
struts2框架的核心元件就是Action,攔截器等。struts2使用包來管理Action,攔截器等。
屬性
name:配置包時,必須指定name屬性,是包的唯一標識。
extends:屬性值必須是另一個包的name屬性。指定extends屬性表示繼承其他包。子包可以整合一個或多個父包中的攔截器,攔截器棧,action等配置。
例如我們前面專案中定義的 <package name="demo" extends="struts-default"> ,就繼承struts-default.xml中的struts-default包。
abstract:可選屬性。指定該包是否是抽象包,抽象包不能包含Action定義。
namespace:該屬性是一個可選屬性,定義該包的名稱空間。一個web應用中可能出現同名Action。同一個名稱空間中不能有同名Action
某個包指定名稱空間後,該包下的所有action的url地址必須是 名稱空間+action
例如我們加一個名稱空間,則訪問這個動作的時候必須加上名稱空間。例如 http://localhost:8080/Struts2Demo/user/hello.action
<package name="demo" extends="struts-default" namespace="/user">
<action name="hello" class="com.cad.struts2.Hello" method="sayHello">
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
如果包沒有指定名稱空間,則預設的名稱空間為""
根名稱空間為"/"
包的執行順序
(1)搜尋配置檔案所有package的namespace
(2)先去匹配名稱空間/user/my,如果匹配到,就查詢Action,查詢到就執行,沒查詢到會到預設名稱空間查詢Action,查詢到執行,沒找到報錯。
(3)如果沒匹配到該名稱空間,就接著匹配名稱空間/user,如果匹配到,就查詢Action,查詢到就執行,沒查詢到會到預設名稱空間查詢Action,查詢到執行,沒找到報錯。
(4)沒匹配到就去根名稱空間(”/“)查詢action,沒查詢到會到預設名稱空間查詢Action,查詢到執行,沒找到報錯。
(5)沒匹配到任何名稱空間直接報錯。
Struts2的Action
開發者需要提供大量的Action,並在struts.xml中配置Action.Action類裡包含了對使用者請求的處理邏輯,因為我們也稱Action為業務控制器。
編寫Action處理類
第一種建立處理類方法 :
struts2採用了低侵入式的設計,struts2不要求Action類繼承任何的struts基類,也不需要實現任何介面。Action類只是一個普通的POJO(Plain Ordinary Java Object簡單的java物件)
第二種:建立一個類實現Action介面,該介面定義了五個字串常量。還包含一個String execute()方法
public interface Action{
五個字串常量
public static final String ERROR="errror";
public static final String INPUT="input";
public static final String LOGIN="login";
public static final String NONE="none";
public static final String SUCCESS="success";
//處理使用者請求的execute方法
public String execute()throws Exception;
}
第三種:繼承Action介面的實現類ActionSupport,該類提供了很多的預設方法,包括獲取國際化資訊,資料校驗的方法等。大大簡化了Action的開發。我們開發中選擇第三種
配置Action
在struts.xml檔案中配置。struts2使用包來組織action。所以action定義放在包定義的下面 。
<action.../>
屬性
name:action的名字
class:指定該action的實現類,class屬性並不是必須的,如果我們不指定class屬性,系統預設使用ActionSupport類
配置Action的預設處理類
如果我們不指定<action>中的class屬性,預設使用ActionSupport類。
我們可以使用<default-class-ref class=""></default-class-ref>來指定預設的動作處理類。
Action的方法呼叫
我們繼承的ActionSupport,當我們執行Action的時候,預設執行他的execute方法,現在我們來執行自己的方法。< action >中有一個method屬性,可以指定使用者呼叫哪個方法。
例子:
我們寫一個Action類,類裡有四個方法。
public class Hello extends ActionSupport{
public String addUser(){
System.out.println("新增使用者");
return SUCCESS;
}
public String updateUser(){
System.out.println("修改使用者");
return SUCCESS;
}
public String selectUser(){
System.out.println("查詢使用者");
return SUCCESS;
}
public String deleteUser(){
System.out.println("刪除使用者");
return SUCCESS;
}
}
我們在struts.xml中配置我們的action
<package name="demo" extends="struts-default">
<action name="addUser" class="com.cad.struts2.Hello" method="addUser">
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
<action name="updateUser" class="com.cad.struts2.Hello" method="updateUser">
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
<action name="selectUser" class="com.cad.struts2.Hello" method="selectUser">
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
<action name="deleteUser" class="com.cad.struts2.Hello" method="deleteUser">
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
在jsp頁面中請求action
<body>
<a href="${pageContext.request.contextPath }/addUser">新增使用者</a>
<a href="${pageContext.request.contextPath }/updateUser">修改使用者</a>
<a href="${pageContext.request.contextPath }/selectUser">檢視使用者</a>
<a href="${pageContext.request.contextPath }/deleteUser">刪除使用者</a>
</body>
我們發現這種方式寫的很多程式碼類似,相當冗餘,為了解決這個問題,struts2提供了萬用字元的配置方式幫我們解決這個問題。
使用萬用字元
我們在struts.xml檔案中配置
<package name="demo" extends="struts-default">
<action name="*" class="com.cad.struts2.Hello" method="{1}">
<result name="success">/{1}.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
action的name中可以使用萬用字元 * , * 可以匹配所有的action, * 的值為傳入的action名字,例如傳入了addUser.action,那麼 * 的值就為addUser。method屬性中可以使用表示式來獲取 * 的值,{第幾個*}
例如 ” * _ * “,我們傳遞add_User,那麼{1}的值就是add,{2}的值就是User。
動態方法呼叫
使用動態呼叫前要先將動態呼叫的常量更改成true,動態呼叫預設是false,因為不安全。
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
我們使用動態方法呼叫我們需要的方法。
格式 :動作名稱!方法名稱
我們配置struts.xml檔案 ,不寫method值,也不用萬用字元
<package name="demo" extends="struts-default">
<action name="user" class="com.cad.struts2.Hello" >
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
我們更改jsp頁面按照動態方法呼叫的格式,就可以呼叫相關的方法。
<body>
<a href="${pageContext.request.contextPath }/user!addUser">新增使用者</a>
<a href="${pageContext.request.contextPath }/user!updateUser">修改使用者</a>
<a href="${pageContext.request.contextPath }/user!selectUser">檢視使用者</a>
<a href="${pageContext.request.contextPath }/user!deleteUser">刪除使用者</a>
</body>
管理處理結果
當Action處理完使用者請求時,處理結果應該通過檢視資源實現,但將哪個檢視呈現給瀏覽者呢。由<result.../>來決定
Action處理完使用者請求後,返回一個普通字串。整個普通字串就是一個邏輯檢視名。
通過配置檔案將邏輯檢視和物理檢視聯絡起來。一旦系統收到Action返回的邏輯檢視名,就把對應的物理檢視呈現給瀏覽者。
struts2支援多種檢視技術。當一個Action處理使用者請求後,僅僅返回一個字串,這個字串只是邏輯檢視名
邏輯檢視名可以和很多檢視資源關聯。例如 JSP,FreeMarker等
結果型別。
比如我們邏輯檢視名是success,對應success.jsp,那麼我們是請求轉發到該頁面還是重定向呢。這就需要我們指定結果型別。struts2提供了一系列的內建結果型別,在struts-default.xml中能看到。
<result../>屬性
name:邏輯檢視名稱,應該與Action返回的字串相同,如果不填寫,預設為success
type:結果檢視型別,不寫的時候預設值為dispatcher(請求轉發)
name是去哪裡,type是怎麼去。
struts內建支援的常用結果型別
-chain:Action鏈式處理。當一個Action處理完成之後,系統並不想轉發到檢視資源,而是希望下一個Action進行處理,此時就需要這個型別。
-dispatcher:請求轉發
-redirect:重定向
-redirectAction:重定向到其他Action
-stream:向瀏覽器返回一個InputStream的結果型別(一般用於檔案下載)
Chain例子
struts.xml檔案配置
當傳送請求demo1時,返回的結果轉發到demo2的Action處理
<package name="demo" extends="struts-default">
<action name="demo1" class="com.cad.struts2.Hello" >
<result type="chain">demo2</result>
</action>
<action name="demo2" >
<result name="success" >/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
不同包之間的請求轉發
<package name="demo" extends="struts-default">
<action name="demo1" class="com.cad.struts2.Hello" >
<result type="chain">
//因為結果型別都有對應的實現類,我們到請求轉發的實現類中發現,有actionName和namespace兩個引數,並提供了get和set方法
//使用的是注入的思想,在請求轉發之前,先呼叫setNamespace和setActionName賦值
<param name="actionName">demo2</param>
<param name="namespace">/user</param>
</result>
</action>
</package>
<package name="demo1" extends="struts-default" namespace="/user">
<action name="demo2" >
<result name="success" >/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
重定向也是一樣。
自定義結果型別
需要實現一個結果型別類,繼承StrutsResultSupport類
我們這裡面使用我們的驗證碼小工具,輸出一個驗證碼
至於這個驗證碼小工具,以前的文章中有詳細的說明。
public class VcodeResult extends StrutsResultSupport {
@Override
protected void doExecute(String arg0, ActionInvocation arg1) throws Exception {
VerifiCode v=new VerifiCode();
HttpServletResponse response=ServletActionContext.getResponse();
BufferedImage b=v.getImage();
v.output(b, response.getOutputStream());
}
}
然後再建立一個Action類 ,什麼都不用寫
public class VcodeAction extends ActionSupport {
}
在struts.xml中進行配置
<package name="vcode" extends="struts-default" >
//配置我們自定義的結果型別
<result-types>
<result-type name="vcode" class="com.cad.struts2.VcodeResult"></result-type>
</result-types>
//我們還是在我們的原頁面,所以不需要指定其他頁面,type即為我們的自定義結果型別
<action name="vcode" class="com.cad.struts2.VcodeAction">
<result name="success" type="vcode"></result>
</action>
</package>
我們可以在自定義的結果型別類中新增get和set方法,來方便我們的一些引數自定義。
例如我們添加了weight,height的get和set方法。
<action name="vcode" class="com.cad.struts2.VcodeAction">
<result name="success" type="vcode">
<param name="weight">100</param>
<param name="height">100</param>
</result>
</action>
我們就可以自定義驗證碼的長寬等。這也又體現了我們的注入思想。
我們前面請求轉發前設定nameSpace和actionName和我們做的其實是相同的操作。
全域性結果檢視和區域性結果檢視
我們在包中定義了自己的結果型別,只有在自己的包或者子包中才能使用,在別的包中還是無法使用這個結果型別,為了所有的Action都能使用,我們需要將其變為全域性。
我們只需要定義一個包,繼承struts2的預設配置檔案
<package name="myresult" extends="struts-default">
<result-types>
<result-type name="vcode" class="com.cad.struts2.VcodeResult"></result-type>
</result-types>
<global-results>
<result>
<param name="weight">500</param>
<param name="height">1000</param>
</result>
</global-results>
</package>
然後如果我們需要這個結果型別,只需要我們的包繼承這個包即可。
在<global-results>中配置全域性引數,所有的action使用這個型別生成的驗證碼尺寸都一樣。
Action訪問Servlet API
第一種方式
Struts2提供了一個ServletActionContext物件可以訪問ServletAPI。
例如
HttpServletRequest request=ServletActionContext.getRequest();
HttpServletResponse response=ServletActionContext.getResponse();
ServletContext context=ServletActionContext.getServletContext();
HttpSession session=request.getSession();
第二種方式,實現ServletContextAware,ServletRequestAware,ServletResponseAware三個介面
public class VcodeAction extends ActionSupport implements ServletContextAware,ServletRequestAware,ServletResponseAware {
//定義三個引數
private HttpServletRequest request;
private HttpServletResponse response;
private ServletContext context;
public String execute() throws Exception {
return null;
}
//實現介面中設定引數的方法
@Override
public void setServletResponse(HttpServletResponse response) {
this.response=response;
}
@Override
public void setServletRequest(HttpServletRequest request) {
this.request=request;
}
@Override
public void setServletContext(ServletContext context) {
this.context=context;
}
}
執行流程是什麼,誰呼叫了set方法?
struts的內建攔截器有一個ServletConfig的攔截器。
它會先得到我們的動作類的引用,
然後通過instanceof方法判斷我們動作類是否屬於ServletContextAware,ServletRequestAware,ServletResponseAware型別
因為我們實現了這個介面,當然屬於這個型別
然後獲取request,response等
然後呼叫我們動作類實現的介面方法 setServletResponse,setServletRequest,setServletContext等為我們的request,response賦值。
分檔案編寫配置檔案
struts2允許將一個配置檔案分解成多個配置檔案,從而進行模組化的設計,也提高了配置檔案的可讀性。
例如我們有一個商城系統,分為使用者模組,訂單模組等等很多模組
<struts>
<include file="struts-user.xml"/>
<include file="struts-order.xml"/>
.......
</struts>