Part 4 达人探店等

1.查询笔记

修改图片文件夹为本地的正确的文件夹,请求url是/update/blog
添加BlogController里管理"/{id}" 的功能blogService.queryBlogById(id)

@Override  
public Result queryBlogById(Long id) {  
    //查询blog  
    Blog blog = getById(id);  
    if (blog == null) {  
        return Result.fail("笔记不存在!");  
    }  
    //查询用户  
    queryBlogUser(blog);  
    return Result.ok(blog);  
}  
  
private void queryBlogUser(Blog blog) {  
    Long userId = blog.getUserId();  
    User user = userService.getById(userId);  
    blog.setName(user.getNickName());  
    blog.setIcon(user.getIcon());  
}

2.点赞功能

需求:

  1. 同一个用户只能点赞一次,再次点击则取消点赞
  2. 如果当前用户已经点赞,则点赞按钮高亮显示

实现步骤:

  1. 给Blog类中添加一个isLike字段,标识是否被当前用户点赞
  2. 修改点赞功能,利用redis的set集合

业务逻辑:

  1. 获取登录用户
  2. 判断当前登录用户是否已经点赞
  3. 如果未点赞,可以点赞
    3.1 数据库点赞数+1
    3.2 保存到redis的set集合
  4. 如果已点赞,取消点赞
    4.1 数据库点赞数-1
    4.2 把用户从redis的set集合移除
@Override  
    public Result likeBlog(Long id) {  
//        1.获取登录用户  
        Long userId = UserHolder.getUser().getId();  
//        2. 判断当前登录用户是否已经点赞  
        String key = RedisConstants.BLOG_LIKED_KEY + id;  
        Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, userId.toString());  
        //        3. 如果未点赞,可以点赞  
        if (BooleanUtil.isFalse(isMember)) {  
            //        3.1 数据库点赞数+1  
  
            boolean isSuccess = update().setSql("liked = liked + 1").eq("id", id).update();  
            if (isSuccess) {  
                //        3.2 保存到redis的set集合  
                stringRedisTemplate.opsForSet().add(key, userId.toString());  
            }  
        } else {  
//        4. 如果已点赞,取消点赞  
//        4.1 数据库点赞数-1  
//        4.2 把用户从redis的set集合移除  
            boolean isSuccess = update().setSql("liked = liked - 1").eq("id", id).update();  
            if (isSuccess) {  
                stringRedisTemplate.opsForSet().remove(key, userId.toString());  
            }  
        }  
  
        return Result.ok();

3.点赞排行榜

使用ZSET,也就是Sorted Set
使用mysql自定义排序方法order by field

//解析id  
List<Long> ids = top5.stream().map(Long::valueOf).collect(Collectors.toList());  
String idstr = StrUtil.join(",", ids);  
//根据id查询用户  
List<UserDTO> users = userService.query()  
        .in("id", ids).last("ORDER BY FIELD(id," + idstr + ")").list()  
        .stream()  
        .map(user -> BeanUtil.copyProperties(user, UserDTO.class))  
        .collect(Collectors.toList());

好友关注

1.关注和取关

@Override  
public Result follow(Long followUserId, Boolean isFollow) {  
    //获取用户  
    Long userId = UserHolder.getUser().getId();  
    //判断是关注还是取关  
    if (isFollow) {  
        //关注,新增  
        Follow follow = new Follow();  
        follow.setUserId(userId);  
        follow.setFollowUserId(followUserId);  
        save(follow);  
    } else {  
        //取关,删除  
        remove(new QueryWrapper<Follow>().eq("user_id", userId).eq("follow_user_id", followUserId));  
    }  
    return Result.ok();  
}

2.共同关注

通过redis里面set求交集opsForSet().intersect

@Override  
public Result followCommons(Long id) {  
    //获取当前用户  
    Long userId = UserHolder.getUser().getId();  
    String key1 = "follows:" + userId.toString();  
    //求交集  
    String key2 = "follows:" + id.toString();  
    Set<String> intersect = stringRedisTemplate.opsForSet().intersect(key1, key2);  
    if (intersect == null || intersect.isEmpty()) {  
        return Result.ok(Collections.emptyList());  
    }  
    //解析id  
    List<Long> ids = intersect.stream().map(Long::valueOf).collect(Collectors.toList());  
    //查询用户  
    List<UserDTO> users = userService.listByIds(ids)  
            .stream().map(user -> BeanUtil.copyProperties(user, UserDTO.class))  
            .collect(Collectors.toList());  
    return Result.ok(users);  
}

3.关注推送

Feed流的模式

  • Timeline:不做内容筛选,常用于好友,例如朋友圈
    • 优点:信息全面,实现简单
    • 缺点:信息噪音较多
  • 智能排序:利用智能算法
    • 优点:投喂用户感兴趣信息,用户黏度高
    • 缺点:算法需要精准

Timeline实现方案:

  • 拉模式
    • 读扩散
  • 推模式
  • 推拉结合
    在保存笔记的时候把笔记推送给所有粉丝
@Override  
public Result saveBlog(Blog blog) {  
    //1.获取登录用户  
    UserDTO user = UserHolder.getUser();  
    blog.setUserId(user.getId());  
    //2.保存探店笔记  
    boolean isSuccess = save(blog);  
    if (!isSuccess) {  
        return Result.fail("保存笔记失败!");  
    }  
    //3.查询用户的所有粉丝 select * from where follow_user_id = ?    List<Follow> follows = followService.query().eq("follow_user_id", user.getId()).list();  
    //4.推送笔记id给所有粉丝  
    for (Follow follow : follows) {  
        Long fansId = follow.getUserId();  
        String key = "feed:" + fansId;  
        stringRedisTemplate.opsForZSet().add(key, blog.getId().toString(), System.currentTimeMillis());  
    }  
    //5.返回id  
    return Result.ok(blog.getId());  
}

分页查询

分页查询参数

  • max:上次查询的最小时间戳 | 当前时间

  • min:0

  • offset: 与上一次最小时间戳一致的所有元素的个数 | 0

  • count: 这里定为3

  • 请求参数

    • lastId:上一次查询的最小时间戳
    • offset:偏移量
  • 返回值

    • List< Blog >:小于指定时间戳的笔记集
    • minTime:本次查询的推送的最小时间戳
    • offset:偏移量
      使用stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores(也就是redis的# Zrevrangebyscore命令)实现滚动排序
@Override  
public Result queryBlogOfFollow(Long max, Integer offset) {  
    //1.获取当前用户  
    Long userId = UserHolder.getUser().getId();  
    //2.查询邮件箱  
    String key = RedisConstants.FEED_KEY + userId;  
    Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, 0, max, offset, 3);  
    if (typedTuples == null || typedTuples.isEmpty()) {  
        return Result.fail("失败!");  
    }  
    //3.解析数据:blogId,minTime,offset  
    List<Long> ids = new ArrayList<>();  
    long minTime = 0;  
    int os = 1;  
    for (ZSetOperations.TypedTuple<String> tuple : typedTuples) {  
        //获取id  
        ids.add(Long.valueOf(tuple.getValue()));  
        //获取时间戳  
        long time = tuple.getScore().longValue();  
        if (time == minTime) {  
            os++;  
        } else {  
            minTime = time;  
            os = 1;  
        }  
    }  
    //4.根据id查询blog  
    String idStr = StrUtil.join(",", ids);  
    List<Blog> blogs = query().in("id", ids).last("ORDER BY FIELD(id," + idStr + ")").list();  
  
    for (Blog blog : blogs) {  
        //查询用户  
        queryBlogUser(blog);  
        //查询用户是否点赞  
        isBlogLiked(blog);  
    }  
    //5.封装并返回  
    ScrollResult scrollResult = new ScrollResult();  
    scrollResult.setList(blogs);  
    scrollResult.setOffset(os);  
    scrollResult.setTime(minTime);  
  
    return Result.ok(scrollResult);  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只桃子z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值