大事件后台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初始化用户路由模块
- 在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
- 在app.js中,导入并使用
用户路由模块
js
//导入并注册用户路由模块
const userRouter=require('./router/user')
//用户每次要请求用户路由时,要加前缀/api
app.use('/api',userRouter)
1.6抽离用户路由模块中的处理函数
目的:为了保证路由模块
的纯粹性,所有的路由处理函数
,必须抽离到对应的路由处理函数模块
中
- 在/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')
}
- 将/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模块
- 在终端安装mysql
npm i mysql@2.18.1
- 在项目根目录中创建/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实现步骤
- 检测表单数据是否合法
- 检测用户名是否被占用
- 对密码进行加密处理
- 插入新用户
2.3.1检测表单数据是否合法 - 检测用户名和密码是否为空
js
//接收表单数据
const userinfo=req.body
//判断数据是否合法
if(!userinfo.username||!userinfo.password){
return res.send({status:1,message:'用户名或密码不能为空!'})
}
2.3.2检测用户名是否被占用
- 导入数据库操作模块:
js
const db=require('./db/index')
- 定义SQL语句:
js
const sql = `select * from ev_users where username=?`
- 执行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对用户密码进行加密,优点:
- 加密之后的密码,无法被逆向破解
- 统一明文密码多次加密,得到的加密结果各不相同,保证了安全性
- 运行如下命令,安装指定版本的bcryptjs:
npm i bcryptjs@2.4.3
- 在/router_handler/user.js中导入bcrtptjs:
js
const bcrypt=require('bcryptjs')
- 在注册用户的处理函数中,确认用户名可用之后,调用bcrypt.hashSync(明文密码,随机盐的长度)方法,对用户的密码进行加密处理:
js
//对用户的密码进行加密,返回值时加密之后的密码字符串
userinfo.password=bcrypt.hashSync(userinfo.password,10)
2.3.4插入新用户
- 定义插入新用户的SQL语句:
js
const addsql = `insert into ev_users set ?`
- 调用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()函数
- 在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
- 安装@hapi/joi包,为表单中携带的每个数据项,定义验证规则:
npm i @hapi/joi@17.1.0
- 安装@escook/express-joi中间件,来实现自动对表单数据进行验证的功能:
npm i @escook/express-joi
- 新建/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,
},
}
- 修改 /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
- 在 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实现步骤
- 检测表单数据是否合法
- 根据用户名查询用户的数据
- 判断用户输入的密码是否正确
- 生成JWT的token字符串
2.6.1检测表单数据是否合法 - 将/router/user.js中的登录路由代码修改如下:
js
//登陆的路由
router.post('/login',expressJoi(reg_login_schema),userHandler.login)
2.6.2根据用户名查询用户的数据
- 接收表单数据
js
const userinfo=req.body
- 定义SQL语句:
js
const sql=`select * from ev_users where username=?`
- 执行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字符串的时候,一定要剔除密码和头像的值
- 通过ES6的高级语法,快速剔除密码和头像的值:
js
//剔除完毕之后,user中只保留了用户的id,username,nickname,email这四个属性的值
const user={...results[0],password:'',user_pic:''}//后面会覆盖前面
- 运行命令,安装生成token字符串的包:
npm i jsonwebtoken@8.5.1
- 在/router_handler/user.js模块的头部区域,导入jsonwebtoken包:
js
//用这个包来生成token字符串
const jwt=require('jsonwebtoken')
- 创建config.js文件,并向外共享加密和还原token的jwtSecretKey字符串:
js
//这是一个全局配置文件
module.exports = {
//加密和解密的token密钥
jwtSecretKey: 'hoshi No1. ^_^',
}
- 将用户信息对象加密成Token字符串:
js
//导入配置文件(放最前面)
const config=require('../config')
//生成token字符串
const tokenStr=jwt.sign(user,config.jwtSecretKey,{
expiresIn:'10h'//token有效期为10小时,也可以在config文件中定义
})
- 将生成的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的中间件
- 运行命令,安装解析token中间件:
npm i express-jwt@5.3.3
- 在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\//]}))
- 在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实现步骤
- 初始化路由模块
- 初始化路由处理函数模块
- 获取用户的基本信息
3.1.1 初始化路由模块 - 创建/router/userinfo.js路由模块,并初始化如下代码结构:
js
const express=require('express')
//创建路由对象
const router=express.Router()
//获取用户基本信息
router.get('/userinfo',(req,res)=>{
res.send('ok')
})
//将路由对象共享出去
module.exports=router
- 在app.js中导入并使用个人中心的路由模块
js
//导入并使用个人中心的路由模块
const userinfoRouter=require('./router/userinfo')
//注意:以/my开头的接口,都是有权限的接口,需要进行token身份认证
app.use('/my',userinfoRouter)
3.1.2初始化路由处理函数模块
- 创建/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获取用户的基本信息
- 在/router_handler/userinfo.js头部导入数据库操作模块:
js
//导入数据库操作模块
const db=require('../db/index')
- 定义SQL语句:
js
//根据用户的id查询用户的基本信息
//注意:为了防止用户的密码泄露,需要排除password字段
const sql=`select id,username,nickname,email,user_pic from ev_users where id=?`
- 调用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实现步骤
- 定义路由和处理函数
- 验证表单数据
- 实现更新用户基本信息的功能
3.2.1定义路由和处理函数 - 在/router/userinfo.js模块中,新增更新用户基本信息的路由:
js
//更新用户的基本信息
router.post('/userinfo',userinfoHandler.updateUserInfo)
- 在/router_handler/userinfo.js模块中,定义并向外共享更新用户基本信息的路由处理函数:
js
//更新用户基本信息的处理函数
exports.updateUserInfo=(req,res)=>{
res.send('ok')
}
3.2.2验证表单数据
- 在/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()
- 并使用exports向外共享如下的验证规则对象:
js
//验证规则对象-更新用户基本信息
exports.update_userinfo_schema = {
body: {
id,//规则中的名字要跟表单数据的名字相同,否则,如果规则为id1,那么这个body中的id要改为 id:id1
nickname,//可以写成nickname:nickname
email
}
}
- 在/router/userinfo.js模块中,导入验证数据合法性的中间件:
js
const expressJoi=require('@escook/express-joi')
- 在/router/userinfo.js模块中,导入需要的验证规则对象:
js
//导入需要的验证规则对象
const {update_userinfo_schema}=require('../schema/user')
- 在/router/userinfo.js模块中,修改更新用户的基本信息的路由如下:
js
//更新用户的基本信息
router.post('/userinfo',expressjoi(update_userinfo_schema),userinfoHandler.updateUserInfo)
3.2.3实现更新用户基本信息的功能
- 定义待执行的SQL语句:
js
const sql=`update ev_users set ? where id=?`
- 调用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实现步骤
- 定义路由和处理函数
- 验证表单数据
- 实现重置密码的功能
3.3.1定义路由和处理函数 - 在/router/userinfo.js模块中新增重置密码路由:
js
router.post('/updatepwd',expressJoi(update_pwd_schema),userinfoHandler.updatePassword)
- 在/router_handler/userinfo.js模块中,定义并向外共享重置密码的路由处理函数:
js
//重置密码的处理函数
exports.updatePassword=(req,res)=>{
res.send('ok')
}
3.3.2验证表单数据
- 在/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)
}
}
- 在/router/userinfo.js中
js
const {update_pwd_schema}=require('../schema/user')
//const {update_userinfo_schema,update_pwd_schema}=require('../schema/user')
3.3.3实现重置密码功能
- 根据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('用户不存在')
})
- 判断旧密码是否正确
js
//在头部导入bcrypt,使用bcrypt.compareSync(提交的密码,数据库中的密码)验证
const bcrypt=require('bcryptjs')
const comapreResult=bcrypt.compareSync(req.body.oldPwd,results[0].password)
if(!comapreResult)return res.cc('原密码错误!')
- 对新密码加密,更新到数据库
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)
})
更新头像
- 在/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)
})
}
- 在/scheme/user.js
js
//dataUri是指如下格式的字符串:
//data:image/png;base64,VE9PTUFOWVNFQ1JFVFM=
const avatar=joi.string().dataUri().required()
exports.update_avatar_schema={
body:{
avatar
}
}
- 在/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实现步骤
- 初始化路由模块
- 初始化路由处理函数模块
- 获取文章分类列表数据
4.2.1初始化路由模块
- 创建 /router/artcate.js路由模块,并初始化如下的代码结构:
js
//导入express
const express=require('express')
//创建路由对象
const router=express.Router()
//获取文章分类的列表数据
router.get('/cates',artcateHandler.getArticles)
//向外共享路由数据
module.exports=router
- 在app.js中导入并使用文章分类的路由模块:
js
//导入并使用文章的路由模块
const articleRouter=require('./router/artcate')
app.use('/my/article',articleRouter)
4.2.2初始化路由处理函数模块
- 创建/router_handler/artcate.js路由处理函数模块,并初始化如下的代码结构:
js
exports.getArticles=(req,res)=>{
res.send('ok')
}
- 修改/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获取文章分类列表数据
- 在/router_handler/artcate.js头部导入数据库操作模块
js
const db=require('../db/index')
- SQL语句
js
//根据分类的状态,获取所有未被删除的分类列表数据
//is_delete为0表示没有被 标记为删除的数据
const sql=`select * from ev_article_cate where is_delete=0 order by id asc`
- 调用db.query()
js
db.query(sql,(err,results)=>{
if(err) return res.cc(err)
//2.执行SQL语句成功
res.send({
status:0,
message:'获取文章分类列表成功',
data:results
})
})