菜鸟笔记:node.js+mysql中将JSON数据构建为树(递归制作树状菜单数据接口)
初学Web端开发,今天是第一次将所学做随笔记录,肯定存在多处欠妥,望大家海涵;若有不足,望大家批评指正。
进实验室后分配到的第一个项目,需要制作一个不确定层级树形菜单的数据接口,对于从来没实战编过程的我,存在太多需要学习的地方。
开发环境:Atom;
语言:javascript;
其他:nodejs;mysql;express;
输入:通过sql语句转换出的一个个JSON对象,如:其中id为唯一编号,parent为其父级的id号。
[
{
"id": 1,
"name": "111",
"parent": null,
"icon": "555,,"
},
{
"id": 2,
"name": "极地测试菜单2",
"parent": 1,
"icon": "/img/002.png"
},
{
"id": 4,
"name": "555",
"parent": 2,
"icon": "88"
},
{
"id": 5,
"name": "ddd",
"parent": 2,
"icon": "555.png"
},
{
"id": 6,
"name": "666",
"parent": 4,
"icon": null
},
{
"id": 7,
"name": "777",
"parent": 5,
"icon": null
},
{
"id": 9,
"name": "8888",
"parent": 1,
"icon": null
},
{
"id": 10,
"name": "9999",
"parent": 9,
"icon": null
},
{
"id": 11,
"name": "10000",
"parent": 1,
"icon": null
}
]
输出:树状JSON结构
{
"id": 1,
"name": "111",
"parent": null,
"icon": "555,,",
"sub": [
{
"id": 2,
"name": "极地测试菜单2",
"parent": 1,
"icon": "/img/002.png",
"sub": [
{
"id": 4,
"name": "555",
"parent": 2,
"icon": "88",
"sub": [
{
"id": 6,
"name": "666",
"parent": 4,
"icon": null,
"sub": []
}
]
},
{
"id": 5,
"name": "ddd",
"parent": 2,
"icon": "555.png",
"sub": [
{
"id": 7,
"name": "777",
"parent": 5,
"icon": null,
"sub": []
}
]
}
]
},
{
"id": 9,
"name": "8888",
"parent": 1,
"icon": null,
"sub": [
{
"id": 10,
"name": "9999",
"parent": 9,
"icon": null,
"sub": []
}
]
},
{
"id": 11,
"name": "10000",
"parent": 1,
"icon": null,
"sub": []
}
]
}
即将从mysql中取出的一条一条JSON数据,按照parent所指向的id号,转变为树桩JSON结构,供AngularJS框架自动生成树桩菜单。
示例图:
变量声明:allMenu为初始输入的JSON数据格式,即包含一条一条JSON对象的数组。
对象的sub属性放置当前对象的所有子节点数组。
思想:利用递归/循环进行树的层级遍历。
比如输入一个根节点对象,首先应对allMenu遍历寻找parent为根节点id的所有对象(方法命名为findItemChild),并将其置入一个临时数组childlist中。然后对该childlist进行遍历,对其中每一个对象利用递归方法,返回该对象的childList并添加进当前对象的sub中,往复递归。举个例子:即当方法输入id=1的对象后,findItemChild方法通过遍历会返回一个数组[{id:2,parent:1,...},{id:9,parent:1,...},{id:11,parent:1,...}],之后对该数组进行遍历,即将id=2的对象递归输入方法,并将获取的childlist遍历继续递归。。。。即树的层级遍历。
算法:
输入:JSON对象item
function getAllChild(res){
①获取所有父级为根节点id的子对象数组childlist
②若childlist为空,则返回[]
③若childlist不为空,遍历childlist,并对每一个childlist[k]递归调用getAllChild(childlist[k])赋予childlist[k].sub
④将childlist输入res.sub
⑤返回childlist
}
输出:以对象item为根节点的树状JSON对象
代码:
router.get('/:id', function(req, res, next) {
pool.getConnection(function(err, connection) {
if (err) return next(err);
connection.query('SELECT * from menuitems ', function(err, rows, fields) {
if (err) throw err;
//get all data
var result = [];//存放起始对象
var allMenu = rows;//获取sql出的全部json对象
for(i=0;i<allMenu.length;i++){
if(allMenu[i].id == req.params.id){
result.push(allMenu[i]) ;//根据id号获取根对象
break;
}
}
//judege result exist or not
if(result.length==0){
return res.json('Failed! id is not exist!');
}else{
result.sub=[];
result.sub=getAllChild(result);//调用
res.json(result[0]);
}
//find some item all child
function findItemChild(item){
var arrayList=[];
for(var i in allMenu){
if(allMenu[i].parent == item.id){
arrayList.push(allMenu[i]);
}
}
return arrayList;
}
//get all child
function getAllChild(array){
var childList=findItemChild(array[0]);
if(childList == null){
return [];
}
else{
for(var j in childList){
childList[j].sub=[];
childList[j].sub=getAllChild([childList[j]]);
}
array[0].sub=childList;
}
return childList;
}
});
});
});
代码执行过程:
getAllChild([id=1])
childlist=[{id:2,parent:1,...},{id:9,parent:1,...},{id:11,parent:1,...}];
for(id=2 id=9 id=11)
↓
childlist[id=2].sub=?
↓
getAllChild([id=2]);
childlist=[{id:4,parent:2,...},{id:5,parent:2,...}];
for(id=4 id=5)
↓
childlist[id=4].sub=?
↓
getAllChild([id=4]);
childlist=[{id:6,parent:4,...}];
for(id=6)
↓
childlist[id=6].sub=?
↓
getAllChild([id=6]),return [];//到底,依次往上返回,将childlist逐步扩充,直到最终返回allchild;
扩充:返回所有树状菜单,即寻找所有JSON数据构成的森林。思想是通过给森林构造一个根节点转换为树,再利用上述方法实现。
router.get('/', function(req, res, next) {
pool.getConnection(function(err, connection) {
if (err) return next(err);
connection.query('SELECT * from menuitems ', function(err, rows, fields) {
if (err) throw err;
//get all data
//create a id= null root for forest
var temp_parent={"id":null,"sub":[]};//新建id为null的对象做为森林的根
var result=[];
var allMenu = rows;
result.push(temp_parent) ;
var output = getAllChild(result);
if(output.length==0){
//if our database do note have any data
return res.json('Failed! do not have any data!');
}else {
res.json(output);
}
//find some item all child //方便阅读依然放上此方法
function findItemChild(item){
var arrayList=[];
for(var i in allMenu){
if(allMenu[i].parent == item.id){
arrayList.push(allMenu[i]);
}
}
return arrayList;
}
//get all child //方便阅读依然放上此方法
function getAllChild(array){
var childList=findItemChild(array[0]);
if(childList == null){
return [];
}
else{
for(var j in childList){
childList[j].sub=[];
childList[j].sub=getAllChild([childList[j]]);
}
array[0].sub=childList;
}
return childList;
}
});
});
});
总结:通过javascript语言利用NodeJS结合mysql可以实现从后台拿到JSON数据后,将数据构造成树状结构的形式供前端使用。这种Javascript全栈开发方式还有很多需要学习。未来的路还很长,加油!
递归的写法需要时常琢磨寻找好的返回方式,在本文的思想下,递归方法的输入与返回的形式应统一,防止程序陷入死循环或不可执行,实在无法下手时应该通过画流程图的形式判断递归的有效性。递归在树层级比较深时肯定会耗费大量计算时间,因此之后通过学习寻找更好的解决方法。
tips:由于本人菜鸟一枚,所述拙见仅供自己学习总结,第一次写博客~若对您造成错误影响请批评指正。
菜鸟笔记:node.js+mysql中将JSON数据构建为树(递归制作树状菜单数据接口)的更多相关文章
- Node.js + MySQL 实现数据的增删改查
通过完成一个 todo 应用展示 Node.js + MySQL 增删改查的功能.这里后台使用 Koa 及其相应的一些中间件作为 server 提供服务. 初始化项目 $ mkdir node-cru ...
- 零代码第一步,做个添加数据的服务先。node.js + mysql
node.js + mysql 实现数据添加的功能.万事基于服务! 增删改查之添加数据. 优点:只需要设置一个json文件,就可以实现基本的添加功能,可以视为是零代码. 添加数据的服务实现的功能: 1 ...
- node.js+mysql环境搭建
https://www.jianshu.com/p/9b338095cbe8 node.js+mysql环境搭建 0x01 前言 随着html web技术的发展,和全栈式开发的需求,对于前端人员来讲, ...
- Node.js NPM Package.json
章节 Node.js NPM 介绍 Node.js NPM 作用 Node.js NPM 包(Package) Node.js NPM 管理包 Node.js NPM Package.json Nod ...
- Node.js实操练习(一)之Node.js+MySQL+RESTful
前言 最近学习了一下node.js相关的内容,在这里初步做个小总结,说实话关于本篇博客的相关内容,自己很久之前就已经有过学习,但是你懂的,“好记性不如烂笔筒”,学过的东西不做笔记的话,很容易就会忘记的 ...
- Ubuntu 16.04 下部署Node.js+MySQL微信小程序商城
转载于这篇文章 关于pm2看这篇文章 最近在研究小程序,申请了域名之后,再一次来配置环境,根据作者的步骤基本上完成了网站的架构,但由于环境路径等不同,配置上会有所不同,因此记录下来. 1.更新系统和安 ...
- node.js+mysql用户的注册登录验证
下面代码实现的功能是:用node.js连接mysql实现用户的注册和登录,这里主要实现的是后端的验证代码,前端显示部分没具体写出. 整个程序的流程是这样的: 1.首先建立数据库reji,数据表user ...
- Node.js学习笔记——Node.js开发Web后台服务
一.简介 Node.js 是一个基于Google Chrome V8 引擎的 JavaScript 运行环境.Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效.Node.j ...
- 笔记-Node.js中的核心API之HTTP
最近正在学习Node,在图书馆借了基本关于Node的书,同时在网上查阅资料,颇有收获,但是整体感觉对Node的理解还是停留在一个很模棱两可的状态.比如Node中的模块,平时练习就接触到那么几个,其他的 ...
随机推荐
- windows 下odoo 不同版本安装运行问题
在开发测试不同版本odoo时,总会遇到在同一浏览器下运行出错的状况.虽然可以把不同版本分属不同的端口,但是登录标识会入写用户本地浏览器cookie,由于cookie只匹配域名及路径但是不区分端口, 所 ...
- 蓝桥网试题 java 基础练习 矩形面积交
------------------------------------------------------------------------------------------- 思路见锦囊2 - ...
- PHP面向对象编程简单实例
<?php date_default_timezone_set("PRC"); /** 1.静态属性用于保存类的公有数据* 2.静态方法里面只能访问静态属性* 3.静态成员 ...
- Struts2系列笔记(2)---Struts.XML
Struts2.xml 本篇博客主要讲Struts2.xml中package下的标签和标签属性,主要分以下四个部分说明: (1)action的配置基本属性 (2)同一个Action类中不同方法满足不同 ...
- 一篇知乎的故事 - javascript技术贴
前言 就像文章题目所示,本文的发表源于知乎的一篇文章.文章链接如下:如果你想靠前端技术还房贷,你不能连这个都不会.这篇文章是群里水群时别人发的,像我这样的菜鸟角色才不会逛知乎~~~.这篇文章主要是讲了 ...
- <context:component-scan>详解
默认情况下,<context:component-scan>查找使用构造型(stereotype)注解所标注的类,如@Component(组件),@Service(服务),@Control ...
- 转载 JDK + Android-SDK + Python + MonkeyRunner 的安装
转载来自: 小海豚的博客 http://blog.sina.com.cn/u/1295334083 我只是搬运工... JDK + Android-SDK + Python + MonkeyRun ...
- POJ 2914 Minimum Cut Stoer Wagner 算法 无向图最小割
POJ 2914 题意:给定一个无向图 小于500节点,和边的权值,求最小的代价将图拆为两个联通分量. Stoer Wagner算法: (1)用类似prim算法的方法求"最大生成树" ...
- Loadrunner之脚本编写
先打开loadrunner的服务器(打开成功之后会出现一个绿色的X) 以订票系统为例(http://127.0.0.1:1080/WebTours/) 录制一个登陆的脚本. 利用C语言编写一个简单的脚 ...
- 【转】简单的java缓存实现
本文转自 http://my.oschina.net/u/866190/blog/188712 提到缓存,不得不提就是缓存算法(淘汰算法),常见算法有LRU.LFU和FIFO等算法,每种算法各有各的优 ...
