当我们完成了用户的登录的注册之后,我们就需要想一想如何先写个人中心了,需要实现用户密码、头像、用户名等的更新操作;也挺简单的,就是挂载路由,然后定义验证方式,在编写对应的处理函数就可以了,话不多说,咱们开始吧:
1、用户更新接口:
//12.1 创建用户更新接口
router.post('/userinfo',expressJoi(update_userinfo_scheml),userinfo_handler.updateuserinfo)
先到我们的路由模块里添加一个路由,访问接口为/userinfo,这里有三个参数,之前我们学过,第二个是验证方式,也就在对我们提交的表单进行数据验证,这个模块里面的参数也是需要我们定义的,打开我们的验证模块:
//12. 3 创建用户更新的规则
const id = joi.number().integer().min(1).required()
const nickname = joi.string().required()
const email = joi.string().email().required()
//12.4 向外暴露更新用户对象
exports.update_userinfo_scheml = {
body:{
id,
nickname,
email
}
}
我们使用joi模块对数据规则进行定义,这里对id、nickname、email进行了定义,相信大家根据这个英文就可以看懂是什么意思了然后通过exports向外暴露出去就,在路由模块将对象抽离出来就可以当做验证模块的一个参数起作用了:
//12.5 导入更新标准和验证模块
const {update_userinfo_scheml,update_password_scheml,update_avator_scheml} = require('../scheml/myScheml')
因为这一期我们要做三个接口,分别为用户更新、密码更新、头像更新,所以这里定义了三个对象,我们需要一步一步实现,每个接口对应一个;
将数据验证完成之后就需要编写处理函数了,怎么处理呢?我们通过用户提交的id,查询到数据库中的用户信息,然后进行修改就可以
//12.2 编写更新用户信息的函数
exports.updateuserinfo = (req,res)=>{
//12.6 创建sql更新语句
const sql = `update ev_users set nickname = '${req.body.nickname}',email = '${req.body.email}' where id = '${req.body.id}'`
db.query(sql,(err,results)=>{
if(err){return res.cc(err)}
if(results.rowsAffected != 1){return res.cc('用户信息更新失败')}
res.cc('用户更新成功',200)
})
}
还是比较简单的,就执行一下update语句就可以了,一般都是一种模式,就是定义sql语句,然后执行,判断一下是否出错,然后判断一下执行结果是否合理,最后就是给用户返回一个更新成功到的信息;可以看到这的函数名就是路由模块里路由的第三个参数,所以一个路由就写完了;
现在来看看效果,我们打开postman,然后发起请求:
可以看到,我们提交表单到这个路由是可以得到数据的,再看看数据库:
2、更新密码接口
//13.1 创建密码更新接口
router.post('/update/password',expressJoi(update_password_scheml),userinfo_handler.updatePwd)
同样我们创建了一个路由,这个路由的接口为/update/password,也是同样的套路,我们打开验证模块:
//13.3 向外暴露密码更新对象
exports.update_password_scheml = {
body:{
oldPwd:password,
newPwd:joi.not(joi.ref('oldPwd')).concat(password)
}
}
不过,对于密码更新要求用户提交一个原来的密码和一个新密码,我们要对原来的密码通过id对数据库中的密码数据进行比对,如果一致就可以进行替换操作,而且旧密码不可以和新密码一致,如果一致就提示给用户一个错误,还有密码是经过了加密的,所以需要用到我们的加密模块bvryptjs;
好看到这里的验证规则,这里提供旧密码依然是需要遵循我们之前建立的密码验证规则的,而新密码有一个要求就是不能和旧密码一致,所以我们使用了joi模块的not(ref())方法,意思就是旧密码和新密码不一致的意思,然后在通过concat()对规则进行合并,也就是旧密码还需要满足密码规则;
接下来就是函数了:
//13.2 编写密码更新函数
exports.updatePwd = (req,res)=>{
//13.4 查询当前用户密码
//编写sql
const sql = `select * from ev_users where id = '${req.user.id}'`
db.query(sql,(err,results)=>{
if(err){return res.cc(err)}
if(results.recordset.length == 0){return rec.cc('查询数据失败')}
//13.5 获取旧密码比对结果
const comparereuslt = bcry.compareSync(req.body.oldPwd,results.recordset[0].password)
if(!comparereuslt){return res.cc('旧密码错误')}
//13.6 没有错误就需要更新密码
//先对新密码进行加密
const newPwd = bcry.hashSync(req.body.newPwd,10)
const sql2 = `update ev_users set password = '${newPwd}' where id ='${req.user.id}'`
db.query(sql2,(err,results)=>{
if(err){return res.cc(err)}
if(results.rowsAffected != 1){return res.cc('更新密码失败')}
res.cc('更新密码成功',200)
})
})
}
这里我们需要拿到旧密码,然后对用户提交的密码进行判断,然后在使用sql语句对密码更新,记得是经过加密的密码;获取数据根据的是id,这个id是在token里面的id,之前我们讲过,当我们开启的身份验证操作的时候会生成一个token,并且响应给客户端,然后客户端再发起需要需要权限的请求的时候需要加上这个响应头,这个token中了除了私密信息以外含有我们的id,所以拿到这个数据之后,我们使用加密模块的compareSync()方法进行对比就可以,这个加密模块的导入还记得人吧?
//13.5 导入加密模块
const bcry = require('bcryptjs')
对比没有问题之后,就将新密码加密之后使用sql语句的update对数据进行更新即可,
const newPwd = bcry.hashSync(req.body.newPwd,10)
这个我们之前也学过,就是加密用的,后面一个参数是加密等级;
让我们来看看效果:
可以看到如果我们输入的密码不一致就会返回一个旧密码错误
3、图片更新接口:
//14.1 图片更新接口
router.post('/update/avator',expressJoi(update_avator_scheml),userinfo_handler.updateAvator)
同样,我们创建好我们的路由,然后定义规则,是图片数据的规则:
//14.2 创建头像更新规则
const avator = joi.string().dataUri().required()
//14.4 向外暴露验证规则对象
exports.update_avator_scheml={
body:{
avator
}
}
在规则模块中写入上面的代码,这个规则要求数据是一个字符串,而且是一个datauri的,还是一个必填项,暴露出去后就可以结合执行函数写到路由的第二个参数了,那么接下来又是我们的处理函数:
//14.2 编写更新头像的函数
exports.updateAvator = (req,res)=>{
//14.5 定义sql在数据库中更新
const sql = `update ev_users set user_pic = '${req.body.avator}' where id ='${req.user.id}'`
db.query(sql,(err,results)=>{
if(err){return res.cc(err)}
if(results.rowsAffected != 1){return rec.cc('查询头像失败')}
res.cc('更新成功',200)
})
}
这个函数也很简单,就是利用sql的update语句进行修改,我们同样的套路不在赘述了;
好了,那么这期就到这了,总之,编写这些接口都非常有规律,一般就是写好路由,然后数据的验证规则,然后处理函数,处理函数里面无非就是对数据库的一些操作,而服务器不需要什么操作,这就是模块化的好处;