Node.js: express + MySQL的使用

目录

一,先确定自己的电脑上的环境

二,express的使用

三,连接Mysql,实现对数据库的增删改查

四,实现登录注册,身份认证


一,先确定自己的电脑上的环境

        需要node.js,npm,数据库(MySQL),数据库管理工具(也可以不用,Navicat,Workbench等都可以)。

二,express的使用

1,使用express建立服务器

(1),先创建一个文件夹,运用 npm init -y 在文件夹中创建一个package.json文件,用来管理下载的包。

(2),执行 npm i express 安装express,在文件夹里创建一个app.js作为主文件。

(3),先起一个服务器

// 引入express
const express = require("express");

// 创建服务器的实例对象
const app = express();

// 启动服务器,3007为端口号,选择一个空闲的端口号
app.listen(3007, () => {
  console.log("Server running at http://127.0.0.1:3007");
});

        引入express,船舰实例对象,运用listen()方法启动服务器。在终端使用node .\app.js命令启动服务器。

        在每次修改完代码后都需要重新启动服务器,新写的代码才会生效。解决:可以全局下载一个nodemon,运行时用 nodemon .\app.js  命令,在修改完代码保存后会自动重新启动。

2,使用express编写接口

        先看代码:

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

// 挂载路由,get请求
app.get('/', (req, res) => {
    res.send('get')
})
// post请求
app.post('/', (req, res)=>{
    res.send('post')
})

// 监听客户端的get请求
app.get('/user', (req, res) => {
    // 调用express调用的res.send()方法
    res.send({
        name: 'zs',
        age: 20,
        gender: '男'
    })
})

// :id是一个动态的参数 
app.get('/infor/:id/:name', (req, res)=> {
    // req.params获取到动态匹配到的参数
    console.log(req.params);
    res.send(req.params);
})

// 启动
app.listen(3007, ()=>{
    console.log('Server running at http://127.0.0.1:3007');
})

        app.get()方法挂载路由,get请求,post()方法,post请求,方法中第一个参数是请求时的路由,前端用路由来请求对应的数据。第二个参数是箭头函数  (req,res)=>{},req可以获取到前端传来的参数,res.send()  可以将数据传到前端。

        然后测试一下,接口测试的话可以使用一个软件Postman。可以选择get或post请求,后面写路由,也有写参数,请求头的地方。下面的图和上面的路由是对应的

get请求

 post请求

 get请求    无参数

 get请求  有参数

  由于最后一个例子有console.log(req.params);这一语句,所以终端也会有一句输出。 

 三,连接Mysql,实现对数据库的增删改查

        先使用  npm i mysql 在项目中安装数据库,安装后需要在项目中进行配置。

        在项目中新建一个文件夹db,文件夹下新建一个文件index.js (也可以不建文件夹,名字也可以用别的,这个就是个人习惯)。

 index.js

// 引入mysql
const mysql = require("mysql");
// 建立一个连接池
const db = mysql.createPool({
  host: "127.0.0.1", // 数据库的IP地址(本地的或者是云服务器的都可以)
  user: "clh",
  password: "clh123",
  database: "nodetest", //指定要操作哪个数据库
});

// 将文件暴露出去
module.exports = db

        配置好后要先检查数据库是否配置正确,是否可以使用。

// 引入mysql
const mysql = require("mysql");
// 建立一个连接池
const db = mysql.createPool({
  host: "127.0.0.1", // 数据库的IP地址(本地的或者是云服务器的都可以)
  user: "clh",
  password: "clh123",
  database: "nodetest", //指定要操作哪个数据库
});

// 检测数据库是否连接成功
// db.query("select 1", (err, results) => {
//   if (err) return console.log(err);
//   console.log(results);
// });

module.exports = db

        单独执行这个文件,终端输出:

         代表数据库已经配置成功。

先在数据库中添加几条数据用于测试,表名为    user_infor

先看代码

// 引入express
const express = require("express");
// 引入Mysql
const db = require("./db/index");
// 创建服务器的实例对象
const app = express();

// 查
app.get("/infor", (req, res) => {
  // 定义sql语句
  const sql = "select * from user_infor";
  // 执行sql语句
  db.query(sql, (err, result) => {
    // 执行失败
    if (err) {
      return res.send({ state: 1, message: err });
    }
    return res.send({ state: 0, message: "查询成功", data: result });
  });
});

// 启动服务器
app.listen(3007, () => {
  console.log("Server running at http://127.0.0.1:3007");
});

由于要操作数据,所以要学会使用数据库操作语言

(1),定义sql语句

(2),使用db.query()方法执行sql语句,第一个参数放sql语句

(3),箭头函数里,第一个参数是执行失败的信息,第二个参数是,执行成功的结果

(4),如果err存在,sql语句执行失败

(5),err不存在,result会拿到数据库中的信息,之后我们用res.send()方法将数据返回

 增

        添加数据需要从前端拿数据,但前端传的数据和后端要写入数据库中的数据的格式不同,要先运用中间件把前端拿到的数据在后端进行解析。

        所以在挂载路由之前先配置解析数据的中间件

// 引入express
const express = require("express");
const db = require("./db/index");
// 创建服务器的实例对象
const app = express();

// 配置解析表单数据的中间件  内置中间件,只能解析application/x-www-form-urlencoded格式的数据
app.use(express.urlencoded({extended: false}))

// 查
app.get("/infor", (req, res) => {
  // 定义sql语句
  const sql = "select * from user_infor";
  // 执行sql语句
  db.query(sql, (err, result) => {
    // 执行失败
    if (err) {
      return res.send({ state: 1, message: err });
    }
    return res.send({ state: 0, message: "查询成功", data: result });
  });
});

// 增
app.get("/increase", (req,res)=>{
  // 先取到要增加的字段值
  const addInfor = req.body
  // 定义sql语句
  const sql = "insert into user_infor set ?"
  // 执行sql语句,第二个参数代表sql语句中?的值
  /**
   * 如果增加的字段和数据库中的字段不是一一对应的
   * 将addInfor换成{name: addInfor.name, age: addInfor.age}
   * name代表数据库中的字段,addInfor.name代表他要增加的值
   */
  db.query(sql, addInfor, (err,results)=>{
    // sql语句执行失败
    if(err) {
      return res.send({status: 1, message: err.message})
    }
    // 数据库语句执行成功,但影响的条数不等于1,没有增加,也属于失败
    if(results.affectedRows !== 1) {
      return res.send({status: 1, message: '数据添加失败'})
    }
    // sql语句执行成功,影响条数也等于1
    return res.send({status:0, message: '添加成功', data:results})
  })
})

// 启动服务器
app.listen(3007, () => {
  console.log("Server running at http://127.0.0.1:3007");
});

        配置中间件app.use(express.urlencoded({extended: false})),这个中间件只能解析application/x-www-form-urlencoded格式的数据。

(1),req.body可以取到从前端传来要增加字段的字段值

(2),定义增加的sql语句,要添加的内容用?表示

(3),db.query()执行sql语句,第一个参数是sql语句,第二个参数,代表sql语句中?的值,要添加的内容

(4),如果添加的字段和数据库中表的字段不是一一对应的,将第二个参数换成{name: addInfor.name, age: addInfor.age},name,age,表示数据库中的字段,addInfor.name表示这个字段要添加的值

(5),err不存在时,还有两种情况,如果sql语句执行成功影响的条数不为1,还是没有添加成功,也属于失败

(6),执行成功后,可以重新请求查询语句查看数据的变化,或直接在数据库中查看

 改和删

// 引入express
const express = require("express");
const db = require("./db/index");
// 创建服务器的实例对象
const app = express();

// 配置解析表单数据的中间件  内置中间件,只能解析application/x-www-form-urlencoded格式的数据
app.use(express.urlencoded({ extended: false }));

// 查
app.get("/infor", (req, res) => {
  // 定义sql语句
  const sql = "select * from user_infor";
  // 执行sql语句
  db.query(sql, (err, result) => {
    // 执行失败
    if (err) {
      return res.send({ state: 1, message: err });
    }
    return res.send({ state: 0, message: "查询成功", data: result });
  });
});

// 改
app.get("/update", (req, res) => {
  // 修改语句,将user_infor表中id为?的年龄改为?,两个问号的值从前端获取
  const sql = "update user_infor set age=? where id=?";
  // 执行sql语句
  db.query(sql, [req.body.age, req.body.id], (err, results) => {
    // sql语句执行失败
    if (err) {
      return res.send({ status: 1, message: err.message });
    }
    // sql语句执行成功,但影响的条数不等于1,没有修改,也属于失败
    if (results.affectedRows !== 1) {
      return res.send({ status: 1, message: "数据修改失败" });
    }
    // 执行成功
    return res.send({ status: 0, message: "修改成功", data: results });
  });
});

// 删
app.get("/delete", (req, res) => {
  // 定义sql语句,从user_infor表中将id为?的那条数据删除
  const sql = "delete from user_infor where id=?";
  db.query(sql, req.body.id, (err, results) => {
    // sql语句执行失败
    if (err) {
      return res.send({ status: 1, message: err.message });
    }
    // sql语句执行成功,但影响的条数不等于1,没有删除,也属于失败
    if (results.affectedRows !== 1) {
      return res.send({ status: 1, message: "删除失败" });
    }
    // 执行成功
    return res.send({ status: 0, message: "删除成功", data: results });
  });
});

// 启动服务器
app.listen(3007, () => {
  console.log("Server running at http://127.0.0.1:3007");
});

         改,删和增一样也需要配置解析数据的中间件。只要从前端获取数据都需要配置解析数据的中间件。

(1),运用db.query(),执行sql语句,第二个参数代表sql语句中的?,sql中有多个?,第二个参数用中括号括起来。

        使用express的重点是要熟悉sql语句,会操作数据库。

​对代码进行优化


        下面的内容是对上面的代码进行优化,上面的所以内容都是在app.js文件中写的。在开发中不可能将所以的内容都写在一个文件里。
        一般都会把路由和路由的处理函数都分开,这样做可以将不同类型的代码进行分类,内容条理,便于维护。
文件结构:

        router文件夹下的文件用来创建路由,router_handler文件夹下的文件作为路由的处理函数,使用时将router_handler中的处理函数导入到router路由模块中,然后再将router路由模块导入到app.js文件中。先看代码:
app.js

// 引入express
const express = require("express");
// 创建服务器的实例对象
const app = express();

// 配置解析表单数据的中间件  内置中间件,只能解析application/x-www-form-urlencoded格式的数据
app.use(express.urlencoded({ extended: false }));
/**
 * 还有自定义中间,自定义中间件最后必须加next()方法
 */

// 封装res.send() ,必须在路由之前封装
/**
 * 不管是输出正确的数据还是错误的信息,每次都需要写这么多东西
 * res.send({ state: 0, message: "查询成功", data: result })
 * 封装之后不需要写这么多
 */
app.use((req, res, next) => {
  // 定义一个输出的函数
  res.output = function(err, status = 1, data) {
      res.send({
          status,
          message: err instanceof Error ? err.message : err,
          data
      })
  }
  next();
})

// 导入并使用路由模块
const inforRouter = require('./router/userInfor')
app.use(inforRouter)

// 启动服务器
app.listen(3007, () => {
  console.log("Server running at http://127.0.0.1:3007");
});

 路由模块    router文件夹下的userInfor.js文件

// 引入express
const express = require('express')
// 创建路由模块
const router = express.Router()

// 将处理函数导入
const infor_handler = require('../router_handler/userInfor')
// 获取用户的基本信息
router.get('/infor', infor_handler.getAllInfor)
// 通过id查找用户name
router.get('/inforById', infor_handler.getNameById)

// 向外共享路由对象
module.exports = router

        这个文件需要引入express来创建路由,并将路由的处理函数部分再分离出去,导入处理函数的文件,根据函数名匹配路由的处理函数。最后需要将路由对象暴露出去,在app.js文件中使用。

路由处理函数模块   router_handler文件夹下的userInfor.js文件

// 导入数据库操作模块
const db = require("../db/index");

// 获取用户信息的处理函数
exports.getAllInfor = (req, res) => {
  // 定义查询的sql语句
  const sql = "select * from user_infor";
  // 执行sql语句
  db.query(sql, (err, results) => {
    // 执行sql语句失败
    if (err) return res.output(err);
    // 执行成功
    res.output("查询成功", 0, results);
  });
};

// 通过id查找用户name,处理函数
exports.getNameById = (req, res) => {
  // 定义sql语句
  const sql = "select name from user_infor where id=?";
  // 执行sql语句,req获取从前端传的值
  db.query(sql, req.body.id, (err, results) => {
    // 执行sql语句失败
    if (err) return res.output(err);
    // 执行成功,但数据长度为0,执行失败
    if (results.length !== 1) return res.output("无数据");
    // 执行成功
    res.output("执行成功!", 0, results);
  });
};

        这个文件中是路由的处理函数,我写了两个处理函数,对应路由中的两个路由,第一个是查询表中所有的信息,第二个是根据id查询姓名,第二个是需要传参数的,传递参数的部分在sql语句中用?表示。

        res.output()这个方法是刚才在app.js文件中封装的res.send()的方法,封装时要在所有路由之前封装,最后必须用next()引出去。

        res.output()有三个参数,第一个参数是输出的信息,如果有err,直接输出err;第二个参数是状态,因为失败的情况比成功的情况要多,所以我在封装时默认是失败的情况,成功的话输出0,失败的话可以不写;第三个参数是输出数据,成功的话才会有数据。

查找id为1的用户的name:

 查找id为6的用户的name,数据库里是没有id为6的用户的:

        报错信息可以自己写,根据报错信息就可以知道是哪儿出现问题。 

校验数据

        不管是前端还是后端,数据校验对处理数据都很重要,开发中不要相信别人传来的数据,要自己进行校验。

        需要用到两个包:@escook/express-joi    和    joi

        joi 表单验证,制定验证规则。

        @escook/express-joi 自动对表单数据进行验证

 文件结构:

         重新创建一个文件夹,制度验证规则。

schema文件夹下的userInfor.js文件

// 导入定义校验规则的包
const joi = require("joi");
// 确定规则
const id = joi.number().integer().min(1).required(); // 数字, 整数,最小值
// 导出规则
exports.select_name_rules = {
  body: {
    id,
  },
};

        使用规则在路由模块下使用,就是router文件夹下的userInfor.js文件,处理函数文件中什么都不用变。

router文件夹下的userInfor.js文件

// 引入express
const express = require("express");
// 创建路由模块
const router = express.Router();
// 引入验证数据的中间件
const expressJoi = require("@escook/express-joi");
// 引入检验的规则
const { select_name_rules } = require("../schema/userInfor");

// 将处理函数导入
const infor_handler = require("../router_handler/userInfor");
// 获取用户的基本信息
router.get("/infor", infor_handler.getAllInfor);
// 通过id查找用户name
router.get(
  "/inforById",
  expressJoi(select_name_rules),
  infor_handler.getNameById
);

// 向外共享路由对象
module.exports = router;

        将规则引入,将自动验证数据的中间件(@escook/express-joi),也引入,在创建好的路由之后,处理函数之前写入校验。

写好之后,写错请求一次:

 

         终端会有报错,报错信息是id值必须是整数。这样就校验了。

        但报错信息还是要用res.send(),输出,所以需要调用错误级别的中间件。在所有的路由下调用错误级别的中间件,这样所有接口报的错都会进入到这个中间件。调用中间件的位置要选择好,像解析表单数据的中间件要定义在所有的路由之前,这样所有从前端传来的数据先通过中间件进行数据解析,再进入路由,从路由出来,报错后,再进入错误级别的中间件。

app.js

// 引入express
const express = require("express");
// 创建服务器的实例对象
const app = express();
// 引入校验规则的包,在定义错误级别的中间件时会用到
const joi = require('joi')

// 配置解析表单数据的中间件  内置中间件,只能解析application/x-www-form-urlencoded格式的数据
app.use(express.urlencoded({ extended: false }));

// 封装res.send() ,必须在路由之前封装
/**
 * 不管是输出正确的数据还是错误的信息,每次都需要写这么多东西
 * res.send({ state: 0, message: "查询成功", data: result })
 * 封装之后不需要写这么多
 */
app.use((req, res, next) => {
  // 定义一个输出的函数
  res.output = function (err, status = 1, data) {
    res.send({
      status,
      message: err instanceof Error ? err.message : err,
      data,
    });
  };
  next();
});


// 导入并使用路由模块
const inforRouter = require("./router/userInfor");
app.use(inforRouter);


// 在所有路由下面调用错误级别的中间件
app.use((err, req, res, next) => {
  // 验证失败导致的错误
  if (err instanceof joi.ValidationError) return res.output(err);
  // 未知的错误
  res.output(err);
  next();
});

// 启动服务器
app.listen(3007, () => {
  console.log("Server running at http://127.0.0.1:3007");
});

        当报的错属于joi.ValidationError这个,就说明是数据校验没通过,输出错误。

         错误信息,id必须为整数。

常用的规则

number():number类型

integer():整数

min():最小值      max()

required():必传项

string():string类型

email():邮箱规则

pattern():正则,参数为正则表达式

alphanum():字母数字都有

dataUri():图片规则,base64

四,实现登录注册,身份认证

登录注册:Node.js: express + MySQL实现注册登录,身份认证_express 登录注册_掉头发类型的选手的博客-CSDN博客

图片上传:Node.js: express + MySQL + Vue实现图片上传_掉头发类型的选手的博客-CSDN博客

  • 27
    点赞
  • 116
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值