如何在JSF后端Bean之间共享实体?

3
我希望将我的JSF 2.1 / Java EE应用程序模块化。我有一个页面,由多个模块组成。每个模块应该使用单独的JSF Backing Bean。其中一些模块需要显示和更改来自/在同一实体上的某些数据。
我已经尝试过一些方法,但到目前为止还不满意。我想知道最好的做法是什么?
所有模块都使用相同的实体,并且它们(可能)需要通知其他Backing Bean如果某些数据发生了变化。
对我已经尝试过的一些方法的评论:
- 通过接口将实体传递给我的组件(XHTML)将不会将其传递到Backing Bean。 - 通过从请求参数中读取ID在bean的postContruct方法中加载实体通常不被鼓励,而应使用"viewParam"方法。 - 使用“viewParam”不如在bean创建后(在我的postConstruct中)拥有实体好。我不确定何时调用bean的setter。

为什么不直接将实体对象保存在会话中,并在所有Bean之间使用它呢? - Adarsh
我不想让会话变得臃肿。我正在寻找更适合JSF框架的解决方案。将某些内容存储在会话中听起来像是一种变通方法。 - Christopher Cudennec
你肯定需要一个 @SessionScoped/@ApplicationScoped 托管的 bean。关于通知的 bean,你需要更具体地说明。 - Aritz
为什么?RequestScope和ViewScope对我的需求似乎已经足够了。我想实现所有bean都使用同一个实体实例,尽管一个bean可能会在操作中更改它的某些部分。 - Christopher Cudennec
2个回答

0

尽管这被“通常不鼓励”(由谁?), 但我在我的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能够保存对实体的更改,所以结果可能会有所不同。当bean需要相互通信以更新或创建实体时,我通常使用javax.enterprise.Event,其中事件将实体作为构造函数参数:

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注入属性。 - Christopher Cudennec
@ChristopherCudennec 是的,但是@Param只是一些非常坦率的糖果。原则是所有bean都同意一组参数名称,以便它们可以在同一实体上工作。 - mabi
不错。我喜欢将值注入到Bean中。另一方面,Bean知道参数的名称。 - Christopher Cudennec
@ChristopherCudennec 是的,这是一个缺点。但是从名称到值的映射必须发生在某个地方。如果你想保持真正的DRY,你可能可以将所有这些参数名称字符串收集到一个枚举中。 - mabi

0

我认为你需要的是CDI - 上下文和依赖注入。只需将页面分解成多个较小的CDI bean,并根据需要将它们注入到彼此中即可。


管理页面不是我关心的问题。我的所有后备bean都已经是可以注入的CDI bean。我感兴趣的是共享实体。假设实体是从数据库中获取的客户。 - Christopher Cudennec
如果您已经在使用CDI bean,只需将客户注入到一个bean X中,然后将该bean X注入到其他bean中以共享相同的客户即可。 - Mr.J4mes
我已经尝试过了。我更喜欢豆子是自治的,即它们不应该互相认识。 - Christopher Cudennec
@ChristopherCudennec:看起来你正在尝试将你的应用程序分解为尽可能多的小独立bean,然后在不同的目的/页面中以不同的组合混合这些bean。然而,注入旨在帮助bean以自我记录的方式共享资源。如果您不想让它们彼此了解,您必须使用中间人,例如HttpSession的属性来存储公共客户。这会很丑陋和混乱 :) - Mr.J4mes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接