JSF中session过期后视图恢复的问题

阅读更多

在jsf中,一旦session过期,生命周期为session的Controller bean对象将会被销毁,因此除了一些静态页面,大多数情况的动态页面视图也就无法恢复。如果没有在web.xml设置error page,那么系统会直接在页面中抛出异常。当然关掉页面重新打开就不会有这个问题,但是普通浏览者这个时候往往会不知所措,以为网站挂掉了,这样可用性会很差。

    一般网上提供的解决方法是在web.xml中设置error page来捕获错误,重定向到一个指定的页面,例如:
     
javax.faces.application.ViewExpiredException     
/login.jsf 


    但悲惨的是,在调试中发现javax.faces.application.ViewExpiredException这个异常并不会被捕获到,com.sun.faces.lifecycle.LifecycleImpl的execute方法抛出的实际上是FacesException。我怀疑可能是jsf的2.0版本修改了这一块,而网上的解决方法是针对老版本的。

    如此,我们只能通过从com.sun.faces.lifecycle.LifecycleImpl派生一个类来处理这个异常,代码如下:

import javax.faces.FacesException;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ppedu.commons.SystemProperty;
import com.sun.faces.lifecycle.LifecycleImpl;

public class TeleLifecycleImpl extends LifecycleImpl {

    public TeleLifecycleImpl() {
        super();
    }
     
    public void execute(FacesContext context) {
        try {
            super.execute(context);
        } 
        catch (ViewExpiredException  vee) {
            //似乎永远不会捕获,应该是异常在父类的同名方法中被包装成了FacesException
            redirect(context);
        }
        catch (FacesException fe) {
            //取得该异常的root cause
            Object obj= fe.getCause();
            //判断是否ViewExpiredException
            if (obj instanceof  ViewExpiredException){                
                redirect(context);
            }
            else{
                throw fe;
            }
        }
    }
     
    private void redirect(FacesContext context) {
        try {
            context.responseComplete();
            context.renderResponse();
            HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
            
            //根据原来的请求路径确定要重定向的路径
            HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
            String path = request.getRequestURI();
            String [] ss = path.split("/");            
            String redirectKey = "session.timeout.redirect.url.general";
            for(int i=0;i                if( ss[i].equals("security") || ss[i].equals("organManagementCenter") || ss[i].equals("webManageCenter")){
                    //管理模块
                    redirectKey = "session.timeout.redirect.url.management";
                    break;
                }
                if( ss[i].equals("usercenter")){
                    //个人中心
                    redirectKey = "session.timeout.redirect.url.usercenter";
                    break;
                }
            }
            //目标页面
            String url = context.getExternalContext().getRequestContextPath() + SystemProperty.getKeyValue(redirectKey);    
            response.sendRedirect(url);
        } catch (Exception e) {
            System.out.println("url redirect wrong ");
        }
    }
}


    这个类可以捕获ViewExpiredException引起的异常,将页面重定向到实现设定的url。com.ppedu.commons.SystemProperty是一个读配置文件的类,读者可以自己实现一个,配置文件设置了三个url,分别指向网站首页、用户中心登陆页和管理中心登录页,设置如下:

#============================================================================
# session过期后的默认页  
#============================================================================
session.timeout.redirect.url.general = /home.jsf
session.timeout.redirect.url.management = /security/managementLogin.jsf
session.timeout.redirect.url.usercenter = /usercenter/login.jsf


    然后,我们创建一个工厂类:

import com.sun.faces.lifecycle.LifecycleFactoryImpl;

public class TeleLifecycleFactoryImpl extends LifecycleFactoryImpl {
    public final static String CUSTOM_LIFECYCLE = "TELEEPOCH";    
    /** Creates a new instance of TeleLifecycleFactoryImpl */
    public TeleLifecycleFactoryImpl() {
        addLifecycle(CUSTOM_LIFECYCLE,new TeleLifecycleImpl());
    }
}

    接着,在faces-config.xml中注册这个工厂类来监查生命周期:


        com.ppedu.view.TeleLifecycleFactoryImpl


    OK,搞定收工,测试一下看看是否能获得预期效果。

你可能感兴趣的:(jsf2,session过期,页面跳转)