基于 redis 实现达人探店和点赞功能

一、发布探店笔记

1.1 简介

        探店笔记类似点评网站的评价,往往是图文结合。点击首页最下方菜单栏中的+按钮,即可发布探店图文:

        文件上传的设置如下:

1.2 需求描述

        点击首页的探店笔记,会进入详情页面,实现该页面的查询接口:

1.3 代码实现

        对应的 controller 层代码如下:

RestController
@RequestMapping("/blog")
public class BlogController {

    @Resource
    private IBlogService blogService;

    @GetMapping("/{id}")
    public Result queryBlogById(@PathVariable("id") Long id){
        return blogService.queryBlogById(id);
    }
}

        对应的 service 层代码如下:

@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {

    @Resource
    private IUserService userService;

    @Override
    public Result queryBlogById(Long id) {

        // 1、查询 blog
        Blog blog = getById(id);
        if(blog == null){
            return Result.fail("笔记不存在");
        }
        // 2、查询 blog 相关的用户
        queryBlogUser(blog);
        return Result.ok(blog);
    }
    public void queryBlogUser(Blog blog){
        Long userId = blog.getUserId();
        User user = userService.getById(userId);
        blog.setName(user.getNickName());
        blog.setIcon(user.getIcon());
    }
}

二、点赞

2.1 简介

        在首页的探店笔记排行榜和探店图文详情页面都有点赞的功能:如下图,当点击点赞按钮的时候,就会向后端发送一个请求,请求的地址也在下图上,其中 url 最后是笔记的 id

2.2 需求描述

        同一个用户只能点赞一次,再次点击则取消点赞;如果当前用户已经点赞,则点赞按钮高亮显示(前端已实现,判断字段 Blog 类的 isLike 属性即可)。

2.3 实现步骤

        1、Blog 类中添加一个 isLike 字段,标示是否被当前用户点赞

        2、修改点赞功能,利用 Redis 的 set 集合判断是否点赞过,未点赞过则点赞数 +1,已点赞过则点赞数 -1

        3、修改根据 id 查询 Blog 的业务,判断当前登录用户是否点赞过,赋值给 isLike 字段

        4、修改分页查询 Blog 业务,判断当前登录用户是否点赞过,赋值给 isLike 字段

2.4 代码实现

        对应的 controller 层代码如下:

RestController
@RequestMapping("/blog")
public class BlogController {

    @Resource
    private IBlogService blogService;

    @GetMapping("/{id}")
    public Result queryBlogById(@PathVariable("id") Long id){
        return blogService.queryBlogById(id);
    }

    @GetMapping("/{id}")
    public Result queryBlogById(@PathVariable("id") Long id){
        return blogService.queryBlogById(id);
    }
}

        对应的 services 层代码如下:

@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {

    @Resource
    private IUserService userService;

    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Override
    public Result queryHotBlog(Integer current) {
        // 根据用户查询
        Page<Blog> page = query()
                .orderByDesc("liked")
                .page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
        // 获取当前页数据
        List<Blog> records = page.getRecords();
        // 查询用户
        records.forEach(blog -> {
            queryBlogUser(blog);
            // 查询 blog 是否被点赞
            isBlogLiked(blog);
        });
        return Result.ok(records);
    }
    private void isBlogLiked(Blog blog){
        // 1、获取当前用户
        UserDTO user = UserHolder.getUser();
        String key = "blog:liked:"+blog.getId();
        // 2、判断当前用户是否已经点赞了
        Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, user.getId().toString());
        blog.setIsLike(BooleanUtil.isTrue(isMember));
    }
    @Override
    public Result likeBlog(Long id) {
        // 1、获取当前用户
        UserDTO user = UserHolder.getUser();
        String key = "blog:liked:"+id;
        // 2、判断当前用户是否已经点赞了
        Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, user.getId().toString());
        // 3、如果没有点赞,可以点赞
        if(BooleanUtil.isFalse(isMember)){
            // 3.1 数据库点赞数 +1
            boolean success = update().setSql("liked = liked + 1").eq("id", id).update();
            if(success){
                // 3.2 保存用户到 redis 的 set 集合
                stringRedisTemplate.opsForSet().add(key,userId.toString());
            }
        }else{
            // 4、如果点赞了,取消点赞
            // 4.1 数据库点赞数 -1
            boolean success = update().setSql("liked = liked - 1").eq("id", id).update();
            if(success){
                // 4.2 保存用户到 redis 的 set 集合
                stringRedisTemplate.opsForSet().remove(key,userId.toString());
            }
        }
        return Result.ok();
    }

    @Override
    public Result queryBlogById(Long id) {

        // 1、查询 blog
        Blog blog = getById(id);
        if(blog == null){
            return Result.fail("笔记不存在");
        }
        // 2、查询 blog 相关的用户
        queryBlogUser(blog);
        isBlogLiked(blog);
        return Result.ok(blog);
    }
    public void queryBlogUser(Blog blog){
        Long userId = blog.getUserId();
        User user = userService.getById(userId);
        blog.setName(user.getNickName());
        blog.setIcon(user.getIcon());
    }
}

三、 点赞排行榜

3.1 简介

        在探店笔记的详情页面,应该把给该笔记点赞的人显示出来,比如最早点赞的 TOP5,形成点赞排行榜:

3.2 需求描述

        按照点赞时间先后排序,返回 Top5 的用户,我们实现点赞功能使用的是 redis set 类型,在这里就不行了,因为 set 不支持排序功能,这里我们需要使用 zset 类型,因为此种类型才有排序、不重复等特点。

3.3 代码实现

        对应的 controller 层代码如下:

RestController
@RequestMapping("/blog")
public class BlogController {

    @Resource
    private IBlogService blogService;

    @GetMapping("/{id}")
    public Result queryBlogById(@PathVariable("id") Long id){
        return blogService.queryBlogById(id);
    }

    @GetMapping("/{id}")
    public Result queryBlogById(@PathVariable("id") Long id){
        return blogService.queryBlogById(id);
    }

    @GetMapping("/likes/{id}")
    public Result queryBlogLikes(@PathVariable("id") Long id){
        return blogService.queryBlogLikes(id);
    }
}

        对应的 services 层代码如下:

@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {

    @Resource
    private IUserService userService;

    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Override
    public Result queryHotBlog(Integer current) {
        // 根据用户查询
        Page<Blog> page = query()
                .orderByDesc("liked")
                .page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
        // 获取当前页数据
        List<Blog> records = page.getRecords();
        // 查询用户
        records.forEach(blog -> {
            queryBlogUser(blog);
            // 查询 blog 是否被点赞
            isBlogLiked(blog);
        });
        return Result.ok(records);
    }
    private void isBlogLiked(Blog blog){
        // 1、获取当前用户
        UserDTO user = UserHolder.getUser();
        if(user == null){
            // 用户未登录
            return ;
        }
        String key = "blog:liked:"+blog.getId();
        // 2、判断当前用户是否已经点赞了
        Double score = stringRedisTemplate.opsForZSet().score(key, user.getId().toString());
        blog.setIsLike(score != null);
    }
    @Override
    public Result likeBlog(Long id) {
        // 1、获取当前用户
        UserDTO user = UserHolder.getUser();
        String key = "blog:liked:"+id;
        // 2、判断当前用户是否已经点赞了
        Double score = stringRedisTemplate.opsForZSet().score(key, user.getId().toString());
        // 3、如果没有点赞,可以点赞
        if(score == null){
            // 3.1 数据库点赞数 +1
            boolean success = update().setSql("liked = liked + 1").eq("id", id).update();
            if(success){
                // 3.2 保存用户到 redis 的 set 集合   zadd key value score
                stringRedisTemplate.opsForZSet().add(key,user.getId().toString(),System.currentTimeMillis());
            }
        }else{
            // 4、如果点赞了,取消点赞
            // 4.1 数据库点赞数 -1
            boolean success = update().setSql("liked = liked - 1").eq("id", id).update();
            if(success){
                // 4.2 保存用户到 redis 的 set 集合
                stringRedisTemplate.opsForZSet().remove(key,user.getId().toString());
            }
        }
        return Result.ok();
    }

    @Override
    public Result queryBlogLikes(Long id) {
        // 查找 top5 的点赞用户
        String key = "blog:liked:"+id;
        Set<String> top5 = stringRedisTemplate.opsForZSet().range(key, 0, 4);
        if(top5 == null || top5.isEmpty()){
            return Result.ok(Collections.emptyList());
        }
        // 2、解析其中的用户 id
        List<Long> ids = top5.stream().map(userId -> Long.valueOf(userId)).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);
    }

    @Override
    public Result queryBlogById(Long id) {

        // 1、查询 blog
        Blog blog = getById(id);
        if(blog == null){
            return Result.fail("笔记不存在");
        }
        // 2、查询 blog 相关的用户
        queryBlogUser(blog);
        isBlogLiked(blog);
        return Result.ok(blog);
    }
    public void queryBlogUser(Blog blog){
        Long userId = blog.getUserId();
        User user = userService.getById(userId);
        blog.setName(user.getNickName());
        blog.setIcon(user.getIcon());
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

快乐的小三菊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值