【问题标题】:Using jsf session scoped managed bean to represent static hierarchical data [closed]使用 jsf 会话范围的托管 bean 来表示静态分层数据 [关闭]
【发布时间】:2012-11-01 18:12:59
【问题描述】:

这可能是一种架构问题,但仍然必须有“最佳实践解决方案”或公认标准。

我说的是需要在网站上显示的某种静态数据,例如产品目录、菜单和菜单项列表、面包屑块列表等。我想这个选项在使用任何标准 CMS 时都可用.

但我想使用纯 JSF 解决方案来解决这个问题。

所以,回到这个问题,我的阐述基于以下原则:

  1. 数据不应该在 facelets 中硬编码,因此我使用数据库来保存值,就像在下面的 db 脚本(在我的例子中是 MYSQL)中一样:

    CREATE TABLE CatalogueGroup (
        CatalogueGroupName VARCHAR(100) NOT NULL PRIMARY KEY,
        URLPath VARCHAR(200) NOT NULL,
        ParentGroupName VARCHAR(100) DEFAULT NULL,
        FOREIGN KEY (ParentGroupName) REFERENCES CatalogueGroup(CatalogueGroupName) ON UPDATE CASCADE ON DELETE SET NULL
    )ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
  2. 然后我想使用要在@ManagedBean 中保存的实体类并将其显示在视图中,例如

    public class CatalogueGroup implements Serializable {
        private String catalogueGroupName;
        private List<CatalogueGroup> children = new ArrayList<CatalogueGroup>();
        private CatalogueGroup parentGroup;
        //other stuff of this bean
    }
    
    @ManagedBean
    @SessionScoped
    public class CatalogueBean implements Serializable {
        private CatalogueGroup catalogue;//loaded via CatalogueGroupDAO with condition parentGroup == null
        //other stuff of this bean
    }
    
    //snippet of xhtml view for a two-level catalogue
    <ul><h:outputText value="#{catalogueBean.catalogue.catalogueGroupName}" />
        <ui:rereat value="#{catalogueBean.catalogue.children}" var="group">
            <li><h:outputText value="#{group.catalogueGroupName}" /></li>
        </ui:repeat>
    </ul>
    

上述设置有效,但感觉很尴尬。 因此,我想向 jsf 社区提出以下公开的“最佳实践”问题:

  1. 像这样设置目录 bean 的正确方法是什么:
    • 一个@SessionScope bean,将被加载一次并在每个视图上重新显示或
    • @RequestScoped bean 将在每个页面显示时访问数据库。
  2. 有没有办法在 facelet 视图中设置递归函数,或者我应该将目录嵌套级别限制为 2 或 3。
  3. 我想显示某种修改后的目录,根据他的角色(在数据库表中添加的列)向登录用户公开更多组,并在没有用户登录时显示基本目录。此外,我想偶尔在目录中插入一些新组,而不是强制用户重新登录,而是立即重新显示正确的数据:
    • 我是否应该在业务层过滤组并将过滤后的 CatalogueGroup 公开给 bean,或者我将加载整个目录并将其子项限制在视图中,并设置为 render=false;
    • 在会话中公开整个目录是否合适;
    • 是否可以在将新数据库条目添加到服务器上所有当前处于活动状态的 CatalogueBean 时发送修改事件,以强制刷新其属性(CatalogueGroup)或实现此功能,我只需要使用 @RequestScoped bean;
    • 如果使用请求范围的 bean 是唯一的选择,那么明智的做法是访问数据库以频繁获取数据以致很少更改,或者有更智能的处理方式;
    • 当用户登录(和注销)时,已经有一个会话范围目录的实例,如何刷新它:我需要在动作/动作侦听器中手动执行它还是需要使会话无效或更合适的操作视情况而定。

【问题讨论】:

    标签: jsf-2 managed-bean


    【解决方案1】:

    非常有趣,但可能是一个开放的问题。

    首先,范围取决于您将为目录提供的实用程序。如果您想将数据链接到特定视图,我建议您通过@ViewScoped@SessionScoped,如果您的目标是实现类似购物篮的东西。

    对于递归函数,我认为您应该在纯视图 (xhtml) 层中避免这种做法,并使用像 PrimefacesRichfaces 这样的库,它们具有内置组件你想做。使用它们,您只需在托管的支持 bean 中以编程方式处理它们的逻辑结构。

    最后,由于目录限制,我建议您仅从数据库中加载要使用的内容。这样,您就不会超载 server-databaseserver-client 连接。你可以有一个@SessionScoped bean 来管理当前登录用户的会话,并且根据它你可以向数据库询问一些值或其他值。

    您还必须注意您的目录,如果您在会话期间对其进行大量修改,那么@ViewScoped bean 可能是一个更好的选择,因为每次请求视图时都会重新加载它。如果您使用@SessionScoped bean,您必须手动添加每个更改,以便在会话期间保持更新。

    "load the whole catalogue and limit its children in views with rendered=false"

    如果你按照我说的方式去做,你就不必做这项工作。如果您正在管理一个复杂的树并在视图中引入更多逻辑,那么有条件地评估每个树节点可能会很麻烦。当然,您应该尽可能避免这种情况。

    即使您已经找到了解决方案,这也是我的主要想法。

    【讨论】:

      【解决方案2】:

      您可以使用缓存来存储各种用户角色的菜单。然后,当您在数据库中插入新数据(如果您从管理页面插入)时,您可以使缓存失效,或者您可以将缓存设置为在特定时间段(每天一次、每隔几个小时等)后过期,然后您缓存过期时再次读取数据。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-30
        • 2012-12-26
        • 1970-01-01
        • 2011-06-08
        • 1970-01-01
        • 1970-01-01
        • 2013-01-15
        • 2010-11-12
        相关资源
        最近更新 更多