我读了BalusC的优秀tutorial on JSF communication,它帮助我建立了我的应用程序的基础知识。我想与SessionScoped BaseBean类中的所有子类共享当前登录的User对象。如果不为需要引用登录用户的每个支持bean注入BaseBean作为@ManagedProperty
,是否可以这样做?
我的课程如下。如果需要更多信息,请告诉我,我很乐意更新我的问题。
所有其他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;
}
}
登录页面的后台bean。为了减少数据库调用次数,我使用上面教程中的@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.
}
这是许多人的一个支持bean的示例。我想引用当前登录的用户以创建报告,但是如果下面的代码运行,则用户将是null
!我可以让它工作的唯一方法是为BaseBean添加一个带有getter和setter的@ManagedProperty
条目,就像在LoginBean类中一样。我真的想避免这种情况,因为我将这个代码复制粘贴到我所拥有的几乎所有支持bean中!
@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";
}
}
我找到的一个解决方案就是直接从FacesContext获取BaseBean的实例(我猜不知道其他bean是不是在同一个上下文中,或者"看不到它?")。下面的代码(来自BaseBean)会做我想要的,但是任何bean子类都必须调用base()
,这看起来很尴尬和错误。
protected FacesContext context = FacesContext.getCurrentInstance();
public BaseBean base() {
return (BaseBean) context.getApplication().evaluateExpressionGet(context, "#{baseBean}", BaseBean.class);
}
答案 0 :(得分:0)
使BaseBean
成为托管bean本身,并将其用作所有其他托管bean的超类是不应该做的两件事。
相反,你可以:
@ManagedBean
删除BaseBean
注释。loggedInUser
保存到会话。将isLoggedIn
保留为BaseBean
中的受保护方法。您可以通过FacesContext
与会话进行会话,并从会话中获取loggedInUser
。
((HttpServletRequest)FacesContext.getCurrentInstance()
.getExternalContext().getRequest()).getSession()
ps:我不知道在提供静态变量时我到底在想什么。
答案 1 :(得分:0)
我可以看到您想要实现身份验证和身份验证控件,然后您可以使用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的优点。
我希望这些信息可以帮到你。
祝你好运。