天天看點

Struts2知識整理

struts2是基于mvc開發模型的架構,屬于表現層架構

核心為攔截器

基于MVC,結構清晰

豐富的标簽庫,提高了開發效率

強大的攔截器

全局異常和全局結果處理

易于擴充的插件化機制

Struts2也有IOC和DI的特性

整體執行圖

Struts2知識整理

下面是一次請求Action的流程

建立actioncontext, 建立valuestack, 并且把整個ActionContext對象放入到threadlocal中,這樣就能保證valueStack的資料的安全性

建立Actionproxy 建立Action

按照順序執行所有的攔截器

執行Action

執行結果集

按照倒叙的方式執行符合規則的攔截器(return invoke)

清空資料

web.xml

struts2.xml

struts2可以包含多個配置檔案(提高了配置檔案的安全性和獨立性),<code>&lt;include file=""&gt;</code>|

default.properties:struts2-core**.jar org.apache.struts包中

struts-default.xml:struts2-core**.jar中

struts-plugin.xml:在插件的jar包中

struts.xml:在應用的建構路徑頂端。自己定義的Struts配置檔案(推薦)

struts.properties:在應用的建構路徑頂端。程式員可以編寫

web.xml:配置過濾器時,指定參數。程式員可以編寫

特别注意:順序是固定的。後面的配置會覆寫前面的同名配置資訊。

通路一次Action就會重新建立一個Action對象(多例)

action

name: 動作名稱,用于使用者請求

class: 映射類的全名,如果不指定預設值為:ActionSupport 預設類可以修改,預設類在struts-default.xml中進行了聲明,可以在配置檔案中用來指定自定義預設類

method: 指定映射方法, 預設值: execute

action内的通配符

通配符配置ACTION

存在多個比對,比對的執行順序:絕對比對-&gt;按照通配符比對的順序

位址:add_Customer

name="*_" {1}代表第一個所代表的的字元 {2}代表的第二個字元

使用方法:如果請求的是 Customer_add

class="com.item.action.{1}Action" method="{2}" // com.item.action.CustomerAction" method="add"

result /customer/{1}{2}.jsp // addCustomer.jsp

動态調用

http://loaclhost:8080/XXX/demo!m1(不安全,不建議使用)

使用前需要開啟動态調用,在struts2.xml中配置:<code>struts.enable.DynamicMethod.Invocation=true</code>

package(類似于java類的包)

name:唯一

extends:struts-default 繼承預設包,包内設定了預設的攔截器,如果不繼承該包,那麼Struts2中的核心功能将無法使用。

namespace: 指定命名空間,一般以"/"開頭。該包中的動作通路路徑:namesapce+動作名稱。如果namespace="",這是預設名稱空間,和不寫該屬性是一樣的。

abstract:沒有action子元素的包可以聲明為抽象包.

編寫動作類的三種方式:

單純POJI

實作Action接口提供了幾個格式化的傳回參數

String SUCCESS:success。一切正常。

String NONE:none。動作方法執行後,不轉向任何的結果視圖。或者在動作方法中傳回null。

String ERROR:error。動作方法執行時遇到異常,轉向錯誤提示頁面。

String INPUT:input。驗證、轉換失敗,轉向輸入頁面。

String LOGIN:login。檢測使用者是否登入,沒有登入轉向此視圖。

實作 ActionSupport(推薦)這個類實作了Action接口,并且提供了一些基本的功能,比如:驗證 國際化提示等

action通路ServletAPI

方式一:ServletActionContext靜态方法(推薦)

ServletActionContext.getRequest(); //struts2 改變了request中的某些功能 ServletActionContext.getResponse(); //apache ServletActionContext.getServletContext(); //apache

方式二:實作接口 ServletRequestAware,ServletResponseAware ,ServletContextAware

執行動作方法前,架構會把HttpServletRequest()對象注入進來

是由一個攔截器負責注入的,servletConfig

type 到達目标形式 預設:轉發,下面是幾個重要的

chain: 轉發到另一個動作

如果對應的action所在的包不在預設空間内,需要用到來設定空間和action名字

&lt;param name="Namespace"&gt;/n2&lt;/param&gt; &lt;param name="ActionName"&gt;math&lt;/param&gt;

dispatcher: 使用者轉發到頁面(請求轉發 jsp)

redirect: 請求重定向到jsp

redirectAction: 請求重定向到action

stream: 用于檔案上傳和下載下傳

freemarker: 轉發到另一個freemarker模闆(頁面靜态化)

httpheader: 輸出http協定的消息頭

plainText:原樣輸出源代碼

在struts2.xml中聲明結果定義類型

首先編寫類,實作com.opensymphony.xwork2.Result接口或者繼承StrutsResultSupport(一般為繼承),然後裡面設定需要輸出的内容(輸出方式和Servlet内相同)輸出驗證碼

表單的的name要與參數名字相同才可以指派

動态參數指派

模型類最好實作Serilalizable接口

參數指派的順序: 模型對象中找,如果沒有對應對象的Set方法,下一步就會從對應的action中尋找.

1.用Action動作類對象作為模型對象,即Javabean内寫上action函數jsp頁面name和屬性名字相同,然後直接通路就可以自動指派

2.動作類和模型分開在動作類裡面聲明模型類,并且設定get,set方法,動作類對象名字為person, 則jsp頁面的name要加上字首,即:person.name才可指派

3.動作類和模型分開(ModelDriven)

動作類繼承ModelDeriven

原因:與Struts2的值棧有關

該功能是由一個叫做modelDriven的攔截器完成的。

靜态參數注入<code>&lt;param name="name"&gt;遊客&lt;/param&gt;</code>

動态參數和靜态參數注入功能實作

是由兩個攔截器來完成。

靜态參數注入:staticParams

動态參數注入:params

批量添加表單

參數的類型轉換

struts2内置了轉換器,多數情況下不需要自己來編寫

struts2的發展過程 OGNL-WebWork-struts2 , 是以一些在ONGL或者WebWork時期定義不明确的方法和參數struts2會有一定程度的改正.

自定義轉換器:

編寫轉換器

繼承<code>StrutsTypeConverter</code>,重寫<code>convertFromString()</code> 和 <code>convertToString()</code> 這兩個方法

轉換器示例代碼

配置轉換器

局部轉換器

字首名字一定要和類名相同

對應模型類或者對應動作類下面建立 ClassName-conversion.properties檔案, 内容: <code>birthday=com.item.MyDateConverter(轉換器類)</code>

Struts2知識整理

全局轉換器

位置在src下面,名字為<code>xwork-conversion.properties</code>,所有動作都可以用

<code>java.util.Date=com.itheima.convertors.MyDateConverter</code> 内容為需要轉換的類型和對應的類

類型轉換失敗提示

轉換失敗,會自動轉到一個name=input的邏輯視圖(需要在result内定義),一般指向輸入的那個頁面,目的回顯(建議使用struts2的表單标簽)

錯誤消息提示中文版本(動作類要繼承ActionSupport類)

<code>類名.properties</code> , 内容為<code>invalid.fieldvalue.birthday=輸入錯誤</code>

Struts2知識整理

驗證功能是由validation攔截器來負責處理的。回顯錯誤資訊是由workflow攔截器來負責處理的。

下面兩種方式都需要在struts.xml配置檔案中添加<code>&lt;result name="input"&gt;/regist.jsp&lt;/result&gt;</code>結果視圖

程式設計式驗證

針對動作類中所有的方法進行驗證

動作類需要實作ActionSupport覆寫掉validate()方法

在validate方法内部編寫規則,不正确的情況用addFieldError添加錯誤資訊

動作類就是模型類: <code>addFieldError("name", "請輸入使用者名");</code>

動作類跟模型類分開: <code>addFieldError("m.name", "請輸入使用者名");</code>

針對指定方法進行驗證

在需要驗證的方法上面添加注解<code>@SkipValidation</code>

将validate()方法改寫成為<code>public void validateDemo1</code> 後面是指定方法的名字.

聲明式驗證

在xml檔案中配置驗證資訊,不需要寫死

在動作類所在的包中建立:動作類名-validation.xml配置檔案。

xml檔案

在模型類和動作類的兩種方式, 隻需要改一下<code>&lt;field name="m.name"&gt;</code> 中的name要和表單名(jsp/name)一緻

針對動作做類的方法進行驗證在動作類所在的包中建立:動作類名-動作名(是請求的struts.xml配置檔案中的)-validation.xml配置檔案。 action配置檔案中可以用method屬性來指定執行那個方法

常用内置驗證器

提供的聲明式驗證器在xwork-core-**.jar包的com\opensymphony\xwork2\validator\validators\default.xml配置檔案中(查詢具體類用CRTL+T)。

内置驗證器示例

自定義聲明式驗證器

編寫一個類,繼承FieldValidatorSupport

定義驗證器,之後就可以和使用内置驗證器一樣使用src目錄下,建立validators.xml

編寫自定義驗證器

是struts2中的核心功能,是一種AOP變成思想的具體應用.

常用的攔截器

modelDriven:模型驅動

servletConfig:擷取ServletAPI

staticParams:靜态參數注入

params:動态參數注入

validation:輸入驗證,聲明式驗證。

結果應該是:

攔截前-動作類-jsp-攔截後

即先執行攔截器,然後在執行方法,執行方法傳回的邏輯視圖,最後再次執行攔截器

使用自定義攔截器

攔截器參數可以用set方法或者在xml中用param來設定, 如果在class中用Set來設定,需要覆寫父類的init()方法.

編寫一個類,繼承AbstractInterceptor(所有方法都會攔截)示例

配置攔截器在pageage裡面用<code>&lt;interceptors&gt;&lt;interceptor name="" class=""/&gt;&lt;/interceptors&gt;</code>來聲明攔截器

使用攔截器(如果隻是在單純的指定自定義攔截器,則預設攔截器不起作用)

在action裡面使用<code>&lt;interceptor-ref name=""&gt;&lt;/interceptor-ref&gt;</code>來使用攔截器(使用了自定義攔截器,則預設攔截器失效)

代碼

指定方法攔截

繼承MethodFilterInterceptor方法代碼

使用

通過<code>&lt;param name="excludeMethods"&gt;query&lt;/param&gt;</code>的形式傳遞不需要過濾的方法(includeMethods需要包含的方法),參數為需要攔截的方法.

攔截組合

定義組,覆寫預設攔截器, 将攔截器聲明為全局的攔截器

簡單的登入驗證

所有方法

指定方法

xml

表單域前提: post, enctype="multipart/form-data"

struts2中,是fileupload攔截器完成的

單檔案上傳

Struts2知識整理

存儲檔案可以用<code>FileUtils.copyFile(file1, target);</code> 方法, file1: file檔案域對象 target: 目标檔案(建立的檔案)

上傳檔案

多檔案上傳

參數和單檔案相同,不過要改成數組或者List方式來存儲

存儲檔案時需要周遊File數組

檔案錯誤資訊提示

修改上傳檔案預設錯誤資訊

在src檔案夾下建立<code>fileupload.properties</code> 檔案

配置參數 <code>struts.messages.upload.error.SizeLimitExceededException</code> 和 <code>struts.messages.error.file.extension.not.allowed</code> 等,可以用{1}來設定系統傳回值

示例

動作類中需要定義InputStream對象,(名稱不能為in)和String Filename

<code>&lt;result type="Stream"&gt;</code> Xml配置檔案結果視圖類型為Stream

需要設定參數

inputStream 設定輸出流,名字為Action中定義的名字

attachment;filename=${@java.net.URLEncoder@encode(fileName,'UTF-8')} ,設定響應頭

導入标簽 <code>&lt;%@ taglib uri="/struts-tags" prefix="s"%&gt;</code>

OGNL不僅僅可以在jsp中使用,在其他地方也可以(例如xml配置檔案)

context上下文

ActionContext私有化會使得jsp頁面擷取不到Context/valuestack中的值

ActionContext和ValueStack聲明周期都是一次http請求

傳輸的資料存儲在context,資料中心

在jsp頁面使用标簽可以顯示context中的資訊

context是一個Map,每個域對象對應一個值, 這個值可以是Map也可以是其他的 即Map

Struts2知識整理

動作類的生命周期,每次通路都會建立新的動作類執行個體,ActionContext和ValueStack, 會一直保持在你的線程中,是以線程安全.

ActionContext API 常用API

ValueStack

ValueStack屬于Context裡面的一個屬性,結構為棧

也可以通過ValueStack獲得Context,ActionContext中的Context和ValueStack裡面的相同

如果ValueStack中有多個名字相同的值<code>&lt;s:property value="[1].month"&gt;</code>

擷取對象資料的不同:

擷取Context中的資料需要用#開頭

擷取ValueStack中的資料直接寫屬性名字就可以,會從棧頂一直往下找.

基本方法

vs.set("b1", "vb1"); //檢測棧頂是不是一個Map,如果不是,建立一個Map,Map中的資料就是p1=pp1,再把這個Map壓入棧頂,如果有,則會把資料直接放入

vs.setValue("name", "三平");//設定ValueStack中存在屬性的值,屬性必須存在

vs.setValue("#name", "三平"); //向Context中設定key為name, value為三平的Map, key可以不存在

vs.findValue(name);//取valuestack中的值不用#,context中的用#,從根中依次尋找對象的屬性,沒有找到會去Context内找(尋找整個Context),加強EL表達式運用的方法.

對EL表達式的增強EL不僅僅會搜尋以前的幾個域中的對象,還會通過find.Value()方法去Context中搜尋

特殊符号的運用

在ognl表達式内如果需要輸出字元串,則字元串需要添加單引号

%{} 将字元串當成ognl表達式

${} 在國際化資源檔案中引用OGNL表達式,在Struts2配置檔案中引用ognl表達式(上次檔案示例)數組和數列:${@java.net.URLEncoder@encode(fileName,'UTF-8')}

Struts2知識整理

壓棧/彈棧

OGNL 建立List和Map

Struts2知識整理

内置标簽需要導入标簽<code>&lt;%@ taglib prefix="s" uri="/struts-tags" %&gt;</code>

<code>&lt;s:property value="'name'"/&gt;</code> //将value輸出,使用ognl表達式都需要在struts2的标簽内才可以

<code>&lt;s:set value="'value'" var="v1" scope="session"&gt;&lt;/s:set&gt;</code> 存放資料,如果沒有指定scope, 預設放到contextMap和request中

<code>&lt;s:property value="'&lt;hr/&gt;'" escapeHtml="true"/&gt;&lt;br/&gt;</code> 是否轉譯

<code>&lt;s:push value="'value3'"&gt;&lt;/s:push&gt;</code> 将對象壓入valuestack棧中,标簽結束後彈棧,則操作必須在結束标簽之前進行

<code>&lt;s:bean name="java.util.Date" var="now"&gt;&lt;/s:bean&gt;</code> 給一個對象去一個名字,并且放到contextMap中

<code>&lt;s:action name="HelloWorldAction" executeResult="true"/&gt;</code> action指向一個動作,将動作結果包含進來,類似于EL标簽的include

<code>&lt;s:iterator value="#request" var="s"&gt;</code> forEach,将目前周遊的元素存儲到contextMap中,key就是var指定的值 m=Map.Entry,如果沒有指定var,會将目前元素放到valuestack中

<code>&lt;s:radio list="{'man','faman'}" name="username"&gt;&lt;/s:radio&gt;</code> 如果contextMap中有key和下面連個标簽的name相同,則會自動周遊内容,選中對應的選項

<code>&lt;s:if test="#grade=='A'"&gt; &lt;/if&gt; &lt;s:elseif test="#grade=='B'"&gt;&lt;/s:elseif&gt;</code> if-else标簽

<code>&lt;s:url action="demo2" var="u1"&gt; &lt;a href="${u1 }"&gt;點我&lt;/a&gt;</code> url标簽和a标簽傳遞參數是用<code>&lt;s:param name="username" value="'你也好'"&gt;</code> 來傳遞

<code>&lt;s:a action="demo1"&gt;&lt;/s:a&gt;</code>

具體代碼

标簽簡單實作防止表單重複送出

在jsp頁面使用

在xml裡面配置 有兩種方法 (token, tokenSession)

<code>&lt;interceptor-ref name="token"&gt;&lt;/interceptor-ref&gt;</code> //需要結果視圖,如果重複送出會轉向結果視圖

<code>&lt;interceptor-ref name="tokenSession"&gt;&lt;/interceptor-ref&gt;</code> //不需要結果視圖,點多次送出會等待

java

jsp

struts2加載配置檔案的順序:

struts-default.xml 核心的配置檔案

struts-plugin.xml 插件的配置檔案

struts.xml 程式員開發的時候需要寫的配置檔案

objectFactory類 : 生産struts2關鍵元件, 如攔截器,結果集,action, 可以通過繼承這個類來改寫方法

插件機制的原理

我們可以通過繼承 objectFactory類來編寫自己需要的方法,然後通過改變配置檔案中的參數,将objectFactory改變為我們自己編寫的類.

在工程的Lib下有很多個struts2-plugin-xx.jar包,在這個包下有一個struts-plugin.xml檔案,在這個檔案中可以配置很多内容,隻需要吧這個jar包放到lib下面,當tomact啟動的時候被加載了, 如果不需要,隻需要把這些jar包移除掉就可以了 這就是插件機制

struts2底層用objectFactory.buildAction方法來建立action的,是以我們可以繼承objectFactory類改寫方法,而在配置檔案中可以指定objectFactory是哪一個具體的類,是以我們隻需要把jar包放進去和配置好Xml檔案就可以了

如果需要在生成Action之前做一些操作,那我們就可以考慮選擇重寫objectfactory方法.

objectfactory說明

該對象稱為對象工廠:生成對象的工廠,struts2的很關鍵的元件都可以是一個對象

在default.properties檔案中有一個常量struts.objectFactory,該值就是對象工廠

objectfactory的示意圖

Struts2知識整理