1.新建api_server文件夹作为项目根目录,并在项目根目录中运行如下的命令,初始化包管理配置文件:
npm init -y
2.运行如下的命令,安装特定版本的express:
npm i express@4.17.1
3.在项目根目录中新建app.js,作为整个项目的入口文件,并初始化如下代码:
//导入express
const express = require('express')
//创建服务器的实例对象
const app = express()
//启动服务器
app.listen(80, ()=> {
console.log('api server runing at http://127.0.0.1');
})
效果如下:
1.运行如下命令,安装 cors 中间件:
npm i cors@2.0.5
2.在app.js中导入并配置cors中间件:
//导入cors中间件
const cors = require('cors')
//将cors注册为全局中间件
app.use(cors())
配置解析表单数据的中间件,注意:这个中间件,只能解析application/x-www-form-urlencoded 格式的表单数据
app.use(express.urlencoded({extended:false}))
1.在项目根目录中,新建router文件夹,用来存放所有的路由模块
路由模块中,只存放客户端的请求与处理函数之间的映射关系
2.在项目根目录中,新建router_handler文件夹,用来存放所有的路由处理函数模块
路由处理函数模块中,专门负责存放每个路由对应的处理函数
1.在router文件夹中,新建user.js文件,作为用户的路由模块,并初始化代码:
const express = require('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
2.在app.js中,导入 并使用用户路由模块:
//导入并使用路由模块
const userRouter = require('./router/user')
app.use(userRouter)
目的:为了保证路由模块的纯粹些,所有的路由处理函数,必须抽离到对应的路由处理函数模块中
1.在/router_handler/user.js中,使用exports对象,分别向外共享如下两个路由处理函数:
exports.regUser = (req,res) => {
res.send('reguser ok')
}
exports.login = (req,res) => {
res.send('login ok')
}
2.引入/router_handler/user.js,将/router/user.js中的代码修改为如下:从而使用/router_handler/user.js下的函数
//导入用户路由处理函数对应的模块
const user_handler = require('../router_handler/user')
//注册新用户
router.post('/reguser',user_handler.regUser )
router.post('/login',user_handler.login )
在新建表前,我们需要去下载mysql,然后去新建自己的数据库,自动生成mysql workbenc这个可视化界面,通过mysql workbench来新建表
1.在my_db_01数据库中,新建ev_users表如下:
点击apply创建该表:
在api接口项目中,需要安装并配置mysql这个第三方模块,来链接和操作mysql数据库
1.运行如下命令,安装mysql模块:
npm 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:'你创建数据库时的密码',
database:'my_db_01'
})
//向外暴露
module.exports = db
1.判断用户名和密码是否为空
const userinfo =req.body
//对表单的数据进行合法性校验
if (!userinfo.username || !userinfo.password) {
return res.send({
status:1,
message:'用户名或密码不合法'
})
}
我们可以用postman做接口测试该效果是否生效、
###2.3.2检测用户名是否被占用
1.导入数据库操作模块
const db =require('mysql')
2.定义sql语句:
const sqlStr = 'select * from ev_users where username=?'
3.执行sql语句结果判断用户名是否被占用:
db.query(sqlStr,userinfo.username,(err,results) => {
//执行sql语句失败
if (err) {
return res.send({
status:1,
message:err.message
})
}
//判断用户名是否被占用
if (results.length > 0) {
return res.send({
status:1,
message:'用户名被占用,请更换其他用户名!'
})
}
})
为了保证密码的安全性,不建议在数据库以明文形式保存用户密码,推荐对密码进行加密存储
在当前项目中,使用 bcryptjs 对用户密码进行加密,优点:
1.加密之后的密码,无法被逆向破解
2.同一明文密码多次加密,得到的加密结果各不相同,保证安全性
1.运行如下命令,安装指定版本的bcryptjs:
npm i bcryptjs@2.4.3
2.在/router_handler/user.js中,导入bcryptjs:
//导入bcryptjs包加密
const bcrypt = require('bcryptjs')
3.在注册用户的处理函数中,确认用户名可用之后,调用bcryptjs.hashSync(明文密码,随机盐的长度)方法,对用户的密码进行加密处理:
//调用bcrypt.hashSync(),对密码进行加密
userinfo.password = bcrypt.hashSync(userinfo.password,10)
1.定义插入用户的sql语句:
const sql = 'insert into ev_users set ?'
2.调用db.query()执行sql语句,插入新用户:
db.query(sql,{username:userinfo.username,password:userinfo.password},(err,results) => {
//判断sql语句是否执行成功
if(err) return res.send({status:1,message:err.message})
//判断影响行数是否为1,否则错误
if (results.affectedRows !==1) {
return res.send({status:1,message:'注册用户失败,请稍后再试'})
}
res.send({
status:0,
message:'注册成功哈!'
})
})
1.在app.js中,所有路由之前,声明一个全局中间件,为res对象挂载一个res.cc()函数:
//一定要在路由之前封装res.cc函数
app.use((req,res,next) => {
//err的值,可能是一个错误对象,也可能是一个错误的表述字符串
res.cc = (err,status = 1) => {
res.send({
status,
message:err instanceof Error ? err.message : err
})
}
next()
})
1.根据用户名查询数据库是否有该用户
//接收表单数据
const userinfo = req.body
//定义sql语句
const sql = 'select * from ev_users where username=?'
//执行sql语句,根据用户名查询用户信息
db.query(sql,userinfo.username,(err,results) => {
//执行语句失败
if(err) return res.cc(err)
//执行sql语句成功,但是获取到的数据条数不等于1
if (results.length !== 1) {
return res.cc('登录失败!')
}
//判断密码是否正确
res.send('登录成功')
})
2.判断输入密码是否正确
调用bcrypt.compareSybc(用户提交的密码,数据库中的秘钥)方法比较用户输入的密码和数据库该用户密码是否一致,返回值是布尔值(true一致,false不一致)
results返回的是匹配到数据库的数据条数,是数组的形式匹配行
//判断密码是否正确
const compareResult = bcrypt.compareSync(userinfo.password,results[0].password)
if (!compareResult) {
return res.cc('登录失败')
}
res.send('登录成功')
2.生成jwt的token字符串
注意点:在生成token字符串的时候,一定要剔除 密码 和 头像 的值
1.通过es6的高级语法,快速剔除 密码 和 头像 的值:
const user = {...results[0],password:'',user_pic:''}
2.运行命令,安装生成token字符串的包:
npm i jsonwebtoken@8.5.1
3.在/router_hander/user.js模块的头部,导入jsonwebtoken包:
//导入生成Token的包
const jwt = require('jsonwebtoken')
4.创建config.js文件,并向外共享 加密 和 还原 token的 jwtSecretKey字符串:
module.exports = {
//加密和解密token的秘钥
jwtSecretKey:'itheima no1',
//token有效期
expiresIn:'10h'
}
5.将用户信息对象加密成token字符串:
//导入配置文件
const config = require('./../config')
//对用户的信息进行加密,生成token字符串
const tokenStr = jwt.sign(user,config.jwtSecretKey,{expiresIn:config.expiresIn})
6.将生成的token字符串响应给客户端:
//调用res.send()将token响应给客户端
res.send({
status:0,
message:'登录成功',
token:'Bearer'+ tokenStr,
})
1.运行命令,安装token中间件:
npm i express-jwt@5.3.3
2.在app.js中注册路由之前,配置解析token的中间件:
//一定要在路由之前配置token的中间件
const expressJWT = require('express-jwt')
const config = require('./config')
app.use(expressJWT({
secret:config.jwtSecretKey,
algorithms:['HS256']
}).unless({path:[/^\/api\//]}))//unless设置api接口开头的过滤认证
3.在app.js中的 错误级别中间件 里面,捕获并处理token认证失败后的错误:
//定义错误级别的中间件
app.use((err,req,res,next) => {
//验证失败后导致错误
if (err instanceof Joi.ValidationError) {
return res.cc(err)
}
//身份认证失败后错误
if (err.name == 'UnauthorizedError') {
return res.cc('身份认证失败')
}
//未知错误
res.cc(err)
})
1.初始化 路由 模块
2.初始化 路由处理函数 模块
3.获取用户的基本信息
1.创建 /router/userinfo.js路由模块,并初始化如下的代码结构:
const express = require('express')
const router = express.Router()
//挂载路由
router.get('/userinfo',(req,res) => {
res.send('ok')
})
//共享模块
module.exports = router
2.在app.js中导入并使用个人中心的路由模块:
//导入并使用用户信息的路由模块
const userinfoRouter = require('./router/userInfo')
app.use('/my',userinfoRouter)
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 userinfo_handler = require('./../router_handler/userinfo')
//挂载路由
router.get('/userinfo',userinfo_handler.getUserInfo)
//共享模块
module.exports = router
1.在/router_handler/userinfo.js头部导入数据库操作模块:
//导入数据库操作模块
const db = require('../db/index')
2.定义sql语句:
//定义查询用户信息的sql语句
const sql = `select id,username,nickname,email,user_pic from ev_users where id=?`
3.调用db.query()执行sql语句:
//调用db.query()执行sql语句
db.query(sql,req.user.id,(err,results) => {
//执行sql语句失败
if(err) return res.cc(err)
//执行sql语句成功,但是查询结果可能为空
if (results.length !== 1) {
return res.cc('获取用户信息失败!')
}
//获取用户信息成功
res.send({
status:0,
message:'获取用户信息成功',
data: results[0]
})
})
1.定义路由和处理函数
2.实现更新用户基本信息的功能
1.在/router/userinfo.js模块中,新增 更新用户基本信息 的路由:
在这里插入代码片
2.在/routrer_handler/userinfo.js模块中,定义并向外共享 更新用户基本信息 的路由处理函数:
//更新用户信息的处理函数
exports.updateUserInfo = (req,res) => {
res.send('ok')
}
1.定义执行的sql语句:
const sql = `update ev_users set? where id=?`
2.调用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)
})
1.定义路由和处理函数
2.实现更新用户头像的功能
1.定义更新用户头像的sql语句:
const sql = `update ev_users set user_pic=? where id=?`
2.调用db.query()执行sql语句,更新对应用户的头像(这里接口传的avatar可以是图片base64的格式):
//调用
db.query(sql, [req.body.avatar, req.user.id], (res, results) => {
//执行sql语句失败
if (err) return res.cc(err)
//执行sql语句成功,但是影响函数不为1
if (results.affectedRows !== 1) {
return res.cc('更换头像失败!')
}
//修改用户头像成功
return res.cc('更换头像成功', 0)
})
}
感谢观看,有帮助的话点点赞点点关注谢谢哈。