bootstrap-treeview多级树形菜单,后台JSON格式如何组织?

树形列表菜单的数据组织形式一般有两种:一种是一次性向服务器请求所有节点的数据,一种是先请求根目录的节点,当用户点击该节点时,再去请求该节点的子叶节点的数据。这里我们的需求是第一种。

bootstrap-treeview多级树形菜单,后台JSON格式如何组织?_第1张图片

树形菜单是我们经常会用到的一种菜单展现方式,这里我推荐bootstrap-treeview,它是一款效果非常酷的基于bootstrap的jQuery多级列表树插件。该jQuery插件基于Twitter Bootstrap,以简单和优雅的方式来显示一些继承树结构,如视图树、列表树等。

前端页面的编写,比较简单,故简略描述,我们着重将后端如何按照要求组织返回所需的Json。

使用方法

首先要在页面中引入依赖的css样式和 bootstrap-treeview.js文件。



 


                 

可以使用任何HTML DOM元素来作为该列表树的容器:


调用
数据源要求的数据格式:
 var tree = [
		            {
		              text: "Parent 1",
		              tags: ['2'],
		              nodes: [
		                {
		                  text: "Child 1",
		                  tags: ['3'],
		                  nodes: [
		                    {
		                      text: "Grandchild 1",
		                      tags: ['1']
		                    },
		                    {
		                      text: "Grandchild 2",
		                      tags: ['1']
		                    }
		                  ]
		                },
		                {
		                  text: "Child 2",
		                  tags: ['1']
		                }
		              ]
		            },
		            {
		              text: "Parent 2",
	                  tags: ['1']
		            },
		            {
		              text: "Parent 3",
	                  tags: ['1']
		            },
		            {
		              text: "Parent 4",
	                  tags: ['1']
		            },
		            {
		              text: "Parent 5",
	                  tags: ['1']
		            }
		          ];  
看到这个数据结构,我们首先想到的是数据结构中的二叉树。欧拉,我们不妨可以把它理解成,这样的数据结构:

bootstrap-treeview多级树形菜单,后台JSON格式如何组织?_第2张图片

创建一个实例,组织所需要的数据结构的json.

public class BootstrapUiTreeNode implements Serializable {
	private static final long serialVersionUID = 1L;
	static final Logger log = Logger.getLogger(BootstrapUiTreeNode.class);

	private String id;
	private String parentId;
	private String text;
	
	//子叶节点
	private List nodes = new ArrayList<>();
	
	//统计该节点分类下文档的数量
	private List tags = new ArrayList<>(); // tags: ['NUM']
	
	public BootstrapUiTreeNode(String id, String parentId, String text) {
		super();
		this.id = id;
		this.parentId = parentId;
		this.text = text;
	}

	
	public BootstrapUiTreeNode(String id, String parentId, String text, List nodes) {
		super();
		this.id = id;
		this.parentId = parentId;
		this.text = text;
		this.nodes = nodes;
	}

	
	public String getParentId() {
		return parentId;
	}


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


	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

	public List getNodes() {
		return nodes;
	}

	public void setNodes(List nodes) {
		this.nodes = nodes;
	}


	public List getTags() {
		return tags;
	}


	public void setTags(List tags) {
		this.tags = tags;
	}

	

	/**
	 * 加载第一层树节点 父节点的根目录的父id必须为"NONE",包含字段名ID,PARENTID,NAME
	 * 
	 * @param parentId
	 *            父亲节点id
	 * @param SortTitle
	 *            排序字段index
	 * @param tableTitle
	 *            表名index
	 * @param id_title
	 *            表id的index
	 * @param parentId_title
	 *            表parentid的index
	 * @param name_title
	 *            表name的index
	 * @param icon_title
	 */
	public static List> queryTreeNodeOne(String parentId, String SortTitle, String tableTitle, String id_title,
			String parentId_title, String name_title) {
		if (StringUtils.isEmpty(parentId)) {
			parentId = "NONE";
		}
		DataResult nodeResult = null;
		DBSort sort = new DBSort("a." + SortTitle, "ASC");
		DataQuery query = DataQuery.getInstance("1", 
				id_title
				+ ","
				+ parentId_title
				+ " as "
				+ parentId_title
				+ ","
				+ name_title
				+ " as "
				+ name_title,
				tableTitle + " a");
		query.setPagesize(100);
		query.addSort(sort);
		DataQuerys.wipeVirus(parentId);
		query.setSqlRule("and " + parentId_title + "='" + parentId + "'");
		try {
			nodeResult = query.search();
		} catch (SQLException e) {
			log.error(e.getMessage());
		}
		return nodeResult.getResultList();
	}

	public static List getPopTypesForReadDoc() {
		DataQuery query = DataQuery.init(new DataQuery(),
				"(SELECT a.NAME as NAME,a.SORT as SORT, a.ID as ID, a.READPOP as READPOP,a.WRITEPOP AS WRITEPOP, a.AUDITPOP AS AUDITPOP, a.PARENTID AS PARENTID, (SELECT COUNT(B1.ID) FROM FARM_DOC B1 LEFT JOIN FARM_RF_DOCTYPE B2 ON B1.ID = B2.DOCID LEFT JOIN FARM_DOCTYPE B3 ON B3.ID = B2.TYPEID WHERE  B1.STATE='1' and  B3.TREECODE  LIKE CONCAT(A.TREECODE,'%') AND B1.STATE='1') AS NUM,f.oid as OID,f.FUNTYPE as FUNTYPE FROM farm_doctype AS a left join FARM_DOCTYPE_POP as f on f.TYPEID=a.ID WHERE 1 = 1 AND (TYPE = '1' OR TYPE = '3') AND PSTATE = '1' ) AS e",
				"NAME,ID,PARENTID,NUM,OID,READPOP,AUDITPOP,WRITEPOP,FUNTYPE,SORT");
		query.setPagesize(1000);
		query.setNoCount();
		query.setCache(Integer.valueOf(0), CACHE_UNIT.second);
		query.addSort(new DBSort("SORT", "ASC"));
		try {
			DataResult result = query.search();
			//利用反射获取对象集合
			return result.getObjectList(TypeBrief.class);
		} catch (SQLException e) {
			log.error(e.toString());
			return new ArrayList();
		}
	}
	
	
	
	/**
	 * 遍历集合获得对象
	 * 
	 * @param nodeList
	 * @return
	 */
	public static List findNode(List typeBriefs, List> data, String id_title,
			String parentId_title, String name_title) {
		List nodeList = new ArrayList<>();
		try {
			for (Map node : data) {
				if (node.get(id_title) == null) {
					continue;
				}
				BootstrapUiTreeNode item = new BootstrapUiTreeNode(node.get(id_title).toString(), 
						node.get(parentId_title).toString(), node.get(name_title).toString());
				//统计该节点下分类的文档数
				for(TypeBrief typeBrief : typeBriefs) {
					if(typeBrief.getId().equals(node.get(id_title).toString())) {
						item.getTags().add(typeBrief.getNum() + "");
						break;
					}
				}
				nodeList.add(item);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return nodeList;
	}
	
	/**
	 * 先用递归构造除第一层几个根节点外的类多叉树结构
	 * @param node
	 * @param parentId
	 * @param sortTitle
	 * @param tableTitle
	 * @param id_title
	 * @param parentId_title
	 * @param name_title
	 * @return
	 */
	public static BootstrapUiTreeNode createSubtreeTreeNodes(List typeBriefs, BootstrapUiTreeNode node, String parentId, String sortTitle, String tableTitle, String id_title,
			String parentId_title, String name_title) {
		
		//获取该根节点下的所有子节点
		List> data = queryTreeNodeOne(parentId, sortTitle, tableTitle, id_title, parentId_title, name_title);
		List roots = findNode(typeBriefs, data, id_title, parentId_title, name_title);
		
		if(null != roots && roots.size() > 0) {
			//递归继续查询
			for(BootstrapUiTreeNode child : roots) {
				BootstrapUiTreeNode treeNode = createSubtreeTreeNodes(typeBriefs, child, child.getId(), sortTitle, tableTitle, id_title, parentId_title, name_title);
				node.getNodes().add(treeNode);
			}
			
		} else {
			node.setNodes(null);  
		}
		
		return node;
	}
	
	/**
	 * 补上第一层的几个根节点
	 * @param parentId
	 * @param sortTitle
	 * @param tableTitle
	 * @param id_title
	 * @param parentId_title
	 * @param name_title
	 * @return
	 * 
	 * 注意:所以会存在叶子节点中的nodes没有数据的情况,这个时候会出现叶子节点是可以伸缩的,
	 * 因为nodes属性就是一个对象数组,它会被认为它还有子节点,其实是没有的。
	 * 
	 */
	public static List createTreeNodes(String parentId, String sortTitle, String tableTitle, String id_title,
			String parentId_title, String name_title) {
		//统计所有节点分类对应的文档数目
		List typeBriefs = getPopTypesForReadDoc();
		
		List nodes  = new ArrayList<>();
		//查询第一层根节点
		List> data = queryTreeNodeOne(parentId, sortTitle, tableTitle, id_title, parentId_title, name_title);
		List treeNodes = findNode(typeBriefs, data, id_title, parentId_title, name_title);
		
		for(BootstrapUiTreeNode node : treeNodes) {
			BootstrapUiTreeNode treeNode = createSubtreeTreeNodes(typeBriefs, node, node.getId(), sortTitle, tableTitle, id_title, parentId_title, name_title);
			nodes.add(treeNode);
		}
		
		return nodes;
	}
}

控制器:

@RequestMapping("/FarmDoctypeLoadTreeNodes")
	@ResponseBody
	public Map loadTreeNodes(DataQuery query, HttpServletRequest request, String id) {
		query = EasyUiUtils.formatGridQuery(request, query);
		try {
			List treeNodes = BootstrapUiTreeNode.createTreeNodes(id, "SORT", "FARM_DOCTYPE", "ID", "PARENTID", "NAME");
			return ViewMode.getInstance().putAttr("nodes", treeNodes).returnObjMode();
		} catch (Exception e) {
			log.error(e.getMessage());
			return ViewMode.getInstance().setError(e.getMessage()).returnObjMode();
		}
	}

访问结果:


最终树形菜单效果:

bootstrap-treeview多级树形菜单,后台JSON格式如何组织?_第3张图片

你可能感兴趣的:(java,web前端)