许多@RequestScoped子类访问来自@SessionScoped bean的变量,而不复制粘贴@ManagedP



我阅读了BalusC关于JSF通信的优秀教程,它帮助我建立了应用程序的基础。我想将SessionScoped BaseBean类中设置的当前登录的User对象与其所有子类共享。在不为每个需要引用登录用户的备份bean注入BaseBean作为@ManagedProperty的情况下,可以做到这一点吗?

下面列出了我的课程。如果需要更多信息,请告诉我,我很乐意更新我的问题。

BaseBean类

所有其他bean都是这个bean的子类。我这样做是为了允许代码在bean之间重用。

@ManagedBean
@SessionScoped
public class BaseBean {
    @EJB
    protected UserDao userDao;
    // Other DAOs along with methods (like isLoggedIn()) shared between beans
    private User loggedInUser;
    public User getLoggedInUser() {
        return loggedInUser;
    }
    public void setLoggedInUser(User user) {
        loggedInUser = user;
    }
    public boolean isLoggedIn() {
        return loggedInUser != null;
    }
}

LoginBean类

登录页面的后台bean。为了减少DB调用的数量,我使用了上面教程中的@ManagedProperty方法来设置@SessionScoped BaseBean中的User对象。现在登录并设置loggedInUser可以正常工作。

@ManagedBean
@RequestScoped
public class LoginBean extends BaseBean {
    @ManagedProperty(value = "#{baseBean}")
    protected BaseBean baseBean;
    private String username;
    private String password;
    public String login() {
        Subject currentUser = SecurityUtils.getSubject();
        try {
            currentUser.login(username, password);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            baseBean.setLoggedInUser(userDao.getUser(username));
        }
        return "index";
    }
    public String getUserFirstName() {
        return baseBean.getLoggedInUser().getFirstName();
    }
    // Getters and Setters, including for the @ManagedProperty baseBean.
}

CreateReport类

这是多个后台bean中的一个例子。我想引用当前登录的用户来创建报告,但如果运行以下代码,则用户将是null!我能让它工作的唯一方法是像在LoginBean类中一样,为BaseBean添加一个带有getter和setter的@ManagedProperty条目。我真的很想避免这种情况,因为我将把这段代码复制粘贴到我拥有的几乎每一个backingbean上!

@ManagedBean
@RequestScoped
public class CreateReport extends BaseBean {
    private Report report = new Report();
    public String createReport() {
        report.setOwner(getLoggedInUser()); // Use inherited method
                                            // instead of DI-ing BaseBean
        reportDao.create(report);
        return "index";
    }
}

使用过的软件

  • 玻璃鱼4
  • Mojarra 2.2

编辑

我发现的一个解决方案是直接从FacesContext中获取BaseBean的实例(我想其他bean不在同一上下文中,或者"看不到?")。下面的代码(来自BaseBean)可以做我想做的事情,但是任何bean子类都必须调用base(),这似乎很尴尬和错误。

protected FacesContext context = FacesContext.getCurrentInstance();
public BaseBean base() {
    return (BaseBean) context.getApplication().evaluateExpressionGet(context, "#{baseBean}", BaseBean.class);
}

我可以看到您想要实现身份验证和身份验证控制,然后可以使用JSF过滤器。您可以将BaseBean类保留为会话范围,创建一个实现javax.servlet.Filter的新类,并在该类中使BaseBean类通过会话,例如:

public class LoginFilter implements javax.servlet.Filter {
    @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {    
    HttpServletRequest req = (HttpServletRequest) request;
    BaseBean base = (BaseBean) req.getSession().getAttribute("baseBean");
    if (base != null && base.isLoggedIn()) {
        // to do something
        chain.doFilter(request, response);
    } else {
        // to do something
        HttpServletResponse res = (HttpServletResponse) response;
        res.sendRedirect(req.getContextPath() + "/index.xhtml");
    }
}
public void init(FilterConfig config) throws ServletException {
    // to do something
}
public void destroy() {
    // to do something
}   
}

现在,如果你想用BaseBean类创建一个报告,你可以得到会话的BaseBean类:

BaseBean base = (BaseBean) ( FacesContext.getCurrentInstance()
    .getExternalContext().getRequest()).getSession().getAttribute("baseBean") );

那么,在您的案例中,我的建议是避免继承并使用JSF的优势。

我希望这些信息对你有所帮助。

祝你好运。

使BaseBean本身成为托管bean,并将其用作所有其他托管bean的超类,这两件事是不应该做的。

相反,您可以:

  • BaseBean中删除@ManagedBean注释
  • loggedInUser保存到会话
  • 在CCD_ 11中保留CCD_。您将能够通过那里的FacesContext到达会话,并从会话中获得loggedInUser

    ((HttpServletRequest)FacesContext.getCurrentInstance() .getExternalContext().getRequest()).getSession()

ps:我不知道当我提供一个静态变量时,我到底在想什么。

最新更新