struts2.1.6教程二、struts.xml配置及例程
?
1.配置文件的優(yōu)先級(jí)
在struts2中一些配置(比如常量)可以同時(shí)在struts-default.xml(只讀性),strtus-plguin.xml(只讀性),struts.xml,struts.properties和web.xml文件中配置,它們的優(yōu)先級(jí)逐步升高,即是說后面的配置會(huì)覆蓋掉前面相同的配置。
?
2.配置形式
下面以對(duì)struts.i18n.encoding=UTF-8的配置為例進(jìn)行說明:
在struts.xml配置形式如下:
?
<constant name="struts.i18n.encoding" value="gbk"></constant>在struts.properties的配置形式如下:
struts.i18n.encoding=UTF-8
在web.xml中配置如下:
<filter><filter-name>struts2</filter-name> <filter-class> org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class><init-param><param-name>struts.i18n.encoding</param-name><param-value>UTF-8</param-value></init-param> </filter>說明:官方聲稱配置了此常量可以解決中文亂碼問題,但實(shí)事上并不能達(dá)到目的,在前面的三個(gè)項(xiàng)目中,如果我們?cè)诒韱沃休斎胫形?#xff0c;其結(jié)果是會(huì)出現(xiàn)亂碼。解決此問題參看[一.7的注意]。這是struts2.1.6中的一bug,它的下一版2.1.8已解決此問題。
?
3.package配置相關(guān)
| 屬性名 | 是否必須 | 說明 |
| Name | 是 | Package的唯一標(biāo)識(shí),不允許同名 |
| Extends | 否 | 指定要繼承的包 |
| Namespace | 否 | 指定名稱空間 |
| Abstract | 否 | 聲明包為抽象否 |
?
?
說明:在上面的配置文件中所用到的Test1Action和Test2Action這兩個(gè)Action都只是繼承了com.opensymphony.xwork2.ActionSupport類,而ActionSupport默認(rèn)返回的就是“success”,所以當(dāng)點(diǎn)擊上面的鏈接分別轉(zhuǎn)到了forward目錄下的test1.jsp和test2.jsp。下面重點(diǎn)來看這個(gè)package元素的namespace屬性及action的name屬性,它們共同定義了action所映射到的實(shí)質(zhì)文件。上圖展示了鏈接地址和action的對(duì)應(yīng)關(guān)系,所以當(dāng)我們要想訪問一個(gè)action所關(guān)聯(lián)到的jsp文件時(shí),應(yīng)該用namespace+action的name 關(guān)于它的內(nèi)容測試可以參考struts2package項(xiàng)目。
?
補(bǔ)充:通常情況下,action元素的name是屬性值是不能出現(xiàn)“/”的,所以希望通過action中name屬性來實(shí)現(xiàn)多級(jí)映射,需要在sturts.xml中增加如下屬性:??
<constant name="struts.enable.SlashesInActionNames" value="true"/>這樣配置后就可以再action的name元素中使用“/”了。比如:
<package name="tt3" extends="struts-default"><action name="test3/test3" class="com.asm.Test3Action"><result name="success">/forward/test3.jsp</result></action> </package>然后輸入<a href="<%=path%>/test3/test3.action">test3</a><br>鏈接地址就可以訪問了
?
強(qiáng)調(diào):namespace默認(rèn)值“”,即不配置namespace屬性。它的意思是:如果action不能進(jìn)行完整路徑匹配,則會(huì)來此namespace下進(jìn)行匹配,比如:.../test/test/test.action,如果參照namespace及action的name不能找到也之完全對(duì)應(yīng)的action,它會(huì)再到依次追溯到上級(jí)目錄中查找,即是說它會(huì)以…/test/test.action這樣的路徑來對(duì)應(yīng)namespace和action的name進(jìn)行查找。如果返回到最終的目錄仍找不到,它就會(huì)到namespace="/"對(duì)應(yīng)的包下查找名為test的action,如果仍找不到,它就會(huì)去默認(rèn)的namespace下查找名為test的action,如果找到則執(zhí)行此action。另外,namespace也可以配置成namespace="/"。它代表配置為項(xiàng)目的根。 總結(jié)action的名稱探索順序:完全對(duì)應(yīng)、逐步追溯到上級(jí)目錄查找、"/"下查找、默認(rèn)namespace下查找。
?
為什么要提出namespace,主要是避免多人共同開發(fā)項(xiàng)目出現(xiàn)名字沖突。如果不使用namespace,多個(gè)人所寫的action中可能出現(xiàn)重名的現(xiàn)象,這樣當(dāng)項(xiàng)目合并時(shí)就會(huì)出現(xiàn)沖突。而有了namespace可以在項(xiàng)目開發(fā)時(shí)由項(xiàng)目經(jīng)理給每一個(gè)人分不同的namespace,這樣每個(gè)開發(fā)人員只需要保證自己所寫的action不同名即可。
?
namespace引發(fā)的鏈接問題:當(dāng)我們?yōu)閍ction配置了namespace時(shí),訪問此action的形式總會(huì)是如下形式:.../webappname/xxx/yyy/ActionName.action 而當(dāng)此action成功執(zhí)行跳轉(zhuǎn)到某個(gè)jsp頁面時(shí),如想在此jsp頁面寫鏈接,一定要寫絕對(duì)路徑,因?yàn)橄鄬?duì)路徑是相對(duì).../webappname/xxx/yyy/,而如果以后我們修改了action的namespace時(shí),相對(duì)路徑又要變,所以鏈接不能寫成相對(duì)路徑。 以下介紹
1.絕對(duì)路徑的寫法:通常用myeclipse開發(fā)時(shí)建立一個(gè)jsp文件,默認(rèn)總會(huì)有如下內(nèi)容:
<% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %>我們寫絕對(duì)路徑可以參此內(nèi)容。還可以參<head>下的<base href="<%=basePath%>"> 來完成絕對(duì)路徑的書寫。?
4.分工合作include:指定多個(gè)配置文件
比如讓jack來單獨(dú)開發(fā)一個(gè)action,在jack.xml中的配置文件為:
<struts><package name="jack" namespace="/jack" extends="struts-default"><action name="test4" class="com.asm.Test4Action"><result name="success">/forward/test4.jsp</result></action></package> </struts>然后在struts.xml文件中增加如下內(nèi)容:<include file="jack.xml"></include> 它實(shí)質(zhì)就是把jack.xml中的<package>及其內(nèi)容寫進(jìn)struts.xml中的<struts>根元素下。
?
鏈接:<a href="<%=path %>/jack/test4.action">test4</a> 這樣便可以訪問到了forward目錄下的test4.jsp了。
?
?
5.tomcat認(rèn)證訪問
接上例:namespce的作用除了在前面提到的避免協(xié)同開發(fā)名字沖突外,還為認(rèn)證提供一個(gè)條件。比如jack開發(fā)的東西所關(guān)聯(lián)到的頁面需要權(quán)限才能被訪問。由于多為tomcat中的內(nèi)容,下面只列出步驟。
步驟一,tomcat的conf目錄下tomcat-users.xml內(nèi)容如下:
<security-constraint><web-resource-collection><web-resource-name>jack</web-resource-name><url-pattern>/jack/*</url-pattern><http-method>POST</http-method><http-method>GET</http-method></web-resource-collection><auth-constraint><role-name>admin</role-name></auth-constraint></security-constraint><security-role><role-name>admin</role-name></security-role><login-config><auth-method>BASIC</auth-method><realm-name>input authentication message</realm-name></login-config>
這樣配置完成后,當(dāng)我們?cè)L問.../jack中的任何內(nèi)容都會(huì)要求輸入密碼認(rèn)證信息,認(rèn)證時(shí)輸入tomcat-users.xml配置的admin權(quán)限的用戶名和密碼即可訪問(這里就只有jack用戶名可以訪問)
?
6.初識(shí)攔截器
攔截器能在action被調(diào)用之前和被調(diào)用之后執(zhí)行一些“代碼”。Struts2框架的大部分核心功能都是通過攔截器來實(shí)現(xiàn)的,如防止重復(fù)提交、類型轉(zhuǎn)換、對(duì)象封裝、校驗(yàn)、文件上傳、頁面預(yù)裝載等等,都是在攔截器的幫助下實(shí)現(xiàn)的。每一個(gè)攔截器都是獨(dú)立裝載的(pluggable),我們可以根據(jù)實(shí)際的需要為每一個(gè)action配置它所需要的攔截器。
在myStruts2項(xiàng)目下,重新對(duì)配置文件作如下修改:
<package name="myFirst" namespace="/" extends="struts-default"> <interceptors><interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor" />
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor" />
</interceptors><action name="login" class="com.asm.LoginAction">
<interceptor-ref name="timer"></interceptor-ref><interceptor-ref name="params"></interceptor-ref>
<result name="loginSuccess">/success.jsp</result><result name="loginFailure">/failure.jsp</result></action></package>
首先在package中定義了兩個(gè)攔截器,然后在login action中引用了這兩個(gè)攔截器,需要說明的是這里使用的攔截器都是系統(tǒng)自帶的攔截器。其實(shí)在extends所繼承的struts-default中就包含了很多攔截器,也包括我們這里所用的攔截器,但如果在此action中不使用params攔截器,將會(huì)報(bào)空指針錯(cuò),因?yàn)閜arams攔截器的作用是傳遞表單參數(shù),如果不使用此攔截器就不能在action中得到表單參數(shù),所以引用時(shí)會(huì)報(bào)空指針錯(cuò)。雖然extends繼承的strust-default自帶有params攔截器,但是當(dāng)我們自己引用了攔截器時(shí),繼承struts-default將不會(huì)再為我們分配默認(rèn)的攔截器(有點(diǎn)類似構(gòu)造器),但是我們?nèi)匀豢梢酝ㄟ^<interceptor-ref name="defaultStack"/>來繼續(xù)使用struts-defalut的攔截器。補(bǔ)充:由于上面的package繼承于struts-default,而我們這里所用到的timer和params都是在struts-defalut中定義過,所以即使我們?cè)?lt;interceptors>中沒有定義過這兩個(gè)攔截器,也可以直接在action中引用。
?
使用<interceptor-stack>組合多個(gè)攔截器:比如我們想把上面的params和timer這兩個(gè)攔截器組合:
<interceptor-stack name="timer_param"><interceptor-ref name="timer" /><interceptor-ref name="params" /></interceptor-stack>然后再在action引用<interceptor-ref name="timer_param"/>”,效果和分別引用兩個(gè)是一樣的。其實(shí)我們使用strtus-default中的<interceptor-ref name="defaultStack"/>也是使用interceptor-stack方式。
?
7.Action中的method屬性
在struts1.x中我們知道通過繼承DispatchAction可以實(shí)現(xiàn)把多個(gè)Action進(jìn)行統(tǒng)一操作,在struts2中實(shí)現(xiàn)action的統(tǒng)一操作也很簡單。我們以crud操作為例,把crud集中到一個(gè)Action中。
步驟一、建立CRUDAction,內(nèi)容如下:
步驟二、配置此Action,為了清晰明了,專為此Action,建立一個(gè)配置文件crud.xml,主要內(nèi)容如下:
<struts><package name="crud" extends="struts-default" namespace="/crud"><action name="add" class="com.asm.CRUDAction" method="add"><result name="success">/crud/addSuccess.jsp</result></action><action name="del" class="com.asm.CRUDAction" method="del"><result name="success">/crud/delSuccess.jsp</result></action><action name="update" class="com.asm.CRUDAction" method="update"><result name="success">/crud/updateSuccess.jsp</result></action><action name="query" class="com.asm.CRUDAction" method="query"><result name="success">/crud/querySuccess.jsp</result></action></package> </struts>分析:上面的method方法的值來源于CRUDAction中方法的名字,這樣當(dāng)我們?cè)L問上面的每一個(gè)Action時(shí),它實(shí)質(zhì)是和method指定的方法關(guān)聯(lián)上。
步驟三、把crud.xml配置文件并入struts.xml中,只需增加如下代碼:
步驟四、編寫相應(yīng)的jsp頁面,在此略去crud文件夾下的四個(gè)跳轉(zhuǎn)jsp頁面(addSuccess.jsp等),重點(diǎn)是crud.jsp頁面。內(nèi)容如下:
<html> <%String path=request.getContextPath(); %><body><a href="<%=path %>/crud/add.action">添加數(shù)據(jù)</a><br><a href="<%=path %>/crud/del.action">刪除數(shù)據(jù)</a><br><a href="<%=path %>/crud/query.action">查詢數(shù)據(jù)</a><br><a href="<%=path %>/crud/update.action">修改數(shù)據(jù)</a><br></body> </html>?
補(bǔ)充擴(kuò)展,動(dòng)態(tài)調(diào)用DMI:不使用method實(shí)現(xiàn)統(tǒng)一.我們?cè)赾rud.xml中增加如下內(nèi)容:
<action name="op" class="com.asm.CRUDAction"><result name="success">/crud/op.jsp</result> </action>然后再在crud.jsp中定義如下鏈接:
<a href="<%=path %>/crud/op!add.action">添加數(shù)據(jù)</a><br> <a href="<%=path %>/crud/op!del.action">刪除數(shù)據(jù)</a><br> <a href="<%=path %>/crud/op!query.action">查詢數(shù)據(jù)</a><br> <a href="<%=path %>/crud/op!update.action">修改數(shù)據(jù)</a><br>注意查看上面的鏈接地址,它們都是針對(duì)op action,然后再加地上“!+CRUDAction中相應(yīng)的方法名”,最后再寫上.action即可以訪問到統(tǒng)一頁面op.jsp。這樣做雖然能減少頁面,但是由于它們實(shí)質(zhì)用到的是同一個(gè)Action,所以這就意味著我們要使用的攔截器相同,相同的跳轉(zhuǎn)result。實(shí)際中這種方式很少使用,在此略作了解。如果不想使用動(dòng)態(tài)方法調(diào)用,我們可以通過常量來關(guān)閉,即在struts.xml中增加如下配置:
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>?
擴(kuò)展2:在CRUDAction中使用do。舉例:我們?cè)贑RUDAction中增加一個(gè)新的方法,內(nèi)容如下:
public String doMain(){return "success";}然后再在在crud.xml中增加如下內(nèi)容:
<action name="main" class="com.asm.CRUDAction" method="main"><result name="success">/crud/main.jsp</result> </action> 注意:配置中method屬性值是doMain中去掉do后M小寫。然后再在crud.jsp中增加如下鏈接:
隨后便可以訪問到.../crud/main.jsp頁面了。
?
8.使用ForwardAction實(shí)現(xiàn)頁面屏蔽。
我們?cè)趈sp頁面之間寫鏈接總會(huì)是.../xxx.jsp,而如果我們想屏蔽掉具體的jsp,只需要所jsp頁面配置成一個(gè)ForwardAction即可實(shí)現(xiàn)。示例如下:在根目錄下有一個(gè)index.jsp主頁,我們strtus.xml中作如下配置:
<package name="def" extends="struts-default"> <action name="forward"><result >/index.jsp</result></action> </package>說明:如果沒有未action指定class,默認(rèn)就是ActionSupport類,如果沒有為action指定method屬性,則默認(rèn)執(zhí)行execute方法,如果沒有指定result的name屬性,默認(rèn)值為success。知道了這些再結(jié)合ActionSupport的源碼就不難理解實(shí)現(xiàn)轉(zhuǎn)發(fā)的原理了。
?
隨后再在前面第7點(diǎn)擴(kuò)展中用到的op.jsp中增加如下代碼:
<a href="<%=request.getContextPath()%>/forward.action">forward</a>最后再測試訪問op.jsp,在op.jsp中頁面中直接點(diǎn)鏈接便可以跳到index.jsp,觀察地址欄發(fā)現(xiàn)此時(shí)跳到index頁面是進(jìn)行的服務(wù)器跳轉(zhuǎn),如果我們?cè)谏厦娴呐渲弥械膔esult增加type屬性變成
<result type="redirect">/index.jsp</result>,實(shí)現(xiàn)的跳轉(zhuǎn)就是客戶端跳轉(zhuǎn)。
補(bǔ)充:像這種forward形式的action實(shí)質(zhì)是執(zhí)行的ActionSupport 這個(gè)Action。因此配置它的result可以參看此類的api文檔,比如它常用的result name有:success、login、input等。
?
9.使用default-Action配置統(tǒng)一訪問
default-action-ref,當(dāng)訪問沒有找到對(duì)應(yīng)的action時(shí),默認(rèn)就會(huì)調(diào)用default-action-ref指定的action.同樣在上面的package中增加如下內(nèi)容
<default-action-ref name="error"></default-action-ref><action name="error"><result>/other/error.jsp</result></action>上面一段內(nèi)容就是說當(dāng)我們?cè)L問的action不能被找到時(shí)便指向名為error的action中去,接著我們?cè)谙旅媾渲昧诉@個(gè)error Action。但是要注意,一個(gè)package內(nèi)只配置一個(gè)<default-action-ref>,如果配置多個(gè),就無法預(yù)測結(jié)果了. 此時(shí)我們只要輸入.../myStruts2/luanFangWen.action這樣的形式,它就會(huì)去訪問這個(gè)默認(rèn)的<default-action-ref>,通常我們會(huì)為它配置一個(gè)錯(cuò)誤頁面,以提示用戶訪問的頁面不存在。
?
在web開發(fā)中,我們還可以把這個(gè)默認(rèn)的action訪問配置成主頁,這樣當(dāng)用戶訪問一些不存在的action時(shí),總會(huì)跳到主頁上去。
通過此配置,只要是訪問一個(gè)不存在的action便會(huì)轉(zhuǎn)向到.../other目錄下的error.jsp頁面。但是如果訪問是其它的不存在資源則仍是報(bào)tomcat所標(biāo)識(shí)的404錯(cuò)誤,我們可以在web.xml中作如下配置:
<error-page><error-code>404</error-code><location>/other/404error.jsp</location> </error-page>這樣配置后,訪問錯(cuò)誤頁面將跳到.../other/404error.jsp頁面中去。
補(bǔ)充說明:如果我們用ie訪問時(shí),如果選中了[工具][IE選項(xiàng)][高級(jí)][瀏覽][顯示友好的http錯(cuò)誤信息],則配置的錯(cuò)誤頁面將失效,因?yàn)檎也坏劫Y源時(shí)會(huì)報(bào)HTTP404錯(cuò)誤,而ie截取到此錯(cuò)誤進(jìn)行了它自身的友好處理,所以我們?cè)O(shè)置<error-page>就失效。
?
?
10.使用通配符
建立struts2wildcard項(xiàng)目,此實(shí)例基本仿照前面前面第7點(diǎn)的實(shí)例改寫而成。為了使用通配符,只需要改寫配置文件即可。此實(shí)例未使用通配時(shí)的配置文件如下:
<action name="addUser" class="com.asm.UserAction" method="addUser"><result name="success">/user/addUser.jsp</result> </action> <action name="delUser" class="com.asm.UserAction" method="delUser"><result name="success">/user/delUser.jsp</result> </action> <action name="queryUser" class="com.asm.UserAction" method="queryUser"><result name="success">/user/queryUser.jsp</result> </action> <action name="updateUser" class="com.asm.UserAction" method="updateUser"><result name="success">/user/updateUser.jsp</result> </action>我們注釋掉上面的配置,使用通配符只需如下內(nèi)容即可達(dá)到相同的效果:
<action name="*User" class="com.asm.UserAction" method="{1}User"><result name="success">/user/{1}User.jsp</result> </action>原理:當(dāng)有.../addUser.action請(qǐng)求時(shí),如果不能在當(dāng)前應(yīng)用中找到完全相同的addUser名字的Action時(shí),通配符配置這時(shí)就起作用了,按通配原則,它便和上面的name="*User"相配成功,這里不難明了*此時(shí)代指的內(nèi)容是add,再來看method恰恰是引用第一個(gè)*的內(nèi)容,所以它的method此時(shí)的完整名為addUser,它剛好和com.asmUserAction中的addUser方法相對(duì),所以它會(huì)去addUser方法,再來看下面的result配置所指代的頁面,它也用到了{(lán)1},所以它的完整頁面是/addUser.jsp。其實(shí)如果我們有良好的編程命名習(xí)慣,所有的Action我們都只需要進(jìn)行一次配置。
?
舉例:規(guī)定所有的Action類都用XXXAction來命名,類中所有的CRUD方法都用add/del/update/query。Jsp頁面也用add/del/update/query_XXX.jsp這樣的形式。即配置文件可以寫成如下形式:
<action name="*_*" class="com.asm.{2}Action" method="{1}"><result name="success">.../{1}_{2}.jsp</result> </action>Name中第一個(gè)*代表CRUD操作的名字,第二個(gè)*代表類的名字。所以訪問鏈接地址舉例如下:
.../del_User.action將訪問到User類的del方法,成功后跳到del_User.jsp頁面。補(bǔ)充說明{0}是代表name中所有的*組合。
?
11.使用0配置:ZERO Annotation
略
?
12.Result配置詳解
說明:在前面的許多案例中我們所用到的Action基本都繼承自ActionSupport這個(gè)類,而在這個(gè)類中我們定義了五個(gè)字段:SUCCESS,NONE,ERROR,INPUT,LOGING。我們可以直接返回這些字段值,這些字段值實(shí)質(zhì)是被定義成:String SUCCESS=”success”這樣的形式,所以我們只要在Result元素中用它們的小寫即可。
<result>標(biāo)準(zhǔn)完整形式如下:
如果我們都采用默認(rèn)的形式,最終可以簡寫成:<result>/default.jsp</result>
探討type類型:
| Type類型值 | 作用說明 | 對(duì)應(yīng)類 |
| chain | 用來處理Action鏈 | com.opensymphony.xwork2.ActionChainResult |
| dispatcher | 用來轉(zhuǎn)向頁面,通常處理JSP | org.apache.struts2.dispatcher.ServletDispatcherResult |
| redirect | 重定向到一個(gè)URL | org.apache.struts2.dispatcher.ServletRedirectResult |
| redirectAction | 重定向到一個(gè)Action | org.apache.struts2.dispatcher.ServletActionRedirectResult |
| plainText | 顯示源文件內(nèi)容,如文件源碼 | org.apache.struts2.dispatcher.PlainTextResult |
| freemarker | 處理FreeMarker模板 | org.apache.struts2.views.freemarker.FreemarkerResult |
| httpheader | 控制特殊http行為的結(jié)果類型 | org.apache.struts2.dispatcher.HttpHeaderResult |
| stream ? | 向?yàn)g覽器發(fā)送InputSream對(duì)象,通常用來處理文件下載,還可用于返回AJAX數(shù)據(jù)。 ? | org.apache.struts2.dispatcher.StreamResult ? |
| velocity | 處理Velocity模板 | org.apache.struts2.dispatcher.VelocityResult |
| xslt ?? | ??處理XML/XLST模板 | ?org.apache.struts2.views.xslt.XSLTResult |
?
以上對(duì)type類型作簡要的說明,下面來看實(shí)例:當(dāng)一個(gè)Action處理后要返回的Result是另一個(gè)Action時(shí),作如何配置,關(guān)鍵就是配置type類型。下面建立struts2result項(xiàng)目說明
步驟一:建立兩個(gè)Action:TestAction、Test2Action
步驟二:web.xml配置省略。struts.xml主要配置內(nèi)容如下:
說明:在名為“test”的action中,我們配置result元素的type類型值為chain,意為將繼續(xù)把Action傳遞到下一個(gè)名為test2的Action中去,在test2.action中會(huì)把頁面轉(zhuǎn)向到test2Suc.jsp中去。
在type類型為chain時(shí),它的param有4個(gè)值可配,除了這里用到的name=”actionName”外(必須配置,否則報(bào)錯(cuò)),還有name=namespace|method|skipActions。其中namespace指定要轉(zhuǎn)向到action的名字空間,由于此處是轉(zhuǎn)到Action位于同一個(gè)namespace下,而namesapace的默認(rèn)值the current namespace,所以可以省略不寫(需要說明的是如果要跳到別的名稱空間的action中去,除了使用namespace指定外,還可以用:/要跳去action所在名稱空間的值/要跳去的action的name值)。Method用于指定轉(zhuǎn)向到一個(gè)目標(biāo)action所調(diào)用的方法,默認(rèn)是調(diào)用下一個(gè)action的execute方法,所以此處仍可以省略。SkipActions是一個(gè)可選的屬性,一般不用。具體可以參看chain所對(duì)應(yīng)類的api幫助
?
在本實(shí)例中,我們還在TestAction中設(shè)定一個(gè)username字段,并在execute方法執(zhí)行為它賦了值,并在test2Suc.jsp中引用了此值。其實(shí)這種做法在web開發(fā)中還是很有用處,比如可以代替隱藏域。需要注意的是之所以在action的傳遞中能把設(shè)定的這個(gè)值保存下去,主要是因?yàn)檗D(zhuǎn)向都是服務(wù)器跳轉(zhuǎn)。如果我們跳轉(zhuǎn)時(shí)采取了客戶端跳轉(zhuǎn),比如在test2 action的result中指定type類型為redirect,要想傳遞參數(shù)可以在result指向的jsp頁面中附加參數(shù)即可,我們可以在test2 action的result中寫成:
<result name="success" type="redirect"> /test2Suc.jsp?username=${username} </result>?
隨后在test2Suc.jsp頁面中引用時(shí)會(huì)出現(xiàn)三個(gè)問題:
1.EL表達(dá)式引用失效,(EL表達(dá)式應(yīng)該使用${param.username}形式)。我們也可以使用<%=request.getParameter("username")%>獲取參數(shù)值。?
2.由于在前面的TestAction中設(shè)定的值為中文,而附加到這里的uri請(qǐng)求的參數(shù)后面時(shí)會(huì)出現(xiàn)亂碼問題。(可以使用URI編碼再解碼解決此問題)
3.值棧取值失效:因?yàn)槊恳淮蝦equest共享同一個(gè)值棧,所以服務(wù)器端的forward跳轉(zhuǎn)也是能共享同一值棧得。但是著當(dāng)test action執(zhí)行后把請(qǐng)求交由test2 action時(shí),test2 action采取的是redirect重定向到test2Suc.jsp頁面,這時(shí)其實(shí)就是重發(fā)的一次request,所以在test action保存的值棧內(nèi)容全部失效。這也就是為什么我們要附加參數(shù)的原因。而參數(shù)是保存在actionContext中,所以采用了#的方式來取出值。圖示說明:
步驟三,編寫鏈接頁面index.jsp。發(fā)布測試:
?
全局result:
如果我們所有的action均有可能跳到相同的頁面,則不防使用全局result。為了方便引用我們專門建立一個(gè)package來存放公共的result。在會(huì)用到個(gè)全局的跳轉(zhuǎn)時(shí),只需要把繼承自這個(gè)公共的package即可。
建立公共包,代碼如下:
<package name="pubResult" extends="struts-default" abstract="true"><global-results><result name="error">/error.jsp</result></global-results> </package>由于它下面沒的action配置,所以我們可以像默認(rèn)的struts-default包一樣,聲明abstract=true,這樣聲明表示此packgage下不會(huì)有action,它一般是用來讓別的package繼承。隨后再在要用到全局result中引用這個(gè)公共的package。代碼如下:
<package name="testGlobal" extends="pubResult" ><action name="error" class="com.asm.ErrorAction"></action><action name="error2" class="com.asm.Error2Action"></action> </package>這樣操作相當(dāng)于把全局的result加到了此package下的所有action中去。
?
動(dòng)態(tài)Result:了解
步驟一:建立DynaAction,主要代碼如下:
package com.asm; public class DynaAction extends ActionSupport {private String username;private String nextAction;public String execute() throws Exception {if (username.equals("admin")) {nextAction = "admin";} else if (username.equals("user")) {nextAction = "user";} else {nextAction = ERROR;}return SUCCESS;}...省略get/set方法 }步驟二、建立jsp頁面dyna.jsp,主要是為了向DynaAction中傳遞username參數(shù)。
步驟三、相關(guān)配置如下:
<package name="dynaTest" extends="pubResult"><action name="dyna" class="com.asm.DynaAction"><result name="success" type="chain">${nextAction}</result></action><action name="admin" ><result>/admin.jsp</result></action><action name="user"><result>/user.jsp</result></action> </package>分析:當(dāng)dyna.jsp把參數(shù)傳遞到DynaAction中去時(shí),如果傳遞的值為admin,我們便設(shè)定了nextAction的值admin,在配置文件中我們通過${nextAction}(用在struts配置文件中的ognl,其實(shí)nextAction的值是存在值棧中,我們通過${}這樣的形式取出。在此只作了解)來獲取值便為admin,隨后再繼續(xù)把請(qǐng)求傳遞到下一個(gè)Action中去(此時(shí)也即admin.action),為了方便我們?cè)O(shè)定了兩個(gè)ForwardAction:admin.action和user.action。這樣便可以跳到指定的jsp頁面。 原理:dyna.action執(zhí)行后會(huì)繼續(xù)把請(qǐng)求傳遞給下一個(gè)Action,而下一個(gè)Action的到底是哪一個(gè)Action,是通過DynaAction中動(dòng)態(tài)指定的,比如這里是根據(jù)傳遞的username的值指定。
?
?
13.異常處理
步驟一、建立struts2exception項(xiàng)目下,在該項(xiàng)目下建立登錄頁面login.jsp。主要代碼如下:
<form action="<%=request.getContextPath() %>/login.action">username:<input type="username" name="username"><br><input type="submit" value="login"> </form>步驟二、建立LoginAction,代碼如下:
package com.asm; public class LoginAction extends ActionSupport {private String username;public String execute() throws Exception {if (username.equals("exception")) {throw new ClassNotFoundException("類未被找到");} else if (username.equals("global")) {throw new Exception("全局異常");} else {return SUCCESS;}}...省力get/set方法 }步驟三、struts.xml配置文件如下:
<struts><package name="ex" extends="def"><action name="login" class="com.asm.LoginAction"><exception-mapping result="myException"exception="java.lang.ClassNotFoundException"></exception-mapping><result name="myException">/exception.jsp</result><result name="success">/main.jsp</result></action></package><package name="def" extends="struts-default" abstract="true"><global-results><result name="myGlobal">/globalException.jsp</result></global-results><global-exception-mappings><exception-mapping result="myGlobal"exception="java.lang.Exception"></exception-mapping></global-exception-mappings></package> </struts>分析:
1.異常處理機(jī)制較為簡單,所以在此只略作說明。當(dāng)?shù)卿洉r(shí)輸入“exception”時(shí),在LoginAction中會(huì)拋出會(huì)一個(gè)ClassNotFoundException異常,此異常我們采取的局部異常處理的方式,如果登錄時(shí)輸入“globla”,則會(huì)拋出Exception異常,此異常我們采取的是全局異常的處理方式,
2.在ex包中我們繼承了全局異常所在的包。提示:<exception-mapping>中的result屬性的值來源于<result>元素中的name屬性的值。從實(shí)例可以看出,我們一般把這種全局性的異常放在一個(gè)抽象包中供其實(shí)包繼承。
?
小結(jié)Action
在struts2中一個(gè)普通的java類只要有public String execute()這樣的方法都可以配置成一個(gè)Action,另外我們可以實(shí)現(xiàn)Action接口來使java類成為一個(gè)Action,但通常的做法是繼承ActionSupport類,這也是以后的項(xiàng)目中慣用的方法,也是推薦的首選方法。 與struts1.x不同的是:在struts2中每一個(gè)Action被請(qǐng)求訪問時(shí)都會(huì)new出這個(gè)Action對(duì)象,所以Action本身不存在線程安全的問題。
?
項(xiàng)目代碼:http://pan.baidu.com/s/1pJkfxnt
?
總結(jié)
以上是生活随笔為你收集整理的struts2.1.6教程二、struts.xml配置及例程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: xcode工程命令行生成ipa安装包
- 下一篇: NOIP 货车运输