尚硅谷大事件后台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
    })
})
复制代码
相关推荐
西岸行者9 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意9 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码9 天前
嵌入式学习路线
学习
毛小茛9 天前
计算机系统概论——校验码
学习
babe小鑫9 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms9 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下9 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。9 天前
2026.2.25监控学习
学习
im_AMBER9 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J9 天前
从“Hello World“ 开始 C++
c语言·c++·学习