Giriş
ViewExpiredException
Zaman atılacağına javax.faces.STATE_SAVING_METHOD
ayarlandığında server
(varsayılan) ve son kullanıcı aracılığı ile görünümde HTTP POST isteği gönderir <h:form>
ile <h:commandLink>
, <h:commandButton>
ya <f:ajax>
ilişkili görünüm eyaleti bundan oturumda mevcut değilken,.
Görünüm durumu gizli bir giriş alanının değeri olarak tanımlanır javax.faces.ViewState
ve <h:form>
. Durum kaydetme yöntemi olarak ayarlandığında server
, bu yalnızca oturumda serileştirilmiş bir görüntüleme durumuna başvuran görünüm durumu kimliğini içerir. Bu nedenle, oturumun herhangi bir nedenle süresi dolduğunda (sunucuda veya istemci tarafında zaman aşımına uğradığında veya oturum çerezi bir nedenden dolayı tarayıcıda veya HttpSession#invalidate()
sunucuda çağrılarak veya oturum çerezleri ile sunucuya özgü bir hata nedeniyle artık korunmazsa WildFly olarak bilinir ), serileştirilmiş görünüm durumu artık oturumda kullanılamaz ve son kullanıcı bu istisnayı alır. Oturumun çalışmasını anlamak için ayrıca bkz. Sunucu uygulamaları nasıl çalışır? Örnekleme, oturumlar, paylaşılan değişkenler ve çoklu kullanım .
Ayrıca JSF'nin oturumda depolayacağı görüntüleme sayısı için bir sınır vardır. Sınıra ulaşıldığında, en son kullanılan görünümün süresi dolar. Ayrıca bkz . Com.sun.faces.numberOfViewsInSession ve com.sun.faces.numberOfLogicalViews .
Durum kaydetme yöntemi olarak ayarlandığında client
, javax.faces.ViewState
gizli giriş alanı bunun yerine tüm serileştirilmiş görünüm durumunu içerir, böylece ViewExpiredException
oturum sona erdiğinde son kullanıcı bir alamaz . Ancak yine de bir küme ortamında ("HATA: MAC doğrulanmadı" semptomatik olduğunu) ve / veya istemci tarafı durumunda yapılandırılan uygulamaya özel bir zaman aşımı olduğunda ve / veya sunucu yeniden başlatma sırasında AES anahtarını yeniden oluşturduğunda gerçekleşebilir durum kaydetme yöntemi istemciye ayarlanırken ve kullanıcı oturumu nasıl çözüleceği geçerliyse, kümelenmiş ortamda ViewExpiredException'ı alma konusuna da bakın .
Ne olursa olsun çözümün, emin do olun değildir kullanın enableRestoreView11Compatibility
. orijinal görünüm durumunu hiç geri yüklemez. Temel olarak görünümü ve tüm ilişkili görünüm kapsamındaki çekirdekleri sıfırdan yeniden oluşturur ve böylece tüm orijinal verileri (durumu) kaybeder. Uygulama kafa karıştırıcı bir şekilde davranacağından ("Hey, girdi değerlerim .. ??"), bu kullanıcı deneyimi için çok kötü. Durum bilgisi olmayan görünümleri daha iyi kullanın veya <o:enableRestorableView>
bunun yerine tüm görünümler yerine yalnızca belirli bir görünümde yönetebilirsiniz.
JSF'nin neden görüntüleme durumunu kaydetmesi gerektiğine gelince , şu yanıta gidin: JSF neden UI bileşenlerinin durumunu sunucuya kaydeder?
Sayfada gezinme sırasında ViewExpiredException özel durumundan kaçınma
ViewExpiredException
Durum kaydetme olarak ayarlandığında server
, örneğin oturumu kapattıktan sonra geriye doğru gitmeyi önlemek için , POST isteğini yalnızca oturumu kapattıktan sonra yeniden yönlendirmek yeterli değildir. İçin de tarayıcı talimat gerek yok dinamik JSF sayfaları önbelleğe bunun üzerine bir GET isteği gönderdiğinizde aksi tarayıcı yerine sunucudan yeni bir URL isteme önbellekten kendilerine gösterebiliriz, (örneğin geri düğmesi ile).
javax.faces.ViewState
Önbelleğe sayfanın gizli alan, geçerli oturumda artık geçerli olmayan bir görünüm devlet kimliği değerini içerebilir. Sayfadan sayfaya gezinme için GET (normal bağlantılar / düğmeler) yerine POST (komut bağlantıları / düğmeler) kullanıyorsanız (ab) ve önbelleğe alınmış sayfada böyle bir komut bağlantısını / düğmesini tıklarsanız, ile başarısız ViewExpiredException
.
JSF 2.0 sistemden çıktıktan sonra bir yönlendirme ateş, ya eklemek için <redirect />
için <navigation-case>
(eğer varsa) Söz konusu veya eklemek ?faces-redirect=true
için outcome
değer.
<h:commandButton value="Logout" action="logout?faces-redirect=true" />
veya
public String logout() {
// ...
return "index?faces-redirect=true";
}
Tarayıcıya dinamik JSF sayfalarını önbelleğe almama talimatı vermek Filter
için, sunucu uygulamacığı adında eşlenen FacesServlet
ve tarayıcı önbelleğini devre dışı bırakmak için gerekli yanıt başlıklarını ekleyen bir sayfa oluşturun . Örneğin
@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);
}
// ...
}
Sayfa yenilemede ViewExpiredException durumundan kaçınma
ViewExpiredException
Durum kaydetme olarak ayarlandığında geçerli sayfayı yenilemekten kaçınmak için server
, yalnızca sayfadan sayfaya yalnızca GET (normal bağlantılar / düğmeler) ile yaptığınızdan emin olmakla kalmaz, aynı zamanda formları göndermek için yalnızca ajax kullandığınız anlamına gelir. Yine de formu eşzamanlı olarak (ajax olmayan) gönderiyorsanız, görünümü vatansız hale getirmeniz (daha sonra bölüme bakın) veya POST sonrasında bir yönlendirme göndermeniz en iyisidir (önceki bölüme bakın).
ViewExpiredException
Sayfa yenilemeye sahip olmak varsayılan yapılandırmada çok nadir görülen bir durumdur. Yalnızca JSF'nin oturumda depolayacağı görüntüleme miktarı sınırı aşıldığında gerçekleşebilir. Bu nedenle, yalnızca bu sınırı çok düşük bir şekilde manuel olarak ayarladığınızda veya "arka planda" sürekli olarak yeni görünümler oluşturduğunuzda (örn. Aynı sayfada kötü uygulanmış bir ajax anketiyle veya kötü uygulanmış 404) aynı sayfanın bozuk resimlerindeki hata sayfası). Bu sınırla ilgili ayrıntılar için ayrıca bkz. Com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews . Başka bir neden, çalışma zamanı sınıfyolunda birbiriyle çakışan yinelenen JSF kitaplıklarına sahip olmaktır. JSF'yi yüklemek için doğru prosedür JSF wiki sayfamızda özetlenmiştir .
ViewExpiredException'ı İşleme
Eğer kaçınılmaz işlemek istediğinizde ViewExpiredException
başka bir sekme / pencerede çıkış yapmış yaparken zaten bazı tarayıcı sekmesi / pencere açıldı keyfi bir sayfadaki bir POST eyleminden sonra, o zaman bir belirtmek istiyorum error-page
bunun için web.xml
hangi gider "Oturumunuz zaman aşımına uğradı" sayfasına gidin. Örneğin
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/WEB-INF/errorpages/expired.xhtml</location>
</error-page>
Gerekirse ana sayfaya veya giriş sayfasına daha fazla yönlendirme yapmak istiyorsanız, hata sayfasında bir meta yenileme başlığı kullanın .
<!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>
(in 0
, content
yönlendirme öncesi saniye miktarını temsil eder, 0
bu nedenle "hemen yönlendirme" anlamına gelir, örneğin 3
tarayıcının yönlendirme ile 3 saniye beklemesini sağlamak için kullanabilirsiniz )
Ajax istekleri sırasında istisnaları işlemenin özel bir işlem gerektirdiğini unutmayın ExceptionHandler
. Ayrıca bkz . JSF / PrimeFaces ajax isteğinde Oturum zaman aşımı ve ViewExpiredException işleme . Canlı bir örneği OmniFaces FullAjaxExceptionHandler
vitrin sayfasında bulabilirsiniz (bu ayrıca ajax dışı istekleri de kapsar).
Ayrıca "genel" hata sayfası üzerinde işaretlendiğini gerektiğini unutmayın <error-code>
ait 500
yerine ait <exception-type>
örn java.lang.Exception
veya java.lang.Throwable
aksi sarılmış tüm istisnalar ServletException
gibi ViewExpiredException
yine genel hata sayfasında sona ereceğini. Ayrıca bkz . Java.lang içinde gösterilen ViewExpiredException. Web.xml dosyasında atılabilir hata sayfası .
<error-page>
<error-code>500</error-code>
<location>/WEB-INF/errorpages/general.xhtml</location>
</error-page>
Durum bilgisi olmayan görünümler
Tamamen farklı bir alternatif, JSF görünümlerini vatansız modda çalıştırmaktır. Bu şekilde JSF durumundan hiçbir şey kaydedilmeyecek ve görünümler hiçbir zaman sona ermeyecektir, ancak her istek üzerine sıfırdan yeniden oluşturulacaktır. Durum bilgisi olmayan görüntülemeleri transient
özelliğini şu şekilde ayarlayarak <f:view>
açabilirsiniz true
:
<f:view transient="true">
</f:view>
Bu şekilde javax.faces.ViewState
gizli alan "stateless"
Mojarra'da sabit bir değer alır ( bu noktada MyFaces'i kontrol etmediler). Bu özelliğin Mojarra 2.1.19 ve 2.2.0'da tanıtıldığını ve eski sürümlerde mevcut olmadığını unutmayın.
Sonuç olarak artık görünüm kapsamındaki çekirdekleri kullanamazsınız. Şimdi talep kapsamındaki fasulye gibi davranacaklar. Dezavantajlardan biri, gizli girdiler ve / veya gevşek istek parametreleriyle uğraşarak durumu kendiniz izlemenizdir. Ağırlıklı olarak girdi ile alanlara sahip olanlar formları rendered
, readonly
ya disabled
ajax olaylar tarafından kontrol edildiği özelliklerde etkilenecektir.
<f:view>
Görünümün benzersiz olması ve / veya yalnızca ana şablonda bulunması gerekmediğini unutmayın . Bir şablon istemcide yeniden bildirmek ve iç içe geçirmek de tamamen yasaldır. Temelde ebeveyni "genişletir" <f:view>
. Örneğin ana şablonda:
<f:view contentType="text/html">
<ui:insert name="content" />
</f:view>
ve şablon istemcisinde:
<ui:define name="content">
<f:view transient="true">
<h:form>...</h:form>
</f:view>
</f:view>
Hatta sarabilirsiniz <f:view>
bir de <c:if>
o koşullu yapmak. Yukarıdaki örnekte olduğu gibi yalnızca iç içe içeriklere değil , tüm görünüme uygulanacağını unutmayın <h:form>
.
Ayrıca bakınız
Somut sorunla ilgisi olmayan , sayfadan sayfaya gezinme için HTTP POST kullanımı çok kullanıcı / SEO dostu değildir. JSF 2.0 gerçekten tercih etmelidir <h:link>
ya <h:button>
üzerinde <h:commandXxx>
düz vanilya sayfadan sayfaya navigasyon için olanlar.
Yani, örneğin
<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>
daha iyi yap
<h:link value="Foo" outcome="foo" />
<h:link value="Bar" outcome="bar" />
<h:link value="Baz" outcome="baz" />
Ayrıca bakınız