【问题标题】:Business logic inside an accessor / getter method in JSFJSF 中访问器/获取器方法中的业务逻辑
【发布时间】:2014-04-01 22:59:54
【问题描述】:

我在 MySQL 数据库中有三个表。

  • 类别(本题除外)
  • 子类别
  • 产品

这些表之间的关系是直观的——按照它们出现的顺序一对多。


我正在使用<p:dataGrid> 遍历SubCategoryList<SubCategory> 的列表,如下所示。

<p:dataGrid var="row" value="#{featuredProductManagedBean}" rows="4" first="0" columns="1" rowIndexVar="rowIndex" paginator="true" paginatorAlwaysVisible="false" pageLinks="10" lazy="true" rowsPerPageTemplate="5,10,15">
    <h:panelGrid columns="1" style="width:100%;">
        <p:carousel value="#{featuredProductManagedBean.getProducts(row.subCatId)}" var="prodRow" numVisible="4" pageLinks="5" headerText="#{row.subCatName}" style="text-align: left;">

            <!--Display product image in <p:graphicImage>-->

        </p:carousel>
        <h:outputLink rendered="#{featuredProductManagedBean.count gt 4}" value="xxx">View More</h:outputLink>
    </h:panelGrid>

    <p:ajax event="page" onstart="PF('blockDataPanelUIWidget').block()" oncomplete="PF('blockDataPanelUIWidget').unblock()"/>
</p:dataGrid>

有一个参数化的getter方法与&lt;/p:carousel&gt;featuredProductManagedBean.getProducts(row.subCatId)的value属性关联。

多次调用该方法,导致多次调用昂贵的业务服务。

托管 bean:

@ManagedBean
@ViewScoped
public final class FeaturedProductManagedBean extends LazyDataModel<SubCategory> implements Serializable
{
    @EJB
    private final FeaturedProductBeanLocal service=null;
    private Product selectedProduct;  //Getter and setter.
    private Long count;               //Getter and setter.  
    private static final long serialVersionUID = 1L;

    public FeaturedProductManagedBean() {}

    public List<Product>getProducts(Long subCatId)
    {
        List<Product>products=null;

        if(FacesContext.getCurrentInstance().getCurrentPhaseId().getOrdinal()==6)
        {
            setCount(service.countProducts(subCatId));
            products=service.getProductList(subCatId);
        }

        return products;
    }

    @Override
    public List<SubCategory> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters)
    {
        int rowCount = service.rowCount().intValue();
        setRowCount(rowCount);

        if(pageSize<=0)
        {
            FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_FATAL, Utility.getMessage("faces.message.error"), Utility.getMessage("pageSize.error.message"));
            FacesContext.getCurrentInstance().addMessage(null, message);
            return Collections.emptyList();
        }
        else if(first>=pageSize&&rowCount<=Utility.currentPage(first, pageSize)*pageSize-pageSize) {
            first-=pageSize;
        }

        setPageSize(pageSize);
        return service.getList(first, pageSize);
    }
}

@PostConstruct不是懒加载在这里都不能用。目前我已经设置了条件检查if(FacesContext.getCurrentInstance().getCurrentPhaseId().getOrdinal()==6),以防止服务方法被多次调用。此条件检查是否执行正确的操作?有副作用吗?

This 答案维护Map,但为大型数据源维护Map 成本很高。

有没有精确的方法来防止这种业务逻辑被多次执行?

【问题讨论】:

  • 为了防止业务逻辑被多次执行,您应该将其移出 getter 并放在 PostConstruct 方法中。不清楚你为什么说不能。
  • 因为使用criteria/JPQL,@perissf 想必是不可能的
  • 如果使用 JPA 无法进行查询,则有许多比您尝试做的更简单的解决方法:更改 db 架构、将查询拆分为中继并在 java 中处理中继等...如果我是你,我会尽可能避免增加应用程序的复杂性。但显然我不知道您应用的所有业务需求...
  • 这只是你所说的将查询拆分成块的尝试,@perissf

标签: jsf primefaces getter-setter jsf-2.2 accessor


【解决方案1】:

我建议将当前加载的subCategory 的产品存储在Map 中,就在它们被&lt;p:dataGrid&gt; 的惰性模型加载之后。 Map 永远不会增长太多,因为您将在每次调用 load 方法时清空它:

@ManagedBean
@ViewScoped
public final class FeaturedProductManagedBean extends LazyDataModel<SubCategory> implements Serializable
{
    @EJB
    private final FeaturedProductBeanLocal service=null;
    private Product selectedProduct;  //Getter and setter.
    private Long count;               //Getter and setter.  
    private Map<Long, Product> productsBySubCategory = new HashMap<>(); //Getter only.
    private static final long serialVersionUID = 1L;

    @Override
    public List<SubCategory> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters)
    {
        int rowCount = service.rowCount().intValue();
        setRowCount(rowCount);

        List<SubCategory> subCategories = service.getList(first, pageSize);
        productsBySubCategory.clear();
        for (SubCategory sc : subCategories) 
        {
            productsBySubCategory.put(sc.getSubCatId(), service.getProductList(sc.getSubCatId());
        }
        return subCategories;
    }
}

并直接从 EL 访问 Map

<p:carousel value="#{featuredProductManagedBean.productsBySubCategory[row.subCatId]}" />

请注意,您不需要检查页面边界和设置页面大小的所有样板。

【讨论】:

  • 完成!非常感谢:)
猜你喜欢
  • 2018-10-02
  • 2012-04-25
  • 2010-11-01
  • 2018-07-30
  • 2017-08-08
  • 2013-01-30
  • 2017-08-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多