Web應用程序中一個常見的用法是,先對請求進行處理而後將請求重定向到另一個控制器、servlet或其餘對象。這種作法自己沒什麼問題,可是當請求被重定向時它會建立一個嶄新的request,並將本來保存在request屬性中的數據全都清除掉,所以重定向的目標操做就沒法再得到這些數據。當咱們使用struts2的actionmessage的時候,遇到重定向,這些消息全都over了。 java
有些開發者爲了不上述狀況的發生而將這些信息保存在session中。這種作法很好,但開發人員會常常忘記清除臨時數據,而且須要開發人員自行維護session的狀態。無疑增長了程序的開發的複雜性和無畏的性能浪費。
爲了解決這個問題,Grails模仿Rails引入了Flash Scope。flash對象只將數據保存在下一次的請求中,在下一次請求以後會自動清除其中的數據。這樣不只減少了開發人員的負擔,也使咱們可以專一於當前的問題而不用擔憂其餘問題。
Flash做用域的確能夠很好的解決這個問題,惋惜咱們經常使用的SSH框架中,卻一直缺乏這樣一個做用域,不知道Struts2的開發者能不能在之後的版本中增長這樣的一個功能。等不了他了,仍是咱們本身手工創造這樣一個對象來解決現有的問題吧。
最簡單的辦法,就是將Grails的實現移植到Struts2中。
首先咱們下載Grails的源代碼包,並找到Flash對象,將其實現按步照班的移植到struts2中。主要修改主要包括兩個部分。第一是將Grails的request上下文改爲struts2的;第二刪掉咱們不適用的Grails對錯誤信息的處理。
下面就開始簡單的介紹修改後的程序,主要有三個類。
第一咱們定義一個Flash對象的接口:FlashScope.java
Java代碼
- public interface FlashScope extends Map, Serializable {
-
- /**
- * 設置一個flash做用域通過新的請求到下個狀態。
- */
- void next();
-
- /**
- * 返回flash對象現有的狀態,若是你不但願在下面的請求中使用包含的變量。
- *
- * @return A map
- */
- Map getNow();
- }
第二開始編寫該接口Struts2的實現:StrutsFlashScope.java
這個實現很好理解,無非內部定義了兩個Map,將保存在裏面的數據,在兩個Map裏來回的轉移,這樣就保證在下一次重定向請求時,咱們只須要將其中一個Map的數據轉移到另一個Map中,而清楚掉一個Map。這樣就保證在重定向時,該做用域下依然保存數據。而在第二次的請求時,若是沒有新的數據加進來,原來的數據將會被清空。經過這種方式,Flash的做用域的數據只能保持在下一次的重定向請求中。
第三步也是很關鍵的一步,若是咱們不去清理該做用域下的數據,那麼這個做用域就沒法達到應有的效果。這就須要咱們在每次重定向的時候要執行做用域的next()方法,來清理數據。
咱們編寫的是Struts2的實現,咱們就須要在Struts2的過濾器中植入對Flash Scope處理的操做。看OecpStruts2FilterDispatcher.java
Java代碼
- public class OecpStruts2FilterDispatcher extends StrutsPrepareAndExecuteFilter {
- @Override
- public void doFilter(ServletRequest req, ServletResponse res,
- FilterChain chain) throws IOException, ServletException {
- HttpServletRequest request = (HttpServletRequest) req;
- HttpServletResponse response = (HttpServletResponse) res;
- try {
- prepare.setEncodingAndLocale(request, response);
- prepare.createActionContext(request, response);
- prepare.assignDispatcherToThread();
- if (excludedPatterns != null
- && prepare.isUrlExcluded(request, excludedPatterns)) {
- chain.doFilter(request, response);
- } else {
- request = prepare.wrapRequest(request);
- ActionMapping mapping = prepare.findActionMapping(request,
- response, true);
- if (mapping == null) {
- boolean handled = execute.executeStaticResourceRequest(
- request, response);
- if (!handled) {
- chain.doFilter(request, response);
- }
- } else {
- /**
- * 更新flash做用域
- */
- FlashScope fs = (FlashScope) ActionContext.getContext()
- .getSession().get(StrutsFlashScope.FLASH_SCOPE);
- if (fs != null) {
- fs.next();
- }
- execute.executeAction(request, response, mapping);
- }
- } finally {
- prepare.cleanupRequest(request);
- }
- }
- }
- }
該類繼承了Struts2原有的過濾器,在web.xml中,將Struts2的配置換成該過濾器。在該過濾器中,咱們對每次新的請求都調用了FlashScope的next()方法,對數據進行清理。
若是咱們爲了使用方便,咱們能夠設計一個Action的頂級類,好比BaseAction.java,在該類中,咱們定義flash的屬性。
Java代碼
- protected FlashScope flash;
- public FlashScope getFlash(){
- this.flash=new StrutsFlashScope();
- return this.flash;
- }
咱們在action就能夠flash.put(「message」,」我是struts2的flash做用域」);在頁面上咱們只須要經過<s:property value=」%{flash.message}」/>來顯示。這樣,咱們刪除一篇文章後重定向到文章列表,咱們就能夠把「刪除成功」這樣的信息,顯示在重定向的文章列表上。而再次刷新文章列表,該消息就消失了。 web
附件下載請移到:http://www.oecp.cn/hi/yongtree/blog/937 session