目录
完善点赞功能
(采用redis中的set集合)
实现
@Override
public Result likeBlog(Long id) {
//1.获取登录用户
Long userId = UserHolder.getUser().getId();
//2.判断当前用户是否点赞
String key="blog:liked:"+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());
}
}
return Result.ok();
}
在查询Blog的业务中添加下面方法,来判断该用户是否点过赞
private void isBlogLiked(Blog blog) {
//1.获取登录用户
Long userId = UserHolder.getUser().getId();
//2.判断当前用户是否点赞
String key="blog:liked:"+blog.getId();
Boolean isMember = stringRedisTemplate.opsForSet().isMember(key,userId.toString());
blog.setIsLike(BooleanUtil.isTrue(isMember));
}
实现点赞排行榜功能
根据上图可知,要想能够对数据进行排序,我们需要更改redis中的数据结构Set为SortedSet
实现
根据当时间戳设置score值进行排序
@Override
public Result likeBlog(Long id) {
//1.获取登录用户
Long userId = UserHolder.getUser().getId();
//2.判断当前用户是否点赞
String key="blog:liked:"+id;
//没有isMember方法,采用score获取当前score值,通过判断是否为空来判断有无点赞
Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());
if(score==null){
//3.如果未点赞
//3.1数据库点赞数+1
boolean isSuccess = update().setSql("liked = liked + 1").eq("id", id).update();
//3.2保存用户到redis的set集合中
if(isSuccess){
stringRedisTemplate.opsForZSet().add(key,userId.toString(),System.currentTimeMillis());
}
}
else{
//4.如果已点赞,取消点赞
//4.1数据库点赞数-1
boolean isSuccess = update().setSql("liked = liked - 1").eq("id", id).update();
//4.2把用户从redis的set集合移除
if(isSuccess){
stringRedisTemplate.opsForZSet().remove(key,userId.toString());
}
}
return Result.ok();
}
@Override
public Result queryBlogLikes(Long id) {
String key="blog:liked:"+id;
//1.查询top5的点赞用户 zrange key 0 4
Set<String> top5 = stringRedisTemplate.opsForZSet().range(key, 0, 4);
if(top5==null||top5.isEmpty()){
return Result.ok(Collections.emptyList());
}
//2.解析出其中的用户id
//stream转流,map映射,collect收集
List<Long> ids = top5.stream().map(Long::valueOf).collect(Collectors.toList());
//3.根据用户id查询用户
List<UserDTO> userDTOS = userService.listByIds(ids)
.stream()
.map(user -> BeanUtil.copyProperties(user, UserDTO.class))
.collect(Collectors.toList());
//4.返回
return Result.ok(userDTOS);
}
修改一个小bug(因为主界面不一定需要登录,所以检索文章时无需考虑该用户是否点赞,所以需要增加判断语句)
private void isBlogLiked(Blog blog) {
//1.获取登录用户
UserDTO user = UserHolder.getUser();
if(user==null){
//用户未登录无需查询是否点赞
return;
}
Long userId = UserHolder.getUser().getId();
//2.判断当前用户是否点赞
String key="blog:liked:"+blog.getId();
Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());
blog.setIsLike(score!=null);
}
仍存在一些问题,虽然我们传入的id是按顺序的,但是listByIds()内部封装的sql语句是采用in的方法,导致查询出来的结构会根据id来进行排序,如下图所示
所以需要进行相应的改造,改造sql
修改如下
@Override
public Result queryBlogLikes(Long id) {
String key="blog:liked:"+id;
//1.查询top5的点赞用户 zrange key 0 4
Set<String> top5 = stringRedisTemplate.opsForZSet().range(key, 0, 4);
if(top5==null||top5.isEmpty()){
return Result.ok(Collections.emptyList());
}
//2.解析出其中的用户id
//stream转流,map映射,collect收集
List<Long> ids = top5.stream().map(Long::valueOf).collect(Collectors.toList());
String idStr = StrUtil.join(",",ids);
//3.根据用户id查询用户
List<UserDTO> userDTOS = userService.query().in("id",ids)
.last("ORDER BY FIELD(id,"+idStr+")")
.list()
.stream()
.map(user -> BeanUtil.copyProperties(user, UserDTO.class))
.collect(Collectors.toList());
//4.返回
return Result.ok(userDTOS);
}