1. 程式人生 > >struts2中的跳轉詳解 ----“請求轉發”和“重定向”之間的區別

struts2中的跳轉詳解 ----“請求轉發”和“重定向”之間的區別

轉載自:http://blog.163.com/shadow_wolf/blog/static/183469097201452625628798/

Struts2的ResultType和Action處理鏈 

Struts2的結果型別
在struts-default.xml中定義了Struts2內建的所有可用的<result-type/>
所有的Struts2結果處理類都要直接或間接的實現com.opensymphony.xwork2.Result介面
在struts-default.xml中的<result-types/>裡面,有這樣一行宣告
Deprecated name form scheduled for removal in Struts 2.1.0. The camelCase versions are preferred.
即:不建議使用以下兩種結果型別,在Struts-2.1.0中它們將被移除,應採用Java命名規則,即駱駝命名方式,也即駝峰命名規則
另外Struts2還有一些外掛,這些外掛還支援一些其它結果型別,這裡暫時先不涉及它們

結果型別為input的頁面的作用
Struts2應用在執行過程中若發現addFieldError()中有資訊或者型別轉換失敗或著輸入校驗失敗等情況
那麼它會自動跳轉到name為input的<result/>,然後轉到INPUT所對應的頁面
若JSP頁面中表單是用普通<form>編寫的,發生錯誤而返回該頁面時,則原資料將消失
若JSP頁面中表單是用<s:form/>編寫的,發生錯誤而返回該頁面時,則原資料仍存在
若沒有提供name值為input的<result/>,那麼發生錯誤時,將直接在瀏覽器中提示404錯誤

結果型別中的httpheader
httpheader結果型別很少使用到,它實際上是返回一個HTTP響應的頭資訊
若單純的設定<result type="httpheader">/result.jsp</result>,執行時控制檯會報如下錯誤
Caught OgnlException while setting property 'status' on type 'org.apache.struts2.dispatcher.HttpHeaderResult'.
java.lang.NoSuchMethodException: setStatus(java.lang.String)
翻譯:應用程式在設定status屬性時捕獲了OgnlException異常
檢視HttpHeaderResult類原始碼發現,它果然定義了private int status = -1
它代表的是一個狀態碼,較常見的狀態碼如下
200對應OK
404對應File Not Found或者requested resource() is not available
500對應伺服器內部錯誤
這時我們在<action/>中修改為<result type="httpheader"><param name="status">404</param></result>即可
這樣當Action執行完畢,就會轉向到SUCCESS結果,所以頁面就會顯示404錯誤提示
關於httpheader結果型別,瞭解即可,平時很少用到的不是很多

結果型別中的plainText
當設定為type="plainText"之後,就可以顯示原始檔案內容,例如檔案原始碼
<result name="success" type="plainText">/testSuc.jsp</result>
這時訪問應用,當跳轉到testSuc.jsp頁面後,右鍵就可以檢視到它的Java程式碼了
它比較適用於Java教學網站,但若僅設定type="plainText"的話,頁面中顯示中文時會亂碼
這時就可以藉助它的charSet屬性以解決中文顯示時的亂碼問題


view plaincopy to clipboardprint?
<result name="success" type="plainText">  

    <param name="location">/testSuc.jsp</param>  
    <param name="charSet">GBK</param>  
</result>  
<result name="success" type="plainText"> <param name="location">/testSuc.jsp</param> <param name="charSet">GBK</param> </result> 如果不設定charSet屬性,反而去配置struts.i18n.encoding全域性屬性,是不能解決問題的
設定charSet屬性的目的就是讓JSP頁面的編碼與明文顯示時的編碼一致

結果型別中redirect和redirectAction的區別
redirect是在處理完當前Action之後,重定向到另外一個實際的物理資源
redirectAction也是重定向,但它重定向到的是另外一個Action
只要是重定向,那麼之前凡是儲存在request裡面的東西就全都消失了
因為重定向實際是傳送第二個請求,故請求中的東西也就不會出現在第二個請求裡面了
也就是說重定向是不共享request的東西,重定向後的頁面中無法接收request裡的東西
另外dispatcher結果型別的default屬性為TRUE,故<result-type/>預設為dispatcher
所以如果沒有設定type屬性的話,那麼預設的是請求轉發,即瀏覽器顯示的是*.action
但是在設定type="redirect"屬性後,就可以重定向了,即瀏覽器顯示的是/login2.jsp

Struts2的Action處理鏈
從一個Action跳轉到另一個Action,有兩種辦法,即將type設定為chain或者redirectAction
chain結果型別表示將多個Action作為一個鏈來處理
而使用chain和redirectAction的好處就是:它會按照框架的預設字尾去自動匹配字尾
而chain和redirectAction的區別與dispatcher和redirect的區別是一樣的
即同樣是跳轉到一個Action上,但chain是伺服器跳轉,而redirectAction是客戶端跳轉
伺服器跳轉的過程中,可以共享資料,這時後面的Action就可以接收前面Action中的屬性資訊進行二次處理

以下是chain結果型別的使用示例


view plaincopy to clipboardprint?
<action name="firstchain" class="com.jadyer.action.FirstAction">  
    <result type="chain">secondchain</result>  
</action>  
<action name="secondchain" class="com.jadyer.action.SecondAction">  
    <result type="chain">thirdchain</result>  
</action>  
<action name="thirdchain" class="com.jadyer.action.ThirdAction">  
    <result type="plainText">/chainResult.jsp</result>  
</action>  
<action name="firstchain" class="com.jadyer.action.FirstAction"> <result type="chain">secondchain</result> </action> <action name="secondchain" class="com.jadyer.action.SecondAction"> <result type="chain">thirdchain</result> </action> <action name="thirdchain" class="com.jadyer.action.ThirdAction"> <result type="plainText">/chainResult.jsp</result> </action> 或者使用<result type="redirect">secondchain.action</result>即手工新增 .action 亦可正常訪問
但不建議這麼做,因為若修改應用的Action字尾,這裡也需手動的把字尾改掉,麻煩得很
儘管在官方幫助文件的案例中,曾使用過這種方式來執行下一個Action,但這是不嚴謹的

下面的例子是訪問不同名稱空間下的Action


view plaincopy to clipboardprint?
<package name="test" extends="struts-default" namespace="/">  
    <action name="test" class="cn.jadyer.action.TestAction">  
        <result name="success" type="redirectAction">  
            <!--這裡也可將兩行<param/>寫成一行,即<param name="actionName">/xx/test1</param> -->  
            <param name="actionName">test1</param>  
            <param name="namespace">/xx</param>  
        </result>  
    </action>  
</package>  
<package name="test1" extends="struts-default" namespace="/xx">  
    <action name="test1" class="cn.jadyer.action.Test1Action">  
        <result name="success" type="redirect">/test1Suc.jsp?name=${name}</result>  
    </action>  
</package>  
<package name="test" extends="struts-default" namespace="/"> <action name="test" class="cn.jadyer.action.TestAction"> <result name="success" type="redirectAction"> <!--這裡也可將兩行<param/>寫成一行,即<param name="actionName">/xx/test1</param> --> <param name="actionName">test1</param> <param name="namespace">/xx</param> </result> </action> </package> <package name="test1" extends="struts-default" namespace="/xx"> <action name="test1" class="cn.jadyer.action.Test1Action"> <result name="success" type="redirect">/test1Suc.jsp?name=${name}</result> </action> </package>

客戶端跳轉中的引數傳遞
若第二個Action使用type="redirect",那麼在頁面中將無法接收Action中所共享的資料
但在客戶端跳轉中,我們可以在連結上傳參。比如result寫成/test1Suc.jsp?name=${username}
在Struts2的XML檔案中可以使用${}表示式,它會自動的取出Action中所有可用的屬性,作為引數傳遞到下一頁面
這裡${}不是EL表示式,實際上它的本質上是OGNL表示式
由於從連結中取值,故用<%=request.getParameter("name")%>或者${param.name},這裡param相當於request.getParameter("")
注意也不能使用${name},因為它是用來從page、request、session、application中取值的
並且頁面中也不能使用<s:property value="name"/>接收引數值,因為它是從ValueStack中取值的
下面是程式碼示例


view plaincopy to clipboardprint?
<action name="test" class="cn.jadyer.action.TestAction">  
    <result name="success" type="redirectAction">  
        <param name="actionName">test1</param>  
    </result>  
</action>  
<action name="test1" class="cn.jadyer.action.Test1Action">  
    <result name="success" type="redirect">/test1Suc.jsp?name=${username}</result>  
</action>  

----“請求轉發”和“重定向”之間的區別

讓瀏覽器獲得另外一個URL所指向的資源可以使用請求轉發(RequestDispatcher.forward)或則是重定向技術(HttpServletResponse.sendRedirect),但是兩者的內部機制有很大的區別:

1 請求轉發只能將請求轉發給同一個WEB應用中的元件,而重定向還可以重新定向到同一站點不同應用程式中的資源,甚至可以定向到一絕對的URL。

2 重定向可以看見目標頁面的URL,轉發只能看見第一次訪問的頁面URL,以後的工作都是有伺服器來做的。

3 請求響應呼叫者和被呼叫者之間共享相同的request物件和response物件,重定向呼叫者和被呼叫者屬於兩個獨立訪問請求和響應過程。

4 重定向跳轉後必須加上return,要不然頁面雖然跳轉了,但是還會執行跳轉後面的語句,轉發是執行了跳轉頁面,下面的程式碼就不會在執行了。