класса javax.сталкиваться.приложение.ViewExpiredException: не удалось восстановить представление
Я написал простое приложение с безопасностью, управляемой контейнером. Проблема в том, что когда я вхожу в систему и открываю другую страницу, на которой я выхожу из системы, я возвращаюсь на первую страницу и нажимаю на любую ссылку и т. д. или обновляю страницу, Я получаю это исключение. Я думаю, это нормально (или, может быть, нет:)), потому что я вышел из системы и сеанс уничтожен. Что делать, чтобы перенаправить пользователя, например, на индекс.XHTML или логин.xhtml и спасти его от просмотра этой страницы/сообщения об ошибке?
другими словами, как я могу автоматически перенаправлять другие страницы на страницу индекса / входа после выхода из системы?
вот это:
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)
10 ответов
введение
на ViewExpiredException
будет брошен всякий раз, когда javax.faces.STATE_SAVING_METHOD
установлено значение server
(по умолчанию), и пользователь отправляет запрос HTTP POST на просмотр через <h:form>
С <h:commandLink>
, <h:commandButton>
или <f:ajax>
, в то время как связанное состояние представления больше не доступно в сеансе.
Просмотр состояния определяется как значение скрытого поля ввода javax.faces.ViewState
на <h:form>
. С помощью метода сохранения состояния установлено значение server
, это содержит только ID состояния представления который ссылается на состояние сериализованного представления в сеансе. Таким образом, когда сеанс по какой-либо причине истек (либо тайм-аут на стороне сервера или клиента, либо cookie сеанса больше не поддерживается по какой-либо причине в браузере, или путем вызова HttpSession#invalidate()
в сервере, или из-за специфической ошибки сервера с сеансовыми куки, как известно в WildFly), то состояние сериализованного представления больше не доступно в сеансе, и пользователь получит это исключение. Чтобы понять работу сеанс, см. Также как работают сервлеты? Создание экземпляров, сеансы, общие переменные и многопоточность.
существует также ограничение на количество просмотров, которые JSF будет хранить в сеансе. Когда предел будет достигнут, то наименее недавно использованное представление будет истекло. См. также com.солнце.сталкиваться.numberOfViewsInSession vs com.солнце.сталкиваться.numberOfLogicalViews.
с помощью метода сохранения состояния client
, the javax.faces.ViewState
скрытое поле ввода вместо этого содержит все состояние сериализованного представления, поэтому конечный пользователь не получит ViewExpiredException
когда сессия истекает. Однако это может произойти в кластерной среде ("ошибка: MAC не проверил" симптоматично) и/или когда на стороне клиента настроено время ожидания реализации и/или когда сервер повторно генерирует ключ AES во время перезапуска, см. Также получение исключения ViewExpiredException в кластеризованной среде, когда метод сохранения состояния установлен в client и User session действует как ее решить.
независимо от решения, убедитесь, что вы делаете не использовать enableRestoreView11Compatibility
. он вообще не восстанавливает исходное состояние представления. Он в основном воссоздает представление и все связанные с ним бобы с областью видимости с нуля и таким образом теряет все исходные данные (состояние). Как приложение будет вести себя странным образом ("Эй, где мои входные значения..??"), это очень плохо для пользователей. Лучше использовать представления без состояния или <o:enableRestorableView>
а не так вы можете управлять им только в определенном представлении, а не во всех представлениях.
как к почему JSF необходимо сохранить состояние просмотра, перейдите к этому ответу:почему JSF сохраняет состояние компонентов пользовательского интерфейса на сервере?
избегая ViewExpiredException на странице навигации
во избежание ViewExpiredException
когда, например, переход назад после выхода из системы, когда сохранение состояния установлено в server
, только перенаправление запроса POST после выхода из системы не достаточный. Вам также необходимо указать браузеру не кэш динамических страниц JSF, в противном случае браузер может показать их из кэша вместо запроса нового с сервера при отправке запроса GET на нем (например, кнопкой "Назад").
на javax.faces.ViewState
скрытое поле кэшированной страницы может содержать значение ID состояния представления, которое больше не является допустимым в текущем сеансе. Если вы (ab)используете POST (командные ссылки/кнопки) вместо GET (обычный ссылки / кнопки) для навигации по страницам и нажмите такую командную ссылку/кнопку на кэшированной странице, тогда это, в свою очередь, завершится неудачей с ViewExpiredException
.
огонь редирект после выхода в JSF 2.0, либо добавить <redirect />
до <navigation-case>
в вопросе (если есть), или добавить ?faces-redirect=true
до outcome
значение.
<h:commandButton value="Logout" action="logout?faces-redirect=true" />
или
public String logout() {
// ...
return "index?faces-redirect=true";
}
чтобы проинструктировать браузер не кэшировать динамические страницы JSF, создайте Filter
который отображается на имя сервлета FacesServlet
и добавляет необходимые заголовки ответа, чтобы отключить кэш браузера. Е. Г.
@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);
}
// ...
}
избегая исключения ViewExpiredException на странице обновления
во избежание ViewExpiredException
при обновлении текущей страницы, когда сохранение состояния установлено в server
, вам не только нужно убедиться, что вы выполняете переход от страницы к странице исключительно с помощью GET (обычные ссылки/кнопки), но вам также необходимо убедиться, что вы используете ajax исключительно для отправки форм. Если вы отправка формы синхронно (не ajax) в любом случае, тогда вам лучше либо сделать вид без состояния (см. Более поздний раздел), либо отправить перенаправление после публикации (см. предыдущий раздел).
имеющего ViewExpiredException
при обновлении страницы в конфигурации по умолчанию очень редкий случай. Это может произойти только тогда, когда ограничение на количество просмотров JSF будет сохранено в сеансе. Таким образом, это произойдет только тогда, когда вы вручную установили этот предел слишком низко или постоянно создаете новые представления в справочная информация (например, плохо проведенный опрос). См. также com.солнце.сталкиваться.numberOfViewsInSession vs com.солнце.сталкиваться.numberOfLogicalViews. Другой причиной является наличие дубликатов библиотек JSF в пути к классам среды выполнения, конфликтующих друг с другом. Правильная процедура установки JSF описана в наша страница JSF wiki.
Обработка ViewExpiredException
когда вы хотите справиться с неизбежным ViewExpiredException
после действия POST на произвольной странице, которая был уже открыт в какой-то вкладке/окне браузера, когда вы вышли из системы в другой вкладке / окне, затем вы хотите указать error-page
для этого в web.xml
который переходит на страницу" ваш сеанс тайм-аут". Е. Г.
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/WEB-INF/errorpages/expired.xhtml</location>
</error-page>
при необходимости используйте заголовок meta refresh на странице ошибок, если вы действительно собираетесь редирект далее к домашней или странице входа в систему.
<!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>
(the 0
на content
представляет количество секунд до редирект, 0
таким образом, означает "перенаправить немедленно", вы можете использовать, например,3
чтобы браузер подождал 3 секунды с перенаправлением)
обратите внимание, что обработка исключений во время AJAX-запросов требует специального ExceptionHandler
. См. также тайм-аут сеанса и обработка ViewExpiredException в запросе ajax JSF/PrimeFaces. Вы можете найти живой пример в OmniFaces FullAjaxExceptionHandler
витрина-страницы (это также охватывает не ajax требования заказчика.)
также обратите внимание, что ваша страница" общая " ошибка должна быть отображена на <error-code>
of 500
вместо <exception-type>
, например,java.lang.Exception
или java.lang.Throwable
, в противном случае все исключения завернуты в ServletException
например ViewExpiredException
равно в конечном итоге в общей страницу ошибки. См. также ViewExpiredException показано в java.ленг.Throwable error-страница в интернете.в XML.
<error-page>
<error-code>500</error-code>
<location>/WEB-INF/errorpages/general.xhtml</location>
</error-page>
вид без гражданства
совершенно другой альтернативой является запуск JSF представления в режиме без состояния. Таким образом ничего Государственного в JSF будет сохранен и мнения никогда не истекает, а просто заново при каждом запросе. Вы можете включить представления без состояния, установив на <f:view>
to true
:
<f:view transient="true">
</f:view>
сюда javax.faces.ViewState
скрытое поле получит фиксированное значение "stateless"
в Mojarra (не проверено MyFaces на данный момент). Обратите внимание, что эта функция была ввел в Mojarra 2.1.19 и 2.2.0 и не доступно в более старых версиях.
следствием является невозможность использования просмотреть больше уровня фасоли. Теперь они будут вести себя, как бобы с просьб. Одним из недостатков является то, что вы должны отслеживать состояние самостоятельно, играя со скрытыми входами и/или параметрами запроса. В основном те формы с полями ввода с rendered
, readonly
или disabled
будут затронуты атрибуты, управляемые событиями ajax.
отметим, что <f:view>
не обязательно должен быть уникальным во всем представлении и / или находиться только в главном шаблоне. Это также полностью законно, чтобы redeclare и вложить его в клиент шаблона. Он в основном "расширяет" родителя <f:view>
затем. Е. Г. в мастер-шаблоне:
<f:view contentType="text/html">
<ui:insert name="content" />
</f:view>
и в шаблоне клиента:
<ui:define name="content">
<f:view transient="true">
<h:form>...</h:form>
</f:view>
</f:view>
вы даже можете обернуть <f:view>
на <c:if>
чтобы сделать его условным. Обратите внимание, что это будет применяться на весь просмотр не только вложенного содержимого, например the <h:form>
в приведенном выше примере.
см. также
- ViewExpiredException показано в java.ленг.Throwable error-страница в интернете.в XML
- проверьте, существует ли сеанс JSF
- тайм-аут сеанса и обработка ViewExpiredException в запросе ajax JSF/PrimeFaces
связаны к конкретной проблеме, используя HTTP POST для чистого страница-для-страницы навигации не очень пользователей/SEO дружественных. В JSF 2.0 вы действительно должны предпочесть <h:link>
или <h:button>
на <h:commandXxx>
для простой ванильной навигации по страницам.
так вместо, например,
<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>
лучше сделать
<h:link value="Foo" outcome="foo" />
<h:link value="Bar" outcome="bar" />
<h:link value="Baz" outcome="baz" />
см. также
вы пытались добавить строки ниже к вашему web.xml
?
<context-param>
<param-name>com.sun.faces.enableRestoreView11Compatibility</param-name>
<param-value>true</param-value>
</context-param>
я обнаружил, что это очень эффективно, когда я столкнулся с этой проблемой.
Первое, что вы должны сделать, прежде чем менять web.в XML убедитесь, что ManagedBean implements Serializable
:
@ManagedBean
@ViewScoped
public class Login implements Serializable {
}
особенно если вы используете MyFaces
избегайте составных форм в Richfaces:
<h:form enctype="multipart/form-data">
<a4j:poll id="poll" interval="10000"/>
</h:form>
Если вы используете Richfaces, я обнаружил, что ajax-запросы внутри составных форм возвращают новый идентификатор представления для каждого запроса.
как отлаживать:
при каждом запросе ajax возвращается идентификатор представления, что нормально, если идентификатор представления всегда один и тот же. Если вы получаете новый идентификатор представления по каждому запросу, то возникает проблема и ее необходимо устранить.
вы можете использовать свой собственный AjaxExceptionHandler или primefaces-extensions
обновите faces-config.в XML
...
<factory>
<exception-handler-factory>org.primefaces.extensions.component.ajaxerrorhandler.AjaxExceptionHandlerFactory</exception-handler-factory>
</factory>
...
добавьте следующий код на страницу jsf
...
<pe:ajaxErrorHandler />
...
Я получал эту ошибку: javax.сталкиваться.приложение.ViewExpiredException.Когда я использую разные запросы, я нашел те, которые имеют тот же JsessionId, даже после перезагрузки сервера. Так это из-за кэша браузера. Просто закройте браузер и попробуйте, он будет работать.
когда наша страница простаивает в течение x времени, представление истекает и выбрасывает javax.сталкиваться.приложение.ViewExpiredException, чтобы предотвратить это одним из решений является создание CustomViewHandler, который расширяет ViewHandler и переопределить метод restoreView все остальные методы делегируются родительскому
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;
}
}
затем вам нужно добавить его в faces-config.в XML
<application>
<view-handler>com.demo.CustomViewHandler</view-handler>
</application>
Спасибо за оригинальный ответ ниже ссылка на сайт: http://www.gregbugaj.com/?p=164
пожалуйста, добавьте эту строку в ваш веб.XML Это работает для меня
<context-param>
<param-name>org.ajax4jsf.handleViewExpiredOnClient</param-name>
<param-value>true</param-value>
</context-param>
Я сам столкнулся с этой проблемой и понял, что это из-за побочного эффекта фильтра, который я создал, который фильтровал все запросы на применение. Как только я изменил фильтр, чтобы выбрать только определенные запросы, эта проблема не возникла. Возможно, неплохо проверить наличие таких фильтров в вашем приложении и посмотреть, как они себя ведут.
Я добавляю следующую конфигурацию в web.в XML и это разрешилось.
<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>