尚硅谷大事件后台API项目(学习自用)

大事件后台API项目

1.初始化

1.1创建项目

首先创建一个文件夹名为api_server,然后用vscode打开这个文件夹,新建终端,在终端输入npm init -y会生成一个package.json文件,接着新建一个文件app.js作为入口文件,在终端安装特定版本的express,输入npm i express@4.17.1 ,然后在app.js中初始化代码如下:

js 复制代码
//导入express模块
const express=require('express')

//创建express服务器实例
const app=express()

//代码实现

//调用app.listen方法,指定端口号并启动web服务器
app.listen(3007,function(){
    console.log('api server running at http://127.0.0.1:3007')
})

1.2配置cors跨域

首先在终端下载特定版本的cors中间件,输入npm i cors@2.8.5,然后在app.js文件中输入如下代码:

js 复制代码
//导入cors中间件
const cors=require('cors')
//将cors注册为全局中间件
app.use(cors())

1.3配置解析表单数据的中间件

直接在app.js中输入如下代码:

js 复制代码
//配置解析application/x-www-form-urlencoded格式的表单数据的中间件
app.use(express.urlencoded({extended:false}))

express.urlencoded(): Express 框架提供的内置中间件,用于解析 URL 编码的请求体。URL 编> > 码是一种将表单数据编码成 URL 格式的方法,常用于 HTTP POST 请求。

{ extended: false }: 配置选项,用于指定如何解析 URL 编码数据。

extended: false 表示使用 querystring 库解析 URL 编码数据,该库只支持浅层嵌套的对象。这适> 用于大部分情况,并且解析速度更快。

extended: true 表示使用 qs 库解析 URL 编码数据,该库支持深层嵌套的对象。如果你需要解析> 复杂结构的表单数据,可以使用 extended: true。

1.4初始化路由相关文件夹

建两个文件夹,

一个router文件夹,用来放所有路由模块。

路由模块中,只存放客户端的请求与处理函数之间的映射关系

一个router_handler文件夹,用来存放所有路由处理函数模块

路由处理模块中,专门负责存放每个路由对应的处理函数

1.5初始化用户路由模块

  1. 在router文件夹中,新建user.js文件,作为用户的路由模块,初始化代码如下:
js 复制代码
const express=reqire('express')

//创建路由对象
const router=express.Router()

//注册新用户
router.post('/reguser',(req,res)=>{
    res.send('reguser OK')
})

//登录
router.post('/login',(req,res)=>{
    res.send('login OK')
})

//将路由对象共享出去
module.exports=router
  1. 在app.js中,导入并使用用户路由模块
js 复制代码
//导入并注册用户路由模块
const userRouter=require('./router/user')
//用户每次要请求用户路由时,要加前缀/api
app.use('/api',userRouter)

1.6抽离用户路由模块中的处理函数

目的:为了保证路由模块的纯粹性,所有的路由处理函数,必须抽离到对应的路由处理函数模块

  1. 在/router_handler/user.js中,使用exports对象,分别向外共享如下两个路由处理函数:
js 复制代码
//定义和用户相关的路由处理函数,供/router/user.js模块进行调用
//注册用户的处理函数
exports.regUser = (req, res) => {
    res.send('reguser OK')
}
//登陆处理函数
exports.login = (req, res) => {
    res.send('login OK')
}
  1. 将/router/user.js中的代码修改为如下结构:
js 复制代码
const express=require('express')

//创建路由对象
const router=express.Router()

//导入用户路由处理函数模块
const userHandler=require('../router_handler/user')

//注册新用户
router.post('/reguser',userHandler.regUser)

//登录
router.post('/login',userHandler.login)

//将路由对象共享出去
module.exports=router

登录注册

2.1新建ev_users表

2.2安装并配置mysql模块

  1. 在终端安装mysqlnpm i mysql@2.18.1
  2. 在项目根目录中创建/db/index.js文件,在此自定义模块中创建数据库的连接对象:
js 复制代码
//导入mysql模块
const mysql = require('mysql')

//创建数据库连接对象
const db = mysql.createPool({
    host: '127.0.0.1',
    user: 'root',
    password: '123456',
    database: 'my_db_01'
})

//向外共享db数据库连接对象
module.exports = db

2.3注册

2.3.0实现步骤

  1. 检测表单数据是否合法
  2. 检测用户名是否被占用
  3. 对密码进行加密处理
  4. 插入新用户
    2.3.1检测表单数据是否合法
  5. 检测用户名和密码是否为空
js 复制代码
//接收表单数据
const userinfo=req.body
//判断数据是否合法
if(!userinfo.username||!userinfo.password){
	return res.send({status:1,message:'用户名或密码不能为空!'})
}

2.3.2检测用户名是否被占用

  1. 导入数据库操作模块:
js 复制代码
const db=require('./db/index')
  1. 定义SQL语句:
js 复制代码
const sql = `select * from ev_users where username=?`
  1. 执行SQL语句并根据结果判断用户名是否被占用:
js 复制代码
db.query(sql, [userinfo.username], function (err, results) {
        //执行语句失败
        if (err) {
            return res.send({status:1,message:err.message})
        }
        //用户名被占用
        if(results.length>0){
            return res.send({status:1,message:'用户名被占用,请更换其他用户名!'})
        }
        //用户名可用
    })

2.3.3对密码进行加密处理

为了保证密码的安全性,不建议在数据库以明文的形式保存用户密码,推荐对密码进行加密存储

在当前项目中,使用bcryptjs对用户密码进行加密,优点:

  • 加密之后的密码,无法被逆向破解
  • 统一明文密码多次加密,得到的加密结果各不相同,保证了安全性
  1. 运行如下命令,安装指定版本的bcryptjs:
    npm i bcryptjs@2.4.3
  2. 在/router_handler/user.js中导入bcrtptjs:
js 复制代码
const bcrypt=require('bcryptjs')
  1. 在注册用户的处理函数中,确认用户名可用之后,调用bcrypt.hashSync(明文密码,随机盐的长度)方法,对用户的密码进行加密处理:
js 复制代码
//对用户的密码进行加密,返回值时加密之后的密码字符串
userinfo.password=bcrypt.hashSync(userinfo.password,10)

2.3.4插入新用户

  1. 定义插入新用户的SQL语句:
js 复制代码
const addsql = `insert into ev_users set ?`
  1. 调用db.query()执行SQL语句,插入新用户:
js 复制代码
        db.query(addsql, { username: userinfo.username, password: userinfo.password }, function (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: '注册用户失败,请稍后再试!' })
            }
            //注册成功
            res.send({ status: 0, message: '注册成功!' })
        })

扩展:

results.affectedRows 是一个数字,表示执行数据库操作(例如插入、更新、删除)后影响到的行数。

当 results.affectedRows === 1 时,说明数据库操作成功影响到了一行数据。

当 results.affectedRows === 0 时,说明数据库操作没有影响到任何数据,可能的原因是:

操作语句错误,没有匹配到任何数据。

数据已被其他用户修改,导致操作语句无法生效。

当 results.affectedRows > 1 时,说明数据库操作影响了多行数据,这通常发生在更新或删除操作中,多个记录符合操作条件。

2.4优化res.send()代码

在处理函数中,需要多次调用res.send()向客户端响应处理失败的结果,为了简化代码,可以手动封装一个res.cc()函数

  1. 在app.js中,所有路由之前声明一个全局中间件,为res对象挂载一个res.cc()函数:
js 复制代码
//一定要在路由之前,封装res.cc函数
//响应数据的中间件
app.use(function (req, res, next) {
    //status=0为成功;status=1为失败;默认status为1,方便处理失败情况
    res.cc = function (err, status = 1) {
        res.send({
            //状态
            status,
            //状态描述,判断err是错误对象还是描述错误的字符串
            message: err instanceof Error ? err.message : err
        })
    }
    next()
})

2.5优化表单数据验证

表单验证原则:前端验证为辅,后端验证为主,后端永远不要相信前端提交过来的任何内容

用if...else形式的判断效率低下,出错率高,所以使用第三方数据验证模块,来降低出错率,提高验证效率。

官方文档:https://www.npmjs.com/package/@escook/express-joi

  1. 安装@hapi/joi包,为表单中携带的每个数据项,定义验证规则:npm i @hapi/joi@17.1.0
  2. 安装@escook/express-joi中间件,来实现自动对表单数据进行验证的功能:npm i @escook/express-joi
  3. 新建/schema/user.js用户信息验证规则模块,并初始化代码如下:
js 复制代码
const joi = require('@hapi/joi')
/**
* string() 值必须是字符串
* alphanum() 值只能是包含 a-zA-Z0-9 的字符串
* min(length) 最小长度
* max(length) 最大长度
* required() 值是必填项,不能为 undefined
* pattern(正则表达式) 值必须符合正则表达式的规则
*/
// 用户名的验证规则
const username = joi.string().alphanum().min(1).max(10).required()
// 密码的验证规则 : 字符串 不能有空格 6-12位 必填
const password = joi.string().pattern(/^[\S]{6,12}$/).required()
// 注册和登录表单的验证规则对象
exports.reg_login_schema = {
    // 表示需要对 req.body 中的数据进行验证
    body: {
        username,
        password,
    },
}
  1. 修改 /router/user.js 中的代码如下:
js 复制代码
const express=require('express')

//创建路由对象
const router=express.Router()

//导入用户路由处理函数模块
const userHandler=require('../router_handler/user')

// 1. 导入验证表单数据的中间件
const expressJoi = require('@escook/express-joi')

// 2. 导入需要的验证规则对象
const { reg_login_schema } = require('../schema/user')

//注册新用户
// 3. 在注册新用户的路由中,声明局部中间件,对当前请求中携带的数据进行验证
// 3.1 数据验证通过后,会把这次请求流转给后面的路由处理函数
// 3.2 数据验证失败后,终止后续代码的执行,并抛出一个全局的 Error 错误,进入全局错误级别中间件中进行处理
router.post('/reguser', expressJoi(reg_login_schema), userHandler.regUser)
// router.post('/reguser',userHandler.regUser)

//登录
router.post('/login',userHandler.login)

//将路由对象共享出去
module.exports=router
  1. 在 app.js 的全局错误级别中间件中,捕获验证失败的错误,并把验证失败的结果响应给客户
    端:
js 复制代码
const joi = require('@hapi/joi')
// 错误中间件
app.use(function (err, req, res, next) {
    // 数据验证失败
    if (err instanceof joi.ValidationError) return res.cc(err) //这里要写return 否则会继续调用下面的res.cc()相当于调用了两次res.send()
    // 未知错误
    res.cc(err)
})

注意:

出错:返回

{

"status": 1,

"message": "Cannot mix different versions of joi schemas"

}

原因:@hapi/joi版本已弃用,换成joi模块就好了,install joi就可以。

2.6登录

2.6.0实现步骤

  1. 检测表单数据是否合法
  2. 根据用户名查询用户的数据
  3. 判断用户输入的密码是否正确
  4. 生成JWT的token字符串
    2.6.1检测表单数据是否合法
  5. 将/router/user.js中的登录路由代码修改如下:
js 复制代码
//登陆的路由
router.post('/login',expressJoi(reg_login_schema),userHandler.login)

2.6.2根据用户名查询用户的数据

  1. 接收表单数据
js 复制代码
const userinfo=req.body
  1. 定义SQL语句:
js 复制代码
const sql=`select * from ev_users where username=?`
  1. 执行SQL语句,查询用户的数据:
js 复制代码
db.query(sql,userinfo.username,function(err,results){
//执行SQL语句失败
if(err)return res.cc(err)
//执行SQL语句成功,但是查询到数据条数不等于1
if(results.length!==1)return res.cc('登陆失败!')
})

2.6.3判断用户输入的密码是否正确

核心实现思路:调用bcrypt.compareSync(用户提交的密码,数据库中的密码)方法比较密码是否一致,因为数据库中存的是加密过的密码,直接比对肯定是不一致的。

返回的是布尔值(true一致,false不一致)

具体实现代码如下:

js 复制代码
//拿着用户输入的密码,和数据库中存储的密码进行比对
const compareReault=bcrypt.compareSync(userinfo.password,result[0].password)

//如果对比的结果等于false,则证明用户输入的密码错误
if(!compareResult){
return res.cc('登陆失败!')
}

2.6.4生成JWT的Token字符串

核心注意点:在生成Token字符串的时候,一定要剔除密码和头像的值

  1. 通过ES6的高级语法,快速剔除密码和头像的值:
js 复制代码
//剔除完毕之后,user中只保留了用户的id,username,nickname,email这四个属性的值
const user={...results[0],password:'',user_pic:''}//后面会覆盖前面
  1. 运行命令,安装生成token字符串的包:
    npm i jsonwebtoken@8.5.1
  2. 在/router_handler/user.js模块的头部区域,导入jsonwebtoken包:
js 复制代码
//用这个包来生成token字符串
const jwt=require('jsonwebtoken')
  1. 创建config.js文件,并向外共享加密和还原token的jwtSecretKey字符串:
js 复制代码
//这是一个全局配置文件
module.exports = {
    //加密和解密的token密钥
    jwtSecretKey: 'hoshi No1. ^_^',
}
  1. 将用户信息对象加密成Token字符串:
js 复制代码
//导入配置文件(放最前面)
const config=require('../config')
//生成token字符串
const tokenStr=jwt.sign(user,config.jwtSecretKey,{
expiresIn:'10h'//token有效期为10小时,也可以在config文件中定义
})
  1. 将生成的token字符串响应给客户端
js 复制代码
res.send({
            status: 0,
            message: '登陆成功!',
            //为了方便客户端使用token,在服务器端直接凭借上Bearer前缀
            token: 'Bearer ' + tokenStr
        })

/router_handler/user.js完整代码:

js 复制代码
//定义和用户相关的路由处理函数,供/router/user.js模块进行调用

//导入数据库操作模块
const db = require('../db/index')
//导入bcrtptjs
const bcrypt = require('bcryptjs')
//用这个包来生成token字符串
const jwt = require('jsonwebtoken')
//导入配置文件
const config = require('../config')

//注册用户的处理函数
exports.regUser = (req, res) => {
    //接收表单数据
    const userinfo = req.body
    //判断数据是否合法
    // if (!userinfo.username || !userinfo.password) {
    //     // return res.send({ status: 1, message: '用户名或密码不能为空!' })
    //     return res.cc(err)
    // }


    //定义 SQL 语句
    const sql = `select * from ev_users where username=?`

    //执行 SQL 语句并根据结果判断用户名是否被占用
    db.query(sql, [userinfo.username], function (err, results) {
        //执行语句失败
        if (err) {
            // return res.send({ status: 1, message: err.message })
            return res.cc(err)
        }
        //判断results的length是否大于0,大于0说明有数据对象就是被占用了
        //用户名被占用
        if (results.length > 0) {
            // return res.send({ status: 1, message: '用户名被占用,请更换其他用户名!' })
            return res.cc(err)
        }

        //用户名可用
        //对用户的密码进行加密,返回值时加密之后的密码字符串
        userinfo.password = bcrypt.hashSync(userinfo.password, 10)

        const addsql = `insert into ev_users set ?`
        db.query(addsql, { username: userinfo.username, password: userinfo.password }, function (err, results) {
            //执行SQL语句失败
            if (err)
                // return res.send({ status: 1, message: err.message })
                return res.cc(err)
            //SQL语句执行成功,但影响行数不为1
            if (results.affectedRows !== 1) {
                // return res.send({ status: 1, message: '注册用户失败,请稍后再试!' })
                return res.cc('注册用户失败,请稍后再试!')
            }
            //注册成功
            // res.send({ status: 0, message: '注册成功!' })
            return res.cc('注册成功!', 0)
        })
    })

}
//登陆处理函数
exports.login = (req, res) => {
    //接收表单数据
    const userinfo = req.body
    //定义SQL语句:
    const sql = `select * from ev_users where username=?`
    // 执行SQL语句,查询用户的数据:
    db.query(sql, userinfo.username, function (err, results) {
        //执行SQL语句失败
        if (err) return res.cc(err)
        //执行SQL语句成功,但是查询到数据条数不等于1
        if (results.length !== 1) return res.cc('登陆失败!')

        const compareResult = bcrypt.compareSync(userinfo.password, results[0].password)
        // console.log(results[0].password);
        //如果对比的结果等于false,则证明用户输入的密码错误
        if (!compareResult) {
            return res.cc('登陆失败!')
        }

        //剔除完毕之后,user中只保留了用户的id,username,nickname,email这四个属性的值
        const user = { ...results[0], password: '', user_pic: '' }//后面会覆盖前面
        // console.log(user);

        //生成token字符串
        const tokenStr = jwt.sign(user, config.jwtSecretKey, {
            expiresIn: '10h'//token有效期为10小时
        })
        // console.log(tokenStr);
        res.send({
            status: 0,
            message: '登陆成功!',
            //为了方便客户端使用token,在服务器端直接凭借上Bearer前缀
            token: 'Bearer ' + tokenStr
        })
    })

}

2.7配置解析Token的中间件

  1. 运行命令,安装解析token中间件:
    npm i express-jwt@5.3.3
  2. 在app.js中注册路由之前,配置解析Token的中间件:
js 复制代码
//一定要在路由之前配置解析token的中间件
//导入配置文件
const config=require('../config')
//解析token的中间件
const expressJWT=require('express-jwt')
//使用.unless({path:[/^\/api\//]})指定哪些接口不需要进行token的身份认证
app.use(expressJWT({secret:config.jwtSecretKey}).unless({path:[/^\/api\//]}))
  1. 在app.js中错误级别中间件里面,捕获并处理token认证失败后的错误:
js 复制代码
//错误中间件
app.use(function(err,req,res,next){
//省略其他代码
//身份认证失败后的错误
    if(err.name==='UnauthorizedError')return res.cc('身份认证失败')
})

3.个人中心

3.1获取用户的基本信息

请求url:/my/userinfo

请求方式:GET

Header:Authorization:Bearer token字符串

参数:无

3.1.0实现步骤

  1. 初始化路由模块
  2. 初始化路由处理函数模块
  3. 获取用户的基本信息
    3.1.1 初始化路由模块
  4. 创建/router/userinfo.js路由模块,并初始化如下代码结构:
js 复制代码
const express=require('express')

//创建路由对象
const router=express.Router()

//获取用户基本信息
router.get('/userinfo',(req,res)=>{
    res.send('ok')
})

//将路由对象共享出去
module.exports=router
  1. 在app.js中导入并使用个人中心的路由模块
js 复制代码
//导入并使用个人中心的路由模块
const userinfoRouter=require('./router/userinfo')
//注意:以/my开头的接口,都是有权限的接口,需要进行token身份认证
app.use('/my',userinfoRouter)

3.1.2初始化路由处理函数模块

  1. 创建/router_handler/userinfo.js路由处理函数模块,并初始化如下的代码结构:
js 复制代码
//获取用户基本信息的处理函数
exports.getUserinfo=(req,res)=>{
    res.send('ok')
}

2.修改/router/userinfo.js中的代码:

js 复制代码
const express=require('express')

//创建路由对象
const router=express.Router()

//导入路由处理函数模块
const userinfoHandler=require('../router_handler/userinfo')

//获取用户基本信息
router.get('/userinfo',userinfoHandler.getUserinfo)

//将路由对象共享出去
module.exports=router

3.1.3获取用户的基本信息

  1. 在/router_handler/userinfo.js头部导入数据库操作模块:
js 复制代码
//导入数据库操作模块
const db=require('../db/index')
  1. 定义SQL语句:
js 复制代码
//根据用户的id查询用户的基本信息
//注意:为了防止用户的密码泄露,需要排除password字段
const sql=`select id,username,nickname,email,user_pic from ev_users where id=?`
  1. 调用db.query执行SQL语句:
js 复制代码
 //注意:req对象的user属性,是token解析成功express-jwt中间件帮我们挂载上去的
    db.query(sql, req.user.id, (err, results) => {
        //执行SQL语句失败
        if (err) return res.cc(err)
        //执行SQL语句成功,但是查询到的数据条数不等于1
        if (results.length !== 1) return res.cc('获取用户信息失败!')
        //将用户信息响应给客户端
        res.send({
            status: 0,
            message:'获取用户基本信息成功!',
            data:results[0]
        })
    })

3.2更新用户的基本信息

3.2.0实现步骤

  1. 定义路由和处理函数
  2. 验证表单数据
  3. 实现更新用户基本信息的功能
    3.2.1定义路由和处理函数
  4. 在/router/userinfo.js模块中,新增更新用户基本信息的路由:
js 复制代码
//更新用户的基本信息
router.post('/userinfo',userinfoHandler.updateUserInfo)
  1. 在/router_handler/userinfo.js模块中,定义并向外共享更新用户基本信息的路由处理函数:
js 复制代码
//更新用户基本信息的处理函数
exports.updateUserInfo=(req,res)=>{
res.send('ok')
}

3.2.2验证表单数据

  1. 在/schema/user.js验证规则模块中,定义id,nickname,email的验证规则如下:
js 复制代码
//定义id,nickname,email的验证规则
const id=joi.number().integer().min(1).required()
const nickname=joi.string().required()
const email=joi.string().email().required()
  1. 并使用exports向外共享如下的验证规则对象:
js 复制代码
//验证规则对象-更新用户基本信息
exports.update_userinfo_schema = {
    body: {
        id,//规则中的名字要跟表单数据的名字相同,否则,如果规则为id1,那么这个body中的id要改为 id:id1
        nickname,//可以写成nickname:nickname
        email
    }
}
  1. 在/router/userinfo.js模块中,导入验证数据合法性的中间件:
js 复制代码
const expressJoi=require('@escook/express-joi')
  1. 在/router/userinfo.js模块中,导入需要的验证规则对象:
js 复制代码
//导入需要的验证规则对象
const {update_userinfo_schema}=require('../schema/user')
  1. 在/router/userinfo.js模块中,修改更新用户的基本信息的路由如下:
js 复制代码
//更新用户的基本信息
router.post('/userinfo',expressjoi(update_userinfo_schema),userinfoHandler.updateUserInfo)

3.2.3实现更新用户基本信息的功能

  1. 定义待执行的SQL语句:
js 复制代码
const sql=`update ev_users set ? where id=?`
  1. 调用db.query()执行SQL语句并传参:
js 复制代码
db.query(sql,[req.body,req.body.id],(err,results)=>{
//执行SQL语句失败
if(err)return res.cc(err)
//执行SQL语句成功,但影响行数不为1
if(results.affectedRows!==1)return res.cc('修改用户基本信息失败!')
//修改用户基本信息成功
return res.cc('修改用户基本信息成功!',0)
})

3.3重置密码

3.3.0实现步骤

  1. 定义路由和处理函数
  2. 验证表单数据
  3. 实现重置密码的功能
    3.3.1定义路由和处理函数
  4. 在/router/userinfo.js模块中新增重置密码路由:
js 复制代码
router.post('/updatepwd',expressJoi(update_pwd_schema),userinfoHandler.updatePassword)
  1. 在/router_handler/userinfo.js模块中,定义并向外共享重置密码的路由处理函数:
js 复制代码
//重置密码的处理函数
exports.updatePassword=(req,res)=>{
    res.send('ok')
}

3.3.2验证表单数据

  1. 在/schema/user.js中:
js 复制代码
exports.update_pwd_schema={
    body:{
        //使用password规则验证req.body.oldPwd的值
        oldPwd:password,
        //使用joi.not(joi.ref('oldPwd')).concat(password)规则验证newPwd
        //joi.ref('oldPwd')表示newPwd的值必须和oldPwd的值保持一致
        //joi.not(joi.ref('oldPwd'))表示newPwd不能等于oldPwd
        //.concat()用于合并joi.not(joi.ref('oldPwd'))和password这两条验证规则
        newPwd:joi.not(joi.ref('oldPwd')).concat(password)
    }
}
  1. 在/router/userinfo.js中
js 复制代码
const {update_pwd_schema}=require('../schema/user')
//const {update_userinfo_schema,update_pwd_schema}=require('../schema/user')

3.3.3实现重置密码功能

  1. 根据id查用户是否存在:
js 复制代码
const sql=`select * from ev_users where id=?`

db.query(sql,req.user.id,(err,results)=>{
if(err)return res.cc(err)
if(results.length!==1)return res.cc('用户不存在')
})
  1. 判断旧密码是否正确
js 复制代码
//在头部导入bcrypt,使用bcrypt.compareSync(提交的密码,数据库中的密码)验证
const bcrypt=require('bcryptjs')

const comapreResult=bcrypt.compareSync(req.body.oldPwd,results[0].password)
if(!comapreResult)return res.cc('原密码错误!')
  1. 对新密码加密,更新到数据库
js 复制代码
        const sql = `update ev_users set password=? where id=?`
        //对新密码进行加密
        const newPwd=bcrypt.hashSync(req.body.newPwd,10)

		//注意这里id是从user对象获取的,跟newPwd不一样
        db.query(sql, [newPwd, req.user.id], (err, results) => {
            if (err) return res.cc(err)
            if (results.affectedRows !== 1) return res.cc('修改密码失败!')
            return res.cc('修改密码成功!', 0)
        })

更新头像

  1. 在/router_handler/userinfo.js
js 复制代码
exports.updateAvatar=(req,res)=>{
    const sql=`update ev_users set user_pic=? where id=?`

    db.query(sql,[req.body.avatar,req.user.id],(err,results)=>{
        if(err)return res.cc(err)
        if(results.affectedRows!==1)return res.cc('更新头像失败!')
        res.cc('更新头像成功',0)
    })
}
  1. 在/scheme/user.js
js 复制代码
//dataUri是指如下格式的字符串:
//data:image/png;base64,VE9PTUFOWVNFQ1JFVFM=
const avatar=joi.string().dataUri().required()
exports.update_avatar_schema={
    body:{
        avatar
    }
}
  1. 在/router/userinfo.js
js 复制代码
const {update_userinfo_schema,update_pwd_schema,update_avatar_schema}=require('../schema/user')
//更新头像
router.post('/update/avatar',expressJoi(update_avatar_schema),userinfoHandler.updateAvatar)

文章分类管理

4.1新建ev_article_cate表

4.2获取文章分类列表

4.2.0实现步骤
  1. 初始化路由模块
  2. 初始化路由处理函数模块
  3. 获取文章分类列表数据
4.2.1初始化路由模块
  1. 创建 /router/artcate.js路由模块,并初始化如下的代码结构:
js 复制代码
//导入express
const express=require('express')

//创建路由对象
const router=express.Router()

//获取文章分类的列表数据
router.get('/cates',artcateHandler.getArticles)

//向外共享路由数据
module.exports=router
  1. 在app.js中导入并使用文章分类的路由模块:
js 复制代码
//导入并使用文章的路由模块
const articleRouter=require('./router/artcate')
app.use('/my/article',articleRouter)
4.2.2初始化路由处理函数模块
  1. 创建/router_handler/artcate.js路由处理函数模块,并初始化如下的代码结构:
js 复制代码
exports.getArticles=(req,res)=>{
    res.send('ok')
}
  1. 修改/router/artcate.js中的代码如下:
js 复制代码
//导入express
const express=require('express')

//创建路由对象
const router=express.Router()


const artcateHandler=require('../router_handler/artcate')

//获取文章分类的列表数据
router.get('/cates',artcateHandler.getArticles)

//向外共享路由数据
module.exports=router
4.2.3获取文章分类列表数据
  1. 在/router_handler/artcate.js头部导入数据库操作模块
js 复制代码
const db=require('../db/index')
  1. SQL语句
js 复制代码
//根据分类的状态,获取所有未被删除的分类列表数据
    //is_delete为0表示没有被 标记为删除的数据
    const sql=`select * from ev_article_cate where is_delete=0 order by id asc`
  1. 调用db.query()
js 复制代码

db.query(sql,(err,results)=>{

//1.执行SQL语句失败

if(err) return res.cc(err)

    //2.执行SQL语句成功
    res.send({
        status:0,
        message:'获取文章分类列表成功',
        data:results
    })
})
复制代码
相关推荐
@小博的博客1 小时前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习
南宫生2 小时前
贪心算法习题其四【力扣】【算法学习day.21】
学习·算法·leetcode·链表·贪心算法
懒惰才能让科技进步2 小时前
从零学习大模型(十二)-----基于梯度的重要性剪枝(Gradient-based Pruning)
人工智能·深度学习·学习·算法·chatgpt·transformer·剪枝
love_and_hope3 小时前
Pytorch学习--神经网络--搭建小实战(手撕CIFAR 10 model structure)和 Sequential 的使用
人工智能·pytorch·python·深度学习·学习
Chef_Chen3 小时前
从0开始学习机器学习--Day14--如何优化神经网络的代价函数
神经网络·学习·机器学习
芊寻(嵌入式)3 小时前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
hong1616883 小时前
跨模态对齐与跨领域学习
学习
阿伟来咯~4 小时前
记录学习react的一些内容
javascript·学习·react.js
Suckerbin4 小时前
Hms?: 1渗透测试
学习·安全·网络安全
水豚AI课代表5 小时前
分析报告、调研报告、工作方案等的提示词
大数据·人工智能·学习·chatgpt·aigc