【问题标题】:How to access a @Named bean in PhaseListener?如何在 PhaseListener 中访问 @Named bean?
【发布时间】:2012-01-23 16:39:35
【问题描述】:

我们正在使用 JBoss 7.1、MySQL/PostgreSQL DB、JSF 2.0 和 CDI bean。

我必须通过登录名和密码实现基于数据库的身份验证。我们有一个管理(行政)门户。当客户端在未登录的情况下打开受限页面时,如果客户端未登录,则应将请求重定向到login.*页面。

我尝试使用PhaseListener 来做到这一点。 我可以登录和注销,但是当我尝试打开另一个页面时遇到了问题: 我无法在 PhaseListener 类中获取 @Named("user") public class UserManager bean。我试图通过使用FacesContext 和 EL ... 来获得它,但这一切都没有帮助我。

UserManager 验证登录并将登录的用户存储为current 属性。对于每个请求,如果#{user.current} 不是null,我想检查PhaseListener。但我无法在PhaseListener 中获取#{user} bean。

如何在beforePhase()afterPhase() 中获得@Named bean?


更新:这是我目前的尝试:

private boolean loggedIn( FacesContext context ) throws IOException, ServletException
{
    LOGSTORE.debug( "loggedIn().2 " );

    HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
    HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();

//  ELContext elContext = FacesContext.getCurrentInstance().getELContext();
//  UserManager userManager = (UserManager) FacesContext.getCurrentInstance().getApplication()
//      .getELResolver().getValue( elContext, null, "user" );

    HttpSession session = (HttpSession) context.getExternalContext().getSession( true );
    UserManager userManager = (UserManager) session.getAttribute( "user" );

//  UserManager userManager = (UserManager) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get( "user" );

    if (!StringUtils.contains( ((HttpServletRequest) context.getExternalContext().getRequest())
        .getRequestURL().toString(), URL_SESSION_EXPIRED ))
    {

        if (userManager == null || !userManager.isLoggedIn())
        {
            LOGSTORE.debug( " userManager is " + (userManager == null ? "" : "not ") + " null" );
            if (userManager != null)
            {
                LOGSTORE.debug( " userManager.isLoggedIn() is "
                    + (userManager.isLoggedIn() ? "TRUE" : "FALSE") );
            }
            LOGSTORE.debug( " doPhaseFilter() - START REDIRECT " );
            response.sendRedirect( request.getContextPath() + "/" + homepage + "?auth-failed" );
        }
        return false;

    } else
    {
        LOGSTORE.debug( "loggedIn().3 it is " + homepage );
        return true;
    }
}

【问题讨论】:

  • 请显示您在说“我试图通过使用FacesContext,& EL...来获取它,但都没有帮助我”时尝试的代码跨度>
  • 我在上面添加了 sn-p - 我尝试在 SessionPhaseListener 中获取 bean

标签: jpa jsf-2 cdi named phaselistener


【解决方案1】:

会话范围的 CDI 托管 bean 与普通会话范围的 JSF 托管 bean 的存储方式不同。一个会话范围的 JSF 管理确实通过 bean 名称作为键存储在会话中。然而,会话范围的 CDI 托管 bean 通过会话范围中的另一个映射被抽象得更远。

您需要通过以编程方式评估 EL 来获取它,而不是从会话映射中获取它。您的 EL 解析器尝试有一个错误,该值不包含任何 #{} 表达式。

ELContext elContext = FacesContext.getCurrentInstance().getELContext();
UserManager userManager = (UserManager) FacesContext.getCurrentInstance().getApplication()
    .getELResolver().getValue(elContext, null, "user");

相应地修复它:

ELContext elContext = FacesContext.getCurrentInstance().getELContext();
UserManager userManager = (UserManager) FacesContext.getCurrentInstance().getApplication()
    .getELResolver().getValue(elContext, null, "#{user}");

顺便说一句,上面的简写是Application#evaluateExpressionGet()

UserManager userManager = context.getApplication()
    .evaluateExpressionGet(context, "#{user}", UserManager.class);

请注意,FacesContext context 也已作为方法参数存在。

【讨论】:

  • 太棒了!仅使用此示例link,我就徒劳地尝试了各种东西。现在我可以去睡觉了!再次感谢 BalusC。
【解决方案2】:

我使用以下代码从 PhaseListener 中获取对 CDI bean 的引用。

public BeanManager getBeanManager() {
    BeanManager beanManager = null;
    try {
        InitialContext initialContext = new InitialContext();
        beanManager = (BeanManager) initialContext.lookup("java:comp/BeanManager");
    } catch (NamingException e) {
        logger.log(Level.SEVERE, "Couldn't get BeanManager through JNDI", e);
    }
    return beanManager;
}

public <T> T getBean(final Class<T> clazz) {
    BeanManager bm = getBeanManager();
    Bean<T> bean = (Bean<T>) bm.getBeans(clazz).iterator().next();
    CreationalContext<T> ctx = bm.createCreationalContext(bean);
    return (T) bm.getReference(bean, clazz, ctx);
}

所以要获得 bean,你可以像下面这样调用它。

DataManager dataManager = getBean(DataManager.class);

本例中的 bean 是 @Dependent bean,在 PhaseListener 中使用。

【讨论】:

    【解决方案3】:

    希望这一问题在 JSF 的下一个版本中得到修复,该版本具有真正的 CDI 集成。您需要做的(并保持可移植性)是通过 JNDI 查找 BeanManager,然后从 BeanManager 中获取命名的 bean。

    【讨论】:

      【解决方案4】:

      另一种可能性是使用Seam Faces。它是一个可移植的 CDI 扩展,允许您观察faces events

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-11-24
        • 2014-03-10
        • 2013-06-20
        • 2021-07-02
        • 2011-06-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多