1. 安装数据库及可视化数据库管理工具(navicat)
2. 创建数据库及表
创建一个名为blog的数据库
双击打开blog数据库,右键表,新建表,创建一个名为users的数据表
3. 实现注册功能
注册功能其实就是给users表中插入数据
注册所需字段:username password
所需npm包:
bcryptjs 用来给密码进行加密
mysql 用来连接数据库,操作数据库
joi 用来数据校验
body-parser 用来提交表单数据,处理表单数据,处理完之后挂载到req.body上
npm install bcryptjs mysql joi body-parser
3.1 实现步骤
3.1.1. 数据库连接
在db文件夹下创建文件index.js
// db/index.js
const mysql = require('mysql')
const db = mysql.createConnection({ // 连接数据库
host: '127.0.0.1', // 127.0.0.1 / localhost
user: 'root', // 数据库用户名
password: '123456', // 密码
database: 'blog' // 数据库名称
})
module.exports = db
操作数据库通过 db.query()方法
mysql详细api文档:https://www.npmjs.com/package/mysql
3.1.2. 创建用户注册字段校验函数和时间格式化函数
joi详细api文档:https://joi.dev/api/?v=17.5.0
在utils中创建validate.js用来校验字段,当做中间件使用
// 校验数据
// schemas 校验对象
const joi = require('joi')
const validateJoi = function (schemas) {
// TODO: 用户指定了什么 schema,就应该校验什么样的数据
return function (req, res, next) {
;['query', 'body', 'params'].forEach((key) => {
// 如果当前循环的这一项 schema 没有提供,则不执行对应的校验
if (!schemas[key]) return
// 执行校验
const schema = joi.object(schemas[key])
const { error, value } = schema.validate(req[key])
if (error) {
// 校验失败
throw error
} else {
// 校验成功,把校验的结果重新赋值到 req 对应的 key 上
req[key] = value
}
})
// 校验通过
next()
}
}
module.exports = validateJoi
在utils中添加时间格式化函数
/*
*@params date {Date Object} 日期
*@params fmt {String} 格式化方式
*@params bool {Boolean} 是否返回周几
*/
function dateFormat(date, fmt, bool) {
date = new Date(date)
var o = {
"M+": date.getMonth() + 1, //月份
"d+": date.getDate(), //日
"h+": date.getHours(), //小时
"m+": date.getMinutes(), //分
"s+": date.getSeconds(), //秒
"q+": Math.floor((date.getMonth() + 3) / 3), //季度
S: date.getMilliseconds(), //毫秒
}
let weekStr = "" // 星期几
const weekList = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
weekStr = weekList[date.getDay()]
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length))
}
for (var k in o) {
if (new RegExp("(" + k + ")").test(fmt)) {
fmt = fmt.replace(
RegExp.$1,
RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
)
}
}
if (bool) fmt = fmt + " " + weekStr
return fmt
}
module.exports = dateFormat
// console.log(dateFormat(+new Date(), "yyyy-MM-dd hh:mm:ss", 1))
在schema文件夹下创建user.js存放用户相关的字段校验对象
// schema/user.js
// 用户相关的字段校验
const joi = require('joi')
// username password
const reg = {
body: {
// 只能包含字母数字最小为1最大为10的字符串,并且必填
username: joi.string().alphanum().min(1).max(10).required(),
// 符合正则的字符串,并且必填
password: joi.string().pattern(/^[\S]{6,12}$/).required()
}
}
module.exports = {
reg
}
3.1.3. 在router文件夹下创建文件 user.js 专门存放用户相关的路由
// router/user.js
// 用户相关的路由
const { Router } = require('express')
const router = Router()
const validateJoi = require('../utils/validate') // 校验数据
// 路由处理函数
const user_handler = require('../router_handler/user')
const userSchema = require('../schema/user') // 用户相关的校验对象
// 用户注册
router.post('/reguser', validateJoi(userSchema.reg), user_handler.regUser)
3.1.4. 在router_handler文件夹下创建文件 user.js 专门存放用户相关的路由处理函数
// touter_handler/user.js
const bcrypt = require('bcryptjs') // 密码加密和解密
const db = require('../db/index') // 导入数据库对象
const dateFormat = require('../utils/dateFormat') // 时间格式化
// 注册
const regUser = (req, res) => {
// 用户名密码校验正确
const userInfo = req.body
const sql = `insert into users set ?`
userInfo.reg_time = dateFormat(new Date(), 'yyyy-MM-dd hh:mm:ss')
userInfo.password = bcrypt.hashSync(userInfo.password, 10) // 对密码加密
db.query(sql, userInfo, (err, result) => {
if (err && err.code === 'ER_DUP_ENTRY') {
const arr = err.sqlMessage.split(' ')
return arr[arr.length - 1] === "'username'" ? res.cc('用户名重复,换一个叭!') : res.cc(err.sqlMessage)
}
if (result.affectedRows !== 1) return res.cc('注册失败,请稍后重试!')
res.cc('注册成功!', 0)
})
}
module.exports = {
regUser
}
3.1.5 在app.js中挂载路由,添加错误级别中间件,以及错误输出状态函数
...
const joi = require('joi')
const bodyParser = require('body-parser')
const userRouter = require('./router/user') // 用户相关的路由
// 定义输出错误状态的中间件
app.use((req, res, next) => {
// 挂载函数,全局能用
res.cc = function (err, status = 1) {
res.send({
status,
msg: err instanceof Error ? err.message : err
})
}
next()
})
// 处理表单数据
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use('/api', userRouter)
// 定义错误级别中间件 放在所有路由后边
app.use((err, req, res, next) => {
// joi校验错误
if (err instanceof joi.ValidationError) return res.cc(err)
})
...
3.1.6 测试注册接口: http://127.0.0.1:8086/api/reguser
- 请求路径:/api/reguser
- 请求方法:post
- 请求参数:
请求参数 | 参数类型 | 参数说明 | 备注 |
---|---|---|---|
username | String | 用户名 | 不能为空 长度1-10位 |
password | String | 密码 | 不能为空 长度6-12位 |
评论 (0)