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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/746047/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 19:00:31  来源:igfitidea点击:

JSF backing bean structure (best practices)

javajsf

提问by Zack Marrapese

I hope that in this post, I can get people's opinions on best practices for the interface between JSF pages and backing beans.

我希望在这篇文章中,我可以得到人们对 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 的结构。此外,我从来没有找到一篇关于这个主题的好文章。

What properties belong on which backing beans? When is it appropriate to add more properties to a given bean as opposed to creating a new bean and adding the properties onto it? For simple applications, does it make sense to just have a single backing bean for the whole page, considering the complexity involved with injecting one bean into another? Should the backing bean contain any actual business logic, or should it strictly contain data?

哪些属性属于哪些支持 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:

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

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

I always require something like:

我总是需要这样的东西:

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

with a backing bean value of:

支持 bean 值为:

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

When I loop over a collection, I use a wrapper class to avoid drilling down into an object in a data table, for instance.

例如,当我循环遍历一个集合时,我使用一个包装类来避免深入到数据表中的对象。

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.

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

采纳答案by Chris Dale

You might want to check this out: making distinctions between different kinds of JSF managed beans.

您可能想检查一下:区分不同种类的 JSF 托管 bean

Here is a description of the different bean types, as defined in the above article by Neil Griffin:

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

  • Model Managed-Bean: Normally session scope.This type of managed-bean participates in the "Model" concern of the MVC design pattern. When you see the word "model" -- think DATA. A JSF model-bean should be a POJO that follows the JavaBean design pattern with getters/setters encapsulating properties. The most common use case for a model bean is to be a database entity, or to simply represent a set of rows from the result set of a database query.
  • Backing Managed-Bean: Normally request scope.This type of managed-bean participates in the "View" concern of the MVC design pattern. The purpose of a backing-bean is to support UI logic, and has a 1::1 relationship with a JSF view, or a JSF form in a Facelet composition. Although it typically has JavaBean-style properties with associated getters/setters, these are properties of the View -- not of the underlying application data model. JSF backing-beans may also have JSF actionListener and valueChangeListener methods.
  • Controller Managed-Bean: Normally request scope.This type of managed-bean participates in the "Controller" concern of the MVC design pattern. The purpose of a controller bean is to execute some kind of business logic and return a navigation outcome to the JSF navigation-handler. JSF controller-beans typically have JSF action methods (and not actionListener methods).
  • Support Managed-Bean: Normally session or application scope.This type of bean "supports" one or more views in the "View" concern of the MVC design pattern. The typical use case is supplying an ArrayList to JSF h:selectOneMenu drop-down lists that appear in more than one JSF view. If the data in the dropdown lists is particular to the user, then the bean would be kept in session scope. However, if the data applies to all users (such as a dropdown lists of provinces), then the bean would be kept in application scope, so that it can be cached for all users.
  • Utility Managed-Bean: Normally application scope.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.
  • 模型 Managed-Bean通常是会话范围。这种类型的托管 bean 参与了 MVC 设计模式的“模型”关注点。当你看到“模型”这个词时——想想数据。JSF 模型 bean 应该是一个 POJO,它遵循 JavaBean 设计模式,使用 getter/setter 封装属性。模型 bean 最常见的用例是作为一个数据库实体,或者简单地表示来自数据库查询结果集中的一组行。
  • 支持 Managed-Bean通常是请求范围。这种类型的托管 bean 参与了 MVC 设计模式的“视图”关注点。后台bean 的目的是支持UI 逻辑,并且与JSF 视图或Facelet 组合中的JSF 表单具有1::1 关系。尽管它通常具有带有关联 getter/setter 的 JavaBean 样式属性,但这些属性是 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通常的应用范围。这种类型的 bean 为一个或多个 JSF 视图提供某种类型的“实用程序”功能。一个很好的例子可能是可以在多个 Web 应用程序中重用的 FileUpload bean。

回答by Adeel Ansari

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

我可能不会回答你的每一个问题,因为似乎很少有人完全依赖于个案。

  • This is fine to have a business logic in your backing bean. It depends where are you coming from. If you are practicing domain driven design, you will be tempted to include the business logic in to backing bean or may be persistence logic as well. They argue that why so dumb object. Object should carry not just state but behavior too. On the other hand if you consider traditional Java EE way of doing things, you might be feeling like having data in your backing bean, which also can be your entity bean, and other business and persistence logic in some session bean or something. That is fine too.

  • Its perfectly fine to have single backing bean for the whole page. I don't see any problem with this alone. This might not look right, but that depends on the case.

  • Your other question is far more dependent on case you are having in hand. I would prefer to go domain driven here, it might be appropriate to add properties to the existing or otherwise create a new bean for that. Which ever suits better. I don't think there is any silver bullet for this.

  • Which properties belongs to which backing bean. Well, is it not depend on the domain object? Or may be the question is not that clear.

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

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

  • 您的另一个问题更多地取决于您手头的情况。我更愿意在这里使用域驱动,向现有添加属性或为此创建一个新 bean 可能是合适的。哪个更适合。我认为这没有任何灵丹妙药。

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

Moreover, in your given code example, I am not seeing any huge benefit.

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

回答by Bhushan Bhangale

I would not necessary keep only one backing bean per page. It depends on functionality but most of the time I had one bean per page as mostly one page handle one functionality. For example on a page I have a register link (I will link with RegisterBean) and a shopping basket link (ShoopingBasketBean).

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

I do use this <:outputText value="#{myBean.anObject.anObjectProperty}" /> as I normally keep backing beans as action beans which holds data object. I don't want to write a wrapper in my backing bean to access the properties of my data objects.

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

回答by Allan Lykke Christensen

Great question. I suffered a lot with the same dilemma when I moved to JSF. It really depends on your application. I'm from the Java EE world so I would recommend to have as little business logic in your backing beans as possible. If the logic is purely related to the presentation of your page, then it is fine to have it in the backing bean.

很好的问题。当我转移到 JSF 时,我遭受了同样的困境。这实际上取决于您的应用程序。我来自 Java EE 世界,所以我建议在您的支持 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 ValueObjectbefore exposing it on the bean.

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

EDIT: Actually, if you are going to encapsulate every object property that you want to expose, I would recommend that you instead bind UI components to the backing bean and then inject the content directly into the value of the component.

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

In terms of bean structure the turning point for me was when I forcefully ignored all the stuff I knew about building web applications and started treating it as a GUI application instead. JSF mimics Swing a lot and therefore the best practices for developing Swing applications would mostly also apply to building JSF applications.

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

回答by Chris Dale

I think the most important thing with your backing beans is to seperate their logics. If you have a front page for a CMS system I would see it as bad practice to put every piece of code into one bean because:

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

  1. The bean would turn very large eventually
  2. Its easier for other people to find what their looking for if they are troubleshooting the login page, if they then can easily just look up the loginBean.java file.
  3. Sometimes you have small pieces of functionality that is clearly distinct from the rest of your code, by separating this I would imagine you would make it easier on yourself to redevelop/expand this code into something bigger, when you already have a nice bean with good structure.
  4. Having 1 big bean, to do it all, will make it more memory dependant if/when you have to do declarations like this MyBigBean bigBean = new MyBigBean(); instead of using the funksjonality you actually needed by doing LoginBean loginBean = new LoginBean(); (Correct me if Im wrong here???)
  5. In my opinion, separating your beans is like separating your methods. You dont want 1 big method which runs over 100's of lines, but rather split it up with new methods that handles their specific task.
  6. Remember, most likely someone other than you will have to work on your JSF projects aswell.
  1. 豆子最终会变得很大
  2. 如果其他人对登录页面进行故障排除,那么他们更容易找到他们要查找的内容,如果他们可以轻松地查找 loginBean.java 文件。
  3. 有时你有一些与你的代码的其余部分明显不同的小功能,通过将它们分开,我想你会更容易重新开发/扩展这些代码,当你已经有了一个好的 bean 时结构体。
  4. 拥有 1 个大 bean,要做到这一切,如果/当您必须执行这样的声明时,它会更加依赖内存 MyBigBean bigBean = new MyBigBean(); 而不是通过执行 LoginBean loginBean = new LoginBean(); 来使用您实际需要的 funksjonality; (如果我错了,请纠正我???)
  5. 在我看来,分离你的 bean 就像分离你的方法。你不想要一个运行超过 100 行的大方法,而是将它与处理其特定任务的新方法分开。
  6. 请记住,很可能除了您之外的其他人也必须为您的 JSF 项目工作。



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

Just my 2 cents regarding this even with the question already marked as answered.

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

回答by jjruiz

I like to test business code without View's, so I consider BackingBeans as interfaces from View to Model code. I never put any rule or process in a BackingBean. That code goes into Services or Helpers, allowing reuse.

我喜欢在没有视图的情况下测试业务代码,因此我将 BackingBeans 视为从视图到模型代码的接口。我从来没有在 BackingBean 中放置任何规则或过程。该代码进入服务或帮助程序,允许重用。

If you use validators, put them out of your BackingBean and reference them from your validation method.

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

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

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

Believe me!. You can inject a JavaBean into a BackingBean, but try to inject a BackingBean into another one. You will be soon in a nigntmare of maintenance and understanding code.

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