2011-11-09 14 views
12

Jaki problem jest: Co się dzieje po kliknięciu przycisku Wstecz w przeglądarce -> otwiera stronę, której viewscoped-managedbean jest już zniszczona -> złożyć wniosek od CommandButton tym strona z zaznaczonymi rekordami siatki?przeglądarka powrotem + viewscope fasola

czego oczekuję: Związane viewscope-managebean jest utworzony ponownie odbiera Siatka-record-wybory, i radzić sobie z nimi, jeśli przeglądarka przycisk wstecz nie jest zaangażowany.

Co mogę doznać:: Związany widok-zarządzenie nie jest ponownie tworzony, nie otrzymuje wyboru rekordów siatki. Musisz ponownie wprowadzić adres URL lub F5 po kliknięciu przycisku wstecz, aby ponownie działał poprawnie.

Więc oto scenariusz sukces, wszystkie ziarna są viewscoped fasola:

  1. GET page1.xhtml -> page1Bean tworzone, pobierania danych, etc w @PostConstruct
  2. check/zaznaczyć kilka rekordów z przycisk datatable, kliknij przycisk procesu
  3. page1 Metoda procesowa Bean przechowuje wybrane rekordy w obiekcie flash i przekierowuje do strony page2.xhtml
  4. page1Bean destroyed, page2Bean created and in preRenderView Metoda słuchacz, pobiera wybrane rekordy od obiektu flash i radzić sobie z nimi
  5. kliknij „przejdź do strony głównej” CommandButton przekierować do page1.xhtml i page2Bean zniszczone, page1Bean utworzony ponownie
  6. pętli z nr 2 - 5 jest nadal wykonalne

teraz to errornous scenariusz udziałem przeglądarkę przycisku wstecz (różne smary dzieje począwszy od # 6):

  1. GET page1.xhtml -> page1Bean utworzony, zapytanie o dat a, etc w @PostConstruct
  2. check/zaznaczyć kilka rekordów z DataTable, kliknij przycisk procesowego
  3. metoda proces page1Bean w sklepach wybrane rekordy obiektu Flash i przekierowanie do page2.xhtml
  4. page1Bean zniszczone, page2Bean stworzył, aw metody detektora preRenderView, pobiera wybrane rekordy z obiektu flash, oraz radzenia sobie z nimi
  5. kliknij przeglądarkę wstecz page2Bean nie jest zniszczony, page1Bean nie jest tworzony
  6. czek/zaznaczyć kilka rekordów z przycisk datatable, kliknij przycisk procesu
  7. the page1Bean method wykonuje (dziwne, ponieważ strona1Bean powinna była zostać zniszczona), ale nie może zobaczyć dokonanych wyborów rekordów i przekierować na stronę2.xhtml
  8. page1Bean nie jest zniszczona (bez wyjścia logowania), page2Bean nie jest tworzony (ponieważ nie został zniszczony), wykonuje słuchacza preRenderView jak zwykle, ale tym razem nie wybrano zapisy w obiekcie typu flash

Czy możliwe jest normalne doświadczenie (jak bez przycisku wstecz przeglądarki) z widokami-fasolki z przyciskiem wstecz przeglądarki?

Oto moja zależność:

<dependency> 
    <groupId>org.glassfish</groupId> 
    <artifactId>javax.faces</artifactId> 
    <version>2.1.3</version> 
    <scope>compile</scope> 
</dependency> 

Proszę podzielić się swoimi pomysłami!

Odpowiedz

15

Wygląda na to, że przeglądarka obsłużyła stronę z pamięci podręcznej zamiast wysyłać do serwera pełne żądanie HTTP GET, podczas gdy metoda zapisywania stanu JSF jest ustawiona na server (która jest domyślna).

Istnieją 2 sposoby rozwiązania tego problemu:

  1. poinformować przeglądarkę, aby nie cache dynamicznych stron JSF. Możesz to zrobić przy pomocy filter.

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
        HttpServletRequest req = (HttpServletRequest) request; 
        HttpServletResponse res = (HttpServletResponse) response; 
    
        if (!req.getRequestURI().startsWith(req.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc) 
         res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1. 
         res.setHeader("Pragma", "no-cache"); // HTTP 1.0. 
         res.setDateHeader("Expires", 0); // Proxies. 
        } 
    
        chain.doFilter(request, response); 
    } 
    

    mapie filtr na FacesServlet lub jego samego URL-wzorca.

  2. Ustaw metodę zapisywania stanu JSF na klienta, tak aby cały stan widoku był przechowywany w ukrytym polu formularza, a nie w sesji po stronie serwera.

    <context-param> 
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name> 
        <param-value>client</param-value> 
    </context-param> 
    

Filtr sposób jest korzystny.

+0

dziękuję za przykład źródła :) próbowałem zmienić metodę oszczędzania stanu na klienta, trochę wkurzyłem się, muszę zmienić wiele fasoli i fasoli domeny w serializowalne. więc wypróbowałem filtr i działało świetnie! chociaż z odrobiną obaw z tym artykułem tutaj: http://turbomanage.wordpress.com/2006/08/08/disable-browser-caching-in-jsf/, który stwierdza, że ​​to nie jest zagwarantowane. Ale z mojego doświadczenia wynika, że ​​działa bardzo dobrze. – bertie

+0

Wykonanie tego w 'PhaseListener' jest niezgrabne. Co do gwarancji, cóż, ma rację, ale wszystkie nowoczesne przeglądarki (IE, FF, GC, AS, O, itp.) Szanują zasady buforowania HTTP poprawnie. Prawdopodobnie zawiedzie tylko wtedy, gdy klient użyje jakiejś wątpliwej przeglądarki. – BalusC

+0

Ale jest jedna rzecz, gdy po kliknięciu przycisku wstecz przeglądarki, pola wyboru wewnątrz p: datatable, które zostały wybrane, są nadal sprawdzane, ale po ich przesłaniu nie są sprawdzane. Dzieje się tak w Google Chrome 15, ale nie w Firefox 5.0.1. Myślę, że jest to ta sama sytuacja: http://stackoverflow.com/questions/6100741/how-to-prevent-browsers- from-remembering-checkbox-state. Chcę spróbować użyć losowych nazw formularzy, jak podano w rozwiązaniu , ale nie jestem pewien, jak odświeżyć inny formularz wewnątrz formularza na stronie z wieloma formularzami, jeśli nie znam nazw zewnętrznej formy. – bertie

0

Wadą wyłączenia pamięci podręcznej przeglądarki na stronie jest to, że użytkownik zobaczy stronę błędu przeglądarki, jeśli używa przeglądarki wstecz, aby przejść do poprzedniej strony. Więc kolejne rozwiązania jest określenie, czy strona pochodzi z serwera lub z pamięci podręcznej przeglądarki przy użyciu javascript:

najpierw utworzyć prosty podkład fasoli, która serwuje unikalny identyfikator (w moim przypadku czas aktualny systemu):

@Named("browserCacheController") 
@RequestScoped 
public class BrowserCacheController implements Serializable { 
private static final long serialVersionUID = 1L; 
/** 
* Returns a unique increasing id for each request 
* @return 
*/ 
public long getCacheID() { 
    return System.currentTimeMillis(); 
} 
} 

Teraz możesz sprawdzić, czy strona jest serwowana z serwera lub przeglądarki i przekierować użytkownika, jeśli bieżąca strona pochodzi z pamięci podręcznej przeglądarki. Zobacz poniższy kod javascript umieszczane w JSF strony, które nie powinny być przechowywane przez przeglądarkę:

<script type="text/javascript"> 
    // check for latestCacheID 
    if (!isValidCacheID(#{browserCacheController.cacheID})) { 
     //redirect to some page 
     document.location="#{facesContext.externalContext.requestContextPath}/index.jsf"; 
    } 

    // test cacheID if it comes from the server.... 
    function isValidCacheID(currentCacheID) { 
     if (!('localStorage' in window && window['localStorage'] !== null)) 
      return true; // old browsers not supported 
     var latestCacheID=localStorage.getItem("org.imixs.latestCacheID"); 
     if (latestCacheID!=null && currentCacheID<=latestCacheID) { 
      return false; // this was a cached browser page! 
     } 
     // set new id 
     localStorage.setItem("org.imixs.latestCacheID", currentCacheID); 
     return true; 
    } 
</script> 

Skrypt może być również umieszczona w facelet aby kod JSF bardziej czyste.

+1

Nie powinieneś używać POST do nawigacji. – BalusC

Powiązane problemy