• 基于node.js的express框架的图书管理功能(2)


      之前的图书管理功能的数据是存放在json文件中的,通过读取json文件的内容渲染到页面上,每次读取都要遍历整个文件,当数据量大时很不方便,把数据存放在数据库中才是正确的做法。

    1.操作数据库的基本功能

    在Mysql中新建一个数据库book,新建一张book的表用来存放图书的数据信息,将id值设为自增。

    利用数据库自增功能有一个问题:在执行删除操作后,再添加数据时,id会出现间隔现象,如下图:

    数据库搭建好后,创建一个项目测试一下数据库操作的一些基本功能:

    新建一个文件夹mydb

    准备一个入口文件:index.js

    初始化该项目:npm init -y

    安装需要的依赖的包:

    npm install mysqljs/mysql

    ①插入数据

    /**
     * 插入数据
     */
    //加载数据库驱动
    const mysql = require('mysql');
    //创建数据库链接
    const connection = mysql.createConnection({
        host: 'localhost',   //数据库所在的服务器的域名或者IP地址
        user: 'root',      //登录数据库的账号
        password: 'password',
        database: 'book'    //数据库的名称book,注意这里不是链接的名称,我创建的链接的名称为mybook
    });
    //执行连接操作
    connection.connect();
    //使用mysql第三方包简化了insert操作,?用来填充数据,只需要提供一个对象
    let sql = 'insert into book set ?'
    //用来插入的数据
    let data = {
        name: '明朝那些事',
        author: '当年明月',
        category: '文学',
        description: '明朝的历史'
    }
    
    //操作数据库
    connection.query(sql,data,(err,results,fields) => {
        if(err) return;
        //console.log(results);   
        if(results.affectedRows == 1){
            console.log('数据插入成功');
        }
    });
    //关闭数据库
    connection.end();

    ②更新数据

    /**
     * 更新数据
     */
    //加载数据库驱动
    const mysql = require('mysql');
    //创建数据库链接
    const connection = mysql.createConnection({
        host: 'localhost',   //数据库所在的服务器的域名或者IP地址
        user: 'root',      //登录数据库的账号
        password: 'password',
        database: 'book'    //数据库的名称book,注意这里不是链接的名称,我创建的链接的名称为mybook
    });
    //执行连接操作
    connection.connect();
    
    let sql = 'update book set name=?,author=?,category=?,description=? where id=?'
    //用来更新的数据
    let data = ['浪潮之巅','吴军','计算机','IT巨头的兴衰史',6];
    
    //操作数据库
    connection.query(sql,data,(err,results,fields) => {
        if(err) return;
        //console.log(results);   
        if(results.affectedRows == 1){
            console.log('数据更新成功');
        }
    });
    //关闭数据库
    connection.end();

    ③删除数据

    /**
     * 删除数据
     */
    //加载数据库驱动
    const mysql = require('mysql');
    //创建数据库链接
    const connection = mysql.createConnection({
        host: 'localhost',   //数据库所在的服务器的域名或者IP地址
        user: 'root',      //登录数据库的账号
        password: 'password',
        database: 'book'    //数据库的名称book,注意这里不是链接的名称,我创建的链接的名称为mybook
    });
    //执行连接操作
    connection.connect();
    
    let sql = 'delete from book where id=?'
    //用来删除的数据
    let data = [6];
    
    //操作数据库
    connection.query(sql,data,(err,results,fields) => {
        if(err) return;
        //console.log(results);   
        if(results.affectedRows == 1){
            console.log('数据删除成功');
        }
    });
    //关闭数据库
    connection.end();

    ④查询数据

    /**
     * 操作数据库基本步骤
     */
    //加载数据库驱动
    const mysql = require('mysql');
    //创建数据库链接
    const connection = mysql.createConnection({
        host: 'localhost',   //数据库所在的服务器的域名或者IP地址
        user: 'root',      //登录数据库的账号
        password: 'password',
        database: 'book'    //数据库的名称book,注意这里不是链接的名称,我创建的链接的名称为mybook
    });
    //执行连接操作
    connection.connect();
    
    let sql = 'select * from book'
    let data = null;
    
    //操作数据库
    connection.query('select 1+1 as solution',(err,results,fields) => {
        if(err) return;
        console.log(results[0]);    
    });
    //关闭数据库
    connection.end();

     上述的增删改查的代码有很多重复性,可以将以上功能封装为一个通用的api文件db.js:

    /**
     * 封装操作数据库的通用API
     */
    const mysql = require('mysql');
    
    exports.base = (sql,data,callback) => {
        //创建数据库链接
        const connection = mysql.createConnection({
            host: 'localhost',   //数据库所在的服务器的域名或者IP地址
            user: 'root',      //登录数据库的账号
            password: 'password',
            database: 'book'    //数据库的名称book,注意这里不是链接的名称,我创建的链接的名称为mybook
        });
        //执行连接操作
        connection.connect();
        
        //操作数据库(数据库操作也是异步的,异步不同通过返回值来处理,只能通过回调函数)
        connection.query(sql,data,(err,results,fields) => {
            if(err) throw err;
            callback(results);
        });
        //关闭数据库
        connection.end();
    }

    测试该api:

    /**
     * 测试通用API
     */
    const db = require('./db.js');
    
    //插入操作
    let sql = 'insert into book set ?';
    let data = {
        name: '笑傲江湖',
        author: '金庸',
        category: '文学',
        description: '武侠小说'
    };
    db.base(sql,data,(result) => {
        console.log(result);
    });
    
    //更新操作
    let sql = 'update book set name=?,author=?,category=?,description=? where id=?';
    let data = ['天龙八部','金庸','文学','武侠小说',5];
    db.base(sql,data,(result) => {
        console.log(result);
    });
    
    //删除操作
    let sql = 'delete from book where id=?'
    let data = [7];
    db.base(sql,data,(result) => {
        console.log(result);
    });
    
    //查询操作
    let sql = 'select * from book where id = ?';
    let data = [8];
    db.base(sql,data,(result) => {
        console.log(result);
    });

    2.通过一个小的登陆验证功能来测试前后端+数据库一起的功能:

    后台逻辑代码login.js:

    /**
     * 登陆验证(前端+后端+数据库)
     */
    const express = require('express');
    const bodyParser = require('body-parser');
    const db = require('./db.js');
    const app = express();
    //启动bodyParser这个API来处理参数,处理表单提交的
    app.use(bodyParser.urlencoded({extended:false}));
    app.use(express.static('./public'));
    
    app.post('/check',(req,res) => {
        let param = req.body;
        console.log(param);
        let sql = 'select count(*) as total from user where username=? and password=?';
        let data = [param.username,param.password];
    
        db.base(sql,data,(result) => {
            console.log(result);
            if(result[0].total == 1){
                res.send('login success!');
            }else{
                res.send('login failure!');
            }
        });
    });
    
    app.listen(3000,() => {
        console.log('running...');
    });

    前端页面代码login.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>登录</title>
    </head>
    <body>
        <form action="http://localhost:3000/check" method="POST">
        用户名:<input type="text" name="username"><br>
        密码:<input type="password" name="password"><br>
        <input type="submit" value="登录">
        </form>
    </body>
    </html>

    3.重构图书管理功能,使数据从数据库中获取

    将操作数据库的通用api文件db.js拷贝到mybook项目下,还需要安装mysql的api

    注意:由于desc字段在数据库中是关键字,不能使用,所以把该字段名称改为description,之前的.art文件里用到的desc字段名称全部要改过来,否则执行过程中会报错

     

     

     只需修改service.js业务模块中的功能:

    /**
     * 业务模块
     */
    const data = require('./data.json');
    const path = require('path');
    const fs = require('fs');
    const db = require('./db.js');
    
    /* //自动生成图书编号(自增)
    let maxBookCode = () => {
        let arr = [];
        data.forEach(item => {
            arr.push(item.id);
        });
        return Math.max.apply(null,arr);
    }
    
    //把内存数据写入到文件
    let writeDataFile = (res) => {
        //需要把内存中的数据写入文件
        //JSON.stringify(data)仅传data一个参数的话,data.json文件是压缩形式的
        fs.writeFile(path.join(__dirname,'data.json'),JSON.stringify(data,null,4),(err) => {
            if(err){
                res.send('server err');  
            }
            //文件写入成功之后重新跳转到主页面
            res.redirect('/');
        });
    }
     */
     //渲染主页面
     exports.showIndex = (req,res) => {
         let sql = 'select * from book';
        //从数据库中获取内容
        db.base(sql,null,(result) => {
            //数据库获取的内容只能通过回调函数来得到
            res.render('index',{list:result});
        })
        //res.render('index',{list:data});
     }
    
     //跳转到添加图书的页面
     exports.toAddBook = (req,res) => {
         //render将会根据views中的模板文件进行渲染,渲染的是空对象{}
         res.render('addBook',{});
     }
    
     //添加图书保存数据
     exports.addBook = (req,res) => {
         //获取表单数据
         let info = req.body;
         let book = {};
         for (const key in info) {
             book[key] = info[key];
         }
    
         let sql = 'insert into book set ?'
         db.base(sql,book,(result) => {
             if(result.affectedRows == 1){
                 //添加成功后跳转到主页面
                 res.redirect('/');
             }
         });
    
         /* book.id = maxBookCode()+1;
         data.push(book);
         //需要把内存中的数据写入文件
         writeDataFile(res); */
     }
    
     //跳转到编辑页面
     exports.toEditBook = (req,res) => {
        let id = req.query.id;
        let sql = 'select * from book where id=?';
        let data = [id];
        db.base(sql,data,(result)=>{
            //注意:必须使用result[0]获取数据才能渲染到页面上,因为得到的resul结果集是一个数组,不是对象,渲染不了
            res.render('editBook',result[0]);
        });
        /* let book = null;
        data.forEach((item)=>{
            if(id == item.id){
                book = item;
                //break;
                //forEach循环中不能有break,用return终结即可
                return;
            }
        }); 
        //render将会根据views中的模板文件进行渲染,渲染的是对应图书的完整信息
        res.render('editBook',book); */
     }
    
     //编辑图书更新数据:
     //1.先查询出对应的数据并渲染到页面上
     //2.然后再提交表单,再重新保存,写入文件
     //编辑的时候要告诉服务器编辑的是哪条数据
     exports.editBook = (req,res) => {
        //报错:为什么总是跳转到addBook的页面?  问题已解决:editBook.art页面的action路径错写成'/addBook',改成'/editBook'就可以正常运行
        //获取表单的数据
        let info = req.body;
    
        let sql = 'update book set name=?,author=?,category=?,description=? where id=?';
        let data = [info.name,info.author,info.category,info.description,info.id];
        db.base(sql,data,(result) => {
            if(result.affectedRows == 1){
                //更新成功后跳转到主页面
                res.redirect('/');
            }
            else{
                res.send('edit failure');
            }
        });
    
         /* //覆盖原有的数据
         data.forEach((item)=>{
             if(info.id == item.id){
                 for (const key in info) {
                     item[key] = info[key];
                 }
                 return;
             }
         });
         //需要把内存中的数据写入文件
         writeDataFile(res); */
     }
    
     //删除图书信息
     exports.deleteBook = (req,res) => {
         //先获取到传过来的id
         let id = req.query.id;
    
        let sql = 'delete from book where id=?';
        let data = [id];
        db.base(sql,data,(result) => {
            if(result.affectedRows == 1){
                //删除成功后跳转到主页面
                res.redirect('/');
            }
        });
    
        /*  data.forEach((item,index)=>{
             if(item.id == id){
                //删除数组的一项数据
                data.splice(index,1);  
             }
             return;
         });
         //需要把内存中的数据写入文件
         writeDataFile(res); */
     }
  • 相关阅读:
    快速幂取模算法详解
    牛客网小白月赛5I区间(差分数组)
    多重背包模板
    hdu5791(DP)
    CodeForces
    最长上升子序列LIS(51nod1134)
    POJ1088(记忆搜索加dp)
    最长公共子序列LCS(POJ1458)
    Gym 100971J-Robots at Warehouse
    模板
  • 原文地址:https://www.cnblogs.com/zcy9838/p/11639293.html
Copyright © 2020-2023  润新知