【问题标题】:JSF backing bean structure (best practices)JSF 支持 bean 结构(最佳实践)
【发布时间】:2010-10-19 06:20:48
【问题描述】:

我希望在这篇文章中,我可以得到人们对 JSF 页面和 backing beans 之间接口的最佳实践的意见。

我永远无法解决的一件事是我的支持 bean 的结构。此外,我从来没有找到关于这个主题的好文章。

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

请随意回答这些问题以及可能出现的任何其他问题。


关于减少 JSF 页面和支持 bean 之间的耦合,我从不允许 JSF 页面访问任何支持 bean 属性的属性。例如,我从不允许这样的事情:

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

我总是需要类似的东西:

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

支持 bean 值为:

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

例如,当我遍历一个集合时,我会使用一个包装类来避免向下钻取到数据表中的对象。

总的来说,这种方法对我来说是“正确的”。它避免了视图和数据之间的任何耦合。如果我错了,请纠正我。

【问题讨论】:

  • 你能举个例子吗:例如,当我循环一个集合时,我使用一个包装类来避免深入到数据表中的对象。
  • 有关更多信息,请参阅 BalusC 在stackoverflow.com/questions/7223055/…的回答

标签: java jsf


【解决方案1】:

你可能想看看这个:making distinctions between different kinds of JSF managed beans

这里是 Neil Griffin 在上述文章中定义的不同 bean 类型的描述:

  • Model Managed-Bean通常是会话范围。这种类型的托管 bean 参与 MVC 设计模式的“模型”关注点。当你看到“模型”这个词时——想想 DATA。 JSF model-bean 应该是遵循 JavaBean 设计模式的 POJO,其中 getter/setter 封装了属性。模型 bean 最常见的用例是作为数据库实体,或者简单地表示数据库查询结果集中的一组行。
  • 支持 Managed-Bean通常请求范围。这种类型的托管 bean 参与 MVC 设计模式的“视图”关注点。 backing-bean 的目的是支持 UI 逻辑,并且与 JSF 视图或 Facelet 组合中的 JSF 表单具有 1::1 的关系。尽管它通常具有带有关联 getter/setter 的 JavaBean 样式属性,但这些是 View 的属性,而不是底层应用程序数据模型的属性。 JSF backing-beans 也可能有 JSF actionListener 和 valueChangeListener 方法。
  • Controller Managed-Bean通常请求范围。这种类型的托管 bean 参与 MVC 设计模式的“控制器”关注点。控制器 bean 的目的是执行某种业务逻辑并将导航结果返回给 JSF 导航处理程序。 JSF 控制器 bean 通常具有 JSF 操作方法(而不是 actionListener 方法)。
  • 支持 Managed-Bean通常是会话或应用程序范围。 这种类型的 bean “支持”MVC 设计模式的“视图”关注点中的一个或多个视图。典型的用例是向 JSF h:selectOneMenu 提供一个 ArrayList 下拉列表,该下拉列表出现在多个 JSF 视图中。如果下拉列表中的数据对用户来说是特定的,那么 bean 将保留在会话范围内。但是,如果数据适用于所有用户(例如省份的下拉列表),则 bean 将保留在应用程序范围内,以便可以为所有用户缓存。
  • Utility Managed-Bean通常是应用程序范围。这种类型的 bean 为一个或多个 JSF 视图提供某种类型的“实用程序”功能。一个很好的例子可能是可以在多个 Web 应用程序中重用的 FileUpload bean。

【讨论】:

  • 这是一篇很棒的文章。我以前从未见过它,我很高兴你把它贴出来。投票否决的人是疯了。这不是 iceFaces 特有的。
  • 链接到实际文章似乎已经消失了。
  • 可以找到一份副本here
  • 不过,我不知道这个答案目前有 71 票。无论谁按照这些规则实现了他们的 JSF 应用程序,毫无疑问,他们事后肯定会抱怨 JSF 是一个非常不透明的框架,他们的 JSF 应用程序是一大堆代码,他们都责怪 JSF 本身,而不是基于错误的教训和所谓的错误方法。学习了“最佳实践”。
  • 这些 bean 的逻辑是否在浏览器而不是服务器中执行?
【解决方案2】:

很好的问题。当我搬到 JSF 时,我遭受了很多同样的困境。这实际上取决于您的应用程序。我来自 Java EE 世界,因此我建议您的支持 bean 中的业务逻辑尽可能少。如果逻辑纯粹与您的页面的呈现相关,那么将它放在 backing bean 中就可以了。

我相信 JSF 的(许多)优势之一实际上是您可以直接在托管 bean 上公开域对象。因此,我强烈推荐&lt;:outputText value="#{myBean.anObject.anObjectProperty}" /&gt; 方法,否则您最终会在手动公开每个属性时为自己做太多工作。此外,如果您封装了所有属性,则在插入或更新数据时会有点混乱。在某些情况下,单个域对象可能不够用。在这些情况下,我会在将其暴露在 bean 上之前准备一个 ValueObject

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

就 bean 结构而言,我的转折点是当我强行忽略所有关于构建 Web 应用程序的知识并开始将其视为 GUI 应用程序时。 JSF 大量模仿 Swing,因此开发 Swing 应用程序的最佳实践也大多适用于构建 JSF 应用程序。

【讨论】:

  • 感谢您的洞察力。我从来没有真正在摇摆应用程序方面做过很多事情(除了很久以前的学术项目)。摇摆应用有哪些好的原则?另外,为什么在插入和更新值时会一团糟?我觉得一样吗?
【解决方案3】:

我认为你的 backing bean 最重要的是分离它们的逻辑。如果您有一个 CMS 系统的首页,我认为将每段代码放入一个 bean 是一种不好的做法,因为:

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


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

即使问题已标记为已回答,也只需我的 2 美分。

【讨论】:

  • 但是,如果您的 bean 中有一个巨大的对象,并且您有 - 比如说 - 从 JSF 页面挖掘到该对象的 15 个 EL 函数,那么您现在不仅与bean,但对那个对象。因此,很难在不破坏 UI 的情况下移除该对象。
  • 但是你的backing bean不会也被绑定到那个对象上吗?并且您的 UI 与支持 bean 相关联?当您必须修改它时,您将不得不更改 UI 和 bean 中的所有 getter/setter。
【解决方案4】:

我可能不会回答你的每一个问题,因为似乎很少有人会视具体情况而定。

  • 在您的支持 bean 中有一个业务逻辑很好。这取决于你来自哪里。如果您正在实践领域驱动设计,您会很想将业务逻辑包含在支持 bean 中,或者也可能包含持久性逻辑。他们争论为什么这么愚蠢的对象。对象不仅应该携带状态,还应该携带行为。另一方面,如果您考虑传统的 Java EE 做事方式,您可能会觉得在您的支持 bean 中有数据,它也可以是您的实体 bean,以及某些会话 bean 或其他东西中的其他业务和持久性逻辑。那也不错。

  • 为整个页面使用单个支持 bean 非常好。我认为仅此一项没有任何问题。这可能看起来不对,但这取决于具体情况。

  • 您的其他问题更多地取决于您手头的情况。我更愿意在这里进行域驱动,将属性添加到现有的或为此创建一个新的 bean 可能是合适的。哪个更适合。我认为这没有什么灵丹妙药。

  • 哪些属性属于哪个支持 bean。那么,它不依赖于域对象吗?或者问题可能不是那么清楚。

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

【讨论】:

  • 如果——例如——我们要从使用 JDBC 查询创建的自制 POJO 更改为字段名称略有不同的 Hibernate 实体,我们不仅要更改支持 bean .我们还必须更改 JSF 页面。我的代码示例并非如此。只需更换 bean。
  • 在这种情况下,您可以制作支持 bean、实体。那么您只需要更改 JSF 页面。或者这取决于你为什么要更改属性的名称?只有当您重命名字段以匹配您的数据库列名时,这才有意义。但那是完全不同的情况。
【解决方案5】:

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

我确实使用了这个 <:outputtext value="#{myBean.anObject.anObjectProperty}">,因为我通常将支持 bean 作为保存数据对象的操作 bean。我不想在我的支持 bean 中编写一个包装器来访问我的数据对象的属性。

【讨论】:

    【解决方案6】:

    我喜欢在没有 View 的情况下测试业务代码,因此我将 BackingBeans 视为从 View 到 Model 代码的接口。我从未在 BackingBean 中放置任何规则或流程。该代码进入服务或助手,允许重用。

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

    如果您访问 DAO 以填充 Selects、Radios、Checkboxes,请始终在 BackingBean 之外执行此操作。

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

    【讨论】:

      猜你喜欢
      • 2012-05-21
      • 1970-01-01
      • 1970-01-01
      • 2011-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多