2016-08-18 37 views
2

我們在啓用了JSF 2.2 + PrimeFaces的應用程序中使用SPA方法。 最初描述的基本想法非常好位置:使用@ViewScoped Bean時刪除SPA JSF 2.2應用程序中的@ViewScoped bean

Refreshing dynamic content with AJAX in JSF using SPA approach

但是,我們知道,使用這種方法SPA有一個缺點。

由於我們實際上總是停留在相同的JSF視圖中,因此當我們用新的SPA內容替換面板組的內容時,不會從內存中刪除@ViewScoped bean。

我找到了一個解決方案,但我想知道它是否是正確的方法,和/或是否有任何缺失。

基本上,我們的NavigationService豆,持有該頁面的名稱SPA AJAX請求期間被渲染,我們始終執行下面的代碼:

private void clearViewScopedBeans() { 
    Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap(); 
    for(Iterator<Map.Entry<String, Object>> it = viewMap.entrySet().iterator(); it.hasNext();) { 
     Map.Entry<String, Object> entry = it.next(); 
     it.remove();  
    } 
} 

這應該確保,新的SPA之後代碼片段被渲染,所有以前存在的@ViewScoped bean都被刪除。

但是,我認爲上面的代碼只會刪除查看範圍的bean,而不是相關的視圖狀態。那是對的嗎 ?

,我發現一箇舊博客條目,這似乎做多一點的邏輯: http://javaevangelist.blogspot.sg/2014/08/jsf-21-tip-of-day-clearing-viewscope.html

,但我不知道它是否是正確的爲好。

此外,如果我們要支持多個窗口標籤,我們的NavigationService豆,保存當前SPA片斷頁面名稱,必須@ViewScoped爲好,這引入了一個小問題:

當運行上面的代碼用於刪除所有現有的@ViewScoped bean ...我們必須排除NavigationService bean本身!否則,我們會始終加載相同的頁面,因爲NavigationService的新實例會實例化,並且會使用默認的SPA頁面名稱,而不是新的實例。因此,總而言之,我們的代碼看起來終於如此,我們在其中保留一個「排除的」bean名稱的Map,我們不想在SPA頁面上刷新(即保存SPA的NavigationService bean頁面名稱)

private void clearViewScopedBeans() { 
    Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap(); 
    for(Iterator<Map.Entry<String, Object>> it = viewMap.entrySet().iterator(); it.hasNext();) { 
     Map.Entry<String, Object> entry = it.next(); 
     if(!exclusionViewScopedBeans.contains(entry.getKey())) { 
      logger.info("Removing an instance of a @ViewScoped bean -> " + entry.getKey()); 
     it.remove(); 
     } 
    } 
} 

現在的問題...... 這是正確的做法處理這些類型的SPA情況呢?我們在這裏錯過了什麼嗎?

任何反饋將不勝感激...先謝謝了很多!

+1

那就是我使用的實現 - 就正確的方法而言,我得到的印象是您應該避免使用JSF中的這種類型,但實際情況有時需要 – farrellmr

+0

爲什麼不使用對話作用域bean? – Kukeltje

+0

因爲這個特定的項目使用Spring IoC而不是CDI,所以目前沒有內置的對話範圍。 (在任何情況下,我也在研究創建可以實現相同功能的新(Spring)範圍。到目前爲止,我已成功爲PrimeFaces TabView組件創建了一個TabScope,每個Tab都可以有自己的JSF bean範圍,當標籤被構建時創建,當標籤關閉時被銷燬,我想我可以使用相同的方法來開發更通用的對話範圍... –

回答

0

我認爲,有一個比你Maikel刪除/在SPA(單頁的應用程序)清除ViewScopedBeans沒有更好的解決辦法:

private void clearViewScopedBeans() { 
Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap(); 
for(Iterator<Map.Entry<String, Object>> it = viewMap.entrySet().iterator(); it.hasNext();) { 
    Map.Entry<String, Object> entry = it.next(); 
    it.remove();  
} 
} 

我試圖找到很多,但SPA是不是「官方推薦」使用JSF的方式,也就是多頁面的應用程序,所以SPA需要更多的擺弄。

或者,Maikel,你找到了嗎?或者你使用其他方法?

+0

SPA不是一種未建議的方式...您只是不能使用功能這與特定的視圖有關,你可以**使用其他的scoped bean(對話想起),你可以更容易地控制,而不是濫用viewscoped beans,你可以看到他有點像這樣解決 – Kukeltje

+0

Hi Radek和Kukeltje。到目前爲止,這是我們正在使用的方法,並且就服務器端而言工作正常。最後的最大問題是在客戶端,因爲許多PrimeFaces jQuery UI小部件不是完全SPA準備好了,造成大的內存泄漏。我們必須遍歷每個SPA頁面上的所有PF小部件,然後才能移動到新視圖,並手動解除特定PF小部件的事件以及一些其他棘手的情況(禁用輪詢,空閒計時器,鍵綁定...)。但到目前爲止,我可以說我們現在正在使用PrimeFaces和SPA方法的JSF 2.2,而現在沒有大問題。 –

+0

嗨Maikel(和Kukeltje) - 非常感謝你的經驗和選擇。我很高興地看到,這種SPA方法在現實世界中有效。我們已經開始使用它們的ViewScopedBean(在每次POST/GET請求後銷燬,不像標準JSF 2.3中的ViewScopedBean)使用Omnifaces(在Tomcat中安裝了CDI)。所以現在我們有可能在SPA方法中使用Omnifaces/ViewScopedBean。我希望,這是不錯的選擇。 – Radek