根据用户权限导航到 preRenderViewEvent 中的不同页面; ExternalContext#dispatch() 不起作用
Navigate to a different page in preRenderViewEvent depending on user permission; ExternalContext#dispatch() does not work
仅当用户有权查看该页面时才应呈现该页面。我尝试通过在 PreRenderView 事件侦听器方法中执行检查来实现这一点:
<f:event type="preRenderView" listener="#{theBean.init}" />
以及方法本身:
public void init() {
if (user.havePermission()) {
// backing bean init
} else {
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.getRequestMap().put("message", no_permissions_message);
try {
ec.dispatch(ec.getRequestContextPath()
+ path_to_no_perm_page);
fc.responseComlete();
} catch (IOException e) {
e.printStackTrace();
}
}
}
当我尝试查看被拒绝的页面时,我看到了它,但在服务器日志中出现异常:
at org.omnifaces.util.FacesLocal.getRequestMap(FacesLocal.java:945) [omnifaces-1.7.jar:1.7]
at org.omnifaces.util.FacesLocal.getRequestAttribute(FacesLocal.java:953) [omnifaces-1.7.jar:1.7]
at org.omnifaces.util.Faces.getRequestAttribute(Faces.java:1416) [omnifaces-1.7.jar:1.7]
at org.omnifaces.eventlistener.CallbackPhaseListener.getCallbackPhaseListeners(CallbackPhaseListener.java:110) [omnifaces-1.7.jar:1.7]
at org.omnifaces.eventlistener.CallbackPhaseListener.afterPhase(CallbackPhaseListener.java:77) [omnifaces-1.7.jar:1.7]
at com.sun.faces.lifecycle.Phase.handleAfterPhase(Phase.java:189) [jsf-impl-2.1.7-jbossorg-2.jar:]
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:107) [jsf-impl-2.1.7-jbossorg-2.jar:]
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139) [jsf-impl-2.1.7-jbossorg-2.jar:]
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:98) [primefaces-4.0.7.jar:4.0.7]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:62) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
...
原因:调度调用后,FacesContext.getCurrentInstance() returns 立即为空。但这不会中断当前阶段。因此在阶段结束时执行 PhaseListener。它试图获取 FacesContext 实例,但得到的是空值。
这里可以避免PhaseListener的执行吗?
或者可能会检查 FacesContext 当前实例是否不应该添加到 omnifaces?
谢谢。
不要使用ExternalContext#dispatch()
, ever. This method has no single sensible use case in a decent JSF web application. It only corrupts the JSF life cycle because it creates another FacesContext
within the current request. You should use JSF's own NavigationHandler
or use ExternalContext#redirect()
。
如果您已经在使用 JSF 2.2,请使用支持导航案例结果的 <f:viewAction action="#{bean.init}">
(如 <h:commandButton action>
):
public String init() {
// ...
return "someViewId";
}
或者当您仍在使用 JSF 2.0/2.1 时,因此只能使用 <f:event type="preRenderView">
,并且假设您使用的是 OmniFaces,请使用它的 Faces#navigate()
or Faces#redirect()
:
public void init() {
// ...
Faces.navigate("someViewId");
}
如果您没有使用 OmniFaces,下面是它的实现方式:
public void init() {
// ...
FacesContext context = FacesContext.getCurrentInstance();
context.getApplication().getNavigationHandler().handleNavigation(context, null, "someViewId");
}
请注意,当使用 @PostConstruct
而不是 f:viewAction
或 preRenderView
时,这一切仍可能会失败。另见 a.o。 Redirect in @PostConstruct causes IllegalStateException.
仅当用户有权查看该页面时才应呈现该页面。我尝试通过在 PreRenderView 事件侦听器方法中执行检查来实现这一点:
<f:event type="preRenderView" listener="#{theBean.init}" />
以及方法本身:
public void init() {
if (user.havePermission()) {
// backing bean init
} else {
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.getRequestMap().put("message", no_permissions_message);
try {
ec.dispatch(ec.getRequestContextPath()
+ path_to_no_perm_page);
fc.responseComlete();
} catch (IOException e) {
e.printStackTrace();
}
}
}
当我尝试查看被拒绝的页面时,我看到了它,但在服务器日志中出现异常:
at org.omnifaces.util.FacesLocal.getRequestMap(FacesLocal.java:945) [omnifaces-1.7.jar:1.7]
at org.omnifaces.util.FacesLocal.getRequestAttribute(FacesLocal.java:953) [omnifaces-1.7.jar:1.7]
at org.omnifaces.util.Faces.getRequestAttribute(Faces.java:1416) [omnifaces-1.7.jar:1.7]
at org.omnifaces.eventlistener.CallbackPhaseListener.getCallbackPhaseListeners(CallbackPhaseListener.java:110) [omnifaces-1.7.jar:1.7]
at org.omnifaces.eventlistener.CallbackPhaseListener.afterPhase(CallbackPhaseListener.java:77) [omnifaces-1.7.jar:1.7]
at com.sun.faces.lifecycle.Phase.handleAfterPhase(Phase.java:189) [jsf-impl-2.1.7-jbossorg-2.jar:]
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:107) [jsf-impl-2.1.7-jbossorg-2.jar:]
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139) [jsf-impl-2.1.7-jbossorg-2.jar:]
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:98) [primefaces-4.0.7.jar:4.0.7]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
at org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:62) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
...
原因:调度调用后,FacesContext.getCurrentInstance() returns 立即为空。但这不会中断当前阶段。因此在阶段结束时执行 PhaseListener。它试图获取 FacesContext 实例,但得到的是空值。
这里可以避免PhaseListener的执行吗? 或者可能会检查 FacesContext 当前实例是否不应该添加到 omnifaces?
谢谢。
不要使用ExternalContext#dispatch()
, ever. This method has no single sensible use case in a decent JSF web application. It only corrupts the JSF life cycle because it creates another FacesContext
within the current request. You should use JSF's own NavigationHandler
or use ExternalContext#redirect()
。
如果您已经在使用 JSF 2.2,请使用支持导航案例结果的 <f:viewAction action="#{bean.init}">
(如 <h:commandButton action>
):
public String init() {
// ...
return "someViewId";
}
或者当您仍在使用 JSF 2.0/2.1 时,因此只能使用 <f:event type="preRenderView">
,并且假设您使用的是 OmniFaces,请使用它的 Faces#navigate()
or Faces#redirect()
:
public void init() {
// ...
Faces.navigate("someViewId");
}
如果您没有使用 OmniFaces,下面是它的实现方式:
public void init() {
// ...
FacesContext context = FacesContext.getCurrentInstance();
context.getApplication().getNavigationHandler().handleNavigation(context, null, "someViewId");
}
请注意,当使用 @PostConstruct
而不是 f:viewAction
或 preRenderView
时,这一切仍可能会失败。另见 a.o。 Redirect in @PostConstruct causes IllegalStateException.