一、问题分析:
初始代码分析:
@GetMapping("/likes/{id}")
public Result queryBlogLikes(@PathVariable("id") Long id) {
//修改点赞数量
blogService.update().setSql("liked = liked +1 ").eq("id",id).update();
return Result.ok();
}
存在问题:这种方式会导致一个用户无限点赞,明显是不合理的造成这个问题的原因是,我们现在的逻辑,发起请求只是给数据库+1,所以才会出现这个问题。
二、解决办法:
需要完善点赞功能,可以借助redis缓存,因为不存在同一用户多次点赞,而应该满足:
- 同一个用户只能点赞一次,再次点击则取消点赞
- 如果当前用户已经点赞,则点赞按钮高亮显示(前端已实现,判断字段Blog类的isLike属性)
这里可以选取redis
的set
结构,在进行点赞的同时,将包含blog
的id作为key
,将用户id作为value
存入redis,在初次进行点赞的同时,将blog的id和用户id存进redis,并且操作数据库进行like字段+1操作,相反,同一用户再进行点赞的时候, 先会从redis
根据key去读用户的id,如果存在,则点赞取消,删除redis的缓存,并且操作数据库进行like字段减一操作:
实现步骤:
- 给Blog类中添加一个isLike字段,标示是否被当前用户点赞
- 修改点赞功能,利用Redis的set集合判断是否点赞过,未点赞过则点赞数+1,已点赞过则点赞数-1
- 修改根据id查询Blog的业务,判断当前登录用户是否点赞过,赋值给isLike字段
- 修改分页查询Blog业务,判断当前登录用户是否点赞过,赋值给isLike字段
为什么采用set集合:
因为我们的数据是不能重复的,当用户操作过之后,无论他怎么操作,都是重复,则是取消点赞,并且移除缓存。
具体步骤:
1、在Blog 添加一个字段
@TableField(exist = false)
private Boolean isLike;
2、修改代码
@Override
public Result likeBlog(Long id){
// 1.获取登录用户
Long userId = UserHolder.getUser().getId();
// 2.判断当前登录用户是否已经点赞
String key = BLOG_LIKED_KEY + id;
Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, userId.toString());
if(BooleanUtil.isFalse(isMember)){
//3.如果未点赞,可以点赞
//3.1 数据库点赞数+1
boolean isSuccess = update().setSql("liked = liked + 1").eq("id", id).update();
//3.2 保存用户到Redis的set集合
if(isSuccess){
stringRedisTemplate.opsForSet().add(key,userId.toString());
}
}else{
//4.如果已点赞,取消点赞
//4.1 数据库点赞数-1
boolean isSuccess = update().setSql("liked = liked - 1").eq("id", id).update();
//4.2 把用户从Redis的set集合移除
if(isSuccess){
stringRedisTemplate.opsForSet().remove(key,userId.toString());
}
}
注意:这里的字段
isLike
可配合前端,进行点赞后的高显,取消点赞后的暗淡色。只是配合前端做数据显示,数据库表中并无此字段