JSF Session timeout处理

本文介绍了一种解决JSF应用中会话超时问题的方法。通过自定义PhaseListener监听器,在会话过期时将用户重定向到登录页面。此方案适用于部署在Tomcat等服务器上的JSF项目。

在用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>

 

### JSF 中使用 Session 级别的 Bean 在 JSF 中,使用 Session 级别的 Bean 可以实现跨多个请求的数据共享。Session 作用域的托管 Bean 会在用户的整个会话期间保持存在,适用于需要在多个页面或请求之间保持状态的场景,例如用户登录状态、购物车信息等。 要声明一个 Session 作用域的 Bean,可以使用 `@ManagedBean` 注解,并结合 `@SessionScoped` 注解来指定其作用域: ```java import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; @ManagedBean @SessionScoped public class UserSessionBean { private String username; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String login() { // 登录逻辑 return "home"; } } ``` 通过上述方式声明的 `UserSessionBean` 会在用户会话期间持续存在,并可在多个页面中访问其属性。由于其生命周期与用户的会话绑定,因此适合存储需要在多个请求之间共享的状态信息[^2]。 在页面中使用该 Bean 时,可以直接通过 EL 表达式调用其方法或访问其属性: ```xhtml <h:form> <h:inputText value="#{userSessionBean.username}" /> <h:commandButton value="登录" action="#{userSessionBean.login}" /> </h:form> ``` ### Session 作用域 Bean 的生命周期管理 Session 作用域的 Bean 由 JSF 容器管理其生命周期。当用户首次访问应用并触发对 Session 作用域 Bean 的请求时,容器会创建该 Bean 的实例。该实例将在用户的整个会话期间保持存在,直到会话被销毁(例如用户注销或会话超时)。 在某些场景下,可能需要手动销毁 Session 作用域的 Bean。可以通过以下方式实现: ```java import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; import javax.faces.context.FacesContext; import java.io.Serializable; @ManagedBean @SessionScoped public class UserSessionBean implements Serializable { public String logout() { FacesContext.getCurrentInstance().getExternalContext().invalidateSession(); return "login"; } } ``` 在页面中调用 `logout()` 方法即可销毁当前会话并重定向到登录页面。 ### 与 Spring 的集成 若在 JSF 项目中使用 Spring 作为依赖注入框架,则可以通过 `@Scope("session")` 声明 Session 作用域的 Bean。为确保 Spring 正确代理 Session 作用域的 Bean,需要配置 `<aop:scoped-proxy/>`: ```xml <bean id="userSession" class="com.example.UserSession" scope="session"> <aop:scoped-proxy/> </bean> <bean id="userService" class="com.example.UserService"> <property name="userSession" ref="userSession"/> </bean> ``` 通过上述配置,Spring 会为 `userSession` Bean 创建代理,使其能够在其他 Bean 中被正确注入和使用[^1]。 ### 适用场景 Session 作用域的 Bean 适用于以下场景: - 用户登录状态管理 - 购物车信息存储 - 多页面共享的临时数据 - 用户个性化设置 由于 Session 作用域的 Bean 在用户会话期间持续存在,因此应避免在其中存储大量数据,以免影响应用性能。对于无状态的业务逻辑,建议使用 `@RequestScoped` 或 `@ApplicationScoped` Bean。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值