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

大事件后台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语句执行成功,但影响行数不为1if (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语句执行成功,但影响行数不为1if (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语句成功,但是查询到数据条数不等于1if (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语句成功,但是查询到的数据条数不等于1if (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:id1nickname,//可以写成nickname:nicknameemail}
}
  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.mzph.cn/bicheng/43138.shtml

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

相关文章

哈尔滨等保测评标准的国际比较与启示

随着信息技术的快速发展和全球化趋势的加深,信息安全成为各国政府和企业共同关注的焦点。哈尔滨作为东北地区重要的经济和科技中心,其信息安全等级保护(简称“等保”)测评标准在确保本地企业信息安全的同时,也面临着与…

Could not find a package configuration file provided by “Torch“ 的参考解决方法

文章目录 写在前面一、问题描述二、解决方法参考链接 写在前面 自己的测试环境: Ubuntu20.04 一、问题描述 自己编译调用 Torch 的程序时,遇到如下报错: Make Error at CMakeLists.txt:15 (find_package):By not providing "FindTor…

设计资料:520-基于ZU15EG 适配AWR2243的雷达验证底板 高速信号处理板 AWR2243毫米波板

基于ZU15EG 适配AWR2243的雷达验证底板 一、板卡概述 本板卡系北京太速科技自主研发,基于MPSOC系列SOC XCZU15EG-FFVB1156架构,搭载两组64-bit DDR4,每组容量32Gb,最高可稳定运行在2400MT/s。另有1路10G SFP光纤接口、1路40G…

使用F1C200S从零制作掌机之构建debian文件系统

前情:使用buildrootfs构建的文件系统调试了很久NES模拟器,执行InfoNES模拟器的时候一直黑屏,无内容显示,调不通了,所以改用debian系统试试。 一、环境配置 首先下载两个工具:qemu-arm-static和debootstra…

uniapp小程序上传文件

需求 小程序需要上传用户相册图片或拍摄的照片到后端服务器 uniapp官方处理小程序文件方法 选择文件方法:uni.chooseMedia uni-app官网uni-app,uniCloud,serverless,uni.chooseVideo(OBJECT),chooseVideo HarmonyOS 兼容性,uni.chooseMedia(OBJECT),uni.saveVid…

Android:如何绘制View

点击查看Android 如何绘制视图官网 一、简介 Android 框架会在 Activity 获得焦点时请求 Activity 绘制其布局。Android 框架会处理绘制流程,但该 Activity 必须提供其布局层次结构的根节点。 Android 框架会绘制布局的根节点,并测量和绘制布局树。它会…

React@16.x(51)路由v5.x(16)- 手动实现文件目录参考

作为前面几篇文章的参考: 实现 Router实现 Route实现 Switch实现 withRouter实现 Link 和 NavLink 以上。

一.4 处理器读并解释储存在内存中的指令

此刻,hello.c源程序已经被编译系统翻译成了可执行目标文件hello,并被存放在硬盘上。要想在Unix系统上运行该可执行文件,我们将它的文件名输入到称为shell的应用程序中: linux>./hello hello, world linux> shell是一个命令…

深度优先搜索和广度优先搜索 使用场景

深度优先搜索(Depth-First Search, DFS)和广度优先搜索(Breadth-First Search, BFS)是图和树结构中常用的遍历算法。两者适用于不同的场景。 深度优先搜索 优点 较低的空间复杂度(只需保存当前路径)&…

JS实现当前元素的同级元素 以及父元素的同级元素

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>实现当前元素的同级元素 以及父元素的同级元素</t…

一.2.(4)放大电路静态工作点的稳定;

1.Rb对Q点及Au的影响 输入特性曲线&#xff1a;Rb减少&#xff0c;IBQ&#xff0c;UBEQ增大 输出特性曲线&#xff1a;ICQ增大&#xff0c;UCEQ减少 AUUO/Ui分子减少&#xff0c;分母增大&#xff0c;但由于分子带负号&#xff0c;所以|Au|减少 2.Rc对Q点及Au的影响 输入特性曲…

用Vue3和Plotly.js绘制交互式3D小提琴图

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 Vue 中使用 Plotly.js 创建小提琴图 应用场景介绍 小提琴图是一种统计图&#xff0c;用于显示数据的分布和中心趋势。它结合了箱线图和密度图的特点&#xff0c;可以直观地展示数据的分散性和形状。 代码基本…

【网络协议】OSPF

OSPF OSPF&#xff08;Open Shortest Path First&#xff09;协议是一种广泛使用的动态路由协议&#xff0c;它属于链路状态路由协议&#xff0c;在单一自治系统&#xff08;AS&#xff09;内部工作。以下是关于OSPF协议的详细解析&#xff1a; 一、基本概念 定义&#xff1…

使用Keil 点亮LED灯 F103ZET6

1.新建项目 不截图了 2.startup_stm32f10x_hd.s Keil\Packs\Keil\STM32F1xx_DFP\2.2.0\Device\Source\ARM 搜索startup_stm32f10x_hd.s 复制到项目路径&#xff0c;双击Source Group 1 3.项目文件夹新建stm32f10x.h&#xff0c; 新建文件main.c #include "stm32f10x…

windows sshkeygen 多平台添加配置

文章目录 .ssh目录生成新的ssh配置添加公钥到仓库验证 .ssh目录 windows下一般为&#xff1a;C:\Users\15237.ssh &#xff0c;其中“15237”为当前登录用户 生成新的ssh .ssh目录下打开“Git Bash Here”&#xff08;如果没有&#xff0c;先安装 Git 软件&#xff09; 执行…

android perfetto使用技巧梳理

1 抓取方法 根据不同的配置参数&#xff0c;会显示不同的功能。 比如有的trace文件就无法显示线程状态信息&#xff0c;有的无法显示锁依赖信息等等&#xff0c;要看你的参数&#xff0c;我这个是很全的&#xff0c;基本够了&#xff0c;如果还想添加&#xff0c;可以命令行看…

腾讯发布2024大模型十大最新趋势!

近日&#xff0c;在2024世界人工智能大会上&#xff0c;腾讯正式发布了《2024大模型十大趋势——走进“机器外脑”时代》报告。目前&#xff0c;这一报告正在AI产业界各大社群快速传播。 报告中&#xff0c;腾讯研究院试图通过10个关键性的趋势&#xff0c;去理解全世界范围内正…

移远BC28_opencpu方案_开发环境搭建

OPEN CPU 代码采用的是 Python 脚本写的 scons 自动化构建工具。从构建这个角度说&#xff0c;它与 GNU make 是同一类的工具。它是一种改进&#xff0c;并跨平台的 gnu make 替代工具&#xff0c;其集成功能类似于 autoconf/automake。 这里给出简单安装方式

[软件安装]linux下安装steam

1、下载安装包到linux系统 SteamTools 发行版 - Gitee.com 2、选择对应的版本 3、解压安装包steam &#xff08;1&#xff09;在opt路径下新建一个文件夹 sudo mkdir steam &#xff08;2&#xff09;进入压缩包路径下&#xff0c;打开终端&#xff0c;执行以下代码进行解压…

Docker容器 为MySQL创建新用户和授权

当您需要为 MySQL 数据库创建一个新用户并配置其访问权限时&#xff0c;可以按照以下步骤操作。我将创建一个名为 newuser 的新用户&#xff0c;并为其授予在任何主机上访问所有数据库的权限。 创建新用户和授权步骤&#xff1a; 登录到 MySQL 服务器 首先&#xff0c;使用具有…