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

news2024/10/7 1:40:53

大事件后台API项目

1.初始化

1.1创建项目

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

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

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

直接在app.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文件,作为用户的路由模块,初始化代码如下:
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中,导入并使用用户路由模块
//导入并注册用户路由模块
const userRouter=require('./router/user')
//用户每次要请求用户路由时,要加前缀/api
app.use('/api',userRouter)

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

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

  1. 在/router_handler/user.js中,使用exports对象,分别向外共享如下两个路由处理函数:
//定义和用户相关的路由处理函数,供/router/user.js模块进行调用
//注册用户的处理函数
exports.regUser = (req, res) => {
    res.send('reguser OK')
}
//登陆处理函数
exports.login = (req, res) => {
    res.send('login OK')
}
  1. 将/router/user.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文件,在此自定义模块中创建数据库的连接对象:
//导入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. 检测用户名和密码是否为空
//接收表单数据
const userinfo=req.body
//判断数据是否合法
if(!userinfo.username||!userinfo.password){
	return res.send({status:1,message:'用户名或密码不能为空!'})
}

2.3.2检测用户名是否被占用

  1. 导入数据库操作模块:
const db=require('./db/index')
  1. 定义SQL语句:
const sql = `select * from ev_users where username=?`
  1. 执行SQL语句并根据结果判断用户名是否被占用:
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:
const bcrypt=require('bcryptjs')
  1. 在注册用户的处理函数中,确认用户名可用之后,调用bcrypt.hashSync(明文密码,随机盐的长度)方法,对用户的密码进行加密处理:
//对用户的密码进行加密,返回值时加密之后的密码字符串
userinfo.password=bcrypt.hashSync(userinfo.password,10)

2.3.4插入新用户

  1. 定义插入新用户的SQL语句:
const addsql = `insert into ev_users set ?`
  1. 调用db.query()执行SQL语句,插入新用户:
        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()函数:
//一定要在路由之前,封装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用户信息验证规则模块,并初始化代码如下:
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 中的代码如下:
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 的全局错误级别中间件中,捕获验证失败的错误,并把验证失败的结果响应给客户
    端:
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中的登录路由代码修改如下:
//登陆的路由
router.post('/login',expressJoi(reg_login_schema),userHandler.login)

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

  1. 接收表单数据
const userinfo=req.body
  1. 定义SQL语句:
const sql=`select * from ev_users where username=?`
  1. 执行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('登陆失败!')
})

2.6.3判断用户输入的密码是否正确
核心实现思路:调用bcrypt.compareSync(用户提交的密码,数据库中的密码)方法比较密码是否一致,因为数据库中存的是加密过的密码,直接比对肯定是不一致的。
返回的是布尔值(true一致,false不一致)
具体实现代码如下:

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

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

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

  1. 通过ES6的高级语法,快速剔除密码和头像的值:
//剔除完毕之后,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包:
//用这个包来生成token字符串
const jwt=require('jsonwebtoken')
  1. 创建config.js文件,并向外共享加密和还原token的jwtSecretKey字符串:
//这是一个全局配置文件
module.exports = {
    //加密和解密的token密钥
    jwtSecretKey: 'hoshi No1. ^_^',
}
  1. 将用户信息对象加密成Token字符串:
//导入配置文件(放最前面)
const config=require('../config')
//生成token字符串
const tokenStr=jwt.sign(user,config.jwtSecretKey,{
expiresIn:'10h'//token有效期为10小时,也可以在config文件中定义
})
  1. 将生成的token字符串响应给客户端
res.send({
            status: 0,
            message: '登陆成功!',
            //为了方便客户端使用token,在服务器端直接凭借上Bearer前缀
            token: 'Bearer ' + tokenStr
        })

/router_handler/user.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的中间件:
//一定要在路由之前配置解析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认证失败后的错误:
//错误中间件
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路由模块,并初始化如下代码结构:
const express=require('express')

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

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

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

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

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

2.修改/router/userinfo.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头部导入数据库操作模块:
//导入数据库操作模块
const db=require('../db/index')
  1. 定义SQL语句:
//根据用户的id查询用户的基本信息
//注意:为了防止用户的密码泄露,需要排除password字段
const sql=`select id,username,nickname,email,user_pic from ev_users where id=?`
  1. 调用db.query执行SQL语句:
 //注意: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模块中,新增更新用户基本信息的路由:
//更新用户的基本信息
router.post('/userinfo',userinfoHandler.updateUserInfo)
  1. 在/router_handler/userinfo.js模块中,定义并向外共享更新用户基本信息的路由处理函数:
//更新用户基本信息的处理函数
exports.updateUserInfo=(req,res)=>{
res.send('ok')
}

3.2.2验证表单数据

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

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

  1. 定义待执行的SQL语句:
const sql=`update ev_users set ? where id=?`
  1. 调用db.query()执行SQL语句并传参:
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模块中新增重置密码路由:
router.post('/updatepwd',expressJoi(update_pwd_schema),userinfoHandler.updatePassword)
  1. 在/router_handler/userinfo.js模块中,定义并向外共享重置密码的路由处理函数:
//重置密码的处理函数
exports.updatePassword=(req,res)=>{
    res.send('ok')
}

3.3.2验证表单数据

  1. 在/schema/user.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中
const {update_pwd_schema}=require('../schema/user')
//const {update_userinfo_schema,update_pwd_schema}=require('../schema/user')

3.3.3实现重置密码功能

  1. 根据id查用户是否存在:
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. 判断旧密码是否正确
//在头部导入bcrypt,使用bcrypt.compareSync(提交的密码,数据库中的密码)验证
const bcrypt=require('bcryptjs')

const comapreResult=bcrypt.compareSync(req.body.oldPwd,results[0].password)
if(!comapreResult)return res.cc('原密码错误!')
  1. 对新密码加密,更新到数据库
        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
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
//dataUri是指如下格式的字符串:
//data:image/png;base64,VE9PTUFOWVNFQ1JFVFM=
const avatar=joi.string().dataUri().required()
exports.update_avatar_schema={
    body:{
        avatar
    }
}
  1. 在/router/userinfo.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路由模块,并初始化如下的代码结构:
//导入express
const express=require('express')

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

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

//向外共享路由数据
module.exports=router
  1. 在app.js中导入并使用文章分类的路由模块:
//导入并使用文章的路由模块
const articleRouter=require('./router/artcate')
app.use('/my/article',articleRouter)
4.2.2初始化路由处理函数模块
  1. 创建/router_handler/artcate.js路由处理函数模块,并初始化如下的代码结构:
exports.getArticles=(req,res)=>{
    res.send('ok')
}
  1. 修改/router/artcate.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头部导入数据库操作模块
const db=require('../db/index')
  1. SQL语句
//根据分类的状态,获取所有未被删除的分类列表数据
    //is_delete为0表示没有被 标记为删除的数据
    const sql=`select * from ev_article_cate where is_delete=0 order by id asc`
  1. 调用db.query()

db.query(sql,(err,results)=>{
//1.执行SQL语句失败
if(err) return res.cc(err)

    //2.执行SQL语句成功
    res.send({
        status:0,
        message:'获取文章分类列表成功',
        data:results
    })
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1908902.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

北森锐途人才竞聘盘点管理测评:高管领导力六大评判标准深度解析万达商管中国绿发等

北森锐途人才管理测评:高管领导力评判标准深度解析 在企业高管的盘点与竞聘测评领域,众多管理人才面临评估自身领导力的挑战。面对能力卓越、职级显赫的同僚,许多管理者感到缺乏一套权威且专业的评价体系。然而,无论是天赋异禀的领…

Html5前端基本知识整理与回顾上篇

今天我们结合之前上传的知识资源来回顾学习的Html5前端知识,与大家共勉,一起学习。 目录 介绍 了解 注释 标签结构 排版标签 标题标签 ​编辑 段落标签 ​编辑 换⾏标签 ​编辑 ⽔平分割线 ⽂本格式化标签 媒体标签 绝对路径 相对路径 …

Chromium编译指南2024 Linux篇-安装官方工具depot_tools(二)

1.引言 在上一节中,我们已经完成了 Git 的安装,并了解了其在 Chromium 编译过程中的重要性。接下来,我们将继续进行环境的配置,首先是安装和配置 Chromium 编译所需的重要工具——depot_tools。 depot_tools 是一组用于获取、管…

怎样优化 PostgreSQL 中对布尔类型数据的查询?

文章目录 一、索引的合理使用1. 常规 B-tree 索引2. 部分索引 二、查询编写技巧1. 避免不必要的类型转换2. 逻辑表达式的优化 三、表结构设计1. 避免过度细分的布尔列2. 规范化与反规范化 四、数据分布与分区1. 数据分布的考虑2. 表分区 五、数据库参数调整1. 相关配置参数2. 定…

linux工具应用_GVIM

gvim 1. introduction1.1 **gvim的功能(选择用gvim的原因)**1.2 模式及切换1.2.1 normal1.2.2 insert1.2.3 visual1.2.4 command2. gvim配置-vimrc2.1 什么是vimrc2.2 配置修改及理解2.2.1 基本修改2.2.2 UI 相关配置2.2.3 编码相关配置2.3.4 文件相关配置2.3.5 编辑器相关配…

用Conda配置 Stable Diffusion WebUI 1.9.4

用Conda配置 Stable Diffusion WebUI 1.9.4 本文主要讲解: 如何用Conda搭建Stable Diffusion WebUI 1.9.4环境,用Conda的方式安装,不需要单独去安装Cuda了。 1. 安装miniconda https://docs.anaconda.com/free/miniconda/index.html 2. 搭建虚拟环境…

Java设计模式---(创建型模式)工厂、单例、建造者、原型

目录 前言一、工厂模式(Factory)1.1 工厂方法模式(Factory Method)1.1.1 普通工厂方法模式1.1.2 多个工厂方法模式1.1.3 静态工厂方法模式 1.2 抽象工厂模式(Abstract Factory) 二、单例模式(Si…

快速掌握AI的最佳途径实践

科技时代,人工智能(AI)已经成为许多人希望掌握的重要技能。对于普通人来说,如何快速有效地学习AI仍然是一个挑战。本文将详细介绍几种快速掌握AI的途径,并提供具体的操作步骤和资源建议。 前言 AI的普及和应用已经深…

逻辑回归模型(非回归问题,而是分类问题)

目录: 一、Sigmoid函数:二、逻辑回归介绍:三、决策边界四、逻辑回归模型训练过程:1.训练目标:2.梯度下降调整参数: 一、Sigmoid函数: Sigmoid函数是构建逻辑回归模型的重要函数,如下…

【Word】快速对齐目录

目录标题 1. 全选要操作的内容 → 右键 → 段落2. 选则制表位3. 配置制表符4. Tab键即可 1. 全选要操作的内容 → 右键 → 段落 2. 选则制表位 3. 配置制表符 4. Tab键即可

js+spring boot实现简单前后端文件下载功能

jsboot项目实现自定义下载 一、前端页面 1、先导入axios的js包 2、注意axios响应的格式:result.data.真实的数据内容 3、这里请求的url就是你boot项目的getMapping的url,保持一致即可 4、如果想在后端设置文件名,那么后端生成后&#xf…

HackTheBox--BoardLight

BoardLight 测试过程 1 信息收集 NMAP端口扫描 端口扫描开放 22、80 端口 80端口测试 # 添加 boardLight.htb 到hosts文件 echo "10.10.11.11 boardLight.htb" | sudo tee -a /etc/hosts检查网页源代码,发现 board.htb # 添加 board.htb 到 hosts 文…

安卓应用开发学习:腾讯地图SDK应用改进,实现定位、搜索、路线规划功能集成

一、引言 我的上一篇学习日志《安卓应用开发学习:通过腾讯地图SDK实现定位功能》记录了利用腾讯地图SDK实现手机定位功能,并能获取地图中心点的经纬度信息。这之后的几天里,我对《Android App 开发进阶与项目实战》一书第九章的内容深入解读…

Open3D KDtree的建立与使用

目录 一、概述 1.1kd树原理 1.2kd树搜索原理 1.3kd树构建示例 二、常见的领域搜索方式 2.1K近邻搜索(K-Nearest Neighbors, KNN Search) 2.2半径搜索(Radius Search) 2.3混合搜索(Hybrid Search) …

STM32F446RE实现多通道ADC转换功能实现(DMA)

目录 概述 1 软硬件介绍 1.1 软件版本 1.2 ADC引脚介绍 2 STM32Cube配置项目 2.1 配置基本参数 2.2 ADC通道配置 2.3 DMA通道配置 3 项目代码介绍 3.1 自生成代码 3.2 ADC-DMA初始化 3.3 测试函数 3.4 ADC1、ADC2、ADC3轮询采集数据存贮格式 4 测试 源代码下载地…

clickhouse学习笔记(五)SQL操作

目录 一、增 二、删改 三、查询以及各种子句 1、with子句 a、表达式为常量 b、表达式为函数调用 c、表达式为子查询 2、from子句 3、array join子句 a、INNER ARRAY JOIN b、LEFT ARRAY JOIN c、数组的一些函数 groupArray groupUniqArray arrayFlatten splitBy…

小米订单锐减背后的挑战与应对之道

近期,富士康印度子公司Bharat FIH面临高管离职、工厂关闭的困境,其背后原因之一是小米订单的显著下滑,据报道,这一降幅高达70%。这一现象不仅反映了富士康在印度市场的艰难处境,也揭示了小米在全球智能手机市场面临的挑…

Atom CMS v2.0 SQL 注入漏洞(CVE-2022-24223)

前言 概要 CVE-2022-24223 是一个发现于 Atom CMS v2.0 中的 SQL 注入漏洞。该漏洞存在于 /admin/login.php 文件中,通过该文件,攻击者可以在未经身份验证的情况下执行任意的 SQL 命令。 漏洞描述 该漏洞位于 Atom CMS 的管理员登录页面(/a…

甄选范文“论区块链技术及应用”,软考高级论文,系统架构设计师论文

论文真题 区块链作为一种分布式记账技术,目前已经被应用到了资产管理、物联网、医疗管理、政务监管等多个领域。从网络层面来讲,区块链是一个对等网络(Peer to Peer, P2P),网络中的节点地位对等,每个节点都保存完整的账本数据,系统的运行不依赖中心化节点,因此避免了中…

跨境电商代购系统与电商平台API结合的化学反应

随着全球化的不断推进和互联网技术的飞速发展,跨境电商已成为国际贸易的重要组成部分。跨境电商代购系统作为连接国内外消费者与商品的桥梁,不仅为消费者提供了更多元化的购物选择,也为商家开辟了更广阔的市场空间。在这一过程中,…