javax.faces.application.ViewExpiredException :보기를 복원 할 수 없습니다
컨테이너 관리 보안으로 간단한 응용 프로그램을 작성했습니다. 문제는 로그인하고 로그 아웃 한 다른 페이지를 열면 첫 페이지로 돌아와서 링크 등을 클릭하거나 페이지를 새로 고치면이 예외가 발생합니다. 로그 아웃하고 세션이 파괴되어 정상적인 것 같습니다. 예를 들어 index.xhtml 또는 login.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)
소개
는 ViewExpiredException
이 때마다 발생합니다 javax.faces.STATE_SAVING_METHOD
으로 설정 server
(기본값)와 최종 사용자가를 통해보기에 HTTP POST 요청을 전송 <h:form>
과 함께 <h:commandLink>
, <h:commandButton>
또는 <f:ajax>
관련 뷰 상태가 더 이상 세션에서 사용할 수없는 상태.
뷰 상태는 숨겨진 입력 필드의 값으로 식별된다 javax.faces.ViewState
의 <h:form>
. 상태 저장 방법을로 설정 server
하면 세션의 직렬화 된보기 상태를 참조하는보기 상태 ID 만 포함됩니다. 따라서 어떤 이유로 세션이 만료 된 경우 (서버 또는 클라이언트 측에서 시간 초과되거나 브라우저에서 또는 HttpSession#invalidate()
서버 를 호출하여 세션 쿠키가 더 이상 유지되지 않거나 세션 쿠키가 있는 서버 특정 버그로 인해 세션 쿠키가 더 이상 유지되지 않는 경우) WildFly 에서 알려진 경우 직렬화 된보기 상태를 더 이상 세션에서 사용할 수 없으며 최종 사용자는이 예외를받습니다. 세션의 작동을 이해하려면 서블릿 작동 방법을 참조하십시오 . 인스턴스화, 세션, 공유 변수 및 멀티 스레딩 .
JSF가 세션에 저장할 뷰의 양에도 제한이 있습니다. 한계에 도달하면 가장 최근에 사용한보기가 만료됩니다. com.sun.faces.numberOfViewsInSession vs. com.sun.faces.numberOfLogicalViews 도 참조하십시오 .
상태 저장 방법을로 설정 client
하면 javax.faces.ViewState
숨겨진 입력 필드에 전체 직렬화 된보기 상태가 포함되므로 ViewExpiredException
세션이 만료 될 때 최종 사용자가 시간을 얻지 못합니다 . 그러나 여전히 클러스터 환경 ( "오류 : MAC이 확인하지 않음"이 증상 임) 및 / 또는 클라이언트 측 상태에 구현 별 시간 초과가 있거나 서버가 다시 시작하는 동안 AES 키를 다시 생성 할 때 발생할 수 있습니다. 상태 저장 방법이 클라이언트로 설정되어 있고 사용자 세션이 올바른 해결 방법 인 동안 클러스터 환경에서 ViewExpiredException 얻기를 참조하십시오 .
해결책에 관계없이를 사용 하지 마십시오 enableRestoreView11Compatibility
. 원래보기 상태를 전혀 복원하지는 않습니다. 기본적으로 뷰와 모든 관련 뷰 범위 Bean을 처음부터 다시 작성하므로 모든 원본 데이터 (상태)가 손실됩니다. 응용 프로그램이 혼란스러운 방식으로 작동하므로 ( "안녕하세요, 입력 값은 어디에 있습니까?.") 사용자 경험에 매우 좋지 않습니다. 상태 비 저장 뷰를보다 잘 사용하거나 <o:enableRestorableView>
모든 뷰가 아닌 특정 뷰에서만 관리 할 수 있습니다.
받는 사람으로 이유 : JSF이 응답에 뷰 상태, 머리를 저장해야하는 이유 JSF는 서버에 UI 구성 요소의 상태를 저장?
페이지 탐색시 ViewExpiredException 방지
ViewExpiredException
상태 저장이로 설정된 경우 로그 아웃 후 다시 탐색하는 경우 를 피하려면 로그 아웃 server
후 POST 요청을 리디렉션하는 것만으로는 충분하지 않습니다. 또한 브라우저에 동적 JSF 페이지를 캐시 하지 않도록 지시해야 합니다. 그렇지 않으면 브라우저에서 GET 요청을 보낼 때 서버에서 새 페이지를 요청하는 대신 브라우저에서 캐시에서 해당 페이지를 표시 할 수 있습니다 (예 : 뒤로 단추).
javax.faces.ViewState
캐시 된 페이지 의 숨겨진 필드는 현재 세션에서 더 이상 유효하지 않은보기 상태 ID 값을 포함 할 수 있습니다. 페이지 간 탐색을 위해 GET (정규 링크 / 버튼) 대신 POST (명령 링크 / 버튼)를 사용하고 캐시 된 페이지에서 해당 명령 링크 / 버튼을 클릭하면 (ab) 로 실패합니다 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를 사용하고 있습니다. 어쨌든 양식을 동기식 (ajaj가 아닌)으로 제출하는 경우 뷰를 상태 비 저장 (나중 섹션 참조) 또는 POST 후 리디렉션을 보내는 것이 가장 좋습니다 (이전 섹션 참조).
갖는 ViewExpiredException
페이지 새로 고침하는 것은 기본 구성에서 매우 드문 경우입니다. JSF가 세션에 저장할 뷰 수의 한계에 도달 한 경우에만 발생할 수 있습니다. 따라서 수동으로 제한을 너무 낮게 설정했거나 "배경"에서 새보기를 지속적으로 생성하는 경우에만 발생합니다 (예 : 동일한 페이지에서 잘못 구현 된 아약스 폴 또는 잘못 구현 됨 404). 같은 페이지의 깨진 이미지에 오류 페이지). 해당 제한에 대한 자세한 내용은 com.sun.faces.numberOfViewsInSession과 com.sun.faces.numberOfLogicalViews 를 참조하십시오 . 또 다른 원인은 런타임 클래스 경로에서 서로 충돌하는 중복 JSF 라이브러리가 있습니다. JSF를 설치하는 올바른 절차는 JSF 위키 페이지에 요약되어 있습니다.
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>
실제로 홈 페이지 나 로그인 페이지로 다시 리디렉션 하려는 경우 오류 페이지에서 메타 새로 고침 헤더를 사용해야 합니다.
<!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>
( 0
in content
은 리디렉션 전의 시간 (초) 을 나타내 0
므로 "즉시 리디렉션"을 의미합니다. 예 3
를 들어 브라우저를 리디렉션하여 3 초 동안 기다리게 할 수 있습니다 )
ajax 요청 중에 예외를 처리하려면 특수한 것이 필요합니다 ExceptionHandler
. JSF / PrimeFaces ajax 요청에 대한 세션 제한 시간 및 ViewExpiredException 처리 도 참조하십시오 . OmniFaces FullAjaxExceptionHandler
쇼케이스 페이지 에서 실제 예제를 찾을 수 있습니다 (이것은 또한 비 요약 요청도 포함합니다).
또한 "일반"오류 페이지에 매핑해야주의 <error-code>
의 500
대신의 <exception-type>
예의 java.lang.Exception
나 java.lang.Throwable
, 그렇지 않은 경우에 싸여 모든 예외 ServletException
등은 ViewExpiredException
여전히 일반 오류 페이지에 끝날 것입니다. web.xml의 java.lang.Throwable error-page에 표시된 ViewExpiredException 도 참조하십시오 .
<error-page>
<error-code>500</error-code>
<location>/WEB-INF/errorpages/general.xhtml</location>
</error-page>
상태 비 저장 뷰
완전히 다른 대안은 상태 비 저장 모드에서 JSF보기를 실행하는 것입니다. 이 방법으로 JSF 상태는 저장되지 않으며 뷰는 절대 만료되지 않지만 모든 요청에서 처음부터 다시 작성됩니다. 의 transient
속성을 <f:view>
로 설정하여 상태 비 저장 뷰를 켤 수 있습니다 true
.
<f:view transient="true">
</f:view>
이 방법으로 javax.faces.ViewState
숨겨진 필드는 "stateless"
Mojarra에서 고정 값을 얻습니다 (이 시점에서 MyFaces를 확인하지 않았습니다). 이 기능은 Mojarra 2.1.19 및 2.2.0에서 도입 되었으며 이전 버전에서는 사용할 수 없습니다.
결과적으로 더 이상 뷰 범위 Bean을 사용할 수 없습니다. 이제 요청 범위 Bean처럼 작동합니다. 단점 중 하나는 숨겨진 입력 및 / 또는 느슨한 요청 매개 변수를 사용하여 상태를 직접 추적해야한다는 것입니다. 주로 입력과 필드와 그 형태 rendered
, readonly
또는 disabled
아약스 이벤트에 의해 제어되는 속성이 영향을받습니다.
가 있습니다 <f:view>
반드시에만 마스터 템플릿보기 및 / 또는 상주 고유하지 않아도됩니다. 또한 템플릿 클라이언트에 다시 선언하고 중첩하는 것이 합법적입니다. 기본적으로 부모 <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>
A의를 <c:if>
이를 조건 적으로 만든다. 위의 예 와 같이 중첩 된 내용뿐만 아니라 전체 보기 에 적용됩니다 <h:form>
.
또한보십시오
- web.xml의 java.lang.Throwable 오류 페이지에 표시된 ViewExpiredException
- 세션에 JSF가 있는지 확인
- JSF / PrimeFaces 아약스 요청에 대한 세션 시간 초과 및 ViewExpiredException 처리
구체적인 문제와 관련이없는 순수한 페이지 간 탐색에 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" />
또한보십시오
- h : commandLink 대신 h : outputLink를 언제 사용해야합니까?
- h : button과 h : commandButton의 차이점
- JSF에서 탐색하는 방법? URL이 현재 페이지를 반영하도록하는 방법 (이전 페이지는 아님)
에 아래 줄을 추가 해 보셨습니까 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 를 사용하는 경우
Richface에서 다중 파트 양식을 피하십시오.
<h:form enctype="multipart/form-data">
<a4j:poll id="poll" interval="10000"/>
</h:form>
Richfaces를 사용하는 경우 멀티 파트 양식 내부의 ajax 요청이 각 요청마다 새로운 View ID를 반환한다는 것을 알았습니다.
디버깅하는 방법 :
각 아약스 요청에서 View ID가 반환됩니다. View ID가 항상 같은 한 괜찮습니다. 각 요청에서 새로운 View ID를 얻는다면 문제가있는 것이므로 수정해야합니다.
자신 만의 커스텀 AjaxExceptionHandler 또는 Primfaces-extensions를 사용하고있다
faces-config.xml 업데이트
...
<factory>
<exception-handler-factory>org.primefaces.extensions.component.ajaxerrorhandler.AjaxExceptionHandlerFactory</exception-handler-factory>
</factory>
...
Add following code in your jsf page
...
<pe:ajaxErrorHandler />
...
I was getting this error : javax.faces.application.ViewExpiredException.When I using different requests, I found those having same JsessionId, even after restarting the server. So this is due to the browser cache. Just close the browser and try, it will work.
When our page is idle for x amount of time the view will expire and throw javax.faces.application.ViewExpiredException to prevent this from happening one solution is to create CustomViewHandler that extends ViewHandler and override restoreView method all the other methods are being delegated to the Parent
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;
}
}
Then you need to add it to your faces-config.xml
<application>
<view-handler>com.demo.CustomViewHandler</view-handler>
</application>
Thanks for the original answer on the below link: http://www.gregbugaj.com/?p=164
Please add this line in your web.xml It works for me
<context-param>
<param-name>org.ajax4jsf.handleViewExpiredOnClient</param-name>
<param-value>true</param-value>
</context-param>
I ran into this problem myself and realized that it was because of a side-effect of a Filter that I created which was filtering all requests on the appliation. As soon as I modified the filter to pick only certain requests, this problem did not occur. It maybe good to check for such filters in your application and see how they behave.
I add the following configuration to web.xml and it got resolved.
<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>
'IT' 카테고리의 다른 글
Xcode에서 벡터 이미지는 어떻게 작동합니까 (예 : pdf 파일)? (0) | 2020.05.28 |
---|---|
mongodb에서 ISODate를 사용한 날짜 쿼리가 작동하지 않는 것 같습니다. (0) | 2020.05.28 |
Eclipse에서 프로젝트를 JAR로 자동 빌드 (0) | 2020.05.28 |
스레드 간 작업이 유효하지 않음 : 에서 작성된 스레드 이외의 스레드에서 액세스하는 제어 'textBox1' (0) | 2020.05.28 |
JavaScript 양식 제출-제출 확인 또는 취소 대화 상자 (0) | 2020.05.28 |