zoukankan      html  css  js  c++  java
  • node.js入门学习(四)--Demo图书的增删改查

    需求:图书的增删改查,图书数据保存在data.json文件中。

    1、Demo结构:

      

    2、首先下载安装node.js,配置环境变量:参考博客

    3、项目初始化

      1)创建项目根目录node-hello,进入到根目录node-hello,右键/在此处打开PowerShell窗口。

      2)创建app.js文件。

      3)在控制台输入命令:npm init -y,会自动创建package.json文件。

      4)在控制台输入命令:npm install mime,会自动创建node_modules文件夹,并下载mime模块到该文件夹,还会自动生成package-lock.json文件。

      5)npm install underscore,下载underscore模块。underscore的使用参考博客

    4、入口文件app.js

    // 加载http模块
    var http = require("http");
    var fs = require("fs");
    var path = require("path");
    var mime = require("mime");
    var url = require("url");
    var querystring = require("querystring");
    var _ = require("underscore");
    
    // 创建一个http服务对象
    http.createServer(function(req, res) {
    
        req.url = req.url.toLowerCase();
        req.method = req.method.toLowerCase();
        if (req.method === 'get') { 
            // 通过url模块的parse方法获取用户get请求提交的数据
            // 第二个参数为true时,urlObj的query属性就是所有的请求参数,类型是json对象
            var urlObj = url.parse(req.url, true);
            // console.log(urlObj);
        } 
    
        // 封装fender函数,将render函数挂在到res对象上;第二个参数是模板数据
        res.render = function (filename, templateData) {
            fs.readFile(filename, function(err, data) {
                if(err) {
                    res.writeHead(404, 'not found', {'Content-Type': 'text/html; charset=utf-8'});
                    res.end("404, not found.");
                    return;
                }
    
                if (templateData) {
                    var fn = _.template(data.toString("utf-8"));
                    data = fn(templateData);
                }
                
                res.setHeader('Content-Type', mime.getType(filename));
                res.end(data);
            });
        };
    
        if(req.url === '/' || req.url === '/index') {
            res.render(path.join(__dirname, 'pages/index.html'));
        } 
        else if(req.url === '/list') {
            // 第一步:读取data.json文件中的数据,转换为list数组
            fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
                if(err && err.code !== 'ENOENT') {throw err;}
                console.log("data.json原来的内容:" + data); // [{"name":"xxx","price":"xxx"}]]
                var bookList = JSON.parse(data || '[]'); // json数组
    
                // 第二步:在服务器使用模版引擎,将bookList数据和list.html页面结合
                res.render(path.join(__dirname, 'pages/list.html'), {msg:'这是list页面', bookList:bookList});
            });
        } 
        else if(req.url.startsWith('/add')) {
            res.render(path.join(__dirname, 'pages/add.html'));
        } 
        else if(req.url.startsWith('/submit') && req.method === 'get') { // 如何获取get请求的参数
            // 用户表单提交get请求数据,保存到data/data.json文件中,新数据以追加的形式添加
            console.log(req.url); // /summit?name=xxx&price=xxx
    
            // 首先读取data.json文件的内容
            fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
                if(err && err.code !== 'ENOENT') {throw err;}
                console.log("data.json原来的内容:" + data); // [{"name":"xxx","price":"xxx"}]]
                var list = JSON.parse(data || '[]'); // json数组
    
                // 获取get请求的参数,将用户提交的数据添加到json数组
                var book = urlObj.query;
                // book.id = list.length + 1;
                book.id = list[list.length - 1].id + 1;
                list.push(book);
                console.log("添加一条记录后,data.json的内容:"  + JSON.stringify(list));
                
                // 将json数组写入data.json文件
                fs.writeFile(path.join(__dirname, 'data', 'data.json'), JSON.stringify(list), function(err) {
                    if(err) throw err;
                    console.log('写入成功');
                });    
            });
    
            // 重定向
            res.statusCode = 302;
            res.statusMessage = 'Found';
            res.setHeader('Location', '/index');
            res.end();
        } 
        else if(req.url.startsWith('/submit') && req.method === 'post') { // 如何获取post请求的参数
            var array = []; // 用来保存用户post请求提交的数据
            var postBody;
            req.on('data', function(chunk) {
                // chunk就是浏览器本次data事件提交的一部分数据;chunk是Buffer类型
                console.log("data事件...");
                array.push(chunk);
            });
    
            req.on('end', function() {
                console.log("end事件...");
                // 把array中多个Buffer对象汇总到一个Buffer对象
                postBody = Buffer.concat(array);
                console.log("postBody: " + postBody); // postBody: name=1&price=1
            });
    
            fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
                if(err && err.code !== 'ENOENT') {throw err;}
                console.log("data.json原来的内容:" + data); // [{"name":"xxx","price":"xxx"}]]
                var list = JSON.parse(data || '[]'); // json数组
    
                // 获取get请求的参数,将用户提交的数据添加到json数组
                // querystring对象可以把表单数据 name=xxx&price=xxx => {"name":"xxx","price":"xxx"}
                var book = querystring.parse(postBody.toString("utf-8"));
                // book.id = list.length + 1;
                book.id = list[list.length - 1].id + 1;
                list.push(book);
                console.log("添加一条记录后,data.json的内容:"  + JSON.stringify(list));
                
                // 将json数组写入data.json文件
                fs.writeFile(path.join(__dirname, 'data', 'data.json'), JSON.stringify(list), function(err) {
                    if(err) throw err;
                    console.log('写入成功');
                });    
            });
    
            /*
            // 首先读取data.json文件的内容
            fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
                if(err && err.code !== 'ENOENT') {throw err;}
                console.log("data.json原来的内容:" + data); // [{"name":"xxx","price":"xxx"}]]
                var list = JSON.parse(data || '[]'); // json数组
    
                // 获取post请求的参数,将用户提交的数据添加到json数组
                // 因为post提交数据的时候,数据量可能比较大,所以可能分多次提交,每次添加一部分数据
                // 此时服务器要获取用户提交的所有数据,必须监听request对象的data事件
                // 什么时候表示浏览器把所有数据都提交到服务器了呢?当request对象的end事件触发
                var array = []; // 用来保存用户post请求提交的数据
                console.log("111...");
                req.on('data', function(chunk) {
                    // chunk就是浏览器本次data事件提交的一部分数据;chunk是Buffer类型
                    console.log("data事件...");
                    array.push(chunk);
                });
                req.on('end', function() {
                    console.log("end事件...");
                    // 把array中多个Buffer对象汇总到一个Buffer对象
                    var postBody = Buffer.concat(array);
                    console.log("postBody: " + postBody);
                    list.push(postBody);
                    console.log("添加一条记录后,data.json的内容:"  + JSON.stringify(list));
    
                    // 将json数组写入data.json文件
                    fs.writeFile(path.join(__dirname, 'data', 'data.json'), JSON.stringify(list), function(err) {
                        if(err) throw err;
                        console.log('写入成功');
                    });
                });
                
                console.log("222...");
            });*/
    
            // 重定向
            res.statusCode = 302;
            res.statusMessage = 'Found';
            res.setHeader('Location', '/index');
            res.end(); 
        } 
        else if(req.url.startsWith('/detail') && req.method === 'get') {
            var queryId = urlObj.query.id;
    
            // 第一步:读取data.json文件中的数据,转换为list数组
            fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
                if(err && err.code !== 'ENOENT') {throw err;}
                console.log("data.json原来的内容:" + data); // [{"name":"xxx","price":"xxx"}]]
                var bookList = JSON.parse(data || '[]'); // json数组
    
                // 查询指定id的记录
                var book = {};
                for (var i = 0; i < bookList.length; i++) {
                    if (bookList[i].id == queryId) { // 不能写“===”,因为queryId是字符串类型
                        book = bookList[i];
                    }
                }
    
                // 第二步:在服务器使用模版引擎,将数据和detail.html页面结合
                res.render(path.join(__dirname, 'pages/detail.html'), {book:book});
            });
        }
        else if(req.url.startsWith('/delete') && req.method === 'get') {
            var queryId = urlObj.query.id;
    
            // 第一步:读取data.json文件中的数据,转换为list数组
            fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
                if(err && err.code !== 'ENOENT') {throw err;}
                console.log("data.json原来的内容:" + data); // [{"name":"xxx","price":"xxx"}]]
                var bookList = JSON.parse(data || '[]'); // json数组
                
                // 删除指定id的记录
                for (var i = 0; i < bookList.length; i++) {
                    if (bookList[i].id == queryId) {
                        bookList.splice(i, 1); // 删除起始下标为queryId-1,长度为1的元素
                    }
                }
    
                // 将json数组重新写入data.json文件
                fs.writeFile(path.join(__dirname, 'data', 'data.json'), JSON.stringify(bookList), function(err) {
                    if(err) throw err;
                    console.log('写入成功');
                });    
    
    
                // 第二步:在服务器使用模版引擎,将bookList数据和list.html页面结合
                res.render(path.join(__dirname, 'pages/list.html'), {msg:'这是list页面', bookList:bookList});
            });
        }
        else if(req.url.includes('static')){
            res.render(path.join(__dirname, req.url));
        }
        else if(req.url.startsWith('/edit') && req.method === 'post') {
            var array = []; // 用来保存用户post请求提交的数据
            var postBody;
            req.on('data', function(chunk) {
                // chunk就是浏览器本次data事件提交的一部分数据;chunk是Buffer类型
                console.log("data事件...");
                array.push(chunk);
            });
    
            req.on('end', function() {
                console.log("end事件...");
                // 把array中多个Buffer对象汇总到一个Buffer对象
                postBody = Buffer.concat(array);
            });
    
            fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
                if(err && err.code !== 'ENOENT') {throw err;}
    
                var bookList = JSON.parse(data || '[]'); // json数组
    
                // 获取get请求的参数,将用户提交的数据添加到json数组
                // querystring对象可以把表单数据 name=xxx&price=xxx => {"name":"xxx","price":"xxx"}
                var book = querystring.parse(postBody.toString("utf-8"));
                console.log("=============book:" + book.id + book.name + book.price);
                for (var i = 0; i < bookList.length; i++) {
                    // console.log("bookList[i].id=" + bookList[i].id);
                    // console.log("book.id=" + book.id);
                    // console.log(bookList[i].id == book.id);
                    if(bookList[i].id == book.id) {
                        bookList[i].name = book.name;
                        bookList[i].price = book.price;
                    }
                }
            
                // 将json数组重新写入data.json文件
                fs.writeFile(path.join(__dirname, 'data', 'data.json'), JSON.stringify(bookList), function(err) {
                    if(err) throw err;
                    console.log('写入成功');
                });    
    
                // 重定向
                res.statusCode = 302;
                res.statusMessage = 'Found';
                res.setHeader('Location', '/list');
                res.end(); 
                });
        }
        else {
            res.writeHead(404, 'not found', {'Content-Type': 'text/html; charset=utf-8'});
            res.end("404,not found!");
        }
    }).listen('8080', function() {
        console.log('服务器已经启动,请访问http://127.0.0.1:8080/');
    });

    5、common.css

    h2 {
        background-color: #ccc;
    }

    6、html页面

      add.html

    <!DOCTYPE html>
    <html>
    <head>
        <title>add页面</title>
        <meta charset="utf-8">
        <link rel="stylesheet" type="text/css" href="/static/css/common.css">
    </head>
    <body>
        <h2>add页面</h2>
        <form method="get" action="/submit">
        <!-- <form method="post" action="/submit"> -->
            书名: <input type="text" name="name">
            价格: <input type="text" name="price">
            <input type="submit" value="添加">
        </form>
    </body>
    </html>

      detail.html

    <!DOCTYPE html>
    <html>
    <head>
        <title>detail页面</title>
        <meta charset="utf-8">
        <link rel="stylesheet" type="text/css" href="/static/css/common.css">
    </head>
    <body>
        <h2>detail页面</h2>
        <form method="post" action="/edit">
            <input type="hidden" name="id" value="<%= book.id %>">
            书名:<input type="text" name="name" value="<%= book.name %>"><br/>
            价格:<input type="text" name="price" value="<%= book.price %>"><br/>
            <input type="submit" value="修改">
        </form>
    </body>
    </html>

      index.html

    <!DOCTYPE html>
    <html>
    <head>
        <title>index页面</title>
        <meta charset="utf-8">
        <link rel="stylesheet" type="text/css" href="/static/css/common.css">
    </head>
    <body>
        <h2>index页面</h2>
        <!-- <img src="/static/images/1.jpg">
        <img src="/static/images/2.png"> -->
        <a href="/list">图书列表</a>
    </body>
    </html>

       list.html

    <!DOCTYPE html>
    <!DOCTYPE html>
    <html>
    <head>
        <title>list页面</title>
        <meta charset="utf-8">
        <link rel="stylesheet" type="text/css" href="/static/css/common.css">
    </head>
    <body>
        <h2>list页面</h2>
        <%= msg %>!</h2><br/>
        <!-- <img src="/static/images/1.jpg">
        <img src="/static/images/2.png"> -->
        <a href="/add">添加</a>
    
        <table border="1" cellpadding="0">
            <tr>
                <td>ID</td>
                <td>书名</td>
                <td>价格</td>
                <td>操作</td>
            </tr>
            <% for(var i = 0; i < bookList.length; i++) { %>
            <tr>
                <td><%= bookList[i].id %></td>
                <td><%= bookList[i].name %></td>
                <td><%= bookList[i].price %></td>
                <td>
                    <a href="/detail?id=<%= bookList[i].id %>">查看</a>
                    <a href="/delete?id=<%= bookList[i].id %>">删除</a>
                </td>
            </tr>
            <% } %>
        </table>
        
    </body>
    </html>

     7、node app.js启动项目,浏览器访问主页 :http://127.0.0.1:8080/

      

      

      

      测试完后data.json文件的数据:

    [{"id":1,"name":"射雕英雄传","price":"45.00"},{"id":2,"name":"天龙八部2","price":"66.00"},
    {"id":3,"name":"倚天屠龙记","price":"50.00"},{"id":4,"name":"Java编程思想2","price":"40.00"},
    {"name":"Java从入门到精通","price":"30.00","id":6},{"name":"ggf","price":"fff","id":8},
    {"name":"af","price":"ff","id":9}]

     

    8、封装app.js里面重复代码

    // 加载http模块
    var http = require("http");
    var fs = require("fs");
    var path = require("path");
    var mime = require("mime");
    var url = require("url");
    var querystring = require("querystring");
    var _ = require("underscore");
    
    // 创建一个http服务对象
    http.createServer(function(req, res) {
    
        req.url = req.url.toLowerCase();
        req.method = req.method.toLowerCase();
        if (req.method === 'get') { 
            // 通过url模块的parse方法获取用户get请求提交的数据
            // 第二个参数为true时,urlObj的query属性就是所有的请求参数,类型是json对象
            var urlObj = url.parse(req.url, true);
            // console.log(urlObj);
        }
    
        // 封装fender函数,将render函数挂在到res对象上;第二个参数是模板数据
        res.render = function (filename, templateData) {
            fs.readFile(filename, function(err, data) {
                if(err) {
                    res.writeHead(404, 'not found', {'Content-Type': 'text/html; charset=utf-8'});
                    res.end("404, not found.");
                    return;
                }
    
                if (templateData) {
                    var fn = _.template(data.toString("utf-8"));
                    data = fn(templateData);
                }
                
                res.setHeader('Content-Type', mime.getType(filename));
                res.end(data);
            });
        };
    
        if(req.url === '/' || req.url === '/index') {
            res.render(path.join(__dirname, 'pages/index.html'));
        } 
        else if(req.url === '/list') {
            // 第一步:读取data.json文件中的数据,转换为list数组
            readFile(function(bookList) {
                // 第二步:使用模版引擎,将bookList数据和list.html页面结合
                res.render(path.join(__dirname, 'pages/list.html'), {msg:'这是list页面', bookList:bookList});
            });
        } 
        else if(req.url.startsWith('/add')) {
            res.render(path.join(__dirname, 'pages/add.html'));
        } 
        else if(req.url.startsWith('/submit') && req.method === 'get') { // 如何获取get请求的参数
            // 用户表单提交get请求数据,保存到data/data.json文件中,新数据以追加的形式添加
            console.log(req.url); // /summit?name=xxx&price=xxx
    
            // 第一步:读取data.json文件中的数据,转换为list数组
            readFile(function(list) {
                // 第二步:获取get请求的参数,将用户提交的数据添加到json数组
                var book = urlObj.query;
                book.id = list[list.length - 1].id + 1;
                list.push(book);
                console.log("添加一条记录后,data.json的内容:"  + JSON.stringify(list));
                
                // 第三步:将json数组写入data.json文件,并重定向到list页面
                writeFile(list, res);
            });
        } 
        else if(req.url.startsWith('/submit') && req.method === 'post') { // 如何获取post请求的参数
            // 用户表单提交post请求数据,保存到data/data.json文件中,新数据以追加的形式添加
            getPostBodyData(req, function(book) { // post请求数据封装成book(json对象)
                // 读取data.json文件中的数据,转换为list数组
                readFile(function(list) {
                    book.id = list[list.length - 1].id + 1;
                    list.push(book);
                    // console.log("添加一条记录后,data.json的内容:"  + JSON.stringify(list));
                    
                    // 将json数组写入data.json文件,并重定向到list页面
                    writeFile(list, res);
                });
            });
        } 
        else if(req.url.startsWith('/detail') && req.method === 'get') {
            // 第一步:读取data.json文件中的数据,转换为list数组
            readFile(function(bookList) {
                // 第二步:查询指定id的记录
                var book = {};
                for (var i = 0; i < bookList.length; i++) {
                    // 不能写"===",因为urlObj.query.id是字符串类型
                    if (bookList[i].id == urlObj.query.id) {
                        book = bookList[i];
                        break;
                    }
                }
    
                // 第三步:使用模版引擎,将数据和detail.html页面结合
                res.render(path.join(__dirname, 'pages/detail.html'), {book:book});
            });
        }
        else if(req.url.startsWith('/delete') && req.method === 'get') {
            // 第一步:读取data.json文件中的数据,转换为list数组
            readFile(function(bookList) {
                // 第二步:删除指定id的记录
                for (var i = 0; i < bookList.length; i++) {
                    if (bookList[i].id == urlObj.query.id) {
                        bookList.splice(i, 1); // 删除起始下标为queryId-1,长度为1的元素
                        break;
                    }
                }
    
                // 第三步:将json数组重新写入data.json文件,并重定向到list页面
                writeFile(bookList, res);
            });
        }
        else if(req.url.includes('static')){
            res.render(path.join(__dirname, req.url));
        }
        else if(req.url.startsWith('/edit') && req.method === 'post') {
            getPostBodyData(req, function(book) { // post请求数据封装成book(json对象)
                console.log("=============book:" + book.id + book.name + book.price);
                // 读取data.json文件中的数据,转换为list数组
                readFile(function(bookList) {                
                    for (var i = 0; i < bookList.length; i++) {
                        // console.log("bookList[i].id=" + bookList[i].id);
                        // console.log("book.id=" + book.id);
                        console.log(bookList[i].id == book.id);
                        if(bookList[i].id == book.id) {
                            bookList[i].name = book.name;
                            bookList[i].price = book.price;
                            break;
                        }
                    }
                
                    // 将json数组重新写入data.json文件,并重定向到list页面
                    writeFile(bookList, res);
                });
            });
        }
        else {
            res.writeHead(404, 'not found', {'Content-Type': 'text/html; charset=utf-8'});
            res.end("404,not found!");
        }
    }).listen('8080', function() {
        console.log('服务器已经启动,请访问http://127.0.0.1:8080/');
    });
    
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 封装读取data.json文件的方法
    function readFile(callback) {
        fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
            if(err && err.code !== 'ENOENT') {throw err;}
            console.log("data.json原来的内容:" + data); // [{"name":"xxx","price":"xxx"}]]
            var bookList = JSON.parse(data || '[]'); // json数组
            callback(bookList);
        });
    }
    
    // 封装写入data.json文件的方法
    function writeFile(list, res) { // 参数list的类型:json数组
        fs.writeFile(path.join(__dirname, 'data', 'data.json'), JSON.stringify(list), function(err) {
            if(err) throw err;
            console.log('写入成功');
    
            // 重定向
            res.statusCode = 302;
            res.statusMessage = 'Found';
            res.setHeader('Location', '/list');
            res.end();
    
            // 使用模版引擎,将bookList数据和list.html页面结合
            // res.render(path.join(__dirname, 'pages/list.html'), {msg:'这是list页面', bookList:bookList});
        });    
    }
    
    // 封装写入data.json文件的方法
    function writeFile2(data, callback) { // 参数data的类型:字符串
        fs.writeFile(path.join(__dirname, 'data', 'data.json'), data, function(err) {
            if(err) throw err;
            console.log('写入成功');
    
            // 调用callback()来执行当写入数据完毕后的操作
            callback();
        });    
    }
    
    // 封装获取用户post提交的数据的方法
    function getPostBodyData(req, callback) {
        var array = []; // 用来保存用户post请求提交的数据
        var postBody;
        req.on('data', function(chunk) {
            // chunk就是浏览器本次data事件提交的一部分数据;chunk是Buffer类型
            console.log("data事件...");
            array.push(chunk);
        });
    
        req.on('end', function() {
            console.log("end事件...");
            // 把array中多个Buffer对象汇总到一个Buffer对象
            var postBody = Buffer.concat(array); // 此处postBody类型:Buffer
            // console.log("postBody: " + postBody); // postBody: name=1&price=1
            // querystring对象可以把表单数据 name=xxx&price=xxx => {"name":"xxx","price":"xxx"}
            postBody = querystring.parse(postBody.toString("utf-8")); // 此处postBody类型:json对象
            callback(postBody);
        });
    }
  • 相关阅读:
    [leetcode]算法题目
    JQuery功能查询页
    [C语言]一个很实用的服务端和客户端进行TCP通信的实例
    Siege——多线程编程最佳实例
    CodeIgniter框架中关于URL(index.php)的那些事
    web压测工具http_load原理分析
    【JAVA】文件各行打乱
    【JAVA】HashMap的原理及多线程下死循环的原因
    【JAVA】高并发优化细节点
    【Linux】日志分析工具grep sed sort
  • 原文地址:https://www.cnblogs.com/xy-ouyang/p/11141206.html
Copyright © 2011-2022 走看看