소개
는 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
합니다.
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>
.
또한보십시오
구체적인 문제와 관련이없는 순수한 페이지 간 탐색에 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" />
또한보십시오