【问题标题】:How to share an entity between JSF backing beans?如何在 JSF 支持 bean 之间共享实体?
【发布时间】:2013-12-09 09:38:30
【问题描述】:

我想模块化我的 JSF 2.1 / Java EE 应用程序。我有一个由几个模块组成的页面。每个模块都应该使用一个单独的 JSF 支持 bean。其中一些模块需要显示和更改来自/关于同一实体的一些数据。

我已经尝试了一些方法,但到目前为止我并不满意。我问自己最好的方法是什么?

所有模块都使用相同的实体,如果某些数据发生了变化,它们(可能)需要通知其他支持 bean。

对我已经尝试过的一些方法的评论:

  • 通过接口将实体传递给我的组件 (XHTML) 也不会将它传递给支持 bean
  • 通常不鼓励通过从请求参数中读取 id 在 bean 的 postContruct 方法中加载实体,而建议使用“viewParam”方法
  • 恕我直言,使用“viewParam”不如在创建 bean 后使用实体(在我的 postConstruct 中)。我不确定何时调用 bean 的 setter。

【问题讨论】:

  • 为什么不将实体对象保存在会话中并在所有 bean 中使用它。
  • 我不想让会话膨胀。我正在寻找更适合 JSF 框架的解决方案。在会话中存储一些东西听起来像是一种解决方法。
  • 你肯定需要一个 @SessionScoped/@ApplicationScoped 托管 bean。关于通知的 bean,您需要更具体。
  • 为什么? RequestScope 和 ViewScope 似乎足以满足我的需求。我想实现所有 bean 都使用同一个实体实例,尽管一个 bean 可能会在一个操作中更改它的某些部分。

标签: jsf jsf-2 managed-bean viewparams


【解决方案1】:

尽管它被“普遍劝阻”(谁?),我在我的 JSF-2.2 支持 bean 中使用了以下技术之一(取决于我是否需要 personId 来做其他事情):

@ViewScoped
public class BeanConverter {
    @Inject @Param(name = "personId")
    private ParamValue<Person> curPerson;
}

@ViewScoped
public class BeanConstruct {
    @PersistenceContext
    private EntityManager em;

    @Inject @Param
    private ParamValue<Long> personId;

    private Person curPerson;

    @PostConstruct
    public void init() {
        curPerson = em.find(Person.class, personId.getValue());
    }
}

这使用了Omnifaces 的出色CDI 支持。 然后我使用merge() 更新实体,但在我的情况下,只有一个 bean 可以保存对实体的更改,因此 YMMV。当 bean 需要在它们之间传递更新或实体创建时,我通常会选择javax.enterprise.Events,其中事件将实体作为构造函数参数:

public class BeanSending {
    @Inject
    private Event<PersonCreated> personCreatedEvent;

    public void constructPerson() {
        Person person = makePerson();
        personCreatedEvent.fire(new PersonCreated(person));
    }
}

public class BeanUpdater {
    public void updatePerson(@Observes PersonCreated evt) {
        doStuffWithPerson(evt.getPerson());
    }
}

【讨论】:

  • 我使用“不鼓励”直接从 FacesContext 读取请求参数。它不是指使用@Param 注入属性的解决方案。
  • @ChristopherCudennec 是的,但@Param 只是(一些非常坦率的)糖在上面。原则是所有 bean 都同意一组参数名称,因此它们可以使用相同的实体。
  • 不错。我喜欢将值注入到 bean 中。另一方面,bean 知道参数的名称。
  • @ChristopherCudennec 是的,这是一个缺点。但是从名称到值的映射发生在某处。如果您想保持真正的 DRY,您可以将所有这些参数名称字符串收集在 enum 中。
【解决方案2】:

我认为您需要的是 CDI - Context & Dependency Injection。只需将您的页面切成多个较小的 CDI bean,然后根据需要将它们相互注入即可。

【讨论】:

  • 管理页面不是我对我的问题感兴趣的部分。我所有的支持 bean 已经是可以注入的 CDI bean。我有兴趣分享实体。假设实体是我从数据库中获取的客户。
  • @ChristopherCudennec:如果您已经在使用 CDI bean,只需将客户注入 bean X 的 1 个,然后将该 bean X 注入其他 bean 以共享同一个客户。
  • 我已经试过了。我希望 bean 是自主的,即它们不应该相互认识。
  • @ChristopherCudennec:您似乎正试图将您的应用程序分解为尽可能多的小型独立 bean,然后将这些 bean 混合为不同的组合以用于不同的目的/页面。尽管如此,注入旨在帮助 bean 以自我记录的方式共享它们的资源。如果不想让他们互相认识,就必须用HttpSession的属性等中间人来存储普通客户。会很丑很乱:)
猜你喜欢
  • 1970-01-01
  • 2011-05-09
  • 2012-01-30
  • 2017-07-08
  • 1970-01-01
  • 2012-06-27
  • 2011-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多