基于springboot+Redis的前后端分离项目(七)-【黑马点评】

news2024/11/15 10:26:28

🎁🎁资源文件分享
链接:https://pan.baidu.com/s/1189u6u4icQYHg_9_7ovWmA?pwd=eh11
提取码:eh11

发布笔记,点赞,点赞排行

  • 达人探店
    • 1、达人探店-发布探店笔记
    • 2、 达人探店-查看探店笔记
    • 3、 达人探店-点赞功能
    • 4、 达人探店-点赞排行榜

达人探店

1、达人探店-发布探店笔记

发布探店笔记

探店笔记类似点评网站的评价,往往是图文结合。对应的表有两个:
tb_blog:探店笔记表,包含笔记中的标题、文字、图片等
tb_blog_comments:其他用户对探店笔记的评价

具体发布流程

在这里插入图片描述
上传接口

@Slf4j
@RestController
@RequestMapping("upload")
public class UploadController {

    @PostMapping("blog")
    public Result uploadImage(@RequestParam("file") MultipartFile image) {
        try {
            // 获取原始文件名称
            String originalFilename = image.getOriginalFilename();
            // 生成新文件名
            String fileName = createNewFileName(originalFilename);
            // 保存文件
            image.transferTo(new File(SystemConstants.IMAGE_UPLOAD_DIR, fileName));
            // 返回结果
            log.debug("文件上传成功,{}", fileName);
            return Result.ok(fileName);
        } catch (IOException e) {
            throw new RuntimeException("文件上传失败", e);
        }
    }

}

注意:在操作时,需要修改SystemConstants.IMAGE_UPLOAD_DIR 自己图片所在的地址,在实际开发中图片一般会放在nginx上或者是云存储上。

BlogController

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

    @Resource
    private IBlogService blogService;

    @PostMapping
    public Result saveBlog(@RequestBody Blog blog) {
        //获取登录用户
        UserDTO user = UserHolder.getUser();
        blog.setUpdateTime(user.getId());
        //保存探店博文
        blogService.saveBlog(blog);
        //返回id
        return Result.ok(blog.getId());
    }
}

2、 达人探店-查看探店笔记

实现查看发布探店笔记的接口
在这里插入图片描述
实现代码:

BlogServiceImpl

@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);
}

3、 达人探店-点赞功能

初始代码

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

问题分析:这种方式会导致一个用户无限点赞,明显是不合理的

造成这个问题的原因是,我们现在的逻辑,发起请求只是给数据库+1,所以才会出现这个问题

在这里插入图片描述
完善点赞功能

需求:

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

实现步骤:

  • 给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());
            }
        }

4、 达人探店-点赞排行榜

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

之前的点赞是放到set集合,但是set集合是不能排序的,所以这个时候,咱们可以采用一个可以排序的set集合,就是咱们的sortedSet
在这里插入图片描述
我们接下来来对比一下这些集合的区别是什么

所有点赞的人,需要是唯一的,所以我们应当使用set或者是sortedSet

其次我们需要排序,就可以直接锁定使用sortedSet啦。
在这里插入图片描述
修改代码

BlogServiceImpl

点赞逻辑代码

@Override
    public Result likeBlog(Long id) {
        // 1.获取登录用户
        Long userId = UserHolder.getUser().getId();
        // 2.判断当前登录用户是否已经点赞
        String key = BLOG_LIKED_KEY + id;
        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集合  zadd key value score
            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();
    }


    private void isBlogLiked(Blog blog) {
        // 1.获取登录用户
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            // 用户未登录,无需查询是否点赞
            return;
        }
        Long userId = user.getId();
        // 2.判断当前登录用户是否已经点赞
        String key = "blog:liked:" + blog.getId();
        Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());
        blog.setIsLike(score != null);
    }

点赞列表查询列表

BlogController

@GetMapping("/likes/{id}")
public Result queryBlogLikes(@PathVariable("id") Long id) {

    return blogService.queryBlogLikes(id);
}

BlogService

@Override
public Result queryBlogLikes(Long id) {
    String key = BLOG_LIKED_KEY + 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
    List<Long> ids = top5.stream().map(Long::valueOf).collect(Collectors.toList());
    String idStr = StrUtil.join(",", ids);
    // 3.根据用户id查询用户 WHERE id IN ( 5 , 1 ) ORDER BY FIELD(id, 5, 1)
    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);
}

后记
👉👉💕💕美好的一天,到此结束,下次继续努力!欲知后续,请看下回分解,写作不易,感谢大家的支持!! 🌹🌹🌹

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

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

相关文章

dvwa靶场通关(八)

第八关&#xff1a;SQL Injection (Blind) low 这一关是盲注&#xff0c; 所以不能用联合查询了&#xff0c;只能靠一点一点手动盲猜了 这里用到length和substr函数 先猜数据库名长度 1 and length(database())1# 用bp抓包&#xff0c;发送到爆破 选择攻击位置 库名长度应该…

ModaHub魔搭社区:向量数据库Zilliz Cloud向量搜索和查询教程(二)

目录 批量搜索 基于条件搜索 查询 批量搜索 Zilliz Cloud 支持在单个请求中同时指定多个查询向量来进行批量搜索。大多数情况下,批量搜索比单向量搜索效率更高,因为批量搜索的总延时会比逐一执行单向量搜索的累计延时要低。 您可以迭代数据集中的行,并以行为单位发送…

【UGUI学习笔记】Canvas

文章目录 组件介绍CanvasRender ModeOverlayCameraWorld Space Canvas ScalerReference Pixels Per UnitUI Scale ModeGraphic RaycasterBlocking Object Canvas Grope UGUI2.0官方文档 一些基础对应控件的Attribute的含义&#xff1a; Canvas相当于Android的Panel&#xff0c;…

二十二、数据运算

目录 一、算术运算 二、比较运算 三、汇总运算 1、count非空值计数 2、sum求和 3、mean求均值 4、max求最大值 5、min求最小值 6、median求中位数 7、mode求众数 8、var求方差 9、std求标准差 10、quantile求分位数 四、相关性运算 一、算术运算 算术运算就是基本…

Boundless Hackathon @Stanford 主题黑客松活动闭幕,一文回顾

由 Stanford Blockchain Accelerator、Zebec Protocol、 Nautilus Chain、Rootz Lab 共同主办了“ Boundless Hackathon Stanford ” 主题的黑客松活动在 7 月 1 日正式落下帷幕。 本次黑客松活动旨在帮助更多的优质开发者参与到 Web3 世界的发展中&#xff0c;以推动链上设施的…

【优选算法题练习】day3

文章目录 一、15. 三数之和1.题目简介2.解题思路3.代码4.运行结果 二、18. 四数之和1.题目简介2.解题思路3.代码4.运行结果 三、209. 长度最小的子数组1.题目简介2.解题思路3.代码4.运行结果 总结 一、15. 三数之和 1.题目简介 15. 三数之和 给你一个整数数组 nums &#xff…

Python---文件与文件夹操作(你想了解的基本都在这)

前言&#xff1a; 计算机操作系统是以文件为单位对数据进行管理的。文件是指存储在某种介质上的数据集合。文件在存储介质上的位置是由驱动器名称、文件夹以及文件名来定位的。Python具有强大的文件处理功能&#xff0c;如文件的创建、打开、文件内容的写入、读出文件中的内容…

初级嵌入式软件工程师养成记(学习路线+学习资源+实战项目汇总)

我的圈子&#xff1a; 高级工程师聚集地 我是董哥&#xff0c;高级嵌入式软件开发工程师&#xff0c;从事嵌入式Linux驱动开发和系统开发&#xff0c;曾就职于世界500强企业&#xff01; 创作理念&#xff1a;专注分享高质量嵌入式文章&#xff0c;让大家读有所得&#xff01; …

【Nginx07】Nginx学习:HTTP核心模块(四)错误页面与跳转

Nginx学习&#xff1a;HTTP核心模块&#xff08;四&#xff09;错误页面与跳转 最最核心的部分学习完了&#xff0c;但其实还有更多的内容要等待着我们探索。今天我们先来看到的就是关于错误页面的设置以及 301、302 跳转相关的内容。这两块内容都有一个特点&#xff0c;那就是…

基于51单片机+SHT30设计的环境温度与湿度检测设备(IIC模拟时序)

一、项目介绍 当前文章介绍基于51单片机和SHT30传感器设计的环境温度与湿度检测设备。设备采用IIC模拟时序通信协议&#xff0c;能够实时监测环境的温度和湿度&#xff0c;并将数据通过LCD显示屏显示出来&#xff1b;可以广泛应用于室内环境监测、气象观测、农业温室监测等领域…

路径规划算法:基于白冠鸡优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于白冠鸡优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于白冠鸡优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法…

leetcode 74. 搜索二维矩阵(java)

搜索二维矩阵 leetcode 74. 搜索二维矩阵题目描述抽象BST代码演示 抽象BST leetcode 74. 搜索二维矩阵 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/search-a-2d-matrix 题目描述 给你一个满足下述两条属性的 m x n 整…

033、TiDB特性_AUTO_INCREMENT

自增列 实现原理使用限制相关参数示例 实现原理 每一个自增列使用一个全局可见的键值对用于记录当前已分配的最大ID为了降低分布式系统分配自增ID的网络开销&#xff0c;每个TiDB节点会缓存一个不重复的ID段当前预分配的ID段使用完毕&#xff0c;或重启&#xff0c;都会重新再…

【数据结构导论】第 6 章:查找

目录 一、基本概念 二、静态查找表 &#xff08;1&#xff09;顺序表上的查找 —— 顺序查找 ① 过程 ② 算法 ③ 算法分析 &#xff08;2&#xff09;有序表上的查找 —— 二分查找 ① 二分查找思想 ② 二分查找过程 ③ 二分查找算法 ④ 示例 ⑤ 算法分析 &#…

CentOS系统内核升级(在线 离线)

centos7.x默认内核版本3.10.x&#xff0c;在安装docker时&#xff0c;部分功能&#xff08;如 overlay2 存储层驱动&#xff09;无法使用&#xff0c;并且部分功能可能不太稳定。所以建议大家升级到最新的稳定内核版本。 在线升级 1. 查看当前内核版本 uname -sr Linux 3.10…

python脚本编译成exe方式进行交付

Python自动化办公越来越方便&#xff0c;我们经常也会利用python来写一些自动化的小脚本&#xff0c;例如批量处理文档&#xff0c;自动发送邮件等等。 也许是平时吹得牛比较多&#xff0c;有一天秦医生就问起我说能不能给她写一个自动化处理生信数据的小脚本。 这当然是毫无问…

Stable Diffusion - 扩展插件 (Extensions) 功能的配置与使用

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/131576762 Prompt: (masterpiece, top quality, best quality, ((standing in centre)), ((1girl, black hair)), ((upper body, symmetrical com…

视频无损放大修复工具:Topaz Video AI对Mac和Windows的系统要求

Topaz Video AI是一款基于人工智能技术的视频增强软件&#xff0c;旨在提供高质量的视频修复、增强和转换功能。它可以通过智能算法和图像处理技术&#xff0c;改善视频的清晰度、稳定性、降噪效果&#xff0c;还能进行视频转码和格式转换。 Mac&#xff1a;Topaz Video AI fo…

[pyqt5]designer设计界面设计工具栏上图标和文字同时显示

打开设计师界面 右侧先选择toolBar然后去属性找到toolButtonStyle设置对应选项即可。

图扑 AR 技术应用与管理:施工建造、机柜扫描、办公室导航解决方案

随着科技的不断革新和创新&#xff0c;越来越多的行业开始迎来数字化时代的变革。建筑行业作为人类历史上最重要的产业之一&#xff0c;在数字化转型方面同样也在不断推进。图扑软件结合 AR 技术的应用&#xff0c;为建筑行业带来了更加便捷高效的建筑施工过程管理。 传统的建筑…