ofbiz学习——畅销产品展示

这篇文章介绍主页中中间的畅销产品展示是如何实现的。


1.打开文件  component://ecommerce/widget/CommonScreens.xml#main

    <screen name="main">
        <section>
            <actions>
                <set field="leftbarScreenName" value="leftbar"/>
                <set field="rightbarScreenName" value="rightbar"/>
                <set field="MainColumnStyle" value="center"/>

                <set field="titleProperty" value="PageTitleMain"/>
                <set field="headerItem" value="main"/>
                <set field="randomSurveyGroup" value="testSurveyGroup"/>

                <script location="component://ecommerce/groovyScripts/Main.groovy"/>
                <script location="component://order/groovyScripts/entry/catalog/Category.groovy"/>
            </actions>
            <widgets>
                <decorator-screen name="main-decorator" location="${parameters.mainDecoratorLocation}">
                    <decorator-section name="body">
                        <platform-specific>
                            <html><html-template location="component://ecommerce/template/Main.ftl"/></html>
                        </platform-specific>
                    </decorator-section>
                </decorator-screen>
            </widgets>
        </section>
    </screen>


2. groovy脚本主要是从数据库中提取数据。先来看看Main.ftl。打开文件component://ecommerce/template/Main.ftl

<#-- Render the category page -->
<#if requestAttributes.productCategoryId?has_content>
  ${screens.render("component://ecommerce/widget/CatalogScreens.xml#bestSellingCategory")}
  ${screens.render("component://ecommerce/widget/CatalogScreens.xml#category-include")}
<#else>
  <center><h2>${uiLabelMap.EcommerceNoPROMOTIONCategory}</h2></center>
</#if>

打开文件component://ecommerce/widget/CatalogScreens.xml#bestSellingCategory

    <screen name="bestSellingCategory">
        <section>
            <widgets>
                <section>
                    <widgets>
                        <!--<label style="h1" text="Popular Categories"/>-->
                        <include-screen name="showBestSellingCategory"/>
                    </widgets>
                </section>
            </widgets>
        </section>
    </screen>
    <screen name="showBestSellingCategory">
        <section>
            <actions>
                <script location="component://ecommerce/groovyScripts/catalog/BestSellingCategory.groovy"/>
            </actions>
            <widgets>
                <platform-specific><html><html-template location="component://ecommerce/template/catalog/ShowBestSellingCategory.ftl"/></html></platform-specific>
            </widgets>
        </section>
    </screen>

查看模板component://ecommerce/template/catalog/ShowBestSellingCategory.ftl

<#if productCategoryList?has_content>
  <h1>Popular Categories</h1>
  <div class="productsummary-container matrix">
    <table>
      <tbody>
        <#list productCategoryList as childCategoryList>
          <tr>
            <#assign cateCount = 0/>
            <#list childCategoryList as productCategory>
              <#if (cateCount > 2)>
                <tr>
                  <#assign cateCount = 0/>
              </#if>
              <#assign productCategoryId = productCategory.productCategoryId/>
              <#assign categoryImageUrl = "/images/defaultImage.jpg">
              <#assign productCategoryMembers = delegator
                  .findByAnd("ProductCategoryAndMember", Static["org.apache.ofbiz.base.util.UtilMisc"]
                  .toMap("productCategoryId", productCategoryId),
                  Static["org.apache.ofbiz.base.util.UtilMisc"].toList("-quantity"), false)>
              <#if productCategory.categoryImageUrl?has_content>
                <#assign categoryImageUrl = productCategory.categoryImageUrl/>
              <#elseif productCategoryMembers?has_content>
                <#assign productCategoryMember =
                    Static["org.apache.ofbiz.entity.util.EntityUtil"].getFirst(productCategoryMembers)/>
                <#assign product = delegator.findOne("Product",
                    Static["org.apache.ofbiz.base.util.UtilMisc"]
                    .toMap("productId", productCategoryMember.productId), false)/>
                <#if product.smallImageUrl?has_content>
                  <#assign categoryImageUrl = product.smallImageUrl/>
                </#if>
              </#if>
              <td>
                <div class="productsummary">
                  <div class="smallimage">
                    <a href="<@ofbizCatalogAltUrl productCategoryId=productCategoryId/>">
                      <span class="popup_link"><img alt="Small Image" src="${categoryImageUrl}"></span>
                    </a>
                  </div>
                  <div class="productbuy">
                    <a class="linktext" style="font-size:12px"
                        href="<@ofbizCatalogAltUrl productCategoryId=productCategoryId/>">
                      ${productCategory.categoryName!productCategoryId}
                    </a>
                  </div>
                  <div class="productinfo">
                    <ul>
                      <#if productCategoryMembers??>
                        <#assign i = 0/>
                        <#list productCategoryMembers as productCategoryMember>
                          <#if (i > 2)>
                            <#if productCategoryMembers[i]?has_content>
                              <a class="linktext" href="<@ofbizCatalogAltUrl productCategoryId=productCategoryId/>">
                                <span>More...</span>
                              </a>
                            </#if>
                            <#break>
                          </#if>
                          <#if productCategoryMember?has_content>
                            <#assign product = delegator.findOne("Product",
                                Static["org.apache.ofbiz.base.util.UtilMisc"].toMap("productId",
                                productCategoryMember.productId), false)>
                            <li class="browsecategorytext">
                              <a class="linktext"
                                  href="<@ofbizCatalogAltUrl productCategoryId="PROMOTIONS"
                                  productId="${product.productId}"/>">
                                ${product.productName!product.productId}
                              </a>
                            </li>
                          </#if>
                          <#assign i = i+1/>
                        </#list>
                      </#if>
                    </ul>
                  </div>
                </div>
              </td>
              <#assign cateCount = cateCount + 1/>
            </#list>
          <tr/>
        </#list>
      </tbody>
    </table>
  </div>
</#if>
从上面的模板中我们可以看到<h1>Popular Categories</h1>代码。这个就是前面要展示的畅销产品。


接下来查看下是如何用groovy脚本提取数据的。

打开文件component://ecommerce/groovyScripts/Main.groovy

import org.apache.ofbiz.product.catalog.*

catalogId = CatalogWorker.getCurrentCatalogId(request)
promoCat = CatalogWorker.getCatalogPromotionsCategoryId(request, catalogId)
request.setAttribute("productCategoryId", promoCat)


打开文件component://order/groovyScripts/entry/catalog/Category.groovy

/*
 * This script is also referenced by the ecommerce's screens and
 * should not contain order component's specific code.
 */

import org.apache.ofbiz.base.util.*
import org.apache.ofbiz.entity.*
import org.apache.ofbiz.product.catalog.*
import org.apache.ofbiz.product.category.CategoryWorker
import org.apache.ofbiz.product.category.CategoryContentWrapper
import org.apache.ofbiz.product.store.ProductStoreWorker

detailScreen = "categorydetail"
catalogName = CatalogWorker.getCatalogName(request)

productCategoryId = request.getAttribute("productCategoryId") ?: parameters.category_id
context.productCategoryId = productCategoryId

context.productStore = ProductStoreWorker.getProductStore(request)

pageTitle = null
metaDescription = null
metaKeywords = null

category = from("ProductCategory").where("productCategoryId", productCategoryId).cache(true).queryOne()
if (category) {
    if (category.detailScreen) {
        detailScreen = category.detailScreen
    }
    categoryPageTitle = from("ProductCategoryContentAndInfo").where("productCategoryId", productCategoryId, "prodCatContentTypeId", "PAGE_TITLE").cache(true).queryList()
    if (categoryPageTitle) {
        pageTitle = from("ElectronicText").where("dataResourceId", categoryPageTitle.get(0).dataResourceId).cache(true).queryOne()
    }
    categoryMetaDescription = from("ProductCategoryContentAndInfo").where("productCategoryId", productCategoryId, "prodCatContentTypeId", "META_DESCRIPTION").cache(true).queryList()
    if (categoryMetaDescription) {
        metaDescription = from("ElectronicText").where("dataResourceId", categoryMetaDescription.get(0).dataResourceId).cache(true).queryOne()
    }
    categoryMetaKeywords = from("ProductCategoryContentAndInfo").where("productCategoryId", productCategoryId, "prodCatContentTypeId", "META_KEYWORD").cache(true).queryList()
    if (categoryMetaKeywords) {
        metaKeywords = from("ElectronicText").where("dataResourceId", categoryMetaKeywords.get(0).dataResourceId).cache(true).queryOne()
    }
    categoryContentWrapper = new CategoryContentWrapper(category, request)
    
    categoryDescription = categoryContentWrapper.get("DESCRIPTION", "html")

    if (pageTitle) {
        context.title = pageTitle.textData
    } else {
        context.title = categoryContentWrapper.get("CATEGORY_NAME", "html")
    }

    if (metaDescription) {
        context.metaDescription = metaDescription.textData
    } else {
        if (categoryDescription) {
            context.metaDescription = categoryDescription
        }
    }

    if (metaKeywords) {
        context.metaKeywords = metaKeywords.textData
    } else {
        if (categoryDescription) {
            context.metaKeywords = categoryDescription + ", " + catalogName
        } else {
            context.metaKeywords = catalogName
        }
    }
    context.productCategory = category
}

// check the catalogs template path and update
templatePathPrefix = CatalogWorker.getTemplatePathPrefix(request)
if (templatePathPrefix) {
    detailScreen = templatePathPrefix + detailScreen
}
context.detailScreen = detailScreen

request.setAttribute("productCategoryId", productCategoryId)
request.setAttribute("defaultViewSize", 10)
request.setAttribute("limitView", true)

这块脚本主要是展示后面的特殊产品界面的。与畅销产品展示没什么关系。

打开文件component://ecommerce/groovyScripts/catalog/BestSellingCategory.groovy

import org.apache.ofbiz.base.util.UtilValidate
import org.apache.ofbiz.base.util.UtilMisc
import org.apache.ofbiz.product.catalog.*
import org.apache.ofbiz.product.category.*

catalogId = CatalogWorker.getCurrentCatalogId(request)
bestSellerCates = []

if (UtilValidate.isNotEmpty(catalogId)) {
    prodCatalogCategoryList = CatalogWorker.getProdCatalogCategories(request, catalogId, "PCCT_BEST_SELL")
    if (prodCatalogCategoryList.size() > 0) {
        for (int i = 0; i < prodCatalogCategoryList.size(); i++) {
            prodCatalogCategory = prodCatalogCategoryList[i]
			//productCategoryId = "CATALOG1_BEST_SELL"
            productCategoryId = prodCatalogCategory.getString("productCategoryId")
            childCategoryList = CategoryWorker.getRelatedCategoriesRet(request, "childCategoryList", productCategoryId, true)
            if (childCategoryList.size() > 0) {
                bestSellerCates.add(childCategoryList)
            }
        }
    }
}

context.productCategoryList = bestSellerCates

上面这个脚本就是从数据库中提取畅销产品列表。这些数据与ShowBestSellingCategory.ftl模板结合起来,就生成了畅销产品展示界面,即参照文章开头的截图。


接下来分析前面源码,得出查询畅销产品的相关sql。

首先,看ShowBestSellingCategory.ftl文件中主要的数据参数是productCategoryList 和 childCategoryList 。


产品分类列表productCategoryList 可以查看脚本 BestSellingCategory.groovy 文件,分析源码得出查询sql。

  1. catalogId = CatalogWorker.getCurrentCatalogId(request)  
catalogId 是目录标志。默认是 DemoCatalog

  1.     prodCatalogCategoryList = CatalogWorker.getProdCatalogCategories(request, catalogId, "PCCT_BEST_SELL")  


查看org.apache.ofbiz.product.catalog.CatalogWorker#getProdCatalogCategories方法 (具体文件路径根据包名知道在product项目的src里)

public static List<GenericValue> getProdCatalogCategories(ServletRequest request, String prodCatalogId, String prodCatalogCategoryTypeId) {
        Delegator delegator = (Delegator) request.getAttribute("delegator");
        return getProdCatalogCategories(delegator, prodCatalogId, prodCatalogCategoryTypeId);
    }

    public static List<GenericValue> getProdCatalogCategories(Delegator delegator, String prodCatalogId, String prodCatalogCategoryTypeId) {
        try {
            List<GenericValue> prodCatalogCategories = EntityQuery.use(delegator).from("ProdCatalogCategory")
                    .where("prodCatalogId", prodCatalogId)
                    .orderBy("sequenceNum", "productCategoryId")
                    .cache(true)
                    .filterByDate()
                    .queryList();

            if (UtilValidate.isNotEmpty(prodCatalogCategoryTypeId) && prodCatalogCategories != null) {
                prodCatalogCategories = EntityUtil.filterByAnd(prodCatalogCategories,
                            UtilMisc.toMap("prodCatalogCategoryTypeId", prodCatalogCategoryTypeId));
            }
            return prodCatalogCategories;
        } catch (GenericEntityException e) {
            Debug.logError(e, "Error looking up ProdCatalogCategories for prodCatalog with id " + prodCatalogId, module);
        }
        return null;
    }


对应的查询sql如下:

SELECT * FROM Prod_Catalog_Category WHERE prod_Catalog_Id = 'DemoCatalog' AND prod_Catalog_Category_Type_Id = 'PCCT_BEST_SELL' ORDER BY sequence_Num


查询结果如下:


所以productCategoryId 的值是 CATALOG1_BEST_SELL

childCategoryList = CategoryWorker.getRelatedCategoriesRet(request, "childCategoryList", productCategoryId, true)  

查看org.apache.ofbiz.product.category.getRelatedCategoriesRet

    public static List<GenericValue> getRelatedCategoriesRet(ServletRequest request, String attributeName, String parentId, boolean limitView) {
        return getRelatedCategoriesRet(request, attributeName, parentId, limitView, false);
    }

    public static List<GenericValue> getRelatedCategoriesRet(ServletRequest request, String attributeName, String parentId, boolean limitView, boolean excludeEmpty) {
        return getRelatedCategoriesRet(request, attributeName, parentId, limitView, excludeEmpty, false);
    }

    public static List<GenericValue> getRelatedCategoriesRet(ServletRequest request, String attributeName, String parentId, boolean limitView, boolean excludeEmpty, boolean recursive) {
      Delegator delegator = (Delegator) request.getAttribute("delegator");

      return getRelatedCategoriesRet(delegator, attributeName, parentId, limitView, excludeEmpty, recursive);
    }

    public static List<GenericValue> getRelatedCategoriesRet(Delegator delegator, String attributeName, String parentId, boolean limitView, boolean excludeEmpty, boolean recursive) {
        List<GenericValue> categories = new LinkedList<GenericValue>();

        if (Debug.verboseOn()) Debug.logVerbose("[CategoryWorker.getRelatedCategories] ParentID: " + parentId, module);

        List<GenericValue> rollups = null;

        try {
            rollups = EntityQuery.use(delegator).from("ProductCategoryRollup").where("parentProductCategoryId", parentId).orderBy("sequenceNum").cache(true).queryList();
            if (limitView) {
                rollups = EntityUtil.filterByDate(rollups, true);
            }
        } catch (GenericEntityException e) {
            Debug.logWarning(e.getMessage(), module);
        }
        if (rollups != null) {
            for (GenericValue parent: rollups) {
                GenericValue cv = null;

                try {
                    cv = parent.getRelatedOne("CurrentProductCategory", true);
                } catch (GenericEntityException e) {
                    Debug.logWarning(e.getMessage(), module);
                }
                if (cv != null) {
                    if (excludeEmpty) {
                        if (!isCategoryEmpty(cv)) {
                            categories.add(cv);
                            if (recursive) {
                                categories.addAll(getRelatedCategoriesRet(delegator, attributeName, cv.getString("productCategoryId"), limitView, excludeEmpty, recursive));
                            }
                        }
                    } else {
                        categories.add(cv);
                        if (recursive) {
                            categories.addAll(getRelatedCategoriesRet(delegator, attributeName, cv.getString("productCategoryId"), limitView, excludeEmpty, recursive));
                        }
                    }
                }
            }
        }
        return categories;
    }

分析代码知道excludeEmpty和recursive的值都是false,所以对应的sql如下:

SELECT t2.* FROM Product_Category_Rollup t1
INNER JOIN product_Category t2 ON t1.product_Category_id = t2.product_Category_id
WHERE t1.parent_Product_Category_Id='CATALOG1_BEST_SELL'    ORDER BY t1.sequence_Num

EntityUtil.filterByDate(rollups, true);这个就是表示数据在当前时间有效,等价条件就没写了。

查询结果如下:



数据提取在这里就完成了。接下来分析模板文件如何组织数据展示给用户。分析ShowBestSellingCategory.ftl文件。


分析界面展示小图片部分源码:

<a href="<@ofbizCatalogAltUrl productCategoryId=productCategoryId/>">

实际结果:

<a href="/ecommerce/best-sell-1-BEST-SELL-1-c">

这个转换需要研究@ofbizCatalogAltUrl  ,这个暂时不管。以后有时间在研究。

<img alt="Small Image" src="${categoryImageUrl}">
对应实际结果:

<img alt="Small Image" src="/images/products/GZ-1000/small.png">

接下来分析categoryImageUrl的值的取值逻辑。

1.默认取值 "/images/defaultImage.jpg"

2.参数productCategoryMembers的值。

    2.1 首先打开实体定义文件F:\个人\学习笔记\ofbiz\apache-ofbiz-16.11.02\applications\datamodel\entitydef\product-entitymodel.xml.

    2.2 查看实体视图ProductCategoryAndMember的定义。

<view-entity entity-name="ProductCategoryAndMember"
            package-name="org.apache.ofbiz.product.category"
            title="ProductCategory And ProductCategoryMember View Entity">
      <member-entity entity-alias="PC" entity-name="ProductCategory"/>
      <member-entity entity-alias="PCM" entity-name="ProductCategoryMember"/>
      <alias-all entity-alias="PC"/>
      <alias-all entity-alias="PCM"/>
      <view-link entity-alias="PC" rel-entity-alias="PCM">
        <key-map field-name="productCategoryId"/>
      </view-link>
      <relation type="one-nofk" rel-entity-name="ProductCategoryMember">
        <key-map field-name="productCategoryId"/>
        <key-map field-name="productId"/>
        <key-map field-name="fromDate"/>
      </relation>
      <relation type="one-nofk" rel-entity-name="ProductCategory">
        <key-map field-name="productCategoryId"/>
      </relation>
      <relation type="one-nofk" rel-entity-name="Product">
        <key-map field-name="productId"/>
      </relation>
    </view-entity>

    2.3 根据源码写出对应的sql。

<#assign productCategoryMembers = delegator
                  .findByAnd("ProductCategoryAndMember", Static["org.apache.ofbiz.base.util.UtilMisc"]
                  .toMap("productCategoryId", productCategoryId),
                  Static["org.apache.ofbiz.base.util.UtilMisc"].toList("-quantity"), false)>
对应的sql:

SELECT PC.*,pcm.* 
FROM Product_Category pc
INNER JOIN Product_Category_Member PCM ON pc.product_Category_Id = PCM.product_Category_Id
WHERE pc.product_Category_Id = 'BEST-SELL-1' ORDER BY quantity DESC
查询结果如下:


3.如果productCategory.categoryImageUrl的值存在,则categoryImageUrl的值就为productCategory.categoryImageUrl。这个之前查询结果可以看到2条记录的categoryImageUrl值都是null。所以走第4步获取categoryImageUrl的值。

4.如果productCategory.categoryImageUrl的值不存在,则通过productCategoryMembers获取categoryImageUrl的值。

获取productCategoryMembers列表第一条记录对应的产品的categoryImageUrl值。

对应的sql如下:

SELECT t.small_Image_Url ,t.* FROM product t WHERE product_id='GZ-1000'
查询结果如下:


从图中我们能看到值为 /images/products/GZ-1000/small.png  。与之前浏览器中看到的源码一致。


接下来展示该类产品的列表信息。

根据productCategoryMembers获取对应的产品实体。主要需要产品实体的product_Id与product_name字段值。

<a class="linktext"
                                  href="<@ofbizCatalogAltUrl productCategoryId="PROMOTIONS"
                                  productId="${product.productId}"/>">

对应的一个结果:

<a class="linktext" href="/ecommerce/nan-gismo-GZ-1001-p">
                                Nan Gizmo
                              </a>
不清楚为什么产品分类标识productCategoryId为什么写死了"PROMOTIONS",然后得到上面了结果。

@ofbizCatalogAltUrl暂时照着源码的方法用吧,以后再研究。


总结,到此整个畅销产品展示界面相关源码分析完毕。主要涉及到的查询sql有:

1.查询指定目录下畅销产品类型的所有分类

SELECT * FROM Prod_Catalog_Category WHERE prod_Catalog_Id = 'DemoCatalog' AND prod_Catalog_Category_Type_Id = 'PCCT_BEST_SELL' ORDER BY sequence_Num


2.畅销产品分类下的子分类,即所有属于畅销产品分类类型的记录。

SELECT t1.* FROM Product_Category_Rollup t1 WHERE t1.parent_Product_Category_Id='CATALOG1_BEST_SELL'  

SELECT t2.* FROM Product_Category_Rollup t1
INNER JOIN product_Category t2 ON t1.product_Category_id = t2.product_Category_id
WHERE t1.parent_Product_Category_Id='CATALOG1_BEST_SELL'    ORDER BY t1.sequence_Num


3.查询指定分类下的所有产品

SELECT PC.*,pcm.* 
FROM Product_Category pc
INNER JOIN Product_Category_Member PCM ON pc.product_Category_Id = PCM.product_Category_Id
WHERE pc.product_Category_Id = 'BEST-SELL-1' ORDER BY quantity DESC

4.根据产品id查询产品的详细信息。

SELECT t.small_Image_Url ,t.* FROM product t WHERE product_id='GZ-1000'














  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值