根据用户权限导航到preRenderViewEvent中的其他页面; ExternalContext#dispatch()不起作用 [英] Navigate to a different page in preRenderViewEvent depending on user permission; ExternalContext#dispatch() does not work

查看:182
本文介绍了根据用户权限导航到preRenderViewEvent中的其他页面; ExternalContext#dispatch()不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

仅当用户有权查看该页面时,才应呈现该页面.我尝试通过在PreRenderView事件侦听器方法中执行检查来实现这一点:

The page should be rendered only if user has permissions to see it. I try to achieve that by performing a check in PreRenderView event listener method:

<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();
        }
    }
}

当我尝试查看被拒绝的页面时,我看到了它,但是在服务器日志中出现了异常:

When I try to look at denied page I see it, but get an exception in server log:

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()立即返回null.但这不会中断当前阶段.因此,在阶段结束时,将执行PhaseListener.它尝试获取FacesContext实例,但获取null.

The cause: immediately after dispatch call, FacesContext.getCurrentInstance() returns null. But this don't interrupt current phase. So on the phase end PhaseListener is executed. It tries to get FacesContext instance, but gets null.

我可以在这里避免执行PhaseListener吗? 还是可能要检查FacesContext当前实例是否不为null,应该将其添加到omnifaces?

Can I avoid PhaseListener execution here? Or may be check for FacesContext current instance is not null should be added to omnifaces?

谢谢.

推荐答案

请勿使用 NavigationHandler 或使用 ExternalContext#redirect() .

Do not use 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>):

When you're already on JSF 2.2, use <f:viewAction action="#{bean.init}"> which supports a navigation case outcome (like <h:commandButton action>):

public String init() {
    // ...
    return "someViewId";
}

或者当您仍在使用JSF 2.0/2.1时,因此只能使用<f:event type="preRenderView">,并且鉴于您正在使用OmniFaces,请使用其

Or when you're still on JSF 2.0/2.1, and can thus only use <f:event type="preRenderView">, and given that you're using OmniFaces use its Faces#navigate() or Faces#redirect():

public void init() {
    // ...
    Faces.navigate("someViewId");
}

如果您不使用OmniFaces,请按照以下步骤进行操作:

In case you aren't using OmniFaces, here's how it's implemented:

public void init() {
    // ...
    FacesContext context = FacesContext.getCurrentInstance();
    context.getApplication().getNavigationHandler().handleNavigation(context, null, "someViewId");
}

请注意,当使用@PostConstruct而不是f:viewActionpreRenderView时,这一切仍然可能失败.另请参阅在@PostConstruct中重定向会导致IllegalStateException .

Note that this all may still fail when using @PostConstruct instead of f:viewAction or preRenderView. See also a.o. Redirect in @PostConstruct causes IllegalStateException.

这篇关于根据用户权限导航到preRenderViewEvent中的其他页面; ExternalContext#dispatch()不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆