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