Node05


前言

本章的学习内容:node.js模块发开发,


1. 学生数据修改接口

接口地址:/api/student/update
请求方式:post
参数:id(必须)
name / nickname / gender / age / score / className / avatar(可以为空,不写的参数就是之前的旧数据)
分析:先设置设置中间件,拿到post的参数,1.判断id是否传递,不存在返回400 提示客户端输入id,2.通过id去数据库找数据,如果返回值的长度是0,提示id不存在,3.当查到信息定义一个对象去接收 results[0](把旧数据存起来),用或的短路运算设置属性的默认值为旧值,4.把数据通过updat set SQL语句更新到数据库 。

const express = require('express');
const app = express();
const mysql = require('mysql');

const connection = mysql.createConnection({
    host: '127.0.0.1',
    user: 'root',
    password: 'root',
    database: 'student'
})
app.use(express.urlencoded({extended:false}));

app.post('/api/student/update',(req,res)=>{
    const newStu = req.body;
    if (!newStu.id) return res.status(400).send({ code: 400, msg: 'id必须要传递' });
    connection.query(`select * from student where id=${newStu.id}`,(error,results)=>{
        if(error) return res.status(500).send({code: 500, msg: '服务器内部错误', error});
        if (results.length == 0) return res.status(400).send({ code: 400, msg: 'id不存在' });
        //id存 
        const oldStu = results[0]; //oldStu是数据库中原来的数据在
        console.log(results[0]);
        newStu.name = newStu.name || oldStu.name;
        newStu.nickname = newStu.nickname || oldStu.nickname;
        newStu.age = newStu.age || oldStu.age;
        newStu.gender = newStu.gender || oldStu.gender;
        newStu.score = newStu.score || oldStu.score;
        newStu.className = newStu.className || oldStu.className;
        newStu.avatar = newStu.avatar || oldStu.avatar;

		connection.query(`update student set name='${newStu.name}',nickname='${newStu.nickname}',
    age=${newStu.age}, gender='${newStu.gender}', score=${newStu.score},
    className='${newStu.className}', avatar='${newStu.avatar}' where id=${newStu.id}`,(error,results)=>{
        if(error) return res.status(500).send({code: 500, msg: '服务器内部错误', error});
        res.status(200).send({
            code: 200,
            msg: '修改成功'
        })
    })
    });

}).listen(80,()=>console.log('服务开启成功'));

2. 模块化开发

node中模块类型的划分:

  1. 内置模块(node自身提供,不需要引用,直接引用 fs path http…)
  2. 第三方模块 (由社区或个人提供,需要npm安装引入 express)
  3. 自定义模块 (自己定义的模块 文件模块 一个文件也可以被认为是1个模块)

模块化开发的好处:

  1. 每个模块都是一个独立的作用域,在这个而文件中定义的变量、函数、对象都是私有的,对其他文件不可见,不会出现命名问题。
  2. 利于团队开发
  3. 利于后期维护

2.1 require函数

require函数是一个同步函数(会按顺序加载引入模块)
require函数的参数:
模块的名字 内置模块 第3方模块.
文件模块的路径

  1. 如果文件模块是一个json文件. 会将json文件中的数据转换为js对象
  2. 如果文件模块是一个.js文件. 会将这个.js文件中的代码执行一遍.

如果require函数的参数是1个文件模块,那么这个文件模块的后缀名可以省略(建议别省略)
使用require函数加载1个文件模块,实际上是将这个文件模块中的代码执行一遍

当require函数的参数是1个模块名称的时候 如何加载

  1. 判断这个模块是不是一个内置模块. 如果是内置模块 直接加载.
    如果不是内置模块,就认为这是1个第3方模块.
  2. 先在当前文件夹下去查找是否有 node_modules这个文件夹.
    如果有,就进去找是否有这个第3方模块.
  3. 就会去上一级目录查找 是否有 node_modules这个文件夹.
  4. 再去上1级目录. 直到找到根目录,如果都没有 就报错.

第3方模块找到之后,如何加载

  1. 先判断文件夹下是否有package.json.
    如果没有,就直接执行 index.js index.json index.node
  2. 如果有package.json文件
    查找main属性: 如果有指定入口文件 就去执行入口文件.
    如果没有main属性: index.js index.json index.node

Node.js的模块化遵守的CommonJS的模块化规范
(现在用的比较多的ES6的模块化)

2.2 module.exports

在文件模块中,有个全局变量叫做module.exports ,它的值,决定了加载这个文件模块的时候,向外界暴露的数据
使用require函数加载1个文件模块,会得到1个返回值,这个返回值就是这个文件模块中module.exports的值
文件模块中的module.exports它的默认值是1个空对象 { }
所以,在一个文件模块中 如果我们没有修改module.exports的值。,
那么我们使用require函数加载它 得到的返回值就是1个空对象.

文件模块中还有1个全局的变量: exports,使用它也能向外界暴露数据
文件模块向外界暴露数据,暴露的是module.exports,默认情况下,exports和module.exports指向的是同1个对象,如果修改了module.exports指向的对象. 这个时候通过exports就没有用了

简单理解就是在一个js文件内封装自定义模块,要通过module.exports暴露出去(默认值是空对象),然后那个地方要引用组件就require(‘组件的js文件地址’)引入组件。

3. 学生信息接口的模块化开发

前面写的这个路由接口,是所有操作都写在一个页面里的,接下来可以通过模块化开发对其进行优化。

3.1 定义一个配置项模块

用于存放msql连接参数,分页接口的pageSize参数

module.exports = {
    port: 80,  //代表web服务运行的端口
    dbConfig: {  //mysql模块的连接配置信息
        host: '127.0.0.1',
        user: 'root',
        password: 'root',
        database: 'dbstudy'
    },
    pageSize: 5 //每一页的数据量
}

主页 index.js

//1. 导入模块
const express = require('express');

const config = require('./config.js');

//2. 创建应用
const app = express();

//注册中间件 - 解析post传递的数据.
app.use(express.urlencoded({extended: false}));

//返回值就是文件模块暴露出来的路由对象,
//这个路由对象上就已经注册好了路由了.
const stuRouter =  require('./router/stuRouter.js');
//将返回的路由对象,挂载到app
// 所有的URL都到stuRouter中进行路由匹配.
app.use('/api/student', stuRouter);  //  -> (req, res) => {  }

//4. 开启监听
app.listen(config.port, () => console.log('服务启动成功'));

3.2 定义路由模块

之前是所有的配置路由都写在起始文件index.js内,定义路由模块,把所有的路由放在自定义模块中,在index.js页面用app.use()方法挂载这些路由接口。

  • stuRoter模块
//这个模块: 路由模块
//作用: 注册路由. 只需要做注册路由.
/* 
  express五大对象
  1. express
  2. application
  3. request
  4. response
  5. router对象: 专门用来做路由注册,并且只能做路由注册.

  我们发现,这个路由模块并不纯粹 因为它除了做路由匹配,还做的事情是逻辑的处理.
   handler 处理

*/

const express = require('express');
const stuHandler = require('../handler/stuHandler.js');

//调用express的Router方法,就能得到这个router对象.
//这个时候,就可以使用这个router对象来进行路由的注册.
const router = express.Router();
//使用router注册路由的方法和我们之前讲的app注册路由的方法一样.


// /api/student/api/student/list
router.get('/list', stuHandler.list)

router.get('/query', stuHandler.query);

router.post('/add', stuHandler.add);

router.get('/delete', stuHandler.delete);

router.post('/update', stuHandler.update);

module.exports = router;
//当前这个文件模块执行完毕之后,router身上就已经注册好了路由
// 并且将其暴露出去了.

3.3 路由处理方法模块

每个接口都有不同的需求和处理,把这些处理方法封装成一个处理方法模块

  • stuHandler模块
//逻辑处理模块.

const stuDb = require('../databse/stuDb.js');

module.exports.list = (req, res) => {
    //0. 将客户端通过URL传递到服务端的q page参数取出来.
    let { q, page } = req.query;
    // 判断1下,page是否有传递 如果page没有传值 那么默认值就设置为1
    page = page || 1; //2
    // 定义1个变量 表示页容量.
    const pageSize = 5;
    //如果q有值,就意味着sql语句的后面要加1个where条件.
    //1. 从数据库中将学生表中的所有数据查询出来返回.
    //1.2 执行sql语句
    //  q=花&page=1
    //   当前接口
    //   q  page参数
    //   都是可选的.
    //   q 没有值,查询所有  有值就查询满足条件的.
    /*
      1.  如果q参数没有值:    select * from student limit (page-1)*size, size
      2.  如果q参数有值:     select * from student where name like '%q%' or nickname like '%q%' limit (page-1)*size, size
    

      1. 查询所有的数据并分页.

      2. 根据关键字查询数据并分页.
 
     */

    if (q) {
        //如果q有值.
        stuDb.getAllStudentByPageAndQ(page, q, results => {
            res.send({
                code: 200,
                count: results.length,
                data: results
            })
        }, error => {
            return res.status(500).send({ code: 500, msg: '服务器内部错误', error });
        });

    } else {
        //q没有值,要去查询所有的学生
        stuDb.getAllStudentByPage(page, results => {
            res.send({
                code: 200,
                count: results.length,
                data: results
            })
        }, error => {
            return res.status(500).send({ code: 500, msg: '服务器内部错误', error });
        });
    }
}

module.exports.query = (req, res) => {
    //1. 从客户端的URL中取出传递的id参数
    const { id } = req.query;   //5
    if (!id) return res.status(400).send({ code: 400, msg: '参数错误' });
    //2. 去数据库中查询出id为传入的id的记录.
    stuDb.getStudentById(id, results => {
        //查询成功
        //判断查询到的结果是否有数据
        if (results.length == 0) return res.status(404).send({ code: 404, msg: 'id不存在' });
        res.send({ code: 200, data: results[0] });
    }, error => {
        res.status(500).send({ code: 500, msg: '服务器内部错误', error });
    })

}

module.exports.add = (req, res) => {
    //1. 先从post请求中取出传递的数据
    const stu = req.body;
    // 对数据进行一些校验.
    // name nickname gender这三个数据是必须要传递,否则就报400
    if (!stu.name || !stu.nickname || !stu.gender) return res.status(400).send({ code: 400, msg: '参数错误' });
    //3个必传的数据都有了.
    //判断1下其它的参数是否有传递,如果有传递,就是它传递的值, 如果没有传递我们就设置1个默认值.
    stu.age = stu.age || 18;
    stu.score = stu.score || 60;
    stu.className = stu.className || '深圳黑马前端就业班第71期';
    stu.avatar = stu.avatar || 'default_avatar.png';

    //调用数据模块的方法新增数据
    stuDb.add(stu, results => {
        res.status(201).send({
            code: 201,
            msg: '新增成功',
            insertId: results.insertId
        });
    }, error => {
        res.status(500).send({ code: 500, msg: '服务器内部错误', error });
    })
}

//当URL是 /delete 的时候,对应的逻辑处理就是交给这个方法。
module.exports.delete = (req, res) => {
    //1. 取出客户端通过URL传递到服务端的id
    const { id } = req.query;
    //2. 判断id是否有传递
    if (!id) return res.status(400).send({ code: 400, msg: '参数错误' });
    //3. 调用数据模块的方法 删除学员
    stuDb.deleteStudentById(id, results => {
        //成功的时候执行
        //1. 判断1下受影响的行数
        if (results.affectedRows == 0)
            return res.status(404).send({ code: 404, msg: 'id不存在' });
        res.send({ code: 200, msg: '删除成功' });
    }, error => {
        res.status(500).send({ code: 500, msg: '服务器内部错误', error });
    });
}

module.exports.update = (req, res) => {
    //1. 取出客户端通过post传递到服务端的数据.
    const newStu = req.body;
    //2. 判断id有没有传递 
    if (!newStu.id) return res.status(400).send({ code: 400, msg: 'id必须要传递' });
    //3. 再判断哪些数据传递了 传了就使用新值 没有传就使用原来的值.
    //3.1 先去数据库中 查询出本身的数据
    ///   根据id去数据库中查询数学生信息

    stuDb.getStudentById(newStu.id, results => {
        //查询成功
        if (results.length == 0) return res.status(400).send({ code: 400, msg: 'id不存在' });
        //id存 
        const oldStu = results[0]; //oldStu是数据库中原来的数据在
        newStu.name = newStu.name || oldStu.name;
        newStu.nickname = newStu.nickname || oldStu.nickname;
        newStu.age = newStu.age || oldStu.age;
        newStu.gender = newStu.gender || oldStu.gender;
        newStu.score = newStu.score || oldStu.score;
        newStu.className = newStu.className || oldStu.className;
        newStu.avatar = newStu.avatar || oldStu.avatar;
        //更新数据
        stuDb.updateStudentById(newStu, results => {
            res.send({
                code: 200,
                msg: '修改成功'
            });
        }, error => {
            res.status(500).send({ code: 500, msg: '服务器内部错误', error });
        })


    }, error => {
        res.status(500).send({ code: 500, msg: '服务器内部错误', error });
    })


}

3.4 mysql模块

每个路由处理方法,都会使用mysql操作数据库数据,可以把这部分代码封装成一个mysql请求数据库模块

-stuDb.js模块

//逻辑处理模块.

const stuDb = require('../databse/stuDb.js');

module.exports.list = (req, res) => {
    //0. 将客户端通过URL传递到服务端的q page参数取出来.
    let { q, page } = req.query;
    // 判断1下,page是否有传递 如果page没有传值 那么默认值就设置为1
    page = page || 1; //2
    // 定义1个变量 表示页容量.
    const pageSize = 5;
    //如果q有值,就意味着sql语句的后面要加1个where条件.
    //1. 从数据库中将学生表中的所有数据查询出来返回.
    //1.2 执行sql语句
    //  q=花&page=1
    //   当前接口
    //   q  page参数
    //   都是可选的.
    //   q 没有值,查询所有  有值就查询满足条件的.
    /*
      1.  如果q参数没有值:    select * from student limit (page-1)*size, size
      2.  如果q参数有值:     select * from student where name like '%q%' or nickname like '%q%' limit (page-1)*size, size
    

      1. 查询所有的数据并分页.

      2. 根据关键字查询数据并分页.
 
     */

    if (q) {
        //如果q有值.
        stuDb.getAllStudentByPageAndQ(page, q, results => {
            res.send({
                code: 200,
                count: results.length,
                data: results
            })
        }, error => {
            return res.status(500).send({ code: 500, msg: '服务器内部错误', error });
        });

    } else {
        //q没有值,要去查询所有的学生
        stuDb.getAllStudentByPage(page, results => {
            res.send({
                code: 200,
                count: results.length,
                data: results
            })
        }, error => {
            return res.status(500).send({ code: 500, msg: '服务器内部错误', error });
        });
    }
}

module.exports.query = (req, res) => {
    //1. 从客户端的URL中取出传递的id参数
    const { id } = req.query;   //5
    if (!id) return res.status(400).send({ code: 400, msg: '参数错误' });
    //2. 去数据库中查询出id为传入的id的记录.
    stuDb.getStudentById(id, results => {
        //查询成功
        //判断查询到的结果是否有数据
        if (results.length == 0) return res.status(404).send({ code: 404, msg: 'id不存在' });
        res.send({ code: 200, data: results[0] });
    }, error => {
        res.status(500).send({ code: 500, msg: '服务器内部错误', error });
    })
}

module.exports.add = (req, res) => {
    //1. 先从post请求中取出传递的数据
    const stu = req.body;
    // 对数据进行一些校验.
    // name nickname gender这三个数据是必须要传递,否则就报400
    if (!stu.name || !stu.nickname || !stu.gender) return res.status(400).send({ code: 400, msg: '参数错误' });
    //3个必传的数据都有了.
    //判断1下其它的参数是否有传递,如果有传递,就是它传递的值, 如果没有传递我们就设置1个默认值.
    stu.age = stu.age || 18;
    stu.score = stu.score || 60;
    stu.className = stu.className || '深圳黑马前端就业班第71期';
    stu.avatar = stu.avatar || 'default_avatar.png';

    //调用数据模块的方法新增数据
    stuDb.add(stu, results => {
        res.status(201).send({
            code: 201,
            msg: '新增成功',
            insertId: results.insertId
        });
    }, error => {
        res.status(500).send({ code: 500, msg: '服务器内部错误', error });
    })
}

//当URL是 /delete 的时候,对应的逻辑处理就是交给这个方法。
module.exports.delete = (req, res) => {
    //1. 取出客户端通过URL传递到服务端的id
    const { id } = req.query;
    //2. 判断id是否有传递
    if (!id) return res.status(400).send({ code: 400, msg: '参数错误' });
    //3. 调用数据模块的方法 删除学员
    stuDb.deleteStudentById(id, results => {
        //成功的时候执行
        //1. 判断1下受影响的行数
        if (results.affectedRows == 0)
            return res.status(404).send({ code: 404, msg: 'id不存在' });
        res.send({ code: 200, msg: '删除成功' });
    }, error => {
        res.status(500).send({ code: 500, msg: '服务器内部错误', error });
    });
}

module.exports.update = (req, res) => {
    //1. 取出客户端通过post传递到服务端的数据.
    const newStu = req.body;
    //2. 判断id有没有传递 
    if (!newStu.id) return res.status(400).send({ code: 400, msg: 'id必须要传递' });
    //3. 再判断哪些数据传递了 传了就使用新值 没有传就使用原来的值.
    //3.1 先去数据库中 查询出本身的数据
    ///   根据id去数据库中查询数学生信息

    stuDb.getStudentById(newStu.id, results => {
        //查询成功
        if (results.length == 0) return res.status(400).send({ code: 400, msg: 'id不存在' });
        //id存 
        const oldStu = results[0]; //oldStu是数据库中原来的数据在
        newStu.name = newStu.name || oldStu.name;
        newStu.nickname = newStu.nickname || oldStu.nickname;
        newStu.age = newStu.age || oldStu.age;
        newStu.gender = newStu.gender || oldStu.gender;
        newStu.score = newStu.score || oldStu.score;
        newStu.className = newStu.className || oldStu.className;
        newStu.avatar = newStu.avatar || oldStu.avatar;
        //更新数据
        stuDb.updateStudentById(newStu, results => {
            res.send({
                code: 200,
                msg: '修改成功'
            });
        }, error => {
            res.status(500).send({ code: 500, msg: '服务器内部错误', error });
        })
    }, error => {
        res.status(500).send({ code: 500, msg: '服务器内部错误', error });
    })
}

4. 问题:请求数据库异步操作

问题描述:之前所有的操作写在一个页面的时候,请求数据库connection.query(sql语句,(error,results)=>{})如果请求失败直接return error,成功也可以直接调用results(成功执行sql语句的结果)。但是封装模块化之后,因为请求数据库是一个异步操作,error和results如果直接return的话是接收不到的,但是我们逻辑处理模块又需要sql请求返回的数据。

解决方法:通过回调函数获得SQL返回参数error和results

SQL模块代码:

module.exports.getAllStudentByPageAndQ = (page,q,  successCallback, errorCallback) => {
    //1.生成sql语句
    const sqlCommand = `select * from student where name like '%${q}%' or nickname like '%${q}%' limit ${(page-1)*config.pageSize}, ${config.pageSize}`;
    //2. 执行sql语句.
    connection.query(sqlCommand, (error, results) => {
        if(error){
            errorCallback(error);
        }else{
            successCallback(results);
        }
    });
}

定义两个回调函数参数 successCallback,errorCallback分别用来存 errorCallback(error)错误信息,successCallback(results)成功返回数据

路由逻辑模块代码:

        stuDb.getAllStudentByPageAndQ(page, q, results => {
            res.send({
                code: 200,
                count: results.length,
                data: results
            })
        }, error => {
            return res.status(500).send({ code: 500, msg: '服务器内部错误', error });
        });

这里results 就是接受的成功执行SQL后的数据,error 就是错误信息
上面用来箭头函数的简写(results)=>{} results参数接受
successCallback(results) results参数保存

总结

今日份学习内容:模块化开发(自定义模块),异步操作返回数据的处理,接口路由练习,node.js中操作mysql请求练习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值