【问题标题】:Inject a Entity into a ViewScoped Bean将实体注入 ViewScoped Bean
【发布时间】:2011-06-14 12:24:58
【问题描述】:

我是 CDI 的新手,想将它用于 JSF2 应用程序。 MyUser 类是一个简单的@Entity-Bean,并且在 bean 中的 @PostConstruct 方法中创建了一个对象:

@Stateful
@Named @javax.faces.bean.SessionScoped
public class UserBean implements Serializable
{
    @Named
    private MyUser user;

    //setter and getter
    //@PostConstruct
}

在 JSF 页面中访问用户就像一个魅力:#{user.lastName}。但现在我想从其他 bean 访问这个对象,例如在这个@ViewScopedBean:

@Named @javax.faces.bean.ViewScoped
public class TestBean implements Serializable
{       
    @Inject private MyUser user;
}

我希望当前(登录)MyUser user 可以在其他几个 bean 中使用,但我不确定如何执行此操作。简单地@Injecting 它不起作用(我很确定这对于 simple 来说有点小意思)。

13:56:22,371 ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController]
Error installing to Start: name=vfs:///Applications/Development/
jboss-6.0.0.Final/server/default/deploy/test.ear_WeldBootstrapBean state=Create:
org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied
dependencies for type [MyUser] with qualifiers [@Default] at injection
point [[field] @Inject private test.controller.mbean.TestBean.user]

从其他 bean 访问 user 的最佳方法是什么?像 UserBean bean = (UserBean)FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("UserBean"); 这样的 JSF1.2 样式代码似乎已经过时了!

【问题讨论】:

    标签: java cdi jboss-weld


    【解决方案1】:

    首先:您不想直接注入实体。实体完全由 ORM 框架独立控制,并有自己的生命周期。不要将它们用作托管 bean。

    根据这个定义,JPA 实体受技术管理 豆子。然而,实体有他们的 拥有特殊的生命周期、状态和 身份模型,通常是 由 JPA 或使用 new 实例化。 所以不直接推荐 注入实体类。我们 特别建议不要分配 @Dependent 以外的范围 实体类,因为 JPA 无法 持久化注入的 CDI 代理。

    详情请见here。

    回答您的问题:您不能“输出”类似(经过身份验证的)用户之类的东西,即使这在 Seam 2 中是可能的,但 CDI 的整个代理机制不再允许这样做。您需要做的是:

    • 编写一个托管 bean 来处理身份验证并将其放入正确的范围(可能是会话范围)。
    • 如果登录成功,则使用此 bean 的属性来存储经过身份验证的用户。
    • 使用生产者方法(可能带有@LoggedIn 之类的限定符)使用户在您的应用程序中可用

    像这样注入用户:

    @Inject
    @LoggedIn
    private User user
    

    这就是 CDI 方式 ;-)

    【讨论】:

    • 感谢您的回答帮助我了解 CDI。使用您提供的关键字,我还找到了这个oracle.com/technetwork/articles/javaee/…,它的工作原理与您的示例一样。我唯一想知道的是@LoggedIn 注释。这里不能解决! @Poduces 被解析为 javax.enterprise.inject.Produces。
    • @LoggedIn 是一个限定符 - 您自己的注释 :-)。这就是 CDI 中类型安全的工作原理:只要有超过一个特定类型的 bean(比如用户),您就需要告诉容器您要注入哪个用户——这是通过限定符实现的。更多详情请看这里:docs.jboss.org/weld/reference/latest/en-US/html/…
    【解决方案2】:

    @Inject ed bean 也是 @Named bean 吗?

    如果是,则 MyUser bean 的范围小于 TestBean。请记住,@ViewScoped bean 的托管属性必须是 @ViewScoped、@SessionScoped 或 @ApplicationScoped

    【讨论】:

    • 是的,看代码。两个 bean 都是@Named。我想从@ViewScoped bean 访问@SessionScoped bean 的属性。
    • 您对纯 JSF 是正确的,您必须关心这个问题。如果您使用 CDI,例如MyFaces CODI,您不必再关心它了。
    【解决方案3】:

    CDI 未指定 @ViewScoped 注释。这是一个 JSF2 注释。唯一允许的注释是:@RequestScoped、@SessionScoped、@ApplicationScoped、@Dependent 和 @ConversationScoped。前三个是 CDI 允许的唯一 JSF 范围。

    如果你需要支持@ViewScope注解,你需要自己写。幸运的是,someone else has done this before。

    【讨论】:

    • 两个范围都是从包javax.faces.bean 导入的(上面的代码已更新)幸运的是SeamFaces 模块可用,我会尝试使用它。我仍然想知道在这种情况下是否允许将@Inject 属性放入另一个 bean 的 方法。
    • 好吧,至少 seam-faces 是可用的,因为我对它有 maven 依赖...
    • MyFaces CODI 和 SeamFaces 都将 ViewScoped 注释转换为 CDI Scope。注意你现在使用哪一个,因为 SeamFaces 转换器被 Weld 破坏了 (issues.jboss.org/browse/SEAMFACES-44)
    猜你喜欢
    • 2015-04-15
    • 2011-06-08
    • 2011-12-29
    • 2013-05-11
    • 1970-01-01
    • 2012-11-14
    • 1970-01-01
    • 2014-02-14
    • 2011-06-11
    相关资源
    最近更新 更多