JSF 支持 bean 结构(最佳实践)

我希望在这篇文章中,我能够得到人们对于 JSF 页面和后台 bean 之间接口的最佳实践的意见。

One thing that I never can settle on is the structure of my backing beans. Furthermore, I have never found a good article on the subject.

哪些属性属于哪些后台 bean?什么时候应该向给定的 bean 添加更多的属性,而不是创建一个新的 bean 并将属性添加到它上面?对于简单的应用程序来说,考虑到将一个 bean 注入到另一个 bean 所涉及的复杂性,在整个页面中只有一个支持 bean 是否有意义?支持 bean 应该包含任何实际的业务逻辑,还是应该严格包含数据?

Feel free to answer these questions and any others that may come up.


As for reducing coupling between the JSF page and the backing bean, I never allow the JSF page to access any backing bean property's properties. For example, I never allow something such as:

<h:outputText value="#{myBean.anObject.anObjectProperty}" />

我总是需要这样的东西:

<h:outputText value="#{myBean.theObjectProperty}" />

支持 bean 值为:

public String getTheObjectProperty()
{
return anObject.getAnObjectProperty();
}

例如,当我在集合上循环时,我使用包装类来避免向下钻取到数据表中的对象。

In general, this approach feels "right" to me. It avoids any coupling between the view and the data. Please correct me if I'm wrong.

75408 次浏览

I might not answer your every question, because few seems quite dependent on case to case.

  • 在您的后台 bean 中有一个业务逻辑是很好的。这取决于你从哪里来。如果您正在实践领域驱动的设计,那么您可能会尝试将业务逻辑包含到备份 bean 中,或者也可能是持久性逻辑。他们争辩说,为什么如此愚蠢的对象。对象不仅应该包含状态,还应该包含行为。另一方面,如果考虑传统的 JavaEE 做事方式,您可能会觉得在后台 bean 中有数据,后台 bean 也可以是您的实体 bean,以及某个会话 bean 或其他东西中的其他业务和持久化逻辑。那也很好。

  • 对于整个页面使用单个后台 bean 非常好。我不觉得这有什么问题。这可能看起来不太对,但这取决于具体情况。

  • 你的另一个问题更多地取决于你手头的情况。我更喜欢在这里使用域驱动,可能适合添加属性到现有的或以其他方式创建一个新的 bean。这样更合适。我不认为有什么灵丹妙药。

  • 哪些属性属于哪个后台 bean。它不是依赖于域对象吗?或者问题不是很清楚。

此外,在您给定的代码示例中,我没有看到任何巨大的好处。

我不需要在每个页面中只保留一个支持 bean。这取决于功能,但是大多数时候,每个页面只有一个 bean,因为大多数情况下,一个页面处理一个功能。例如,在一个页面上,我有一个注册链接(我将链接 RegisterBean)和一个购物篮链接(ShoopingBasketBean)。

我使用 < : outputText value = “ # { myBean.anObject.anObjectProperty }”/> ,因为我通常将后备 bean 作为保存数据对象的操作 bean。我不想在后台 bean 中编写一个包装器来访问数据对象的属性。

问得好。当我转移到 JSF 时,同样的困境让我吃了很多苦头。这真的取决于你的申请。我来自 JavaEE 世界,因此我建议在您的后台 bean 中尽可能少地使用业务逻辑。如果逻辑纯粹与页面的表示相关,那么将其放在后台 bean 中就可以了。

I believe one of the (many) strengths of JSF is actually the fact that you can expose domain objects directly on the managed beans. I would therefore strongly recommend the <:outputText value="#{myBean.anObject.anObjectProperty}" /> approach, otherwise you end up making too much work for yourself in manually exposing each property. Furthermore it would be a bit of a mess when inserting or updating data if you encapsulated all the properties. There are situations where a single domain object may not be sufficient. In those cases I prepare a ValueObject before exposing it on the bean.

编辑: 实际上,如果您要封装您想要公开的每个对象属性,我建议您将 UI 组件绑定到后台 bean,然后将内容直接注入到组件的值中。

在 bean 结构方面,我的转折点是,我强制性地忽略了所有关于构建 Web 应用程序的知识,转而开始将其视为 GUI 应用程序。JSF 非常模仿 Swing,因此开发 Swing 应用程序的最佳实践大多也适用于构建 JSF 应用程序。

我认为对于你的支持 bean 来说最重要的事情就是分离它们的逻辑。如果你有一个 CMS 系统的首页,我认为把每一段代码放在一个 bean 中是不好的做法,因为:

  1. 豆子最终会变得非常大
  2. 如果他们正在对登录页面进行故障排除,如果他们可以轻松地查找 loginBean.java 文件,那么其他人更容易找到他们要查找的内容。
  3. 有时候你有一些小的功能,这些功能与你的其他代码是明显不同的,通过分离这些功能,我可以想象,当你已经有了一个结构良好的漂亮的 bean 时,你可以更容易地重新开发/扩展这些代码,使之变得更大。
  4. 如果/当你不得不使用像 MyBigBean bigBean = new MyBigBean ()这样的声明,而不是使用实际需要的 funksjonality,那么使用一个大 bean 来完成所有的操作,将使它更加依赖于内存。(如果这里我说错了,请纠正我
  5. 在我看来,分开你的豆子就像分开你的方法。您不想要一个运行超过100行的大方法,而是将它与处理特定任务的新方法分开。
  6. 请记住,除了您之外,很可能还有其他人也需要为您的 JSF 项目工作。


至于耦合,我不认为允许 JSF 页面访问 backingbean 中对象的属性是一个麻烦的问题。这是内置在 JSF 中的支持,实际上只是简化了对 imo 的读取和构建。你已经严格分离了 MVC 逻辑。通过这样做,您可以为自己在 backingbean 中节省大量使用 getter 和 setter 的代码行。例如,我有一个非常巨大的对象给我的 Web 服务,我需要在我的演示文稿中使用一些属性。如果我要为每个属性创建一个 getter/setter,我的 bean 将扩展至至少100多行变量和方法来获取属性。通过使用内置的 JSF 功能,我节省了时间和宝贵的代码行。

只是我的2分关于这个问题,即使已经标记为回答。

You might want to check this out: 区分不同类型的 JSF 托管 bean.

下面是 Neil Griffin 在上一篇文章中定义的对不同 bean 类型的描述:

  • Model Managed-Bean : 通常会话范围。这种类型的受管 bean 参与 MVC 设计模式的“模型”关注点。当你看到“模型”这个词时——想想 DATA。JSF 模型 bean 应该是遵循 JavaBean 设计模式的 POJO,其中使用 getters/setter 封装属性。模型 bean 最常见的用例是数据库实体,或者仅仅表示数据库查询结果集中的一组行。
  • 支持托管 bean : 通常请求范围。这种类型的托管 bean 参与 MVC 设计模式的“视图”关注点。后台 bean 的用途是支持 UI 逻辑,它与 JSF 视图或 Faclet 组合中的 JSF 表单有1: : 1的关系。虽然它通常具有 JavaBean 风格的属性和相关的 getter/setter,但这些属性是 View 的属性——而不是底层应用程序数据模型的属性。JSF 后台 bean 还可能具有 JSF actionListener 和 valueChangeListener 方法。
  • Controller Managed-Bean : 通常请求范围。这种类型的受管 bean 参与到 MVC 设计模式的“控制器”关注中。控制器 bean 的用途是执行某种业务逻辑,并将导航结果返回给 JSF 导航处理程序。JSF 控制器-bean 通常具有 JSF 操作方法(而不是 actionListener 方法)。
  • 支持 Managed-Bean : 通常是会话或应用程序范围。这种类型的 bean“支持”MVC 设计模式的“视图”关注点中的一个或多个视图。典型的用例是向出现在多个 JSF 视图中的 JSF h: selectOneMenu 下拉列表提供 ArrayList。如果下拉列表中的数据对于用户是特定的,那么 bean 将保留在会话范围中。但是,如果数据适用于所有用户(比如省份的下拉列表) ,那么 bean 将保留在应用程序范围内,以便可以为所有用户缓存它。
  • Utility Managed-Bean: 通常的应用范围。 This type of bean provides some type of "utility" function to one or more JSF views. A good example of this might be a FileUpload bean that can be reused in multiple web applications.

我喜欢测试没有视图的业务代码,所以我认为 BackingBeans 是从视图到模型代码的接口。我从未在 BackingBean 中放入任何规则或过程。该代码进入服务或帮助程序,允许重用。

如果您使用验证器,请将它们从 BackingBean 中移除,并从验证方法中引用它们。

If you access DAOs for filling Selects, Radios, Checkboxes, do that always out of a BackingBean.

相信我!.您可以将 JavaBean 注入到 BackingBean 中,但是可以尝试将 BackingBean 注入到另一个 BackingBean 中。您很快就会陷入维护和理解代码的噩梦之中。