熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java開源技術 >> 正文

Struts教程-Struts的幾個精細之處

2013-11-23 20:05:44  來源: Java開源技術 

  最近在網上看到一篇N Alex Rupp寫的Beyond MVC: A New Look at the Servlet Infrastructure文章意思大致是說MVC被Struts等框架錯誤地應用到了Servlet架構中我想只有對Struts有足夠的了解再加上在MVC方面有足夠深的功力才敢發此言論不是經常聽人說最熟悉自己的人是你的敵人本人功力尚淺沒有引領風潮的能力而且生活還得繼續只能先來熟悉熟悉Struts

  申明 強烈建議在閱讀本文之前先閱讀一下N Alex Rupp老兄的文章如果你贊同他的看法可能你會覺得研究Struts就沒什麼意義了

  說明本文所講的Struts知識基於Struts 版本除非特別說明本文中的Struts都特指Struts 這個版本

  精細之處一利用Token解決重復提交背後的前提

  我們知道可以利用同步令牌(Token)機制來解決Web應用中重復提交的問題Struts也給出了一個參考實現服務器端在處理到達的請求之前會將請求中包含的令牌值與保存在當前用戶會話中的令牌值進行比較看是否匹配在處理完該請求後且在答復發送給客戶端之前將會產生一個新的令牌該令牌除傳給客戶端以外也會將用戶會話中保存的舊的令牌進行替換這樣如果用戶回退到剛才的提交頁面並再次提交的話客戶端傳過來的令牌就和服務器端的令牌不一致從而有效地防止了重復提交的發生對應於這段描述你可能會在你的Action子類中有這麼一段代碼

  

  if (isTokenValid(request true)) { // your code here return mappingfindForward(success); } else { saveToken(request); return mappingfindForward(submitagain); }

  其中isTokenValid()和saveToken()都是orgapachestrutsactionAction類中的方法而具體的Token處理邏輯都在orgapachestrutsutilTokenProcessor類中Struts中是根據用戶會話ID和當前系統時間來生成一個唯一(對於每個會話)令牌的具體實現可以參考TokenProcessor類中的generateToken()方法

  不知道大家有沒有注意到這樣一個問題因為Struts是將Token保存在Session的一個屬性中也就是說對於每個會話服務器端只保存而且只能保存一個最新Token值對於這一點我的同事就提出了疑問那如果我在同一個會話中打開兩個頁面那麼後提交的那個頁面肯定不能提交成功了他還給出了一個實際的例子比如現在需要把兩個客戶A和B的地址都改為某個值那用戶就可能同時打開兩個頁面修改A修改B提交A提交B按照Struts中的處理邏輯B的修改提交就肯定不能成功但是這個提交操作對於用戶來說並不存在操作不正確的地方

  在這裡可能有人要問怎麼可能在同一個會話中打開兩個頁面呢?重新打開一個IE浏覽器不是重新開始了一個會話嗎?不錯這種情況下是兩個會話不存在任何問題但是你還可以通過菜單文件新建窗口(或者快捷鍵Ctrl+N)來復制當前窗口這個時候你會發現該頁面與原有頁面同處在一個會話當中其實能夠發現這個問題得歸功於我的那位同事對IE習慣性的操作方法

  這下我的那位同事不滿意啦他於是開始動手修改Struts中的實現方式讓每個頁面(至少某類頁面)在服務器端都保存有一個唯一的Token值這樣前面所講的客戶AB同時修改的限制就不存在了但是不久我的那位同事就開始意識到他正在走向一條危險的道路首先如果每個頁面都在服務器端保存一個Token值則服務器端保存的數據量將越來越大而且如果考慮這種同一個會話中打開多個頁面的情況的話就好像打開了潘多拉魔盒將會給自己帶來無窮無盡的麻煩比如首先打開頁面P然後利用Ctrl+N得到頁面PP提交P提交目前為止一切正常但是如果此時在PP中點擊後退按鈕然後再提交P P情況會是怎樣?如果在P中提交完後執行其它操作而在P中回退後提交情況又是怎麼樣呢?如果有PPP那情況又是如何呢?太復雜啦!我想你也會和我們有同感你需要考慮許多種可能的組合而且有的時候結果並不是你想象中的那樣簡單

  此路不通還得回來看看Struts其實經過以上一番折騰我們可以發現在Struts中的Token機制背後隱藏著這樣一個前提不允許你(客戶端)在同一會話中打開多個頁面注意是同一會話如果打開兩個IE浏覽器那已經是兩個會話啦不受該限制其實這個看似不合理的規定卻自有其道理一是它極大地簡化了Token的實現二個這種限定也符合大部分人的使用習慣

  精細之處二頁面流轉控制中的職責分配

  我們知道Struts的執行過程大致如下首先控制器接收到客戶端請求將這些請求映射至相應的Action並調用Action的execute方法這中間可能還涉及到ActionForm的創建和填充Action的execute方法執行完以後返回一個ActionForward對象控制器根據該ActionForward對象將請求轉發至下一個Action或JSP最後產生視圖響應客戶在大的層面上Struts是采用了MVC這種架構沒什麼特別之處但從一些小的地方我們還是可以看出Craig R McClanahan老兄的一些考慮我們看到Action與控制器之間傳遞的是ActionForward對象由於Action的execute方法要求返回一個ActionForward對象所以你會經常在Action子類中看到如下語句

  

  return (new ActionForward(mappinggetInput()));

  或

  

  return (mappingfindForward(success));

  其實返回的就是一個ActionForward對象在Action中我們根據程序執行的不同情況決定接下來的頁面走向(比如返回到輸入頁面或者轉到下一個頁面)並將這些信息保存在ActionForward對象中而接下來控制器就可以直接利用該ActionForward對象來進行頁面的流轉下面是orgapachestrutsactionRequestProcessor類的processForwardConfig()方法的摘錄該方法調用發生在Action實例調用後

  

  protected void processForwardConfig(HttpServletRequest request HttpServletResponse response ForwardConfig forward) throws IOException ServletException { … String forwardPath = forwardgetPath(); String uri = null; // paths not starting with / should be passed through without any processing // (ie theyre absolute) if (forwardPathstartsWith(/)) { uri = RequestUtilsforwardURL(request forward); // get module relative uri } else { uri = forwardPath; } if (forwardgetRedirect()) { // only prepend context path for relative uri if (uristartsWith(/)) { uri = requestgetContextPath() + uri; } responsesendRedirect(responseencodeRedirectURL(uri)); } else { doForward(uri request response); } }

  注意 ForwardConfig是ActionForward的父類

  該方法首先調用ForwardConfig的getPath()方法獲得下一步流轉的路徑在某些條件下還需要進行一些拼裝得到正確的URI最後根據該URI進行頁面跳轉可見在processForwardConfig()方法中只是對ActionForward進行了一些技術上的處理沒有任何和業務相關的內容這樣就將控制器(ActionServlet)和Action完全分開來兩者互不影響達到了功能模塊之間松散耦合的目的

  模塊間(系統間)松散耦合一直是OO設計所追求的但是具體如何去實現這樣一種松散耦合卻不是那麼容易做到的Struts中的設計給了我們一些啟示模塊間相互關聯影響因素的傳遞可以用對象的形式來包裝起來其實個人覺得Struts中的做法還可以稍微有一點點改進就是在ActionForward中提供一個getURI()方法來給出最終的URI豈不是更好?

  參考

  Beyond MVC: A New Look at the Servlet Infrastructure

  Allen Holub的Build user interfaces for objectoriented systems系列文章可以從這篇文章中學到很多面向對象設計方面的知識雖然作者並不認為MVC是一種面向對象的方法但是我們這些MVC的實踐者仍然可以從中學到面向對象的知識

  Struts 的介紹性文章深入Struts

  Apache Struts Website

  關於重復提交問題的討論及其解決方案可以參考《Core JEE Patterns》一書(中文版《JEE核心模式》)

  Deepak AlurJohn CrupiDan Malks: Core JEE Patterns-Best Practices and Design Strategies


From:http://tw.wingwit.com/Article/program/Java/ky/201311/27929.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.