【问题标题】:Best Practice In JSF for Forms, Datatables, etc表单、数据表等的 JSF 最佳实践
【发布时间】:2013-04-13 10:57:43
【问题描述】:

我应该为 JSF 中的每个表单、数据表等都有一个 bean 吗?

例如,我有一个注册表格,它只有 2 个字段和一个按钮,它们是: 昵称、密码、提交

应该提交这个表单到一个RegistirationFormBean 还是在UserBean 或UserServiceBean 的某个地方?

最佳做法是什么?

谢谢。

【问题讨论】:

标签: java jsf jakarta-ee model-view-controller managed-bean


【解决方案1】:

调整任何JSF情人的大脑实际上是一个非常有趣的话题,所以我无法抗拒自己,我想详细解释一下。

JSF 的发明背后的一个非常有趣和重要的原因是,像任何 Swing 应用程序一样,将客户端事件连接到服务器端应用程序代码,并显式地摆脱了请求和响应对象的处理。与任何 Swing 应用程序一样,我们现在可以简单地将任何客户端事件(例如,按钮单击)与一些服务器端代码绑定以处理该事件,而无需担心编写 Web 应用程序的事实和复杂性。

因此,在设计任何使用 JSF 的 Web 应用程序时,设计人员可以像设计事件驱动的 Swing 应用程序一样轻松地关注用户体验。因此,您可以设计视图页面并识别事件以执行任务并在视图之间导航。最后,您编写一些要在这些事件中执行的服务器端代码,以完成您想要的工作。这些服务器端代码驻留在您的托管 bean 中。

如果我们根据类型职责来分类,托管bean有几种类型:

  • 模型托管-Bean
  • 支持托管 Bean
  • Controller Managed-Bean
  • 支持托管 Bean
  • 实用程序托管 Bean

您将在this article 中找到每种类型的详细信息。

你的问题是,如何分配Controller Managed-Bean的职责。在分配此类责任时,需要考虑几个问题:

  1. 要完成的任务的复杂性。
  2. 它的可重用性。
  3. 在责任(要做的工作类型)方面的模块化。
  4. 业务角度的模块化。
  5. 将职责分离。等

您可以将您的系统设计为使用单个controller 来查看model 的简单CURD 操作的所有视图。但是,如果您需要在单个 create 操作中处理多个复杂事务,那么将操作分离到多个 controllers 将是更好的设计。虽然您的注册过程非常简单,但您应该使用单独的controller 来处理任务。因为将任何任务放在同一个托管 bean 中并不是一个好主意,这并不简单且相关性不足以与任务“注册”一起驻留。我想这可以结束您的查询!

【讨论】:

    【解决方案2】:

    要决定是否应该专门为页面的组件(例如表单、数据表)创建@ManagedBean,我认为您应该考虑设计中的modularity

    您应该问自己的第一个问题是:Will the component be re-used in many pages?。例如,在ChangePasswordDeleteAccount等敏感页面上,通常会要求用户输入当前密码以验证其身份,然后再执行任何逻辑。在这种情况下,您绝对应该为验证密码组件设置一个专有 bean,这样您就可以一次又一次地重复使用该组件,而不必每次都重新编码验证功能。

    其次,我通常使用@ManagedBean 作为存放所有相关函数的地方,这些函数朝着同一个目标工作。这种功能分组可能非常主观。例如,我可以有一个名为CreateProduct.xhtml 的页面和一个名为CreateProductBean 的bean,它具有创建产品的所有功能。在这种情况下,就像1 bean per view。另一种方法是拥有一个名为ProductManager 的bean,它具有与Product 对象相关的所有功能(即创建、读取、更新、删除)。在这种情况下,它就像1 bean for many views(例如CreateProduct.xhtmlRemoveProduct.xhtml)。为了方便以后的维护和分工,我一般使用1 bean per view。第二种方法1 bean for many views 在某些情况下也很好,但我突然想不出一个例子:P...当我得到一个好的答案时,我会更新我的答案;)。

    第三,我更喜欢遵循 ​​3 层 MVC 模型,将后端逻辑与前端分离。例如,要在数据库中持久化一个新帐户,我将注入一个@EJB@WebServiceRef 以要求后端系统执行必要的逻辑。将来肯定对维护更友好:)。

    所以,使用您的 RegisterAccount 示例,我将拥有

    • 1 个名为 UserExistenceValidator 的 bean 用于检查数据库中是否存在 nickname。在注册过程中,如果用户选择了一个nickname,我会抛出一个错误。我还可以使用这个 bean 来检查AddFriend.xhtml 页面中是否存在用户。
    • 另一个名为 RegistirationFormBean 的 bean 用于捕获用户的输入并与后端对话以保留新帐户。

    【讨论】:

    • CreateProductBean 和 ProductManager bean 那么都是 requestscoped 吗?
    • @KorayTugay:@Scope 是另一个故事:P...CreateProductBean 绝对应该是@​​987654347@。但是,对于ProductManager,您可能需要一个名为List<Product> 的属性来帮助显示产品以进行更新、删除等。在这些情况下,大多数时候我使用@ViewScoped
    • 所有这些都在我发布的与 OP 问题相关的链接中进行了解释。 BalusC 甚至解释了托管 bean 的不同种类及其各自的范围......
    • @LuiggiMendoza:对不起,我认为 BalusC 的解释与我的回答没有任何关系 :)。甚至 BalusC 的回答在某种意义上也与 OP 的问题有关,我的回答更接近于我自己认为在决定应用程序的设计时很重要。
    【解决方案3】:

    在类似的情况下,我总是有一个UserManagedBean来处理用户相关的操作,例如登录、注册、更改密码等...
    为了处理这些操作,我在User(或任何类名)类型的UserManagedBean 中放置了一个属性,该属性对应于与用户相关的持久数据(通常在数据库表用户中)。
    在您的情况下,nicknamepasswordUser 类的属性。至于submit,它将调用UserManagedBean中的一个方法来验证用户:

    <h:inputText value="#{userManagedBean.user.nickname}"/>
    <h:inputSecret value="#{userManagedBean.user.password}"/>
    <h:commandButton value="Login" action="#{userManagedBean.loginUser}"/>
    

    当然,loginUser 方法将调用对服务层的调用,该调用将调用 DAO 层来检查数据库(或其他存储)的凭据。
    如果登录成功,我们的托管 bean 中的用户属性(应该是会话范围的)将使用来自 DB 的返回对象进行初始化。

    【讨论】:

    • 你是否也有类似的情况,如果 UserManagedBean 中的用户不为空,则用户已登录?
    • 你的意思是直接重定向?如果是,那么您应该使用过滤器,您可以在其中实现“记住我”功能和用户已登录时的重定向
    【解决方案4】:

    您应该分别使用一个数据传输对象 bean 和一个域 bean 来进行 ui 提交和数据库中的持久性。 使用控制器类,处理您的 ui jsf 提交数据并创建一个干净的域 bean 并使用它来持久化。

    如果可能,最佳实践应始终将流程/实体解耦。 此外,您的 dto bean 可能具有附件和比域 bean 更多的数据,您可能出于多种目的需要这些数据。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-19
      • 2014-06-21
      • 1970-01-01
      • 1970-01-01
      • 2016-02-28
      • 1970-01-01
      相关资源
      最近更新 更多