在网站开发的时候我们会对网站的栏目进行分类,一个栏目可以有多个子分类,一个子分类又可以有分裂,例如:新闻栏目下有每日早报和每日晚报两个栏目,其中每日早报下面又分为上海早报,北京早报,杭州早报,下面是京东首页的分类图。

 

数据库设计
我们在设计数据库的时候仅仅使用一张表就可以把上面的关系给捋清楚,就是通过一个parentid字段,让我们开看一下这张表的表结构
 

各位看官可以看一下建表语句
DROP TABLE IF EXISTS `menu`;
CREATE TABLE `menu` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键递增',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '分类名称',
`parentid` int(11) NULL DEFAULT NULL COMMENT '父节点id',
`url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '分类链接',
`icon` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '分类图标',
`order` int(11) NULL DEFAULT NULL COMMENT '分类排序权重',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

再让我们来插入一点测试数据

INSERT INTO `menu` VALUES (1, '新闻', 0, '/www/xinwen', 'xxx', 1);
INSERT INTO `menu` VALUES (2, '每日日报', 1, '/www/meiriribao', 'xxx', 2);
INSERT INTO `menu` VALUES (3, '每日晚报', 1, '/www/zaobao', 'xxx', 1);
INSERT INTO `menu` VALUES (4, '河南日报', 2, '/www/henan', 'xxx', 2);
INSERT INTO `menu` VALUES (5, '上海日报', 2, '/www/shanghai', 'xxx', 1);
INSERT INTO `menu` VALUES (6, '南京日报', 2, '/www/nanjing', 'xxx', 3);
INSERT INTO `menu` VALUES (7, '开封日报', 4, '/www/zhoukou', 'xxx', 2);
INSERT INTO `menu` VALUES (8, '郑州日报', 4, '/www/zhenghzou', 'xxx', 3);
 现在我们来看一下Java程序中该如何从数据库中读取数据这样的数据返回页面。在下在项目中用的是SSM框架因为并不是SSM框架教程,这里仅仅贴出Dao层,简单至极
List<Menu> findAll();
 <select id="findAll" resultMap="BaseResultMap">
select * from menu;
</select>
看一下菜单对应的实体

package com.sys.domain;

import java.util.List;

public class Menu implements Comparable<Menu> {
private Integer id; private String name; private Integer parentid; private String url; private String icon; private Integer order; //子菜单列表
private List<Menu> children; public List<Menu> getChildren() {
return children;
}
public void setChildren(List<Menu> children) {
this.children = children;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name == null ? null : name.trim();
} public Integer getParentid() {
return parentid;
} public void setParentid(Integer parentid) {
this.parentid = parentid;
} public String getUrl() {
return url;
} public void setUrl(String url) {
this.url = url == null ? null : url.trim();
} public String getIcon() {
return icon;
} public void setIcon(String icon) {
this.icon = icon == null ? null : icon.trim();
} public Integer getOrder() {
return order;
} public void setOrder(Integer order) {
this.order = order;
} @Override
public int compareTo(Menu o) {
if (this.order != o.order) {
return this.order - o.order;
}
return 0;
}
}

实体关键点1:实体Menu实现了Comparable接口并实现了compareTo方法

这样就可以直接使用Collections.sort()方法进行List排序

实体关键点2:实体中新增一个属性List<Menu> children,用于存储返回页面的子节点

 

实体较介绍完了,我们就可以直接看代码啦,都加上注释了很简单

package com.sys.menutree;

import com.sys.dao.MenuMapper;
import com.sys.domain.Menu;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody; import java.util.*; /**
* @Author:jimisun
* @Description:
* @Date:Created in 18:02 2018/8/8
* @Modified By:
*/
@Controller
@RequestMapping("/menu")
public class MenuController { @Autowired
private MenuMapper menuMapper; @RequestMapping(value = "/findTree", method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> findTree(@RequestBody(required = false) Menu menu) {
//构建返回数据
Map<String, Object> data = new HashMap<String, Object>(); try {
//查询到的所有菜单
List<Menu> allMenu = menuMapper.findAll();
//根节点
List<Menu> rootMenu = new ArrayList<Menu>(); //根据传递的参数设置根节点
if (menu != null && menu.getId() != null) {
//父节点为传递的id为根节点
for (Menu nav : allMenu) {
if (nav.getParentid().equals(menu.getId())) {
rootMenu.add(nav);
}
}
} else {
//父节点是0的,为根节点。
for (Menu nav : allMenu) {
if (nav.getParentid().equals(0)) {
rootMenu.add(nav);
}
}
} // 根据Menu类的order排序
Collections.sort(rootMenu); //为根菜单设置子菜单,getClild是递归调用的
for (Menu nav : rootMenu) {
//获取根节点下的所有子节点 使用getChild方法
List<Menu> childList = getChild(nav.getId(), allMenu);
//给根节点设置子节点
nav.setChildren(childList);
} data.put("success", "true");
data.put("list", rootMenu);
return data;
} catch (Exception e) {
data.put("success", "false");
data.put("list", new ArrayList());
return data;
} } /**
* 递归设置栏目的子节点
*
* @param id 父节点id
* @param allMenu 节点列表
* @return
*/
private List<Menu> getChild(Integer id, List<Menu> allMenu) {
//子菜单
List<Menu> childList = new ArrayList<Menu>();
for (Menu nav : allMenu) {
// 遍历所有节点,将所有菜单的父id与传过来的根节点的id比较
//相等说明:为该根节点的子节点。
if (nav.getParentid().equals(id)) {
childList.add(nav);
}
}
//递归设置子节点
for (Menu nav : childList) {
nav.setChildren(getChild(nav.getId(), allMenu));
}
//排序
Collections.sort(childList);
//如果节点下没有子节点,返回一个空List(递归退出)
if (childList.size() == 0) {
return new ArrayList<Menu>();
}
return childList;
} }

最后我们来看一下功能演示

直接发送直接请求接口,获取的是所有分类

请求结果

{
"success": "true",
"list": [
{
"id": 5,
"name": "上海日报",
"parentid": 2,
"url": "/www/shanghai",
"icon": "xxx",
"order": 1,
"children": []
},
{
"id": 4,
"name": "河南日报",
"parentid": 2,
"url": "/www/henan",
"icon": "xxx",
"order": 2,
"children": [
{
"id": 7,
"name": "开封日报",
"parentid": 4,
"url": "/www/zhoukou",
"icon": "xxx",
"order": 2,
"children": []
},
{
"id": 8,
"name": "郑州日报",
"parentid": 4,
"url": "/www/zhenghzou",
"icon": "xxx",
"order": 3,
"children": []
}
]
},
{
"id": 6,
"name": "南京日报",
"parentid": 2,
"url": "/www/nanjing",
"icon": "xxx",
"order": 3,
"children": []
}
]
}

发送请求接口,并附带要查询的分类id

结果如下

{
"success": "true",
"list": [
{
"id": 5,
"name": "上海日报",
"parentid": 2,
"url": "/www/shanghai",
"icon": "xxx",
"order": 1,
"children": []
},
{
"id": 4,
"name": "河南日报",
"parentid": 2,
"url": "/www/henan",
"icon": "xxx",
"order": 2,
"children": [
{
"id": 7,
"name": "开封日报",
"parentid": 4,
"url": "/www/zhoukou",
"icon": "xxx",
"order": 2,
"children": []
},
{
"id": 8,
"name": "郑州日报",
"parentid": 4,
"url": "/www/zhenghzou",
"icon": "xxx",
"order": 3,
"children": []
}
]
},
{
"id": 6,
"name": "南京日报",
"parentid": 2,
"url": "/www/nanjing",
"icon": "xxx",
"order": 3,
"children": []
}
]
}

Java构建网站多级菜单功能解决方案的更多相关文章

  1. java实现网站paypal支付功能并且异步修改订单的状态

    java实现网站paypal支付功能并且异步修改订单的状态:步骤如下 第一步:去paypal的官网https://www.paypal.com注册一个个人账号,在创建沙箱测试账号时需要用到 第二步:p ...

  2. java生成多级菜单树

    使用java实现一个多级菜单树结构 先上数据库 ps_pid字段很重要,是父级菜单的id Menu类 Menu类要新增一个字段,用来存放子菜单 /** * 子菜单列表 */ private List& ...

  3. Python简单实现多级菜单

    # -*- coding: utf-8 -*- # @Time : 2018-06-01 13:40 # @Author : 超人 # @Email : huxiaojiu111@gmail.com ...

  4. Atitit.excel导出 功能解决方案 php java C#.net版总集合.doc

    Atitit.excel导出 功能解决方案 php java C#.net版总集合.docx 1.1. Excel的保存格式office2003 office2007/2010格式1 1.2. 类库选 ...

  5. java 24 - 7 GUI之 创建多级菜单窗体

    需求: 创建多级菜单 步骤: A:创建窗体对象(并设置属性和布局) B:创建菜单栏 C:创建菜单和子菜单 D:逐步添加菜单(子菜单添加到菜单中,菜单添加到菜单栏中) E:窗体中设置菜单栏(菜单栏并不是 ...

  6. Vue2 实现树形菜单(多级菜单)功能模块

    结构示意图 ├── index.html ├── main.js ├── router │ └── index.js # 路由配置文件 ├── components # 组件目录 │ ├── App. ...

  7. 网站开发---js与java实现的一些小功能

    记录一下网站开发过程中的一些小功能 1.js获取当前年份: <span>Copyright © 2017-<script>document.write( new Date(). ...

  8. 使用Java语言开发微信公众平台(八)——自定义菜单功能

    随着上一篇文章的结束,我们已经实现了所有消息的类型的回复功能.今天,我们来学习更加高大上,也更加重要的自定义菜单功能. 一.了解自定义菜单 自定义菜单是微信公众平台最常用也是最重要的功能之一.根据微信 ...

  9. Java中各类Cache机制实现解决方案[来自CSDN]

    摘要:在Java中,不同的类都有自己单独的Cache机制,实现的方法也可能有所不同,文章列举了Java中常见的各类Cache机制的实现方法,同时进行了综合的比较. 在Java中,不同的类都有自己单独的 ...

随机推荐

  1. getconf命令【一天一个命令】

    我们时常需要查询系统相关的信息,比如页面大小,整数大小之类,如果编写程序去计算会比较繁琐,这里有一个很有用的命令,可以用来获取系统相关信息.它就是getconf.   $ getconf PAGE_S ...

  2. plink参数说明

    Plink: command-line connection utilityRelease 0.67Usage: plink [options] [user@]host [command]       ...

  3. MySql图解给表添加外键

    关于外键约束的几种方式,请移步鄙人的另外一个博客中的博文  http://blog.csdn.net/hadues/article/details/52558184

  4. libxml2实例

    // libxmlTest.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <stdio.h> #includ ...

  5. pc或者微信上用pdf.js在线预览pdf和word

    最近项目要求pdf和word可以在线预览功能,pc端还好解决,但是微信端就有点坑了,pc端原来的思路是将文件转成base64,然后用html格式显示 ,但是微信端不支持, 这种方式就pass掉了,谷歌 ...

  6. js 树菜单 ztree

    http://www.ztree.me/v3/api.php 官网 api js /** <div id="menuContent" class="menuCont ...

  7. Netty 源码分析之 番外篇 Java NIO 的前生今世

    简介 Java NIO 是由 Java 1.4 引进的异步 IO. Java NIO 由以下几个核心部分组成: Channel Buffer Selector NIO 和 IO 的对比 IO 和 NI ...

  8. 设计模式 ( 十二 ) 职责链模式(Chain of Responsibility)(对象行为)

     设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型) 1.概述 你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我这里能解决就解决.不能解决就 ...

  9. 由于内部错误,服务器无法处理该请求。有关该错误的详细信息,请打开服务器上的 IncludeExceptionDetailInFaults (从 ServiceBehaviorAttribute 或从 <serviceDebug> 配置行为)以便将异常信息发送回客户端,或打开对每个 Microsoft .NET Framework SDK 文档的跟踪并检查服务器跟踪日志。

    客户端调用WCF的时候报上面的错误,WCF只能序列化基础的数据类型,不能直接序列化SqlParameter类型,需要使用自定义类,然后在WCF服务端转换的方式解决: 自定义类代码如下: using S ...

  10. 在windows中将Tomcat作为服务启动

    http://www.cnblogs.com/chuyuhuashi/archive/2012/04/28/2475315.html ————————————————————————————————— ...