返回在 jsf 中销毁的会话的欢迎页面 [重复]
Posted
技术标签:
【中文标题】返回在 jsf 中销毁的会话的欢迎页面 [重复]【英文标题】:returning to welcome page on session destroyed in jsf [duplicate] 【发布时间】:2012-02-10 17:28:30 【问题描述】:我已经实现了一个会话监听器。我希望当用户在会话被破坏后尝试使用该站点时,他应该被重定向到欢迎页面(登录页面)。
我已经通过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 谢谢。
【问题讨论】:
我认为你应该向我们展示你的会话监听器 【参考方案1】:如果用户未通过身份验证,您可以使用 servlet 过滤器或 JSF 阶段侦听器重定向到登录页面。
【讨论】:
JSF 相位监听器在这种情况下并不是一个非常理想的解决方案。应该使用 Servlet 过滤器。【参考方案2】:我们在应用程序中遇到了类似的问题。以下是我们最终使用的解决方案。我们使用阶段监听器在会话过期的情况下重定向到登录页面(并且它们不在登录页面上)。然后,我们使用自定义视图处理程序来防止用户在登录页面上遇到过期会话。基本上,如果我们在登录页面上看到会话已过期,我们会创建一个新的。
注意:针对特定用例需要更新的部分代码已标记。 我们针对我们在网上发现的特定问题汇总了几个示例,从而提出了这种方法。部分参考资料如下:
http://www.gregbugaj.com/?p=164
https://***.com/a/6816513/2212458
https://***.com/a/4992869/2212458
这里是阶段监听器,负责确保访问者有会话,如果没有会话(例如过期时),则将其转发到登录页面。它还执行其他 2 项检查。它确保他们是否有会话,他们是否已通过身份验证(登录),并确保他们有权访问他们正在点击的页面。
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>
【讨论】:
以上是关于返回在 jsf 中销毁的会话的欢迎页面 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
JSF 中的 ViewExpiredException [重复]