内容参考:
windos下安装mysql
express 使用mysql
一、创建一个空项目
二、创建一个包管理工具
npm init -y
三、安装需要的插件及app.js的部分实现
npm i express 安装express 框架
npm i cors 安装cors 用于跨域
npm install mysql2 安装mysql数据库
npm i bcryptjs 用于加密密码 。加密之后的密码,无法被逆向破解。同一明文密码多次加密,得到的加密结果各不相同,保证了安全性
npm i @escook/express-joi 自动对表单数据进行验证
npm install joi 用于表单数据验证 解决if else 效率低下问题
创建app.js 及其代码
// 引入 express 框架
const express = require("express");
const cors = require("cors");
const app = express();
// 将cors 注册成全局中间件 用于跨域
app.use(cors());
// 没有配置json 返回的时undefined 没有配置urlencoded 返回的时{}
// 配置解析application/x-www-form-urlencoded(表单数据)的中间件
app.use(express.urlencoded({ extends: false }));
// 配置json数据的中间件
app.use(express.json());
const port = 3000;
app.get("/", (req, res) => res.send("Hello World!"));
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
四、创建路由模块
1、创建文件
1.在项目根目录中,新建 router 文件夹,用来存放所有的 路由 模块
路由模块中,只存放客户端的请求与处理函数之间的映射关系
2.在项目根目录中,新建 router_handler 文件夹,用来存放所有的 路由处理函数模块
路由处理函数模块中,专门负责存放每个路由对应的处理函数
3.在项目根目录中,新建 db文件夹,用于链接数据库
2、连接数据库 db/index.js
const mysql = require("mysql2");
// 2、建立与mysql 数据库的链接
const db = mysql.createPool({
host: "127.0.0.1", // 数据库的ip地址
user: "root", // 登录数据库的账号
password: "", // 登录数据库的密码
database: "my_db_01", //指定要操作的数据库
});
module.exports = db;
3、 创建一个用户表
4、初始化用户模块 router_handler模块在后续 router/user.js
const { Router } = require("express");
const router = Router();
// 导入user模块路由的处理函数
const userHandle = require("../router_handler/user");
// 注册新用户
router.post("/reguser", userHandle.regUser);
// 登录
router.post("/login", userHandle.login);
module.exports = router;
5、把router模块引入app.js
// 导入用户模块
const userRouter = require("./rooter/user");
// /api请求前缀 user模块中的所有请求都要在前面加上/api
app.use("/api", userRouter);
4、抽离用户模块中的处理函数
目的:为了保证 路由模块 的纯粹性,所有的 路由处理函数 ,必须抽离到对应的 路由处理函数模块 中
1.在 /router_handler/user.js
中,使用 exports 对象,分别向外共享如下两个 路由处理函数
exports.regUser = (req, res) => {
res.send("reguuser ok");
};
exports.login = (req, res) => {
res.send("login ok");
};
三、优化
1、对用户数据进行校验
目的:为了保证 路由模块 的纯粹性,所有的 校验函数 ,必须抽离到对应的 校验处理函数模块 中
在根目录下创建schema目录,在其下新建user.js文件
// 导入定义验证的包
const joi = require("joi");
// 定义用户名和密码的验证规则
const username = joi.string().alphanum().min(1).max(10).required();
const password = joi
.string()
.pattern(/^[\S]{6,12}$/)
.required();
//定义验证注册和登录表单数据的对象
exports.reg_login_schma = {
body: {
username,
password,
},
};
2、对rooter模块中的 user.js 增加校验方法
const { Router } = require("express");
const router = Router();
const expressJoi = require("@escook/express-joi");
// 导入user模块路由的处理函数
const userHandle = require("../router_handler/user");
// 导入登录验证
const { reg_login_schma } = require("../schema/user");
// 1、导入验证数据的中间件
// 注册新用户
router.post("/reguser", expressJoi(reg_login_schma), userHandle.regUser);
router.post("/login", userHandle.login);
module.exports = router;
3、封装一个全局错误中间件
// 封装res.custom_err 函数 处理错误情况
app.use((req, res, next) => {
// status =0 为成功 status=1为失灵
// err的值,可能是一个错误对象,也可能是一个错误的描述字符串
res.custom_err = (err, status = 1) => {
res.send({
status,
message: err instanceof Error ? err.message : err,
});
};
next();
});
4、在app.js中注册全局中间件注意res.custom_err 是我封装的方法 见其上
const joi = require("joi");
app.use((err, req, res, next) => {
// 4.1 Joi 参数校验失败
if (err instanceof joi.ValidationError) return res.custom_err(err);
// // 4.2 未知错误
res.custom_err(err);
});
完整代码
db/index.js
const mysql = require("mysql2");
// 2、建立与mysql 数据库的链接
const db = mysql.createPool({
host: "127.0.0.1", // 数据库的ip地址
user: "root", // 登录数据库的账号
password: ".", // 登录数据库的密码
database: "my_db_01", //指定要操作的数据库
});
module.exports = db;
rooter/user.js
const { Router } = require("express");
const router = Router();
const expressJoi = require("@escook/express-joi");
// 导入user模块路由的处理函数
const userHandle = require("../router_handler/user");
// 导入登录验证
const { reg_login_schma } = require("../schema/user");
// 1、导入验证数据的中间件
// 注册新用户
router.post("/reguser", expressJoi(reg_login_schma), userHandle.regUser);
router.post("/login", userHandle.login);
module.exports = router;
router_handler/user.js
const db = require("../db/index");
// 导入加密
const bcryptjs = require("bcryptjs");
exports.regUser = (req, res) => {
const userInfo = req.body;
if (!userInfo.username || !userInfo.password)
return res.custom_err("账号或密码不能为空");
const sqlStr = "select * from ev_users where username=?";
db.query(sqlStr, userInfo.username, (err, results) => {
if (err) return res.custom_err(err);
// 如果>0 便是已存在
if (results.length > 0) {
return res.custom_err("用户名被占用");
}
// 在注册用户的处理函数中,确认用户名可用之后,调用 bcrypt.hashsync(明文密码,随机盐的长度)方法,对用户的密码进行加密处理
userInfo.password = bcryptjs.hashSync(userInfo.password, 10);
db.query("insert into ev_users set ?", userInfo, (err, results) => {
if (err) return res.custom_err(err);
// 判断影响行数是否为1
if (results.affectedRows !== 1)
res.custom_err("注册用户失败,请稍后再试");
res.send({
status: 0,
msg: "注册成功",
});
});
});
};
exports.login = (req, res) => {
res.send("login ok");
};
schema/user.js
// 导入定义验证的包
const joi = require("joi");
// 定义用户名和密码的验证规则
const username = joi.string().alphanum().min(1).max(10).required();
const password = joi
.string()
.pattern(/^[\S]{6,12}$/)
.required();
//定义验证注册和登录表单数据的对象
exports.reg_login_schma = {
body: {
username,
password,
},
};
app.js
// 引入 express 框架
const express = require("express");
const cors = require("cors");
const joi = require("joi");
const app = express();
// 将cors 注册成全局中间件
app.use(cors());
// 没有配置json 返回的时undefined 没有配置urlencoded 返回的时{}
// 配置解析application/x-www-form-urlencoded(表单数据)的中间件
app.use(express.urlencoded({ extended: false }));
// 配置json数据的中间件
app.use(express.json());
const port = 3000;
// 封装res.custom_err 函数 处理错误情况
app.use((req, res, next) => {
// status =0 为成功 status=1为失灵
// err的值,可能是一个错误对象,也可能是一个错误的描述字符串
res.custom_err = (err, status = 1) => {
res.send({
status,
message: err instanceof Error ? err.message : err,
});
};
next();
});
// 导入用户模块
const userRouter = require("./rooter/user");
// /api请求前缀
app.use("/api", userRouter);
// 错误中间件 应该放到最后
app.use((err, req, res, next) => {
// 4.1 Joi 参数校验失败
if (err instanceof joi.ValidationError) return res.custom_err(err);
// // 4.2 未知错误
res.custom_err(err);
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`));