共计 12116 个字符,预计需要花费 31 分钟才能阅读完成。
其实温习一次的作用实在太大了,真的,自从上次 ajax 开始其实就开始 i 有点懵懵懂懂的感觉,始终拖想到了 node 在去回顾一遍,这一次回去温习,ajax 曾经很纯熟了,node 之前搞不懂那些原理也顺分明了好多,其实这次温习没有什么须要说的知识点,因为要说的后面都说过了,我来说一下这个做的一个大我的项目吧,这个我的项目真的,应该是我不纯熟的违心那边,就是用 express 写接口,用 postman 来测试,三个模块,三个数据库,基本上都在我的代码外面了,写的很具体步骤,用到的技术,基本上是用 node 的 express 模块,去写接口,而后中途中到了一些中间件,比方规定语义规定的 joi,比方给明码解码加密的 bcryptjs,我做了一天才做下来这一个案例
一个我的项目初试化,首先要创建一个独自的我的项目文件夹,而后终端 npm init 间接装置 package.json,api.js 接口文件,路由模块创建一个文件夹夹,路由函数又要分为一个模块,再把数据库创建好,根本就能够开始实现性能需要了,用后端 node 实现增删改查
我的项目文件分类:
1
接口文件
// 1. 初始化
// 1.1 创立我的项目
const express = require('express')
const app = express()
// 1.2 配置跨域
const cors = require('cors')
app.use(cors())
// 1.3 配置解析表单中间件
// 谬误点:记住要有参数
app.use(express.urlencoded({extended : false}))
// 2.3 因为前面处理函数用到了很多 res.send 所以封装为一个全局中间件,给 res 绑定一个函数,那前面的中间件路由都能够用到这个函数了
app.use((req, res, next) => {res.cc = function(err, status = 1) {
res.send({
status,
msg : err instanceof Error ? err.message : err
})
}
next()})
// 2.4.6 配置解析 token 的中间件
const expressJWT = require('express-jwt')
const secretKey = require('./secretKey')
app.use(expressJWT({secret : secretKey.secretKey, algorithms : ['HS256']}).unless({path : [/^\/api\//]}))
// 1.4.4 导入路由模块
const routerUser = require('./router/user')
const Joi = require('joi')
const {expressjwt} = require('express-jwt')
const {path} = require('express/lib/application')
app.use('/api', routerUser)
// 3.1.1 集体核心路由导入
const infoRouter = require('./router/userinfo')
app.use('/my', infoRouter)
// 4.1.2 文章治理导入
const article = require('./router/acticle')
app.use('/my/article', article)
// 5.1.2 公布文章路由导入
const cates = require('./router/cate')
app.use('/my/article', cates)
// 2.2.3 定义规定 joi 的谬误级别中间件
app.use((err, req, res, next) => {if (err instanceof Joi.ValidationError) return res.send(err.message)
// 2.4.7 减少 jwt 谬误中间件
if (err.name == 'UnauthorizedError') return res.cc('身份认证失败')
return res.send('其余谬误')
})
app.listen(80, () => {console.log('http://127.0.0.1');
})
2.
写好接口文件该去给路由创立模块
// 1.4 初始化路由相干文件夹 不光要给路由分装一个模块 外面的处理函数也要有一个模块
const express = require('express')
const {append} = require('express/lib/response')
const router = express.Router()
// 1.4.2 导入路由处理函数
const routerHandler = require('../router_handler/user')
// 注册
// 2.2.2 导入 joi 验证输出进来的是否非法
const expressJOI = require('@escook/express-joi')
const {schema_user_info} = require('../schema/user')
router.post('/reguser',expressJOI(schema_user_info), routerHandler.getReguser)
// 2.4 登录
// 2.4.1 增加语法规定,能够间接用注册的
router.post('/login',expressJOI(schema_user_info), routerHandler.getLogin)
module.exports = router
3.
处理函数模块
// 1.4.1 初始化路由处理函数模块
// 注册
const db = require('../mysql')
// 导入明码加密解密包
const bcrypt = require('bcryptjs')
function getReguser(req, res) {// res.send('这里是注册模块')
// 2.2.4 检测用户名是否被占用 导入 mysql
let selectUser = 'select * from users where username = ?'
db.query(selectUser, req.body.username, (err, results) => {
// 2.3.1 用到咱们后面定义的全局中间件优化 res.send
if (err) return res.cc(err)
if (results.length == 1) return res.cc('用户名已被占用')
// 2.2.5 如果过了前两关的验证 根本能够验证胜利了 就先对明码进行加密解决装置 bcryptjs
req.body.password = bcrypt.hashSync(req.body.password, 10)
// console.log(req.body.password);
// 2.2.6 插入新用户
let insertUser = 'insert into users set ?'
// ------------- 留神一下这里插入数据库的参数怎么写的
db.query(insertUser, [{username : req.body.username, password : req.body.password}], (err, results) => {if (err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('注册失败')
res.cc('注册胜利',0)
})
})
}
// 登录
// 2.4.4.1 导入 jwt
const jwt = require('jsonwebtoken')
const secretKey = require('../secretKey')
const {result} = require('@hapi/joi/lib/base')
function getLogin(req, res) {// res.send('这里是登录模块')
// 2.4.2 依据用户名查问用户的数据
let selectLoginuser = 'select * from users where username = ?'
db.query(selectLoginuser, req.body.username, (err, results) => {if (err) res.cc(err)
if (results.length !== 1) res.cc('未找到该用户')
// 2.4.3 有数据就去判断明码是否正确
// console.log(results);
if (!bcrypt.compareSync(req.body.password, results[0].password)) return res.cc('明码谬误')
// 2.4.4 用户名有,明码 也对上了阐明登陆胜利,开始 jwt 身份认证
// 先剔除明码和头像的值
let user = {...results[0], password : '', user_pic:'',algorithms : ['HS256']}
let userToken = jwt.sign(user, secretKey.secretKey, {expiresIn : '1h'})
// 2.4.5 向客户端发送 token
res.send({
status : 0,
msg : '登录胜利',
token : 'Bearer' + userToken
})
})
}
// 获取用户根本信息
function getInfo(req,res) {// res.send('集体核心')
// 3.1.2 获取用户根本信息
let selectInfo = 'select id,username,nickname,email,user_pic from users where id = ?'
db.query(selectInfo, req.user.id, (err, results) => {if (err) return res.cc(err)
if (results.length !== 1) return res.cc('获取信息失败')
res.send({
status : 0,
msg : '获取信息胜利',
data : results[0]
})
})
}
// 3.2 更新用户信息
function updateInfo(req, res) {// res.send('更新用户信息')
// 3.2.4 更新用户性能
let updateInfo = 'update users set ? where id = ?'
db.query(updateInfo, [req.body, req.user.id], (err, results) => {if (err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('更新信息失败')
res.cc('更新信息胜利', 0)
})
}
// 3.3 重置明码
function updatePwd(req, res) {// res.send('重置明码')
// 3.3.2 查问用户是否存在
let selectExist = 'select * from users where id = ?'
db.query(selectExist, req.user.id, (err, results) => {if (err) return res.cc(err)
if (results.length !== 1) return res.cc('用户不存在')
// 3.3.3 后面那一步尽管无所谓但这一步必须的 判断输出的旧明码是否正确
if(!bcrypt.compareSync(req.body.oldPwd, results[0].password)) return res.cc('输出明码谬误')
// 3.3.4 对新密码加密后更新到数据库
let password = bcrypt.hashSync(req.body.newPwd)
let updatePwd = 'update users set password =? where id =?'
db.query(updatePwd, [password,req.user.id], (err, results) => {if (err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('批改明码失败')
res.cc('更新明码胜利', 0)
})
})
}
// 3.4 更换头像
function updateAvatar(req, res) {// res.send('更换头像')
// 3.4.3
let updateAvatar = 'update users set user_pic = ? where id = ?'
db.query(updateAvatar, [req.body.avatar, req.user.id], (err, results) => {if (err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('更新头像失败')
res.cc('更新头像胜利', 0)
})
}
module.exports = {
getLogin,
getReguser,
getInfo,
updateInfo,
updatePwd,
updateAvatar
}
4.
这个时候就能够去 api 入口文件测试一下了,而后在数据库写好咱们的数据表,创建一个 js 文件链接数据库
// 2. 登录注册
// 2.1 建好数据库后配置数据库
const {result} = require('@hapi/joi/lib/base')
const mysql = require('mysql')
const db = mysql.createPool({
host : '127.0.0.1',
user : 'root',
password : 'admin123',
database : 'mydb'
})
// 测试
/* db.query('select 1' , (err, results) => {if(err) return console.log(err.message);
return console.log(results);
}) */
module.exports = db
5.
没记错的话,在登录接口应该应用 jwt 认证机制生成 token 吧
const express = require('express')
const router = express.Router()
const routerHandler = require('../router_handler/user')
// 3. 集体核心
// 3.1 获取用户根本信息
router.get('/userinfo', routerHandler.getInfo)
// 3.2.1 更新用户信息
// 3.2.3 增加验证规定
const expressJoi = require('@escook/express-joi')
const {schema_update_info, schema_update_avatar} = require('../schema/user')
router.post('/userinfo',expressJoi(schema_update_info),routerHandler.updateInfo)
// 3.3.1 重置明码
const {schema_update_pwd} = require('../schema/user')
router.post('/updatepwd',expressJoi(schema_update_pwd), routerHandler.updatePwd)
// 3.4.1 更换头像
const {schema_updatee_avatar} = require('../schema/user')
router.post('/update/avatar',expressJoi(schema_updatee_avatar), routerHandler.updateAvatar)
module.exports = router
token 的验证规定
module.exports = {secretKey : 'sdfafsfds'}
下面就是整个 user 局部的接口了包含登录注册,增加删除批改账号或者明码等,上面是咱们的 user 的验证规定
// 2.2 注册
// 2.2.1 对表单数据验证,这里就不 if else 了间接用上 joi 来验证 joi 要下最新版而且间接导入 joi
const {number} = require('joi')
const joi = require('joi')
const username = joi.string().alphanum().min(1).max(10).required()
// 谬误点:正则{}外面的量词之间不能以空格隔开
const password = joi.string().pattern(/^[\S]{6,12}$/).required()
// 3.2.2 更新用户信息规定
const id = joi.number().integer().min(1).required()
const nickname = joi.string().required()
const email = joi.string().email().required()
// 3.4.2 更换头像规定
const avatar = joi.string().dataUri().required()
module.exports.schema_user_info = {
body : {
username,
password
}
}
module.exports.schema_update_info = {
body : {
id,
nickname,
email
}
}
module.exports.schema_update_pwd = {
// 3.3.2 重置明码规定
body : {
oldPwd : password,
// -------------- 谬误点这里就算是变量也要增加引号
newPwd : joi.not(joi.ref('oldPwd')).concat(password)
}
}
module.exports.schema_updatee_avatar = {
body : {avatar}
}
6.
这个局部是对文章的名字和别名的增删改查的操作了,这外面的难点在于要去了解那个怎么来判断是否重名哪里
// 4.1.1 文章分类列表函数
const {result} = require('@hapi/joi/lib/base')
const db = require('../mysql')
function getArticleList(req, res) {// res.send('文章分类列表')
// 4.1.3 获取文章数据
let selectArticleList = 'select * from article where is_delete = 0'
db.query(selectArticleList, (err, results) => {if (err) return res.cc(err)
res.send({
status : 0,
msg : '获取文章分类列表胜利',
data : results
})
})
}
// 4.2.1 新增文章分类
function addCates(req,res) {
// 4.2.3 名字与别名是否重名
let selectDuplicate = 'select * from article where name = ? or alias = ?'
db.query(selectDuplicate, [req.body.name, req.body.alias], (err, results) => {if(err) return res.cc(err)
if(results.length == 2) return res.cc('文章名字和别名已被占用')
if(results.length == 1 && results[0].name == req.body.name && results[0].alias == req.body.alias) return res.cc('文章名字和别名已被占用')
if(results.length == 1 && results[0].name == req.body.name) return res.cc('文章名字被占用')
if(results.length == 1 && results[0].alias == req.body.alias) return res.cc('文章别名被占用')
// 4.2.4 实现文章分类新增
let addArt = 'insert into article set ?'
db.query(addArt, req.body, (err, results) => {if(err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('新增文章失败')
res.cc('新增文章分类胜利', 0)
})
})
}
// 4.3.1 依据 idshanchuwenzhan
function deleteCate(req, res) {
// 4.3.3 实现删除性能
let deleteId = 'update article set is_delete = 1 where id = ?'
db.query(deleteId, req.params.id, (err, results) => {if (err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('删除文章失败')
res.cc('删除文章分类胜利', 0)
})
}
// 4.4.1 依据 id 获取文章分类
function requireArt(req,res) {
// 4.4.2
let selectArt = 'select * from article where id = ?'
db.query(selectArt, req.params.id, (err, results) => {if (err) return res.cc(err)
if (results.length !== 1 || results[0].is_delete == 1) return res.cc('没有该文章')
res.send({
status : 0,
msg : '获取文章分类数据胜利',
data : results[0]
})
})
}
// 4.5.1 依据 id 更新文章
function updateArt(req, res) {
// 4.5.2 查看是否重名
// ----------------- 这里须要先将本人这一项排除进去
let selectIdDuplicate = 'select * from article where id != ? and (name = ? or alias = ?)'
db.query(selectIdDuplicate, [req.body.id, req.body.name, req.body.alias], (err, results) => {if (err) return res.cc(err)
if (results.length == 2) return res.cc('文章名称和别名已被占用')
if (results.length == 1 && results[0].name == req.body.name && results[0].alias == req.body.alias) return res.cc('文章名称和别名已被占用')
if (results.length == 1 && results[0].name == req.body.name) return res.cc('文章名称已被占用')
if (results.length == 1 && results[0].alias == req.body.alias) return res.cc('别名已被占用')
let updateIdArt = 'update article set ? where id = ?'
db.query(updateIdArt, [req.body, req.body.id] , (err,results) => {if (err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('文章更新失败')
res.cc('更新分类信息胜利', 0)
})
})
}
module.exports = {
getArticleList,
addCates,
deleteCate,
requireArt,
updateArt
}
这是路由模块,下面是路由的处理函数
// 4. 文章类别治理
const express = require('express')
const router = express.Router()
const routerhanlder = require('../router_handler/article')
// 4.1 获取文章分类列表
router.get('/cates',routerhanlder.getArticleList)
// 4.2 新增文章分类
const expressJoi = require('@escook/express-joi')
const {add_article_list, update_id_cate} =require('../schema/article')
router.post('/addcates',expressJoi(add_article_list),routerhanlder.addCates)
// 4.3 依据 id 删除文章
const {delete_id_cate} = require('../schema/article')
router.get('/deletecate/:id',expressJoi(delete_id_cate),routerhanlder.deleteCate)
// 4.4 依据 id 获取文章分类数据
router.get('/cates/:id',expressJoi(delete_id_cate), routerhanlder.requireArt)
// 4.5 依据 id 更新文章分类数据
const {update_id_Art} = require('../schema/article')
router.post('/updatecate',expressJoi(update_id_Art) ,routerhanlder.updateArt)
module.exports = router
而后咱们的规定
const joi = require('joi')
// 4.2.2 新增文章规定
const name = joi.string().required()
const alias = joi.string().alphanum().required()
// 4.3.2 依据 id 删除文章 留神这个 id 是动静的而且是 get 申请,所以不再是 body 数据
const id = joi.number().integer().min(1).required()
module.exports.add_article_list = {
body : {
name,
alias
}
}
module.exports.delete_id_cate = {
params : {id}
}
module.exports.update_id_Art = {
body : {
id : id,
name : name,
alias : alias
}
}
7.
最初是咱们的增加文章这个性能,就是往每一个方才创立好的文章外面,增加新文章,间接看逻辑的实现吧
// 5.1.1 公布文章函数
const path = require('path')
const db = require('../mysql')
function addCate(req, res) {
// 5.1.5 因为上传表单无奈用 joi 所以要独自规定
if (!req.file || req.file.fieldname !== 'cover_img') return res.cc('请上传图片')
// 5.1.6 当时公布文章性能
const cateObj = {
...req.body,
cover_img : path.join('/uploads', req.file.filename),
pub_date : new Date(),
author_id : req.user.id
}
let addInsert = 'insert into articles set ?'
db.query(addInsert, cateObj, (err, results) => {if (err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('公布文章失败')
res.cc('公布文章胜利', 0)
})
}
module.exports = {addCate}
// 1.4 初始化路由相干文件夹 不光要给路由分装一个模块 外面的处理函数也要有一个模块
const express = require('express')
const {append} = require('express/lib/response')
const router = express.Router()
// 1.4.2 导入路由处理函数
const routerHandler = require('../router_handler/user')
// 注册
// 2.2.2 导入 joi 验证输出进来的是否非法
const expressJOI = require('@escook/express-joi')
const {schema_user_info} = require('../schema/user')
router.post('/reguser',expressJOI(schema_user_info), routerHandler.getReguser)
// 2.4 登录
// 2.4.1 增加语法规定,能够间接用注册的
router.post('/login',expressJOI(schema_user_info), routerHandler.getLogin)
module.exports = router