在用JSF做项目的时候,经常会碰到session timeout问题,比如部署在tomcat下的时候,默认的timeout时间为30分钟,则在30分钟以后,点击页面上的任何commandButton或commandLink都会导致抛出javax.faces.application.ViewExpiredException异常:
提供一种解决方式:
自定义PhaseListener,并且在RESTORE_VIEW阶段的beforePhase中进行处理
<lifecycle> <phase-listener>com.tcb.flow.webui.jsf.listener.AuthenticationPhaseListener</phase-listener> </lifecycle>
AuthenticationPhaseListener的代码如下:
package com.test.listener;
import javax.faces.FacesException;
import javax.faces.application.Application;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.test.Constants;
public class AuthenticationPhaseListener implements PhaseListener {
private static final Log logger = LogFactory.getLog(AuthenticationPhaseListener.class);
public void afterPhase(PhaseEvent event) {
// other operation
}
public void beforePhase(PhaseEvent event) {
FacesContext context = event.getFacesContext();
ExternalContext externalContext = context.getExternalContext();
HttpSession session = (HttpSession) externalContext.getSession(false);
boolean newSession = session == null || session.isNew();
boolean postBack = !externalContext.getRequestParameterMap().isEmpty();//form submit
if (newSession && postBack) {//timeout
ViewHandler viewHandler = context.getApplication().getViewHandler();
UIViewRoot viewRoot = viewHandler.createView(context, "/index.jsp");
context.setViewRoot(viewRoot);
context.renderResponse();
try {
viewHandler.renderView(context, viewRoot);
context.responseComplete();
} catch (Exception e) {
throw new FacesException("Session is timeout", e);
}
}
}
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
}
如果是new session且是表单提交则跳转到登录页面。
【附faces-config.xml配置信息】
<?xml version="1.0" encoding="UTF-8"?> <faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" version="2.0"> <lifecycle> <phase-listener>com.tcb.flow.webui.jsf.listener.AuthenticationPhaseListener</phase-listener> </lifecycle> <application> <action-listener>com.tcb.flow.webui.jsf.listener.AuthenticationActionListener</action-listener> <variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver> <message-bundle>resource.messages</message-bundle> <resource-bundle> <description>i18n message for framework</description> <base-name>resource.messages</base-name> <var>msg</var> </resource-bundle> <resource-bundle> <description>i18n message for common action</description> <base-name>com.action.package</base-name> <var>comMsg</var> </resource-bundle> <resource-bundle> <description>i18n message for action used by managing user</description> <base-name>com.action.manage.package</base-name> <var>mgrMsg</var> </resource-bundle> <resource-bundle> <description>i18n message for system action</description> <base-name>com.action.system.package</base-name> <var>sysMsg</var> </resource-bundle> </application> <navigation-rule> <navigation-case> <from-outcome>error</from-outcome> <to-view-id>/common/systemMessage.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>index</from-outcome> <to-view-id>/index.jsp</to-view-id> <redirect /> </navigation-case> <navigation-case> <from-outcome>confirmLogout</from-outcome> <to-view-id>/confirmLogout.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>viewLoginInfo</from-outcome> <to-view-id>/common/viewLoginInfo.jsp</to-view-id> <redirect /> </navigation-case> </navigation-rule> </faces-config>