这篇文章介绍主页中左边的分类树是如何实现的。

1. 首先打开主页,https://localhost:8443/ecommerce/control/main

2.找到 上面分类树界面对应的html源码。可以看到开始是以  component://ecommerce/widget/CatalogScreens.xml#productCategories 开始的。

3.打开component://ecommerce/widget/CatalogScreens.xml#productCategories

    <screen name="productCategories"><section><actions><set field="tabButtonItem" value="LookupProductCategories"/><script location="component://ecommerce/groovyScripts/catalog/ProductCategories.groovy"/></actions><widgets><platform-specific><html><html-template location="component://ecommerce/template/catalog/ProductCategories.ftl"/></html></platform-specific></widgets></section></screen>

打开component://ecommerce/groovyScripts/catalog/ProductCategories.groovy

/** This script is also referenced by the ecommerce's screens and* should not contain order component's specific code.*/
import org.apache.ofbiz.entity.util.EntityUtilimport org.apache.ofbiz.base.util.*
import org.apache.ofbiz.product.catalog.*
import org.apache.ofbiz.product.category.*
import org.apache.ofbiz.entity.*List fillTree(rootCat ,CatLvl, parentCategoryId) {if(rootCat) {rootCat.sort{ it.productCategoryId }def listTree = []for(root in rootCat) {preCatChilds = from("ProductCategoryRollup").where("parentProductCategoryId", root.productCategoryId).queryList()catChilds = EntityUtil.getRelated("CurrentProductCategory",null,preCatChilds,false)def childList = []// CatLvl uses for identify the Category level for display different css classif(catChilds) {if(CatLvl==2)childList = fillTree(catChilds,CatLvl+1, parentCategoryId.replaceAll("/", "")+'/'+root.productCategoryId)// replaceAll and '/' uses for fix bug in the breadcrum for href of categoryelse if(CatLvl==1)childList = fillTree(catChilds,CatLvl+1, parentCategoryId.replaceAll("/", "")+root.productCategoryId)elsechildList = fillTree(catChilds,CatLvl+1, parentCategoryId+'/'+root.productCategoryId)}productsInCat  = from("ProductCategoryAndMember").where("productCategoryId", root.productCategoryId).queryList()// Display the category if this category containing products or contain the category that's containing productsif(productsInCat || childList) {def rootMap = [:]category = from("ProductCategory").where("productCategoryId", root.productCategoryId).queryOne()categoryContentWrapper = new CategoryContentWrapper(category, request)context.title = categoryContentWrapper.get("CATEGORY_NAME", "html")categoryDescription = categoryContentWrapper.get("DESCRIPTION", "html")if(categoryContentWrapper.get("CATEGORY_NAME", "html").toString())rootMap["categoryName"] = categoryContentWrapper.get("CATEGORY_NAME", "html")elserootMap["categoryName"] = root.categoryNameif(categoryContentWrapper.get("DESCRIPTION", "html").toString())rootMap["categoryDescription"] = categoryContentWrapper.get("DESCRIPTION", "html")elserootMap["categoryDescription"] = root.descriptionrootMap["productCategoryId"] = root.productCategoryIdrootMap["parentCategoryId"] = parentCategoryIdrootMap["child"] = childListlistTree.add(rootMap)}}return listTree}
}CategoryWorker.getRelatedCategories(request, "topLevelList", CatalogWorker.getCatalogTopCategoryId(request, CatalogWorker.getCurrentCatalogId(request)), true)
curCategoryId = parameters.category_id ?: parameters.CATEGORY_ID ?: ""
request.setAttribute("curCategoryId", curCategoryId)
CategoryWorker.setTrail(request, curCategoryId)categoryList = request.getAttribute("topLevelList")
if (categoryList) {catContentWrappers = [:]CategoryWorker.getCategoryContentWrappers(catContentWrappers, categoryList, request)context.catContentWrappers = catContentWrapperscompletedTree = fillTree(categoryList, 1, "")context.completedTree = completedTree
}

打开component://ecommerce/template/catalog/ProductCategories.ftl

<script language="javascript" type="text/javascript"src="<@ofbizContentUrl>/images/jquery/plugins/jsTree/jquery.jstree.js</@ofbizContentUrl>"></script>
<script type="text/javascript"src="<@ofbizContentUrl>/images/jquery/ui/js/jquery.cookie-1.4.0.js</@ofbizContentUrl>"></script><script type="text/javascript"><#-- some labels are not unescaped in the JSON object so we have to do this manuely -->function unescapeHtmlText(text) {return jQuery('<div />').html(text).text()}jQuery(window).load(createTree());<#-- creating the JSON Data -->var rawdata = [<#if (requestAttributes.topLevelList)??><#assign topLevelList = requestAttributes.topLevelList></#if><#if (topLevelList?has_content)><@fillTree rootCat=completedTree/></#if><#macro fillTree rootCat><#if (rootCat?has_content)><#list rootCat?sort_by("productCategoryId") as root>{"data": {"title": unescapeHtmlText("<#if root.categoryName??>${root.categoryName?js_string}<#elseif root.categoryDescription??>${root.categoryDescription?js_string}<#else>${root.productCategoryId?js_string}</#if>"),"attr": {"href": "javascript: void(0);","onClick": "callDocument('${root.productCategoryId}', '${root.parentCategoryId}')","class": "${root.cssClass!}"}},"attr": {"id": "${root.productCategoryId}"}<#if root.child?has_content>, "children": [<@fillTree rootCat=root.child/>]</#if><#if root_has_next>},<#else>}</#if></#list></#if></#macro>];<#-------------------------------------------------------------------------------------define Requests-->var editDocumentTreeUrl = '<@ofbizUrl>/views/EditDocumentTree</@ofbizUrl>';var listDocument = '<@ofbizUrl>/views/ListDocument</@ofbizUrl>';var editDocumentUrl = '<@ofbizUrl>/views/EditDocument</@ofbizUrl>';var deleteDocumentUrl = '<@ofbizUrl>removeDocumentFromTree</@ofbizUrl>';<#-------------------------------------------------------------------------------------create Tree-->function createTree() {jQuery(function () {jQuery("#tree").jstree({"themes": {"theme": "classic","icons": false},"cookies": {"cookie_options": {path: '/'}},"plugins": ["themes", "json_data", "cookies"],"json_data": {"data": rawdata}});});}<#-------------------------------------------------------------------------------------callDocument function-->function callDocument(id, parentCategoryStr) {var checkUrl = '<@ofbizUrl>productCategoryList</@ofbizUrl>';if (checkUrl.search("http"))var ajaxUrl = '<@ofbizUrl>productCategoryList</@ofbizUrl>';elsevar ajaxUrl = '<@ofbizUrl>productCategoryListSecure</@ofbizUrl>';//jQuerry Ajax RequestjQuery.ajax({url: ajaxUrl,type: 'POST',data: {"category_id": id, "parentCategoryStr": parentCategoryStr},error: function (msg) {alert("An error occurred loading content! : " + msg);},success: function (msg) {jQuery('#div3').html(msg);}});}<#-------------------------------------------------------------------------------------callCreateDocumentTree function-->function callCreateDocumentTree(contentId) {jQuery.ajax({url: editDocumentTreeUrl,type: 'POST',data: {contentId: contentId,contentAssocTypeId: 'TREE_CHILD'},error: function (msg) {alert("An error occurred loading content! : " + msg);},success: function (msg) {jQuery('#Document').html(msg);}});}<#-------------------------------------------------------------------------------------callCreateSection function-->function callCreateDocument(contentId) {jQuery.ajax({url: editDocumentUrl,type: 'POST',data: {contentId: contentId},error: function (msg) {alert("An error occurred loading content! : " + msg);},success: function (msg) {jQuery('#Document').html(msg);}});}<#-------------------------------------------------------------------------------------callEditSection function-->function callEditDocument(contentIdTo) {jQuery.ajax({url: editDocumentUrl,type: 'POST',data: {contentIdTo: contentIdTo},error: function (msg) {alert("An error occurred loading content! : " + msg);},success: function (msg) {jQuery('#Document').html(msg);}});}<#-------------------------------------------------------------------------------------callDeleteItem function-->function callDeleteDocument(contentId, contentIdTo, contentAssocTypeId, fromDate) {jQuery.ajax({url: deleteDocumentUrl,type: 'POST',data: {contentId: contentId,contentIdTo: contentIdTo,contentAssocTypeId: contentAssocTypeId,fromDate: fromDate},error: function (msg) {alert("An error occurred loading content! : " + msg);},success: function (msg) {location.reload();}});}<#-------------------------------------------------------------------------------------callRename function-->function callRenameDocumentTree(contentId) {jQuery.ajax({url: editDocumentTreeUrl,type: 'POST',data: {contentId: contentId,contentAssocTypeId: 'TREE_CHILD',rename: 'Y'},error: function (msg) {alert("An error occurred loading content! : " + msg);},success: function (msg) {jQuery('#Document').html(msg);}});}<#------------------------------------------------------pagination function -->function nextPrevDocumentList(url) {url = '<@ofbizUrl>'+ url+'</@ofbizUrl>';jQuery.ajax({url: url,type: 'POST',error: function (msg) {alert("An error occurred loading content! : " + msg);},success: function (msg) {jQuery('#Document').html(msg);}});}</script><div id="quickadd" class="screenlet"><div class="screenlet-title-bar"><ul><li class="h3">${uiLabelMap.ProductCategories}</li></ul></div><div class="screenlet-body" id="tree"></div>
</div>

数据填充部分主要看<#-- creating the JSON Data -->那一块。看rawdata是如何组织的。

分析ProductCategories.groovy代码:

1.  CatalogWorker.getCurrentCatalogId(request)

这个应该是获取当前目录id。默认是DemoCatalog

2. CategoryWorker.getRelatedCategories(request, "topLevelList", CatalogWorker.getCatalogTopCategoryId(request, CatalogWorker.getCurrentCatalogId(request)), true)

查看源码CategoryWorker.getRelatedCategories

public static String getCatalogTopCategoryId(ServletRequest request, String prodCatalogId) {if (UtilValidate.isEmpty(prodCatalogId)) return null;List<GenericValue> prodCatalogCategories = getProdCatalogCategories(request, prodCatalogId, "PCCT_BROWSE_ROOT");if (UtilValidate.isNotEmpty(prodCatalogCategories)) {GenericValue prodCatalogCategory = EntityUtil.getFirst(prodCatalogCategories);return prodCatalogCategory.getString("productCategoryId");} else {return null;}}

可以知道实际执行的sql语句是:

SELECT * FROM Prod_Catalog_Category t WHERE t.prod_catalog_id='DemoCatalog' AND t.prod_catalog_category_type_id='PCCT_BROWSE_ROOT'

结果如下:

查询结果会放入request的topLevelList属性里。即categoryList就是上面的查询结果。这个例子的查询结果只有一条记录。

3.接下来重点看fillTree方法。

3.1 for(root in rootCat) {  //由于categoryList结果只有一条记录,所以for只会循环一次。

3.2 preCatChilds = from("ProductCategoryRollup").where("parentProductCategoryId", root.productCategoryId).queryList() 等价于

SELECT * FROM Product_Category_Rollup WHERE parent_Product_Category_Id='CATALOG1'

root.productCategoryId的取值就是上面 categoryList结果的product_Category_Id字段的值。

结果显示:

3.3 catChilds = EntityUtil.getRelated("CurrentProductCategory",null,preCatChilds,false)

这行代码是根据preCatChilds关联对应的分类记录。等价于下面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'

结果显示:


3.4 递归调用获取分类的子分类。

// CatLvl uses for identify the Category level for display different css classif(catChilds) {if(CatLvl==2)childList = fillTree(catChilds,CatLvl+1, parentCategoryId.replaceAll("/", "")+'/'+root.productCategoryId)// replaceAll and '/' uses for fix bug in the breadcrum for href of categoryelse if(CatLvl==1)childList = fillTree(catChilds,CatLvl+1, parentCategoryId.replaceAll("/", "")+root.productCategoryId)elsechildList = fillTree(catChilds,CatLvl+1, parentCategoryId+'/'+root.productCategoryId)}

第一次执行时CatLvl是等于1.

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=?

上面的参数?表示catChilds列表每条记录的产品分类id即Product_Category_id,取值有:100,200,dropShip,FA-100,FOOD-001,GC-100,PC-100,SERV-001  八条记录循环遍历。

3.5 构造rootMap。

rootMap的主要属性有:categoryName,categoryDescription,productCategoryId,parentCategoryId,child,cssClass

研究了很久,发现下面三条记录的category_name和description字段都为null,而分类树中确显示Configurables Foods,Gift Cards,Configurables PCs。不知道这些内容是哪里来的,找了好久也没找到,暂时先不管了。以后有时间再研究。

ofbiz学习——分类相关推荐

  1. CVPR2018论文看点:基于度量学习分类与少镜头目标检测

    CVPR2018论文看点:基于度量学习分类与少镜头目标检测 简介 本文链接地址:https://arxiv.org/pdf/1806.04728.pdf 距离度量学习(DML)已成功地应用于目标分类, ...

  2. 深度学习分类任务常用评估指标

    摘要:这篇文章主要向大家介绍深度学习分类任务评价指标,主要内容包括基础应用.实用技巧.原理机制等方面,希望对大家有所帮助. 本文分享自华为云社区<深度学习分类任务常用评估指标>,原文作者: ...

  3. matlab朴素贝叶斯手写数字识别_从“手写数字识别”学习分类任务

    机器学习问题可以分为回归问题和分类问题,回归问题已经在线性回归讲过,本文学习分类问题.分类问题跟回归问题有明显的区别,回归问题是连续的数值,而分类问题是离散的类别,比如将性别分为[男,女],将图片分为 ...

  4. 机器学习实战-54: 集成学习分类算法(ada-boost)

    集成学习分类算法 深度学习原理与实践(开源图书)-总目录,建议收藏,告别碎片阅读! 集成学习分类算法(ada-boost)属于监督学习算法.常用分类算法包括:逻辑回归(Logistic Regress ...

  5. 深度学习分类pytorch_pytorch使用转移学习的狗品种分类器

    深度学习分类pytorch So have you heard the word deep learning before? Or have you just started learning it? ...

  6. 【学习笔记】迁移学习分类

    什么是迁移学习 通俗来讲,就是运用已有的知识来学习新的知识,核心是找到已有知识和新知识之间的相似性,用成语来说就是举一反三.由于直接对目标域从头开始学习成本太高,我们故而转向运用已有的相关知识来辅助尽 ...

  7. 使用深度学习分类猫狗图片

    使用深度学习分类猫狗图片 前言 一.下载数据 二.构建网络 三.数据预处理 四.使用数据增强 总结 前言 本文将介绍如何使用较少的数据从头开始训练一个新的深度学习模型.首先在一个2000个训练样本上训 ...

  8. 强化学习分类与汇总介绍

    1.强化学习(Reinforcement Learning, RL) 强化学习把学习看作试探评价过程,Agent选择一个动作用于环境,环境接受该动作后状态发生变化,同时产生一个强化信号(奖或惩)反馈给 ...

  9. 卷积神经网络经典论文集合(深度学习分类篇)

    卷积神经网络经典论文集合 为方便撰写深度学习分类网络综述,现将近年以来经典论文做一个整理.文章时间大部分参考arXiv分享时间为准,小部分为期刊的出版日期. 下载地址 CSDN:https://dow ...

最新文章

  1. FCN制作自己的数据集、训练和测试 caffe
  2. 网易云信助力中国航空工业集团,打造数字化云办公平台
  3. VTK:可视化之LabeledMesh
  4. [整理]ASP.NET MVC 5
  5. 一个娃娃竟然拍出50万......
  6. js实现页面跳转重定向的几种方式
  7. 小心使用tf.image.resize_images,填坑经验分享给你
  8. react 更新input 默认值setfieldsvalue_值得收藏的React面试题
  9. 教程-TObjectList.Clear、TStringList.Clear方法对象有没有被释放
  10. 联合主键使用in和not in
  11. CSDN资源分享分红2元,哈哈
  12. 【POJ 1838 --- Banana】
  13. java中如何添加画板背景图,几何画板中如何添加背景图片
  14. 防辐射门行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  15. html 导航栏颜色代码,CSS实现五颜六色按钮组成的导航条效果代码
  16. 在线python编程网页-手把手教你用Python写一个在线网站,这真的很装逼!
  17. 《富兰克林自传》读后感:从这个接地气的伟人身上我们可以学到什么?
  18. Android 9.0 一定要适配htpps请求?
  19. 美颜SDK是什么?美颜SDK和美颜APP有什么区别?
  20. java知识点博客园_Java知识点总结1

热门文章

  1. Simsimi 小黄鸡机器人最新无限制接口api simsimi机器人接口api 微信公众号
  2. 利用自制回流焊高温炉焊接表贴LED
  3. Go核心开发学习笔记(廿九) —— 反射
  4. 通信协议以及protobuf使用、语法指南一
  5. 负载均衡服务器的搭建(linux)
  6. python在家创业项目_适合在家里做的互联网创业虚拟项目
  7. Python中*和**的区别
  8. Your host does not meet minimum requirements to run VMware workstation with hyper-v or device/creden
  9. Python Learning Notes - 2
  10. JQuery选择器汇总