码迷,mamicode.com
首页 > 编程语言 > 详细

java 参仿京东天猫的分类树结构,实现无限级分类结构

时间:2015-08-13 12:35:51      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:


技术分享 技术分享
参考于京东和天猫的分类树结构,整理了个人在做电商项目分类树的开发思路及演变过程:

第一种方式:
   纯粹的采用Java代码和SQL语句方式,不断的递归查询,其自身是否拥有子节点,这样有不好的缺点就是,访问时数据SQL链接比较多,占用了数据库链接。
   实现思路:
  •       查询是否拥有子节点的SQL是:
            select c.* from category c  where  c.status = 1 and c.parent_id=?
   
  •       实现组装的TreeNo:
            // 分类ID
           private Long categoryId;

            // 分类名称
           private String categoryName;    
     
            private List< TreeNo > childrens;

           不断通过   java 递归方式去获取该节点是否拥有子节点,如果拥有则继续往下递归,直到递归到没有子节点。

          方式:比较影响数据库的访问,可以通过MemcachedCache缓存起来,定时的刷新分类树缓存。


第二种方式:
      利用 函数 Function遍历一张 数据库数据 表中分类树关系:

     如:

       

CREATE DEFINER=`localhot` FUNCTION `Tree`(treeId INT) RETURNS VARCHAR(4000) CHARSET utf8
BEGIN
DECLARE sTemp VARCHAR(4000);
DECLARE sTempChd VARCHAR(4000);
SET sTemp = ‘$‘;
SET sTempChd = CAST(treeId AS CHAR);
WHILE sTempChd IS NOT NULL DO
SET sTemp = CONCAT(sTemp,‘,‘,sTempChd);
SELECT GROUP_CONCAT(id) INTO sTempChd FROM Category WHERE FIND_IN_SET(parent_id,sTempChd)>0;
END WHILE;
RETURN sTemp;
END$$
DELIMITER


返回当前节点的晚辈集合:
技术分享
再去分析出来,进行数据组装;



第三种方式:

    取出表中的全部SQL数据,再去组装分类树的结构数据:

    参考 Java 多叉树的实现,完成树的初始化和遍历

   

public final class CategoryHelper {

	private static  TreeNode root;
	
	public  static  HashSet<TreeNode> tempNodeList;
	
	private static CategoryHelper treeHelper;
	
	private final static Lock lock =new ReentrantLock();   //创建一个锁

	private CategoryHelper() {
		
		/**
		 * TODO 加载分类树
		*/
		
	}
	
	public static CategoryHelper getInstance() {
		if (treeHelper == null) {
			lock .lock();
			try {
				if (treeHelper == null) {
					treeHelper = new CategoryHelper();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				lock.unlock();
			}
		}
		return treeHelper;
	}
	

	/**
	 *  找到一颗树中某个节点 
	 * @param tree
	 * @param id
	 * @return
	 */
	public static TreeNode getTreeNodeById(TreeNode tree, int id) {
		if (tree == null)
			return null;
		TreeNode treeNode = tree.findTreeNodeById(id);
		return treeNode;
	}
	
	/**
	 * 根据节点ID找到TreeNote 
	 */
	public static TreeNode getTreeNodeById(int id){
		if(id==-1)
			return null;
		HashMap<String,TreeNode> hashMap=getNodesIntoMap();
		TreeNode node=hashMap.get(String.valueOf(id));
		return node;
	}
	

	 /** generate a tree from the given treeNode or entity list 
      *  生成树或实体由给定的treeNode名单
     *
     * */
	public static void generateTree() {
		HashMap nodeMap = getNodesIntoMap();
		Iterator it = nodeMap.values().iterator();
		while (it.hasNext()) {
			TreeNode treeNode = (TreeNode) it.next();
			int parentId = treeNode.getParentId();
			String parentKeyId = String.valueOf(parentId);
			if (nodeMap.containsKey(parentKeyId)) {
				TreeNode parentNode = (TreeNode) nodeMap.get(parentKeyId);
				if (parentNode == null) {
					return;
				} else {
					parentNode.addChildNode(treeNode);
				}
			}
		}
		
	}

	 /**
     * set the parent nodes point to the child nodes
     * 设置子节点集合添加到父节点上。
     * @param nodeMap
     *            a hashmap that contains all the treenodes by its id as the key
     *            一个hashmap,包括所有treenodes由其id作为关键
     */
	@Deprecated
	private  void putChildIntoParent(HashMap nodeMap) {
		Iterator it = nodeMap.values().iterator();
		while (it.hasNext()) {
			TreeNode treeNode = (TreeNode) it.next();
			int parentId = treeNode.getParentId();
			String parentKeyId = String.valueOf(parentId);
			if (nodeMap.containsKey(parentKeyId)) {
				TreeNode parentNode = (TreeNode) nodeMap.get(parentKeyId);
				if (parentNode == null) {
					return;
				} else {
					parentNode.addChildNode(treeNode);
				}
			}
		}
	}
	
	/**
     * put all the treeNodes into a hash table by its id as the key
     *  把所有的treeNodes成一张哈希表由其id作为关键
     * @return hashmap that contains the treenodes
     */
	protected static HashMap<String,TreeNode> getNodesIntoMap() {
		int maxId = Integer.MAX_VALUE;
		HashMap<String,TreeNode> nodeMap = new HashMap<String, TreeNode>();
		Iterator<TreeNode> it = tempNodeList.iterator();
		while (it.hasNext()) {
			TreeNode treeNode = (TreeNode) it.next();
			int id = treeNode.getSelfId();
			if (id < maxId) {
				maxId = id;
				root = treeNode;
			}
			String keyId = String.valueOf(id);
			nodeMap.put(keyId, treeNode);
		}
		return nodeMap;
	}


	/** 
	 * add a tree node to the tempNodeList 
     *  添加一个树节点的tempNodeList
     * 
     * */
	public static void addTreeNode(TreeNode treeNode) {
		lock.lock();
		try {
			 boolean insertFlag =root.insertJuniorNode(treeNode); //将已经产生的树节点插入到树
			   if (insertFlag) {
				   tempNodeList.add(treeNode);
			   }
			   else{
				   throw new BusinessException(treeNode.getParentId()+"这父节点不存在", ErrorCode.BUSINESS_ERROR);
			   }
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
	
	/* 删除节点和它下面的晚辈 */
	public static void delTreeNode(TreeNode treeNode){
		boolean absent = tempNodeList.contains(treeNode);
		if(absent){
			lock.lock();
			try {
				List<TreeNode> delTempNodeList = new ArrayList<TreeNode>();
				List<TreeNode> childList = treeNode.getJuniors();
				if (AppUtils.isNotBlank(childList)) {
					for (int i = 0; i < childList.size(); i++) {
						delTempNodeList.add(childList.get(i));
					}
				}
				delTempNodeList.add(treeNode);
				tempNodeList.removeAll(delTempNodeList); // 更新tempNodeList
				treeNode.deleteNode();
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				lock.unlock();
			}
		}
	}
	
	/* 删除当前节点的某个子节点 */
	public static void delTreeNode(TreeNode treeNode,int childId){
		boolean absent = tempNodeList.contains(treeNode);
		if(absent){
			lock.lock();
			try {
				List<TreeNode> childList = treeNode.getChildList();
				if(AppUtils.isNotBlank(childList)){
					int childNumber = childList.size();
					for (int i = 0; i < childNumber; i++) {
						TreeNode child = childList.get(i);
						if (child.getSelfId() == childId) {
							tempNodeList.remove(child); 
							treeNode.deleteChildNode(childId);
						}
					}
					
				}
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				lock.unlock();
			}
		}
	}
	
	
	/**
	 * 更新树节点
	 * @param sourceTreeNode 源对象
	 * @param targetTreeNode 目标对象
	 */
	public static void updateTreeNode(TreeNode sourceTreeNode,String noteName){
		boolean absent = tempNodeList.contains(sourceTreeNode);
		if(absent){
			
			lock.lock();
			try {
				sourceTreeNode.setNodeName(noteName);
				Object obj=sourceTreeNode.getObj();
				if(obj!=null && obj instanceof OrganizationEntity){
					OrganizationEntity entity=(OrganizationEntity)obj;
					entity.setOrgName(noteName);
				}
			    tempNodeList.add(sourceTreeNode);
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				lock.unlock();
			}
		}
	}
	
	/**
	 * 更新树节点
	 * @param sourceTreeNode 源对象
	 * @param targetTreeNode 目标对象
	 */
	public static void updateTreeNode(TreeNode sourceTreeNode,TreeNode targetTreeNode){
		boolean absent = tempNodeList.contains(sourceTreeNode);
		if(absent){
			lock.lock();
			try {
				sourceTreeNode.setNodeName(targetTreeNode.getNodeName());
				OrganizationEntity entity=new OrganizationEntity(targetTreeNode.getParentId(), targetTreeNode.getSelfId(), targetTreeNode.getNodeName());
				sourceTreeNode.setObj(entity);
				tempNodeList.add(sourceTreeNode);
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				lock.unlock();
			}
		}
	}

	

	  /**
     * adapt the entities to the corresponding treeNode
     *  适应于相应的treeNode的实体
     * @param entityList
     *            list that contains the entities       列表包含的实体
     *@return the list containg the corresponding treeNodes of the entities
     *  containg相应的treeNodes名单的实体
     */
	public static HashSet<TreeNode> changeEnititiesToTreeNodes(Set entityList) {
		OrganizationEntity orgEntity = new OrganizationEntity();
		Set<TreeNode> tempNodeList = new HashSet<TreeNode>();
		Map<Integer, TreeNode> map=new HashMap<Integer, TreeNode>();
		TreeNode treeNode;

		Iterator<OrganizationEntity> it = entityList.iterator();
		while (it.hasNext()) {
			orgEntity = (OrganizationEntity) it.next();
			treeNode = new TreeNode();
			treeNode.setObj(orgEntity);
			treeNode.setParentId(orgEntity.getParentId());
			treeNode.setSelfId(orgEntity.getOrgId());
			treeNode.setNodeName(orgEntity.getOrgName());
			treeNode.setParentNode(map.get(orgEntity.getParentId()));
			tempNodeList.add(treeNode);
			map.put(orgEntity.getOrgId(), treeNode);
		}
		return (HashSet<TreeNode>) tempNodeList;
	}

	public static TreeNode getRoot() {
		return root;
	}

	public static HashSet<TreeNode> getTempNodeList() {
		return tempNodeList;
	}

	public  static void setTempNodeList(HashSet<TreeNode> tempNodeList) {
		CategoryHelper.tempNodeList = tempNodeList;
	}

	
	
}



public class TreeNode implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private int parentId;
	
	private int selfId;
	
	protected String nodeName;
	
	protected Object obj;
	
	protected TreeNode parentNode;
	
	protected List<TreeNode> childList;

	public TreeNode() {
		initChildList();
	}

	public TreeNode(TreeNode parentNode) {
		this.getParentNode();
		initChildList();
	}

	public boolean isLeaf() {
		if (childList == null) {
			return true;
		} else {
			if (childList.isEmpty()) {
				return true;
			} else {
				return false;
			}
		}
	}

	/* 插入一个child节点到当前节点中 */
	public void addChildNode(TreeNode treeNode) {
		initChildList();
		childList.add(treeNode);
	}

	public void initChildList() {
		if (childList == null)
			childList = new ArrayList<TreeNode>();
	}

	public boolean isValidTree() {
		return true;
	}

	/* 返回当前节点的父辈节点集合 */
	public List<TreeNode> getElders() {
		List<TreeNode> elderList = new ArrayList<TreeNode>();
		TreeNode parentNode = this.getParentNode();
		if (parentNode == null) {
			return elderList;
		} else if(parentNode.getParentId()==-1) {
			return elderList;
		}else{
			elderList.add(parentNode);
			elderList.addAll(parentNode.getElders());
			return elderList;
		}
	}

	/* 返回当前节点的晚辈集合 */
	public List<TreeNode> getJuniors() {
		List<TreeNode> juniorList = new ArrayList<TreeNode>();
		List<TreeNode> childList = this.getChildList();
		if (childList == null) {
			return juniorList;
		} else {
			int childNumber = childList.size();
			for (int i = 0; i < childNumber; i++) {
				TreeNode junior = childList.get(i);
				juniorList.add(junior);
				juniorList.addAll(junior.getJuniors());
			}
			return juniorList;
		}
	}
	
	/* 返回当前节点的同级的集合 */
	public List<TreeNode> getCompatriots(){
		List<TreeNode> compatriotList = new ArrayList<TreeNode>();
		TreeNode parentNode = this.getParentNode();
		if (parentNode == null) {
			return compatriotList;
			
		}else if(this.getParentId()==0){ //说明是一级节点
			compatriotList=getParentNode().getChildList();	
		} else if(parentNode.getParentId()==-1) { //说明是根节点
			compatriotList= this.getChildList();
		}else{
			compatriotList.add(this.getParentNode());
			compatriotList.addAll(parentNode.getChildList());
		}
		return compatriotList;
	}
	
	
	

	/* 返回当前节点的孩子集合 */
	public List<TreeNode> getChildList() {
		return childList;
	}

	/* 删除节点和它下面的晚辈 */
	public void deleteNode() {
		TreeNode parentNode = this.getParentNode();
		int id = this.getSelfId();

		if (parentNode != null) {
			parentNode.deleteChildNode(id);
		}
	}

	/* 删除当前节点的某个子节点 */
	public void deleteChildNode(int childId) {
		List<TreeNode> childList = this.getChildList();
		int childNumber = childList.size();
		for (int i = 0; i < childNumber; i++) {
			TreeNode child = childList.get(i);
			if (child.getSelfId() == childId) {
				childList.remove(i);
				return;
			}
		}
	}

	/* 动态的插入一个新的节点到当前树中 */
	public boolean insertJuniorNode(TreeNode treeNode) {
		int juniorParentId = treeNode.getParentId();
		if(juniorParentId==0){
			addChildNode(treeNode);
			return true;
		}
		else if (this.parentId == juniorParentId) {
			List<TreeNode> list=this.getParentNode().getChildList();
			if(list==null || list.isEmpty()){
				list = new ArrayList<TreeNode>();
				list.add(treeNode);
			}else{
				list.add(treeNode);
			}
			return true;
		} else {
			List<TreeNode> childList = this.getChildList();
			int childNumber = childList.size();
			boolean insertFlag;

			for (int i = 0; i < childNumber; i++) {
				TreeNode childNode = childList.get(i);
				insertFlag = childNode.insertJuniorNode(treeNode);
				if (insertFlag == true)
					return true;
			}
			return false;
		}
	}

	/* 找到一颗树中某个节点 */
	public TreeNode findTreeNodeById(int id) {
		if (this.selfId == id)
			return this;
		if (childList.isEmpty() || childList == null) {
			return null;
		} else {
			int childNumber = childList.size();
			for (int i = 0; i < childNumber; i++) {
				TreeNode child = childList.get(i);
				TreeNode resultNode = child.findTreeNodeById(id);
				if (resultNode != null) {
					return resultNode;
				}
			}
			return null;
		}
	}

	/* 遍历一棵树,层次遍历 */
	public void traverse() {
		if (selfId < 0)
			return;
		print(this.selfId);
		if (childList == null || childList.isEmpty())
			return;
		int childNumber = childList.size();
		for (int i = 0; i < childNumber; i++) {
			TreeNode child = childList.get(i);
			child.traverse();
		}
	}

	public void print(String content) {
		System.out.println(content);
	}

	public void print(int content) {
		System.out.println(String.valueOf(content));
	}

	public void setChildList(List<TreeNode> childList) {
		this.childList = childList;
	}

	public int getParentId() {
		return parentId;
	}

	public void setParentId(int parentId) {
		this.parentId = parentId;
	}

	public int getSelfId() {
		return selfId;
	}

	public void setSelfId(int selfId) {
		this.selfId = selfId;
	}

	public TreeNode getParentNode() {
		return parentNode;
	}

	public void setParentNode(TreeNode parentNode) {
		this.parentNode = parentNode;
	}

	public String getNodeName() {
		return nodeName;
	}

	public void setNodeName(String nodeName) {
		this.nodeName = nodeName;
	}

	public Object getObj() {
		return obj;
	}

	public void setObj(Object obj) {
		this.obj = obj;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + selfId;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if(obj instanceof TreeNode){
			TreeNode node=(TreeNode)obj;
			return this.selfId==node.getSelfId();
		}
		return false;
	}

	public TreeNode(int parentId, int selfId, String nodeName, Object obj) {
		super();
		this.parentId = parentId;
		this.selfId = selfId;
		this.nodeName = nodeName;
		this.obj = obj;
	}
	
	
	
	

}



public class OrganizationEntity {

	public int parentId;
	
	public int orgId;
	
	public String orgName;

	public int getParentId() {
		return parentId;
	}

	public void setParentId(int parentId) {
		this.parentId = parentId;
	}

	public int getOrgId() {
		return orgId;
	}

	public void setOrgId(int orgId) {
		this.orgId = orgId;
	}

	public String getOrgName() {
		return orgName;
	}

	public void setOrgName(String orgName) {
		this.orgName = orgName;
	}

	public OrganizationEntity(){
		
	}
	
	
	public OrganizationEntity(int parentId, int orgId, String orgName) {
		super();
		this.parentId = parentId;
		this.orgId = orgId;
		this.orgName = orgName;
	}
	
	
}


  数据库表结构设计:

   方式一:通过一张表来实现分类树:

    

CREATE TABLE `ls_category` (
  `id` bigint(20) NOT NULL DEFAULT ‘0‘ COMMENT ‘产品类目ID‘,
  `parent_id` bigint(20) DEFAULT NULL COMMENT ‘父节点‘,
  `name` varchar(50) NOT NULL DEFAULT ‘‘ COMMENT ‘产品类目名称‘,
  `pic` varchar(300) DEFAULT NULL COMMENT ‘类目的显示图片‘,
  `seq` int(5) DEFAULT NULL COMMENT ‘排序‘,
  `enable` int(1) NOT NULL DEFAULT ‘1‘ COMMENT ‘默认是1,表示正常状态,0为下线状态‘
  `keyword` varchar(256) DEFAULT NULL COMMENT ‘SEO关键字‘,
  `cat_desc` varchar(256) DEFAULT NULL COMMENT ‘SEO描述‘,
  `title` varchar(256) DEFAULT NULL COMMENT ‘SEO标题‘,
  `rec_date` datetime DEFAULT NULL COMMENT ‘记录时间‘,
  `level` int(2) DEFAULT NULL COMMENT ‘分类层级‘,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=‘产品类目‘;




   方式二:用两种表结构实现产品的分类树,表一:存放商品分类的一级分类 表二:存放商品分类的无限下级分类,及关联一级分类表的ID引用:

  

CREATE TABLE `ls_first_cat` (
  `first_cat_id` int(11) NOT NULL DEFAULT ‘0‘ COMMENT ‘产品分类ID‘,
  `first_cat_name` varchar(50) NOT NULL DEFAULT ‘‘ COMMENT ‘产品分类名称‘,
  `first_cat_picture` varchar(250) DEFAULT NULL COMMENT ‘分类的显示图片‘,
  `seq` int(11) DEFAULT NULL COMMENT ‘排序‘,
  `status` int(1) NOT NULL DEFAULT ‘1‘ COMMENT ‘默认是1,表示正常状态,0为下线状态‘
  PRIMARY KEY (`first_cat_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=‘商品分类‘;

CREATE TABLE `ls_cat` (
  `cat_id` int(11) NOT NULL DEFAULT ‘0‘ COMMENT ‘产品分类ID‘,
  `cat_name` varchar(50) NOT NULL DEFAULT ‘‘ COMMENT ‘产品分类名称‘,
  `first_cat_id` varchar(250) DEFAULT NULL COMMENT ‘对应的一级类型‘,
  `seq` int(11) DEFAULT NULL COMMENT ‘排序‘,
  `status` int(1) NOT NULL DEFAULT ‘1‘ COMMENT ‘默认是1,表示正常状态,0为下线状态‘,
  `parent_cat_id` int(11)  COMMENT ‘父节点ID‘
  PRIMARY KEY (`cat_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=‘商品子类表‘;


  资料参考:

    http://my.oschina.net/bootstrap/blog/166805








java 参仿京东天猫的分类树结构,实现无限级分类结构

标签:

原文地址:http://my.oschina.net/nuotang/blog/491702

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!