Redis框架(十四):大众点评项目 基于Redis实现点赞功能实现

news2024/11/28 4:39:29

大众点评项目 基于Redis的点赞功能实现

  • 需求:基于Redis实现点赞功能实现
  • 业务实战
  • 总体代码展示
  • 总结

SpringCloud章节复习已经过去,新的章节Redis开始了,这个章节中将会回顾Redis实战项目 大众点评
主要依照以下几个原则

  1. 基础+实战的Demo和Coding上传到我的代码仓库
  2. 在原有基础上加入一些设计模式,stream+lamdba等新的糖
  3. 通过DeBug调试,进入组件源码去分析底层运行的规则和设计模式

代码会同步在我的gitee中去,觉得不错的同学记得一键三连求关注,感谢:
Redis优化-链接: RedisFunctionLikeProject

需求:基于Redis实现点赞功能实现

** 点赞功能的基本实现, 点赞用户排序, 相关用户信息显示**

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

业务实战

  1. 在原有Blog类的基础上添加相关字段
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("tb_blog")
public class Blog implements Serializable {
    /**
     * 用户图标
     */
    @TableField(exist = false)
    private String icon;
    /**
     * 用户姓名
     */
    @TableField(exist = false)
    private String name;
    /**
     * 是否点赞过了
     */
    @TableField(exist = false)
    private Boolean isLike;
 }

**@TableField(exist = false)**表示不存在,我们通过在业务层手动注入这些信息

在这里插入图片描述

  1. 通过相应的url进行基本操作,业务放到Service层去做

在这里插入图片描述

原有业务

    @PutMapping("/like/{id}")
    public Result likeBlog(@PathVariable("id") Long id) {
        // 修改点赞数量
        return blogService.likeBlog(id);
        blogService.update()
                .setSql("liked = liked + 1").eq("id", id).update();
        return Result.ok();
    }

这里对点赞次数没有限制,是不行的,我们希望对点赞功能只能一次;

    @PutMapping("/like/{id}")
    public Result likeBlog(@PathVariable("id") Long id) {
        // 修改点赞数量
        return blogService.likeBlog(id);

    }

  1. 将点赞信息存放到Redis中,存放类型是zset类型,通过这种类型,可以保证
  • 数据唯一性
  • 指定SCORE属性进行排序,我们选用时间戳System.currentTimeMillis()
    /**
     * @Function:点赞功能实现
     * @param id
     * @return
     */
    @Override
    public Result likeBlog(Long id) {
        Long userId = UserHolder.getUser().getId();
        //判断当前用户是否点赞
        String key = RedisConstants.BLOG_LIKED_KEY + id;
        Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());

//        if (!member) {  包装类可能为null
//        if (BooleanUtil.isFalse(member)) {
        if (score == null) {
            //如果set中不存在,说明没有
//            blog.setIsLike(false);
            boolean flag = update().setSql("liked = liked + 1").eq("id", id).update();
            if (flag) {
                stringRedisTemplate.opsForZSet().add(key, userId.toString(), System.currentTimeMillis());
            }

        }else{
            //如果没有点赞
//            blog.setIsLike(true);
            boolean flag = update().setSql("liked = liked - 1").eq("id", id).update();
            if (flag) {
                stringRedisTemplate.opsForZSet().remove(key, userId.toString());
            }
        }

        return Result.ok();
    }
  1. 点赞排序,显示用户信息

在这里插入图片描述

    @GetMapping("/likes/{id}")
    public Result likesBlog(@PathVariable("id") Long id) {
        // 修改点赞数量
        return blogService.queryBlogLikes(id);
    }
    @Override
    public Result queryBlogLikes(Long id) {

        String key = RedisConstants.BLOG_LIKED_KEY + id;
        Set<String> topFive = stringRedisTemplate.opsForZSet().range(key, 0, 4);

        if (topFive == null || topFive.isEmpty()) {
            return Result.ok(Collections.emptyList());
        }

        List<Long> userIdOrder = topFive.stream().map(Long::valueOf).collect(Collectors.toList());
        String idStr = StrUtil.join(",", userIdOrder);

        List<UserDTO> userDTOS = userService.query()
                .in("id", userIdOrder)
                .last("ORDER BY FIELD(id, "+ idStr +  ")").list()
                .stream()
                .map(user -> {
            return BeanUtil.copyProperties(user, UserDTO.class);
        }).collect(Collectors.toList());



        return Result.ok(userDTOS);
    }

这里需要注意下 userService.query() .in("id", userIdOrder) .last("ORDER BY FIELD(id, "+ idStr + ")").list()
这个是为了按时间顺序展示来进行的,ORDER BY FIELD就是值其排序方式按我们的要求来进行,这里通过MP的last方法进行了拼装

总体代码展示

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

    @Resource
    private IBlogService blogService;

    @Resource
    private IUserService userService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;


    /**
     * @Function:点赞功能实现
     * @param id
     * @return
     */
    @Override
    public Result likeBlog(Long id) {
        Long userId = UserHolder.getUser().getId();
        //判断当前用户是否点赞
        String key = RedisConstants.BLOG_LIKED_KEY + id;
        Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());

//        if (!member) {  包装类可能为null
//        if (BooleanUtil.isFalse(member)) {
        if (score == null) {
            //如果set中不存在,说明没有
//            blog.setIsLike(false);
            boolean flag = update().setSql("liked = liked + 1").eq("id", id).update();
            if (flag) {
                stringRedisTemplate.opsForZSet().add(key, userId.toString(), System.currentTimeMillis());
            }

        }else{
            //如果没有点赞
//            blog.setIsLike(true);
            boolean flag = update().setSql("liked = liked - 1").eq("id", id).update();
            if (flag) {
                stringRedisTemplate.opsForZSet().remove(key, userId.toString());
            }
        }

        return Result.ok();
    }

    @Override
    public Result queryBlogLikes(Long id) {

        String key = RedisConstants.BLOG_LIKED_KEY + id;
        Set<String> topFive = stringRedisTemplate.opsForZSet().range(key, 0, 4);

        if (topFive == null || topFive.isEmpty()) {
            return Result.ok(Collections.emptyList());
        }

        List<Long> userIdOrder = topFive.stream().map(Long::valueOf).collect(Collectors.toList());
        String idStr = StrUtil.join(",", userIdOrder);

        List<UserDTO> userDTOS = userService.query()
                .in("id", userIdOrder)
                .last("ORDER BY FIELD(id, "+ idStr +  ")").list()
                .stream()
                .map(user -> {
            return BeanUtil.copyProperties(user, UserDTO.class);
        }).collect(Collectors.toList());



        return Result.ok(userDTOS);
    }




总结

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/91892.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解读一个四路组相联cache代码

解读一个四路组相联cache代码 在《计算机组成原理&#xff0c;软硬件接口》中&#xff0c;第五章便是cache的学习。本人初学cache&#xff0c;难免有疏漏之处&#xff0c;源代码github地址&#xff1a;https://github.com/airin711/Verilog-caches 1、四路组相联cache主要特征…

Milvus 2.1.x 到 Milvus 2.2.x 升级实践

近日&#xff0c;Milvus 2.2.0 发布&#xff0c;新版本里支持了许多激动人心的功能&#xff0c;包括&#xff1a;磁盘索引&#xff08;DiskANN&#xff09;、从文件中批量导入数据&#xff08;bulk_insert&#xff09;、基于角色的访问控制&#xff08;RBAC&#xff09;、集合生…

Linux | 网络概念理解 | 对网络的初始

文章目录重新看待计算机体系结构软件分层的思想网络中的分层协议的理解局域网的理解MAC地址 && IP地址报头的作用端口号&#xff08;port&#xff09;重新看待计算机体系结构 计算机由硬件组成&#xff0c;而不同硬件之间要怎么通信&#xff0c;或者说要怎么进行数据的…

MySQL——count(*)的底层实现以及相关优化

在开发系统的时候&#xff0c;可能需要需要计算一个表的行数这时候你可能会想&#xff0c;一条 select count(*) from t 语句不就解决了吗&#xff1f; 但是&#xff0c;会发现随着系统中记录数越来越多&#xff0c;这条语句执行得也会越来越慢。然后可能就想了&#xff0c;My…

盘点2022企业网络安全的七大成功要素

网络安全弹性已成为企业的重中之重&#xff0c;高达62%的受访企业在过去两年中经历了影响业务的安全事件。 最流行的四大攻击事件类型是&#xff1a; 1)网络或数据泄露&#xff08;51.5%&#xff09; 2)网络或系统中断&#xff08;51.1%&#xff09; 3)勒索软件事件&#x…

openpnp - 软件调试环境搭建

文章目录openpnp - 软件调试环境搭建概述笔记openpnp官方站点将openpnp工程克隆到本地将openpnp的wiki工程克隆到本地查看openpnp开发指南根据openpnp开发指南搭建openpnp开发环境IDE的选择IntelliJ IDEA学习版的安装引入openpnp工程在IDEA中, 运行openpnp主程序配置IntelliJ I…

工业手持终端并非“单兵作战”,5G智能模组时刻在线赋能

随着智能终端技术的不断演进&#xff0c;稳定性、实时性和续航能力强的工业手持终端为移动通信、消费电子、工业信息采集等领域提供便捷、高效的数据采集、存储、传输等功能服务。在智慧物流、智慧零售、智能制造、智慧医疗等领域&#xff0c;工业手持终端仍表现出需求激增、功…

Neuron 2.3.0 发布:更轻松地接入和管理海量工业设备

Neuron 2.3.0 版本现已正式发布&#xff01; 除了新增数据统计、模糊搜索、页面下载日志等功能提升产品易用性外&#xff0c;Neuron 2.3.0 版本还新增了 CIP Ethernet/IP、Mitsubishi Melsec 1E frame E71 和 Fanuc Focas 三个协议驱动&#xff0c;以更强大的能力帮助工业用户…

chatgpt使用教程

** 使用门槛&#xff1a;需要自行准备能开全局代理的科学上网工具 好评赠送免费科学上网工具&#xff0c;也可以自己准备科学工具。 ** 下单以后&#xff0c;我们会发送一串账号密码给您。如图&#xff1a; 其中卡号就是chatgpt的账号&#xff0c;密码就是chatgpt密码。 第…

数据结构---优先队列

优先队列实现方式入队出队JAVA实现总结二叉堆是实现优先队列的基础&#xff0c;上一篇二叉堆博文&#xff1a; 二叉堆队列的特点是先进先出&#xff08;FIFO&#xff09;。 优先队列不再遵循先入先出的原则&#xff0c;而是分为两种情况。 最大优先队列&#xff0c;无论入队顺…

Ansible 服务器主机配置

使用 ansible 来对远程主机进行部署的话。我们需要首先对远程主机进行配置。 配置文件路径 配置文件位于&#xff1a;/etc/ansible/hosts 路径下面。 可以使用 vi 工具进行打开。 配置示例 下面是一个简单的配置示例。 [db]127.0.0.1[app]127.0.0.1 ansible_connections…

关于Playwright Xpath找不到元素问题解决方案

今日像往常进行xpath定位元素 发现代码里定位不出来 所以我就手动修改定位xpath 最后怎么修改都获取不到 返回None 那我就向上找 找到他的外祖母 最后进行inner_html() 发现元素是存在的 没有任何问题 这里我就又更加怀疑自己定位出错 折腾了半天发现定位不出来 于是我放弃了…

目标检测算法——车辆牌照识别数据集汇总 2(附下载链接)

&#x1f384;&#x1f384;近期&#xff0c;小海带在空闲之余收集整理了一批车辆牌照识别数据集供大家参考。 整理不易&#xff0c;小伙伴们记得一键三连喔&#xff01;&#xff01;&#xff01;&#x1f388;&#x1f388; 目录 一、伊朗车牌数据集 &#x1f384;&#x1f3…

【目标跟踪】光流法运动视频跟踪【含Matlab源码 1357期】

⛄一、光流场简介 1 案例背景 运动视觉研究的内容是如何从变化场景中的一系列不同时刻的图像中提取有关场景中物体的形状、位置和运动的信息。根据研究的方法&#xff0c;它可以分为两类&#xff1a;基于特征的方法和基于光流场的方法。基于特征的方法抽取特征点&#xff0c;是…

傻白探索Chiplet,Chiplet面临的挑战之互连和封装(四)

目录 一、互连技术 二、封装技术 &#xff08;1&#xff09;英特尔 &#xff08;2&#xff09;台积电 三、生产流程 四、软件技术 实施Chiplet技术面临的主要挑战包括&#xff1a; 互连技术。Chiplet技术需要开发新型互连技术&#xff0c;以便将小芯片组合在一起。目前&a…

51单片机模块化编程

模块化 传统方式编程&#xff1a;所有的函数均放在 main.c 里&#xff0c;若使用的模块比较多&#xff0c;则一个文件内会有很多的代码&#xff0c;不利于代码的组织和管理&#xff0c;而且很影响编程者的思路。 模块化编程&#xff1a;把各个模块的代码放在不同的 .c 文件里…

FL Studio21新版终于有内置的强大混响插件了

FL Studio 21新版终于有内置的强大混响插件了FL Studio 21新版不光如此&#xff0c;还增加很多官方主题&#xff0c;并内置了多款可选&#xff0c;满足大家对个性化的需求&#xff01; 而且每一个人都能快速地创建属于自己的主题&#xff0c;彰显你的与众不同&#xff01; 一分…

JavaScript(五):函数、作用域

JavaScript函数函数的基本使用return返回语句arguments的使用函数的两个案例作用域函数的基本使用 1.函数声明 格式&#xff1a; function 函数名(){ 函数体代码 } function是声明函数的关键字&#xff0c;必须小写 2.函数调用 函数名(); 调用的时候不要忘记加小括号函数如果…

【数据分析】大型ADCP数据集的处理和分析(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

猿如意中的【Sublime Text Build 3211】开发工具详情介绍

目录 一、工具名称 二、下载安装渠道 2.1 什么是猿如意&#xff1f; 2.2 如何下载猿如意&#xff1f; 2.3 如何在猿如意中下载Sublime Text Build 3211&#xff1f; 三、Sublime Text Build 3211介绍 四、软件安装过程 五、软件界面 六、Sublime Text Build 3…