JSF AJAX請求的會話超時處理
當我們使用AJAX行為開發JSF應用程序時,在處理Ajax請求超時場景時可能會遇到問題。 例如,如果您使用的是基于J2EE表單的身份驗證,則會話超時后應將正常請求重定向到登錄頁面。 但是,如果您的請求是AJAX,則無法在客戶端正確處理響應。 用戶將保留在同一頁面上,并且不知道會話已過期。
許多人為此問題提出了解決方案。 以下是涉及使用Spring安全框架的兩種可能的解決方案:
1. Oleg Varaksin的帖子
2. Spring Security 3和ICEfaces 3教程
但是,某些應用程序可能只是使用簡單的機制將其身份驗證和授權信息存儲在會話中。 對于那些不使用Spring Security框架的應用程序,他們如何處理此類問題? 我剛剛修改了Oleg Varaksin提出的解決方案,作為我的參考。
首先,創建一個名為“ MyJsfAjaxTimeoutSetting”的簡單會話范圍內的JSF托管bean。
該POJO的主要目的只是允許您在faces-config.xml中的會話超時后配置重定向URL。 如果您不希望配置超時URL,則可能不需要此類。
public class MyJsfAjaxTimeoutSetting {public MyJsfAjaxTimeoutSetting() {}private String timeoutUrl;public String getTimeoutUrl() {return timeoutUrl;}public void setTimeoutUrl(String timeoutUrl) {this.timeoutUrl = timeoutUrl;}}
其次,創建一個PhaseListener來處理Ajax請求的重定向。
此PhaseListener是解決方案中最重要的部分。 它重新創建響應,以便超時后可以重定向Ajax請求。
import org.borislam.util.FacesUtil;
import org.borislam.util.SecurityUtil;
import java.io.IOException;
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.primefaces.context.RequestContext;public class MyJsfAjaxTimeoutPhaseListener implements PhaseListener
{public void afterPhase(PhaseEvent event){}public void beforePhase(PhaseEvent event){ MyJsfAjaxTimeoutSetting timeoutSetting = (MyJsfAjaxTimeoutSetting)FacesUtil.getManagedBean('MyJsfAjaxTimeoutSetting');FacesContext fc = FacesContext.getCurrentInstance();RequestContext rc = RequestContext.getCurrentInstance();ExternalContext ec = fc.getExternalContext();HttpServletResponse response = (HttpServletResponse) ec.getResponse();HttpServletRequest request = (HttpServletRequest) ec.getRequest();if (timeoutSetting ==null) {System.out.println('JSF Ajax Timeout Setting is not configured. Do Nothing!');return ;}UserCredential user = SecurityUtil.getUserCredential(); //// You can replace the above line of code with the security control of your application.// For example , you may get the authenticated user object from session or threadlocal storage.// It depends on your design.if (user==null) {// user credential not found. // considered to be a Timeout caseif (ec.isResponseCommitted()) {// redirect is not possiblereturn;}try{if ( ( (rc!=null && RequestContext.getCurrentInstance().isAjaxRequest())|| (fc!=null && fc.getPartialViewContext().isPartialRequest()))&& fc.getResponseWriter() == null&& fc.getRenderKit() == null) {response.setCharacterEncoding(request.getCharacterEncoding());RenderKitFactory factory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);RenderKit renderKit = factory.getRenderKit(fc,fc.getApplication().getViewHandler().calculateRenderKitId(fc));ResponseWriter responseWriter =renderKit.createResponseWriter(response.getWriter(), null, request.getCharacterEncoding());fc.setResponseWriter(responseWriter);ec.redirect(ec.getRequestContextPath() + (timeoutSetting.getTimeoutUrl() != null ? timeoutSetting.getTimeoutUrl() : '')); }} catch (IOException e) {System.out.println('Redirect to the specified page '' + timeoutSetting.getTimeoutUrl() + '' failed');throw new FacesException(e);}} else {return ; //This is not a timeout case . Do nothing !}}public PhaseId getPhaseId(){return PhaseId.RESTORE_VIEW;}}
FacesUtil.getManagedBean('MyJsfAjaxTimeoutSetting')的詳細信息如下所示:
public static Object getManagedBean(String beanName) {FacesContext fc = FacesContext.getCurrentInstance();ELContext elc = fc.getELContext();ExpressionFactory ef = fc.getApplication().getExpressionFactory();ValueExpression ve = ef.createValueExpression(elc, getJsfEl(beanName), Object.class);return ve.getValue(elc);
}
組態
如前所述,會話作用域受管bean MyJsfAjaxTimeoutSetting的目的只是為了使您可以在faces-config.xml中配置timeoutUrl。
<managed-bean>
<managed-bean-name>MyJsfAjaxTimeoutSetting</managed-bean-name>
<managed-bean-class>org.borislam.security.MyJsfAjaxTimeoutSetting</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>timeoutUrl</property-name>
<value>/login.do</value>
</managed-property>
</managed-bean>
最重要的是,將PhaseListener添加到faces-config.xml中。
<lifecycle>
<phase-listener id="JSFAjaxTimeoutPhaseListener">hk.edu.hkeaa.infrastructure.security.JSFAjaxTimeoutPhaseListener </phase-listener>
</lifecycle>
如果您使用的是Spring框架,則可以在SpringBeanFacesELResolver的幫助下在Spring中管理MyJsfAjaxTimeoutSetting。 然后,您可以使用以下配置。
<bean id="MyJsfAjaxTimeoutSetting" class="org.borislam.security.MyJsfAjaxTimeoutSetting" scope="session"> <property name="timeoutUrl" value="/login.do">
參考: “ 編程和平”博客上JCG合作伙伴 Boris Lam 對JSF AJAX請求的會話超時處理 。
翻譯自: https://www.javacodegeeks.com/2012/12/session-timeout-handling-on-jsf-ajax-request.html