效果图
接口分析
通过上面的效果图可以看出,点赞入口主要是在书籍的详情页面。
而书籍详情页面,有以下几个功能是和点赞有关的:
- 获取点赞状态
- 点赞
- 取消点赞
所以项目中理论上与点赞相关的接口就以上三个。
点赞 model 的设计
既然明确了接口数量,那么下一步就是设计接口对应的
model
,通过model
生成表格like
,里面存放点赞数据。
那么需要存在哪些点赞数据呢?
这里简单分析后,记录一条点赞信息只需要保存以下的信息即可:
- 点赞
id
- 书籍
id
- 用户
id
created_at
deleted_at
updated_at
因此最终在数据库表中生成的内容如下:
获取点赞状态
在书籍详情页面需要根据书籍的点赞状态显示不同的
icon
图标。
如何获取点赞状态呢?
只需要向like
表中传递当前用户id
及书籍id
进行搜索即可。有数据则证明该用户对书籍已经点赞了,没有数据则反之。
代码具体实现:
// 获取书籍的喜欢状态
static async userLikeIt(uid, bid) {
const like = await Like.findOne({
where: {
bkid: bid,
uid: uid
}
})
return like ? true : false
}
通过以上代码的返回值,判断用户是否点赞,返回true
则表示用户对该书籍已点赞,反之则未点赞。
点赞实现
获取到点赞状态之后,我们可以通过点击
点赞 icon
来实现点赞或者取消点赞功能。
点赞的实现,需要传递当前用户 id
,书籍 id
,通过数据库查询是否有数据,有数据则将点赞结果保存到数据表中。并提示点赞成功,返回的数据格式如下:
{"msg":"ok","error_code":0,"request":"POST /v1/like"}
这里还做了一步额外的操作,因为用户的点赞是和书籍的点赞数量挂钩的。
也就是说用户点赞或者取消赞,书籍表中的书籍点赞数量也相应的会增加或者减少。
伪代码实现如下:
static async like(uid,bkid){
const like = await Like.findOne({
where: {
uid: uid,
bkid: bkid
}
})
if (like) {
throw new global.errs.NotFound("喜欢失败", NotFound.LIKE_FAIL)
}
return sequelize.transaction(async t => {
await Like.create({
uid,
bkid
}, {
transaction: t
})
const book = await Book.detail(bkid)
await book.increment(\'like_count\', {
by: 1,
transaction: t
})
})
}
上面代码使用到了数据库中的事务
功能。具体的事务
介绍可参考这篇文章 javaweb学习总结(三十八)——事务
书籍的点赞数量有可能因为多人同一时间下操作而导致数据的不正确性,使用事务可以避免出现这种问题。
取消点赞实现
取消点赞功能,其实可以使用点赞的接口,然后再接口中添加一个类别区分是点赞还是取消点赞,然后做相应的处理。我这里是设计了取消点赞的接口。
取消点赞功能需要传递用户 id
和书籍 id
,然后根据两个id
查询数据库。查询到数据将like 表的数据 destroy
以及将book 表的数据 decrement
即可。
伪代码如下:
static async disLike(uid,bid){
let like = await Like.findOne({
where: {
uid: uid,
bkid: bid
}
})
if (!like) {
throw new global.errs.NotFound("不喜欢失败", NotFound.UN_LIKE_FAIL)
}
// Favor 表 favor 记录
return sequelize.transaction(async t => {
await like.destroy({
force: true,
transaction: t
})
const book = await Book.detail(bid)
await book.decrement(\'like_count\', {
by: 1,
transaction: t
})
})
}
以上就是本次的介绍。
扫码关注公众号,轻撩即可。