javax.faces.application.ViewExpiredException: Die Ansicht konnte nicht wiederhergestellt werden

175

Ich habe eine einfache Anwendung mit Container-verwalteter Sicherheit geschrieben. Das Problem ist, wenn ich mich anmelde und eine andere Seite öffne, auf der ich mich abmelde, dann zur ersten Seite zurückkehre und auf einen Link usw. klicke oder eine Seite aktualisiere, auf der diese Ausnahme auftritt. Ich denke, es ist normal (oder vielleicht auch nicht :)), weil ich mich abgemeldet habe und die Sitzung zerstört wurde. Was kann ich tun, um den Benutzer beispielsweise zu index.xhtml oder login.xhtml umzuleiten und ihn vor dem Anzeigen dieser Fehlerseite / -meldung zu bewahren?

Mit anderen Worten, wie kann ich andere Seiten nach dem Abmelden automatisch auf die Index- / Anmeldeseite umleiten?

Hier ist es:

javax.faces.application.ViewExpiredException: viewId:/index.xhtml - View /index.xhtml could not be restored.
    at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:212)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:110)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:312)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
    at filter.HttpHttpsFilter.doFilter(HttpHttpsFilter.java:66)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:277)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
    at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
    at java.lang.Thread.run(Thread.java:619)
l245c4l
quelle

Antworten:

353

Einführung

Das ViewExpiredExceptionwird ausgelöst, sobald die javax.faces.STATE_SAVING_METHODeingestellt ist server(Standard) und die Enduser sendet eine HTTP POST - Anforderung auf einen Blick über <h:form>mit <h:commandLink>, <h:commandButton>oder <f:ajax>, während der zugehörige Anzeigestatus nicht mehr zur Verfügung in der Sitzung ist.

Der Ansichtsstatus wird als Wert eines ausgeblendeten Eingabefeldes javax.faces.ViewStatedes identifiziert <h:form>. Wenn die Methode zum Speichern des Status auf festgelegt ist server, enthält diese nur die Ansichtsstatus-ID, die auf einen serialisierten Ansichtsstatus in der Sitzung verweist. Wenn die Sitzung aus irgendeinem Grund abgelaufen ist (entweder auf Server- oder Clientseite abgelaufen oder das Sitzungscookie aus irgendeinem Grund nicht mehr im Browser oder durch Aufrufen HttpSession#invalidate()des Servers oder aufgrund eines serverspezifischen Fehlers mit Sitzungscookies als verwaltet wird bekannt in WildFly ), dann ist der Status der serialisierten Ansicht in der Sitzung nicht mehr verfügbar und der Endbenutzer erhält diese Ausnahme. Informationen zum Verständnis der Funktionsweise der Sitzung finden Sie unter Wie funktionieren Servlets? Instanziierung, Sitzungen, gemeinsam genutzte Variablen und Multithreading .

Die Anzahl der Ansichten, die JSF in der Sitzung speichert, ist begrenzt. Wenn das Limit erreicht ist, ist die zuletzt verwendete Ansicht abgelaufen. Siehe auch com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews .

Wenn die Methode zum Speichern des Status auf festgelegt ist client, enthält das javax.faces.ViewStateausgeblendete Eingabefeld stattdessen den gesamten Status der serialisierten Ansicht, sodass der Endbenutzer nach ViewExpiredExceptionAblauf der Sitzung keine erhält . Dies kann jedoch weiterhin in einer Clusterumgebung auftreten ("FEHLER: MAC wurde nicht überprüft" ist symptomatisch) und / oder wenn ein implementierungsspezifisches Zeitlimit für den clientseitigen Status konfiguriert ist und / oder wenn der Server den AES-Schlüssel während des Neustarts neu generiert Siehe auch Abrufen von ViewExpiredException in einer Clusterumgebung, während die Statusspeichermethode auf Client festgelegt ist und die Benutzersitzung gültig ist , um sie zu lösen.

Stellen Sie unabhängig von der Lösung sicher, dass Sie nicht verwenden enableRestoreView11Compatibility. Der ursprüngliche Ansichtsstatus wird überhaupt nicht wiederhergestellt. Grundsätzlich werden die Ansicht und alle zugehörigen Beans mit Ansichtsbereich von Grund auf neu erstellt, wodurch alle Originaldaten (Status) verloren gehen. Da sich die Anwendung verwirrend verhält ("Hey, wo sind meine Eingabewerte .. ??"), ist dies sehr schlecht für die Benutzererfahrung. Verwenden <o:enableRestorableView>Sie besser zustandslose Ansichten oder verwenden Sie sie stattdessen nur für eine bestimmte Ansicht anstatt für alle Ansichten.

Informationen dazu, warum JSF den Ansichtsstatus speichern muss, finden Sie in der folgenden Antwort: Warum speichert JSF den Status von UI-Komponenten auf dem Server?

Vermeiden von ViewExpiredException bei der Seitennavigation

Um zu vermeiden, ViewExpiredExceptiondass z. B. nach dem Abmelden zurück navigiert wird, wenn die serverStatusspeicherung auf gesetzt ist, reicht es nicht aus, nur die POST-Anforderung nach dem Abmelden umzuleiten. Sie müssen den Browser auch anweisen, die dynamischen JSF-Seiten nicht zwischenzuspeichern. Andernfalls zeigt der Browser sie möglicherweise aus dem Cache an, anstatt eine neue vom Server anzufordern, wenn Sie eine GET-Anforderung darauf senden (z. B. über die Schaltfläche "Zurück").

Das javax.faces.ViewStateausgeblendete Feld der zwischengespeicherten Seite enthält möglicherweise einen Ansichtsstatus-ID-Wert, der in der aktuellen Sitzung nicht mehr gültig ist. Wenn Sie (ab) POST (Befehlslinks / Schaltflächen) anstelle von GET (reguläre Links / Schaltflächen) für die Navigation von Seite zu Seite verwenden und auf einen solchen Befehlslink / eine solche Befehlsschaltfläche auf der zwischengespeicherten Seite klicken, wird dies wiederum durchgeführt scheitern mit a ViewExpiredException.

Um eine Umleitung nach dem Abmelden in JSF 2.0 auszulösen, fügen Sie entweder <redirect />das <navigation-case>betreffende Element (falls vorhanden) oder ?faces-redirect=trueden outcomeWert hinzu.

<h:commandButton value="Logout" action="logout?faces-redirect=true" />

oder

public String logout() {
    // ...
    return "index?faces-redirect=true";
}

Um den Browser anzuweisen, die dynamischen JSF-Seiten nicht zwischenzuspeichern, erstellen Sie eine, Filterdie dem Servlet-Namen des zugeordnet ist, FacesServletund fügen Sie die erforderlichen Antwortheader hinzu, um den Browser-Cache zu deaktivieren. Z.B

@WebFilter(servletNames={"Faces Servlet"}) // Must match <servlet-name> of your FacesServlet.
public class NoCacheFilter implements 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);
    }

    // ...
}

Vermeiden von ViewExpiredException bei Seitenaktualisierung

Um zu vermeiden, dass ViewExpiredExceptionbeim Aktualisieren der aktuellen Seite das Speichern des Status aktiviert ist server, müssen Sie nicht nur sicherstellen, dass Sie die Navigation von Seite zu Seite ausschließlich über GET (reguläre Links / Schaltflächen) durchführen, sondern auch sicherstellen dass Sie ausschließlich Ajax verwenden, um die Formulare einzureichen. Wenn Sie das Formular ohnehin synchron senden (nicht Ajax), sollten Sie die Ansicht entweder zustandslos machen (siehe späterer Abschnitt) oder eine Weiterleitung nach dem POST senden (siehe vorherigen Abschnitt).

Eine ViewExpiredExceptionOn-Page-Aktualisierung ist in der Standardkonfiguration ein sehr seltener Fall. Dies kann nur passieren, wenn das Limit für die Anzahl der Ansichten, die JSF in der Sitzung speichert, erreicht wird. Es wird also nur passieren, wenn Sie diesen Grenzwert manuell viel zu niedrig eingestellt haben oder wenn Sie kontinuierlich neue Ansichten im "Hintergrund" erstellen (z. B. durch eine schlecht implementierte Ajax-Umfrage auf derselben Seite oder durch eine schlecht implementierte 404 Fehlerseite bei fehlerhaften Bildern derselben Seite). Siehe auch com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews für Details zu dieser Grenze. Eine andere Ursache ist, dass doppelte JSF-Bibliotheken im Laufzeitklassenpfad in Konflikt miteinander stehen. Das richtige Verfahren zum Installieren von JSF finden Sie auf unserer JSF-Wiki-Seite .

ViewExpiredException behandeln

Wenn Sie eine unvermeidbare behandeln möchten ViewExpiredExceptionnach einer POST Aktion auf einer beliebigen Seite , die bereits in einigen Browser - Tab / Fenster geöffnet wurde , während Sie in einem anderen Tab / Fenster abgemeldet, dann möchten Sie eine angeben , error-pagefür die in web.xmldem geht auf eine Seite "Ihre Sitzung ist abgelaufen". Z.B

<error-page>
    <exception-type>javax.faces.application.ViewExpiredException</exception-type>
    <location>/WEB-INF/errorpages/expired.xhtml</location>
</error-page>

Verwenden Sie bei Bedarf einen Meta-Refresh-Header auf der Fehlerseite, falls Sie tatsächlich weiter zur Startseite oder Anmeldeseite umleiten möchten.

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Session expired</title>
        <meta http-equiv="refresh" content="0;url=#{request.contextPath}/login.xhtml" />
    </head>
    <body>
        <h1>Session expired</h1>
        <h3>You will be redirected to login page</h3>
        <p><a href="#{request.contextPath}/login.xhtml">Click here if redirect didn't work or when you're impatient</a>.</p>
    </body>
</html>

(Das 0In contentstellt die Anzahl der Sekunden vor der Umleitung dar 0und bedeutet somit "Sofort umleiten". Sie können z. B. verwenden 3, um den Browser 3 Sekunden mit der Umleitung warten zu lassen.)

Beachten Sie, dass für die Behandlung von Ausnahmen bei Ajax-Anforderungen eine spezielle Anforderung erforderlich ist ExceptionHandler. Siehe auch Sitzungszeitlimit und ViewExpiredException-Behandlung für JSF / PrimeFaces-Ajax-Anforderungen . Ein Live-Beispiel finden Sie auf der OmniFaces- FullAjaxExceptionHandlerPräsentationsseite (dies gilt auch für Nicht-Ajax-Anfragen).

Beachten Sie auch , dass Ihre „allgemeine“ Fehlerseite sollte auf kartiert werden <error-code>von 500anstelle eines <exception-type>von zBjava.lang.Exception oder java.lang.Throwable, sonst alle Ausnahmen in gewickelt ServletExceptionals solche ViewExpiredExceptionwürde am Ende noch in der allgemeinen Fehlerseite. Siehe auch ViewExpiredException in java.lang.Throwable-Fehlerseite in web.xml .

<error-page>
    <error-code>500</error-code>
    <location>/WEB-INF/errorpages/general.xhtml</location>
</error-page>

Staatenlose Ansichten

Eine völlig andere Alternative besteht darin, JSF-Ansichten im zustandslosen Modus auszuführen. Auf diese Weise wird nichts vom JSF-Status gespeichert und die Ansichten verfallen nie, sondern werden bei jeder Anforderung von Grund auf neu erstellt. Sie können , indem das auf stateless Ansichten drehen transientAttribut <f:view>zu true:

<f:view transient="true">

</f:view>

Auf diese Weise die javax.faces.ViewState erhält ausgeblendete Feld "stateless"in Mojarra einen festen Wert von (habe MyFaces zu diesem Zeitpunkt noch nicht überprüft). Beachten Sie, dass diese Funktion wurde eingeführt in Mojarra 2.1.19 und 2.2.0 und ist in älteren Versionen nicht verfügbar.

Die Folge ist, dass Sie keine Bohnen mit Sichtbereich mehr verwenden können. Sie verhalten sich jetzt wie Bohnen mit Anforderungsbereich. Einer der Nachteile ist, dass Sie den Status selbst verfolgen müssen, indem Sie mit versteckten Eingaben und / oder losen Anforderungsparametern herumspielen. Hauptsächlich diejenigen Formen mit Eingabefeldern mit rendered, readonlyoder disabledbetroffenen Attribute , die durch ajax Ereignisse gesteuert werden.

Beachten Sie, dass das <f:view>nicht unbedingt in der gesamten Ansicht eindeutig sein und / oder sich nur in der Master-Vorlage befinden muss. Es ist auch völlig legitim, es neu zu deklarieren und in einem Vorlagenclient zu verschachteln. Es "erweitert" im Grunde die Eltern<f:view> dann im . ZB in der Master-Vorlage:

<f:view contentType="text/html">
    <ui:insert name="content" />
</f:view>

und im Vorlagenclient:

<ui:define name="content">
    <f:view transient="true">
        <h:form>...</h:form>
    </f:view>
</f:view>

Sie können das sogar <f:view>in ein einwickeln <c:if>, um es bedingt zu machen. Beachten Sie, dass es auf die gelten würde gesamte Ansicht gilt, nicht nur für den verschachtelten Inhalt, wie <h:form>im obigen Beispiel.

Siehe auch


Unabhängig vom konkreten Problem ist die Verwendung von HTTP POST für die reine Navigation von Seite zu Seite nicht sehr benutzer- / SEO-freundlich. In JSF 2.0 sollten Sie wirklich bevorzugen <h:link>oder<h:button> die über <h:commandXxx>diejenigen für Plain - Vanilla - Seite-zu-Seite - Navigation.

Also statt z

<h:form id="menu">
    <h:commandLink value="Foo" action="foo?faces-redirect=true" />
    <h:commandLink value="Bar" action="bar?faces-redirect=true" />
    <h:commandLink value="Baz" action="baz?faces-redirect=true" />
</h:form>

besser machen

<h:link value="Foo" outcome="foo" />
<h:link value="Bar" outcome="bar" />
<h:link value="Baz" outcome="baz" />

Siehe auch

BalusC
quelle
Wie kann ich das mit impliziter Navigation in Java EE 6 machen? Ich benutze keine Gesichter-Konfiguration.
l245c4l
1
Oh, Sie verwenden JSF 2.0? Das hättest du in deiner Frage erwähnen sollen! ?faces-redirect=trueZum hinzufügen outcome. Ich habe die Antwort entsprechend aktualisiert.
BalusC
Ja, ich habe gerade mit Java ee angefangen :) und ich verwende in all meinen Navigationen face-redirect = true. Ich benutze h: commandLink nur, wenn mir Aktionen zugeordnet sind. Zum Beispiel Abmeldelink ... Ich habe die Aktion String logout (), bei der ich die Sitzung ungültig mache und zur Anmeldung umleitung, aber es funktioniert nicht auf der Seite, auf der ich angemeldet war und im Moment abgemeldet bin, und löst diese Ausnahme aus :(
l245c4l
1
Nochmals vielen
1
@LS: Der Filter ist jedoch für den Fall immer noch obligatorisch, wenn nach einem abgelaufenen POST die Zurück-Taste gedrückt wird und versucht wird, eine andere POST-Anforderung darauf aufzurufen. Dies würde sonst unbeabsichtigt zu dieser Ausnahme führen.
BalusC
56

Haben Sie versucht, Zeilen unten zu Ihrem hinzuzufügen web.xml?

<context-param>
   <param-name>com.sun.faces.enableRestoreView11Compatibility</param-name>
   <param-value>true</param-value>
</context-param>

Ich fand das sehr effektiv, als ich auf dieses Problem stieß.

Mike GH
quelle
1
es hat auch bei mir funktioniert. Danke für die Antwort. Was ist der Zweck davon?
MartK
2
Ich erinnere mich nicht genau, aber ich habe diese Lösung auf der ICEFaces-Website gefunden.
Mike GH
Ich bin vielleicht etwas spät zur Party, aber das hat auch bei mir funktioniert. Vielen Dank!
stellarossa
4
Ist dies auch nur für JSF 1.2 oder JSF 2 definiert?
SRy
17
Dadurch wird die Ausnahme nicht mehr ausgelöst, wenn die Ansicht abgelaufen ist, und die Anforderung wird einfach fortgesetzt. JSF kann jedoch weiterhin den Ansichtsstatus nicht wiederherstellen und keine zugehörigen Beans mit Ansichtsbereich finden. Diese Transaktion verhält sich wie zustandsloses JSF und Sie müssen den Ansichtsstatus basierend auf den POST-Anforderungsparametern selbst wiederherstellen, um "wtf?" Die Erfahrung des Endbenutzers bei der Verarbeitung des Formulars hat unerwartet geantwortet. Wenn Sie dies nur auf bestimmte JSF-Seiten anwenden möchten, verwenden Sie lieber OmniFaces <o:enableRestorableView>anstelle eines anwendungsweiten Kontextparameters.
BalusC
5

Bevor Sie die Datei web.xml ändern , müssen Sie zunächst sicherstellen, dass Ihre ManagedBean implements Serializable:

@ManagedBean
@ViewScoped
public class Login implements Serializable {
}

Vor allem, wenn Sie MyFaces verwenden

ZuzEL
quelle
3

Vermeiden Sie mehrteilige Formulare in Richfaces:

<h:form enctype="multipart/form-data">
    <a4j:poll id="poll" interval="10000"/>
</h:form>

Wenn Sie Richfaces verwenden, habe ich festgestellt, dass Ajax-Anforderungen in mehrteiligen Formularen bei jeder Anforderung eine neue Ansichts-ID zurückgeben.

So debuggen Sie:

Bei jeder Ajax-Anforderung wird eine Ansichts-ID zurückgegeben. Dies ist in Ordnung, solange die Ansichts-ID immer dieselbe ist. Wenn Sie bei jeder Anforderung eine neue Ansichts-ID erhalten, liegt ein Problem vor und muss behoben werden.

tak3shi
quelle
Seien Sie vorsichtig, wenn Sie mit Umfragen spielen. Dies kann verhindern, dass die Sitzungen Ihrer Benutzer ablaufen.
Jonathan Simas
0

Sie können Ihren eigenen AjaxExceptionHandler oder Primefaces-Erweiterungen verwenden

Aktualisieren Sie Ihre Gesichter-config.xml

...
<factory>
  <exception-handler-factory>org.primefaces.extensions.component.ajaxerrorhandler.AjaxExceptionHandlerFactory</exception-handler-factory>
</factory>
...

Fügen Sie folgenden Code in Ihre jsf-Seite ein

...
<pe:ajaxErrorHandler />
...
myset
quelle
0

Ich habe folgende Fehlermeldung erhalten: javax.faces.application.ViewExpiredException.Wenn ich verschiedene Anforderungen verwendet habe, habe ich festgestellt, dass diese auch nach dem Neustart des Servers dieselbe JsessionId haben. Das liegt also am Browser-Cache. Schließen Sie einfach den Browser und versuchen Sie es, es wird funktionieren.

rahul
quelle
0

Wenn unsere Seite x Mal inaktiv ist, läuft die Ansicht ab und löst eine javax.faces.application.ViewExpiredException aus, um dies zu verhindern. Eine Lösung besteht darin, einen CustomViewHandler zu erstellen, der ViewHandler erweitert und die restoreView-Methode überschreibt, an die alle anderen Methoden delegiert werden Elternteil

import java.io.IOException;
import javax.faces.FacesException;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;

public class CustomViewHandler extends ViewHandler {
    private ViewHandler parent;

    public CustomViewHandler(ViewHandler parent) {
        //System.out.println("CustomViewHandler.CustomViewHandler():Parent View Handler:"+parent.getClass());
        this.parent = parent;
    }

    @Override 
    public UIViewRoot restoreView(FacesContext facesContext, String viewId) {
    /**
     * {@link javax.faces.application.ViewExpiredException}. This happens only  when we try to logout from timed out pages.
     */
        UIViewRoot root = null;
        root = parent.restoreView(facesContext, viewId);
        if(root == null) {
            root = createView(facesContext, viewId);
        }
        return root;
    }

    @Override
    public Locale calculateLocale(FacesContext facesContext) {
        return parent.calculateLocale(facesContext);
    }

    @Override
    public String calculateRenderKitId(FacesContext facesContext) {
        String renderKitId = parent.calculateRenderKitId(facesContext);
        //System.out.println("CustomViewHandler.calculateRenderKitId():RenderKitId: "+renderKitId);
        return renderKitId;
    }

    @Override
    public UIViewRoot createView(FacesContext facesContext, String viewId) {
        return parent.createView(facesContext, viewId);
    }

    @Override
    public String getActionURL(FacesContext facesContext, String actionId) {
        return parent.getActionURL(facesContext, actionId);
    }

    @Override
    public String getResourceURL(FacesContext facesContext, String resId) {
        return parent.getResourceURL(facesContext, resId);
    }

    @Override
    public void renderView(FacesContext facesContext, UIViewRoot viewId) throws IOException, FacesException {
        parent.renderView(facesContext, viewId);
    }

    @Override
    public void writeState(FacesContext facesContext) throws IOException {
        parent.writeState(facesContext);
    }

    public ViewHandler getParent() {
        return parent;
    }

}   

Dann müssen Sie es zu Ihrer gesicht-config.xml hinzufügen

<application>
    <view-handler>com.demo.CustomViewHandler</view-handler>
</application>

Vielen Dank für die ursprüngliche Antwort auf den folgenden Link: http://www.gregbugaj.com/?p=164

user4924157
quelle
Bei diesem Ansatz werden Beans mit Ansichtsbereich nicht wiederhergestellt.
BalusC
-2

Bitte fügen Sie diese Zeile in Ihre web.xml ein. Es funktioniert für mich

<context-param>
        <param-name>org.ajax4jsf.handleViewExpiredOnClient</param-name> 
        <param-value>true</param-value>     
    </context-param>
Harshal
quelle
4
Ihre Antwort ist nützlicher, wenn Sie eine Erklärung und einen Kontext dazu enthalten, was der Code tut.
Palpatim
1
Auch wenn dies die richtige Antwort ist, rät StackOverflow von solchen Antworten ohne Erklärung ab. Es wäre für die Community hilfreich, weitere Informationen darüber hinzuzufügen, warum es funktioniert.
RacerNerd
-2

Ich bin selbst auf dieses Problem gestoßen und habe festgestellt, dass es sich um einen Nebeneffekt eines von mir erstellten Filters handelt, der alle Anforderungen in der Anwendung filtert. Sobald ich den Filter so geändert habe, dass nur bestimmte Anforderungen ausgewählt wurden, trat dieses Problem nicht auf. Es ist möglicherweise gut, in Ihrer Anwendung nach solchen Filtern zu suchen und zu sehen, wie sie sich verhalten.

Javshak
quelle
-3

Ich füge die folgende Konfiguration zu web.xml hinzu und sie wurde behoben.

<context-param>
    <param-name>com.sun.faces.numberOfViewsInSession</param-name>
    <param-value>500</param-value>
</context-param>
<context-param>
    <param-name>com.sun.faces.numberOfLogicalViews</param-name>
    <param-value>500</param-value>
</context-param>
Mohamed Ali
quelle
6
Schrecklicher Rat. Tun Sie dies nur, wenn Sie über genügend Speicher verfügen und Ihre Endbenutzer wirklich bis zu 500 Browser-Registerkarten geöffnet haben und die Zurück-Taste des Browsers bis zu 500 Mal drücken, um frühere synchrone Postbacks zu erhalten.
BalusC