【问题标题】:Can't @Inject a @ManagedBean in another @ManagedBean不能在另一个 @ManagedBean 中 @Inject @ManagedBean
【发布时间】:2011-07-15 06:29:56
【问题描述】:

好的,这是我的会话 bean。我总是可以从任何 Servlet 或过滤器中检索 currentUser。那不是问题 问题是fileList 和currentFile。我已经用简单的 int 和 Strings 进行了测试,它的效果相同。如果我从我的视图范围 bean 中设置一个值,我可以从另一个类中获取数据。

@ManagedBean(name = "userSessionBean")
@SessionScoped
public class UserSessionBean implements Serializable, HttpSessionBindingListener {

    final Logger logger = LoggerFactory.getLogger(UserSessionBean.class);

    @Inject
    private User currentUser;

    @EJB
    UserService userService;

    private List<File> fileList;   

    private File currentFile;

    public UserSessionBean() {

        fileList = new ArrayList<File>();
        currentFile = new File("");
    }

    @PostConstruct
    public void onLoad() {

        Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
        String email = principal.getName();

        if (email != null) {
            currentUser = userService.findUserbyEmail(email);
        } else {

            logger.error("Couldn't find user information from login!");
        }
    }

这是一个例子。

我的视图范围 bean。这就是它的装饰方式。

 @ManagedBean
 @ViewScoped
 public class ViewLines implements Serializable {

    @Inject
    private UserSessionBean userSessionBean; 

现在是代码。

    userSessionBean.setCurrentFile(file);
    System.out.println("UserSessionBean : " + userSessionBean.getCurrentFile().getName());

我可以完美地看到当前文件名。这实际上是从 jsf 操作方法打印出来的。所以很明显 currentFile 正在被设置。

现在如果我这样做。

@WebFilter(value = "/Download")
public class FileFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {        
        HttpSession session = ((HttpServletRequest) request).getSession(false);
        UserSessionBean userSessionBean = (UserSessionBean) session.getAttribute("userSessionBean");       

        System.out.println(userSessionBean.getCurrentUser().getUserId()); //works

        System.out.println("File filter" + userSessionBean.getCurrentFile().getName()); //doesn't work


        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }
}

currentUser 显示正常,但我看不到文件。它只是空白。字符串、整数等也会发生同样的事情。

感谢您对此提供的任何帮助。

INFO:UserSessionBean:第 3B 行--8531268875812004316.csv(从视图范围 bean 打印的值)

INFO:文件过滤器 tester.csv(运行过滤器时打印的值。)

**编辑**

这行得通。

 FacesContext context = FacesContext.getCurrentInstance();
    userSessionBean = (UserSessionBean) context.getApplication().evaluateExpressionGet(context, "#{userSessionBean}", UserSessionBean.class);

我把它放在 ViewScoped 的构造函数中,一切都很好。现在为什么注入没有按照我的想法进行?起初我想可能是因为我使用的是 JSF 托管 bean 而不是新的 CDI bean。但是我把豆子改成了新的样式(带命名的),效果是一样的。

注入是否只允许您访问 bean 而不能更改它们的属性?

【问题讨论】:

  • 功能需求是什么?您是否意识到 Filter JSF 之前运行?
  • 是的。我基本上想删除会话侦听器中的文件。那也行不通。该文件永远不会在会话 bean 中。我一直在使用过滤器作为测试方法。我还想对用户会话应用一个令牌,这样当他们点击 servlet 时,用户会话对象必须定义该字符串才能下载文件。只是一些额外的安全性。这不是必须的。我想在会话 bean 中再存储一些东西。我现在无法存储任何东西,并且能够访问一个视图范围 bean 之外的数据。
  • 会话监听器应该是正确的工具。如果文件不存在,那么您只是在访问错误的 bean 或覆盖 bean 和/或其他地方的文件列表。运行调试器。
  • 嘿巴鲁斯。使用 faces 上下文在 viewscoped bean 中获取 sessionbean 效果很好。 bean 在过滤器和 servlet 以及 sessionListener 中显示更新的值..!这是怎么回事?

标签: jsf cdi managed-bean inject


【解决方案1】:

关于为什么会发生这种情况,我最好的猜测是因为变量文件被设置在视图范围内,然后通过引用传递到会话范围的 bean 中。可能发生这种情况是因为当视图范围 bean 被销毁时,它仍然具有对该变量的引用,但不会费心查看会话范围内是否有任何其他对它的引用,应该保留它。因此,在这种情况下,当它被销毁时,它会从视图和会话范围中删除。

您可以尝试使用“new”实例化的对象调用 setCurrentFile 吗?这可能证明或反驳我的这个假设。

否则,我最好的建议是打开调试器,查看 getCurrentFile 的确切更改位置。

【讨论】:

  • 是的,我也尝试过使用 new。忘记指定了。 userSessionBean.setCurrentFile(new File(file.getAbsolutePath()));同样的事情。
  • 好的,只要我点击下载按钮,过滤器就会被触发。这是文件对象转到“”的时候。唯一设置该值的是会话 bean 的构造函数。我调试了它,构造函数没有被解雇。我不知道这里发生了什么。
  • 这是一个令人头疼的问题......我会尝试的其他事情:1)更改构造函数以将值设置为疯狂的值,以确保空字符串不是巧合。 2) 使用绝对不引用文件的 File 对象调用 setCurrentFile;编造一些疯狂的道路。 3)在调试器中对该变量设置一个监视,看看你是否可以让它在它被重置的点上中断。 4)我注意到 currentUser 有 Inject 注释。也是豆子吗?也许尝试在该类中包装 fileList 和 currentFile,因为 currentUser 似乎不受这种奇怪行为的影响。
  • 好吧,我又搞砸了。我将当前文件对象设置为另一个文件而不是“”。当我从视图范围的 bean 打印文件名时,它会正确显示。如果我从过滤器打印它,它会显示在构造函数中设置的文件。这真的很奇怪。就像有两个会话bean。我误解了什么注入吗?那应该只给我那个bean的当前实例。更新了原帖。顺便说一句:currentUser 是一个 JPA 实体。
  • 嗯,我自己并没有真正使用过inject注解,所以我不能和它说太多。但我只是注意到您将它与视图范围的 bean 结合使用,所以也可以尝试:1)暂时将 ViewLines 更改为 SessionScope,看看 ViewScope 是否是问题所在。 2)直接访问会话bean,无需注入。我对 JSF 的体验完全基于维护现有的代码库,从我开始我就发现我之前的那个人做了一些有问题的事情,但我可以给你一个代码 sn-p 用于直接访问 SessionBean,如果你需要的话。
【解决方案2】:

您正在混合 JSF 和 CDI。您的 UserSessionBean 是 JSF @ManagedBean,但您使用 CDI @Inject 将其注入另一个 bean。 CDI 不重用 JSF 托管的,而是创建一个全新的。使用其中之一,而不是两者。注入 JSF 管理的 bean 的正确注解是 @ManagedProperty

替换

@Inject
private UserSessionBean userSessionBean; 

通过

@ManagedProperty(value="#{userSessionBean}")
private UserSessionBean userSessionBean; 

并确保您的代码(即 CDI 注释包)中的任何位置都没有 import javax.enterprise.context

或者,将所有 JSF bean 管理注释迁移到 CDI bean 管理注释。

import javax.inject.Named;
import javax.enterprise.context.SessionScoped;

@Named
@SessionScoped
public class UserSessionBean implements Serializable {}

import javax.inject.Named;
import javax.faces.view.ViewScoped;

@Named
@ViewScoped
public class ViewLines implements Serializable {}

额外的好处是您可以在常规 servlet 或过滤器中将其 @Inject 它,而无需手动将其作为请求/会话/应用程序属性获取。

此外,自 JSF 2.3 起,JSF bean 管理注释已被弃用。另见Backing beans (@ManagedBean) or CDI Beans (@Named)?

【讨论】:

  • 玛莎丹基! ;-)
猜你喜欢
  • 2012-03-04
  • 1970-01-01
  • 1970-01-01
  • 2014-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-07
  • 1970-01-01
相关资源
最近更新 更多