基于node.js的express框架的图书管理功能

Posted 浮华夕颜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于node.js的express框架的图书管理功能相关的知识,希望对你有一定的参考价值。

  之前的图书管理功能的数据是存放在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); */
 }

 

以上是关于基于node.js的express框架的图书管理功能的主要内容,如果未能解决你的问题,请参考以下文章

基于node.js的web框架express

Express - 基于 Node.js 平台的 web 应用开发框架

node.js基于express框架搭建一个简单的注册登录Web功能

Ajax--express框架介绍与基本使用

Node.js基于Express框架 + 连接MongoDB + 写后端接口

express js 可以做啥