返回到在jsf中销毁的会话的欢迎页面

时间:2012-01-15 09:29:03

标签: java jsf glassfish

我已经实现了一个会话监听器。我希望当用户在会话被销毁后尝试使用该网站时,他应该被重定向到欢迎页面(登录页面)。 我已经通过loging?faces-redirect=true尝试了这个,但我必须先点击两次才能真正重定向到登录页面。 此外,当会话在欢迎页面(登录页面)上到期时。应用程序崩溃,如以下错误所示:

    WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception
javax.faces.application.ViewExpiredException: viewId:/loginpage.xhtml - View /loginpage.xhtml could not be restored.
        at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:205)
        at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
        at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:116)
        at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
        at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
        at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
        at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
        at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
        at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
        at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
        at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
        at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
        at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
        at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
        at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
        at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
        at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
        at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
        at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
        at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
        at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
        at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
        at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
        at java.lang.Thread.run(Thread.java:662)

我在netbeans上使用primefaces 3.0,glassfish 3.1.1 感谢。

2 个答案:

答案 0 :(得分:1)

如果用户未经过身份验证,您可以使用servlet过滤器或JSF阶段侦听器重定向到登录页面。

答案 1 :(得分:0)

我们的申请中也有类似的问题。以下是我们最终使用的解决方案。我们使用阶段监听器在会话过期时重定向到登录页面(并且它们不在登录页面上)。然后,我们使用自定义视图处理程序来防止用户在登录页面上遇到过期的会话。基本上,如果我们在登录页面上看到会话已过期,我们会创建一个新会话。

注意:标记了需要针对特定​​用例更新的部分代码。 我们通过汇总我们在网上发现的具体问题的几个例子,提出了这种方法。一些参考文献是:

http://www.gregbugaj.com/?p=164

https://stackoverflow.com/a/6816513/2212458

https://stackoverflow.com/a/4992869/2212458

这是阶段监听器,负责确保访问者有会话并将其转发到登录页面,如果他们没有会话(例如它已过期)。它还执行另外两项检查。它确保他们有一个会话,他们是经过身份验证(登录),并确保他们有权访问他们正在访问的页面。

import javax.faces.application.NavigationHandler;
import javax.faces.context.FacesContext;
import javax.faces.event.*;
import javax.servlet.http.HttpSession;

/**
 * A phase listener.  Runs after the restore view phase.  Makes sure that the user is logged on
 * to view any page other than the login page.
 */
public class AuthorizationListener implements PhaseListener
{
    /**
     * Called after phase executes.  Makes sure we are logged in if we are not on the login page.
     * @param phaseEvent
     */
    @Override
    public void afterPhase(PhaseEvent phaseEvent)
    {
        // get page we are on
        FacesContext facesContext = phaseEvent.getFacesContext();
        String currentPage = facesContext.getViewRoot().getViewId();

        // determine if we are on the login page
        boolean isLoginPage = currentPage.contains("login"); <--- CHANGE
        if (isLoginPage)
        {
            return;
        }

        // get session - do not create one if it does not exist
        HttpSession session = (HttpSession) facesContext.getExternalContext().getSession(false);

        // no session is present
        if(session==null)
        {
            NavigationHandler nh = facesContext.getApplication().getNavigationHandler();
            nh.handleNavigation(facesContext, null, "login?faces-redirect=true&reason=expired"); <--- CHANGE
            return;
        }

        // if not logged in send to login page
        if (USER IS NOT LOGGED IN) <--- CHANGE
        {
            NavigationHandler nh = facesContext.getApplication().getNavigationHandler();
            nh.handleNavigation(facesContext, null, "login?faces-redirect=true&reason=expired"); <--- CHANGE
            return;
        }

        // they are logged in, make sure they have rights to page they are visiting
        if (USE DOES NOT HAVE RIGHTS TO THE PAGE THEY ARE VISITING) <--- CHANGE
        {
            // user does not have privilege to go to this page
            NavigationHandler nh = facesContext.getApplication().getNavigationHandler();
            nh.handleNavigation(facesContext, null, accessDenied); <--- CHANGE
        }
    }

    /**
     * Called before phase executes.  Does nothing.
     * @param phaseEvent the phase event
     */
    @Override
    public void beforePhase(PhaseEvent phaseEvent)
    {
        // intentionally left blank
    }

    /**
     * Identifies the phase we want to listen and respond to.
     * @return the phase
     */
    @Override
    public PhaseId getPhaseId()
    {
        return PhaseId.RESTORE_VIEW;
    }
}

以下是负责在登录页面上停止会话过期的自定义视图处理程序。

import javax.faces.application.ViewHandler;
import javax.faces.application.ViewHandlerWrapper;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import java.io.IOException;

/**
 * This class adds additional behavior to the facelet view handler.  Specifically it
 * prevents the user from experiencing session/view timeout errors at the login screen.
 */
public class CustomViewHandler extends ViewHandlerWrapper
{
    /** The default view handler we are adding extra behavior to. */
    private ViewHandler wrapped;

    /**
     * Constructor.
     * @param wrapped the wrapped handler.  Ref.
     */
    public CustomViewHandler(ViewHandler wrapped)
    {
        super();
        this.wrapped = wrapped;
    }

    /**
     * Expose the wrapped handler (required by base class).
     * @return the handler.  Ref.
     */
    @Override
    public ViewHandler getWrapped()
    {
        return wrapped;
    }

    /**
     * Called when a view is restored.  Prevents expiration on login page.
     * @param facesContext the context for this request
     * @param viewId the view identifier for the current request
     * @return the restored view
     */
    @Override
    public UIViewRoot restoreView(FacesContext facesContext, String viewId)
    {
        // have the wrapped handler restore the view
        UIViewRoot root = super.restoreView(facesContext, viewId);

        // if there was no view to restore (maybe because it expired)
        if (root == null)
        {
            // if the view expired on the login page make a new view, don't allow login page to expire
            if ( viewId.contains("login") ) <--- CHANGE
            {
                // create a new view
                // for some reason the starting slash is required else we get errors in server log about not finding the page
                root = createView(facesContext, "/" + "login"); <--- CHANGE
                // saves view - without this session never gets created so we will just keep hitting this code
                facesContext.renderResponse();
            }
        }

        return root;
    }

    /**
     * Called when a view is rendered.  Does nothing but log a message.
     * @param context the context for this request
     * @param viewToRender the view to render
     * @throws IOException thrown if an input/output error occurs in wrapped handler
     */
    @Override
    public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException
    {
        super.renderView(context, viewToRender);
    }
}

使用此代码需要更改配置文件。

添加到faces-config.xml

<view-handler>PACKAGE.CustomViewHandler</view-handler> <--- CHANGE
<lifecycle>
    <phase-listener>PACKAGE.AuthorizationListener</phase-listener> <--- CHANGE
</lifecycle>

添加到web.xml

<error-page>
    <exception-type>javax.faces.application.ViewExpiredException</exception-type>
    <location>/login.xhtml?reason=expired</location> <--- CHANGE
</error-page>-<session-config><session-timeout> 10 </session-timeout></session-config>
<listener><listener-class> com.sun.faces.config.ConfigureListener </listener-class></listener>