达人探店

发布探店笔记

探店笔记类似于点评网站的评价,往往是图文结合,对应的表有两个:

  • tb_blog:探店笔记表,包含笔记中的标题、文字、图片等

  • tb_blog_comments:其他用户对探店笔记的评价

tb_blog表结构如下:

image-20250702181240618

可以从结构中看出,跟发布探店笔记相关的字段有shop_id,title,images,content,liked,comments

业务流程:

点击首页最下方菜单栏的+按钮,即可发布探店图文:

image-20250702181724959

image-20250702181739831

需要注意的是发布照片与发布笔记是两个分离的功能,因为上传照片的功能不仅仅是发笔记有这个需求,在其他业务中可能也会需要发布照片,因此上传照片功能是一个独立功能,点击上传照片时会先发出一个请求实现上传,上传成功后返回这张图片的地址,也就是上传之后的可访问的地址,这个地址就会做为表单的参数,在发布笔记时一起提交到后台,即在发布笔记时上传的其实不是照片的本身,而是上传成功后的图片地址,因此发布照片和发布笔记是不同的功能,会发起两个不同的请求。

而黑马点评这边已经将接口写好了,http: //127.0.0.1:8081/upload/blog,这个接口是为了上传图片的,因此需要修改存放的地址,是将其存放在前端服务器中的目录中,另一个接口http: //127.0.0.1:8081/blog,上传博客。

测试接口:

image-20250702221715696

image-20250702222000809

可以查看数据库表:

image-20250702222120371

而在发布完探店笔记后,发现没有实现查看探店笔记的接口。

image-20250702222431898

因此:

案例展示:实现查看探店笔记的接口

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

controller层:

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

service层

@Override
public Result queryBlogById(Long id) {// 1.查询blogBlog blog = getById(id);if (blog == null) {return Result.fail("笔记不存在!");}// 2.查询blog有关的用户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());}

测试:

image-20250702230047012

点赞

在首页的探店笔记排行榜和探店图文详情页面都有点赞功能:

在Java代码中直接利用MyBatisPlus来修改数据库中的liked字段,每一次点赞都是进行一次接口请求,并且没有点赞限制,没有进行用户判断。而且是直接修改数据库,影响性能。

案例:完善点赞功能

需求:

  • 同一个用户只能点赞一次,再次点击则为取消点赞

  • 如果当前用户已经点赞,则点赞按钮高亮(前端已实现,判断字段blog类的isLike属性)

实现思路:可以在新建一个表,记录笔记的id,以及点赞用户的id,这样每次点赞只需要看表中存在不存在这个用户的值即可,不需要去使用MySQL数据库,可以使用轻量级的数据库,比如redis,可以使用集合类的数据结构,key为笔记的id,value则为点赞的用户id,并且一个用户只能点赞一次,所以value不能重复,所以可以使用set数据结构。

实现步骤:

  1. 给blog类中添加一个isLike字段,标识是否被当前用户点赞

  2. 修改点赞功能,利用redis的set集合判断是否点赞过,未点赞过则点赞数+1,已点赞过则点赞数-1,并且点赞过的用户需要添加在set集合中。

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

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

代码实现:

 /*** 用户图标*/@TableField(exist = false)private String icon;/*** 用户姓名*/@TableField(exist = false)private String name;/*** 是否点赞过了*///该注解表示该成员变量不是数据库表中的字段@TableField(exist = false)private Boolean isLike;

service层业务代码:

 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(Boolean.FALSE.equals(isMember)){//3.如果未点赞,可以点赞//3.1点赞数+1boolean success = lambdaUpdate().set(Blog::getLiked, getById(id).getLiked() + 1).eq(Blog::getId, id).update();//3.2,将用户id存储到redis的set集合中if (success) {stringRedisTemplate.opsForSet().add(key, userId.toString());}}else {//4.如果已点赞,取消点赞//4.1.数据库点赞数-1,boolean success = lambdaUpdate().set(Blog::getLiked, getById(id).getLiked() - 1).eq(Blog::getId, id).update();//4.2将用户id从Redis的set集合中删除if (success) {stringRedisTemplate.opsForSet().remove(key, userId.toString());}}return Result.ok();}

其次,我们还需要修改查询blog的业务代码,在查询用户之后,还需要查询该博客是否被点赞,再去修改isLiked的值。

由于查询有两种查询,一种分页查询,一种普通查询,因此我们将是否被点赞这个业务封装成函数,进行简化代码。

代码实现:

private void isBlogLiked(Blog blog) {Long userId = UserHolder.getUser().getId();String key = BLOG_LIKED_KEY + blog.getId();Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, userId.toString());//防止包装类为空blog.setIsLike(Boolean.TRUE.equals(isMember));}

进行测试:

进行点赞:

image-20250705160213204

检查redis数据库:

image-20250705160227537

取消点赞:

image-20250705160325467

再次查看Redis数据库:

发现已经不存在。

至此业务实现成功。

点赞排行榜

业务详情:

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

我们可以借鉴微信朋友圈点赞的机制。谁先点赞,谁在前面

接口信息:

image-20250705161123523

案例实现:实现查询点赞排行榜的接口

需求:按照点赞时间先后排序,返回top5的用户

思路分析:

我们需要按照点赞时间先后排序,但是点赞的用户信息存储在redis中的set集合里,set集合是无序集合,因此我们需要去更换集合,同时还要满足唯一性与有序性,将Redis中的集合数据结构进行对比。

ListSetSortedSet
排序方式按添加顺序排序无序可排序,根据score值
唯一性不唯一唯一唯一
查找方式按照索引查找或者首尾查找按照元素查找根据元素查找

由此看来,SortedSet更符合业务需求。

但是SortedSet和set有很多不同之处,就别去set中有sismember命令去查询某个元素是否在集合内,但是SortedSet就没有这样的命令,但是我们可以使用zscore命令来查询score值,如果元素不存在则score值就不存在,如果存在则有score值。这个命令也可以判断元素是否存在。如果查询排行榜可以使用zrange命令来查询。zrange命令就是查找范围内的元素。并且会天然的排序,可以按照时间戳来排序时,就会按照时间戳从小到大排序,最早插入的在最前面,这样就可以完成查询排行榜的业务。

思路实现:

改造之前的点赞业务,将set集合替换为SortedSet集合:

 private void isBlogLiked(Blog blog) {Long userId = UserHolder.getUser().getId();String key = BLOG_LIKED_KEY + blog.getId();Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());//防止包装类为空blog.setIsLike(score != null);}​@Overridepublic 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点赞数+1boolean success = lambdaUpdate().set(Blog::getLiked, getById(id).getLiked() + 1).eq(Blog::getId, id).update();//3.2,将用户id存储到redis的set集合中if (success) {stringRedisTemplate.opsForZSet().add(key, userId.toString(),System.currentTimeMillis());}}else {//4.如果已点赞,取消点赞//4.1.数据库点赞数-1,boolean success = lambdaUpdate().set(Blog::getLiked, getById(id).getLiked() - 1).eq(Blog::getId, id).update();//4.2将用户id从Redis的set集合中删除if (success) {stringRedisTemplate.opsForZSet().remove(key, userId.toString());}}return Result.ok();}

实现排行榜接口:

 @Overridepublic Result queryBlogLikes(Long id) {//1.获取当前blog的点赞top5String key = BLOG_LIKED_KEY + id;Set<String> top5 = stringRedisTemplate.opsForZSet().range(key, 0, 4);//2.解析出其中的用户id,map映射,将long类型的字符串转为Longif (top5 == null || top5.isEmpty()) {return Result.ok(Collections.emptyList());}List<Long> ids = top5.stream().map(Long::valueOf).collect(Collectors.toList());//3.根据用户ID查询用户,这里直接返回的是user对象,但是在前端页面应该显示的是UserDTO,所以这里需要将user对象转为UserDTO对象List<UserDTO> userDTOS = userService.listByIds(ids).stream().map(user -> BeanUtil.copyProperties(user, UserDTO.class)).collect(Collectors.toList());//4.返回return Result.ok(userDTOS);}

进行测试:

先尝试一个账号点赞:

image-20250705172826834

测试成功,在进行多个账户点赞:

发现bug:新开网页时,发现下面的博客不登录看不到,根据报错提示发现是空指针异常,即userid为空,解决方案,在从UserHolder中取user时先进行判断,如果为空,则直接return;

代码演示:

private void isBlogLiked(Blog blog) {UserDTO user = UserHolder.getUser();if (user == null){return;}Long userId = user.getId();String key = BLOG_LIKED_KEY + blog.getId();Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());//防止包装类为空blog.setIsLike(score != null);}

解决;

继续测试:

image-20250705173141042

发现顺序不对,去IDEA中检查:

image-20250705173222559

发现顺序是对的,在进入数据库中查询:

image-20250705172647714

发现是使用关键字in的问题,

因此要使用order by ,但不能直接指定id,因为默认order by id 的话是按顺序从小到大的,因此要指定顺序:

image-20250705173758401

因此需要修改查询语句,又因为MyBatisPlus没有封装该方法,只能去自定义SQL语句。

修改代码如下:

 //3.根据用户ID查询用户,这里直接返回的是user对象,但是在前端页面应该显示的是UserDTO,所以这里需要将user对象转为UserDTO对象//where id in (ids) order by field(id,ids)List<UserDTO> userDTOS = userService.lambdaQuery().in(User::getId, ids).last("order by field(id,"+ idStr+")").list().stream().map(user -> BeanUtil.copyProperties(user, UserDTO.class)).collect(Collectors.toList());

再次进行刷新测试:

image-20250705180255556

至此,点赞排行榜业务实现成功。

希望对大家有所帮助!

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一探 3D 互动展厅的神奇构造​

3D 互动展厅的神奇之处&#xff0c;离不开一系列先进技术的强力支撑 。其中&#xff0c;VR(虚拟现实)技术无疑是核心亮点之一。通过佩戴 VR 设备&#xff0c;观众仿佛被瞬间 “传送” 到一个全新的世界&#xff0c;能够全身心地沉浸其中&#xff0c;360 度无死角地观察周围的一…

C++ 网络编程(15) 利用asio协程搭建异步服务器

&#x1f680; [协程与异步服务器实战]&#xff1a;[C20协程原理与Boost.Asio异步服务器开发] &#x1f4c5; 更新时间&#xff1a;2025年07月05日 &#x1f3f7;️ 标签&#xff1a;C20 | 协程 | Boost.Asio | 异步编程 | 网络服务器 文章目录前言一、什么是协程&#xff1f;二…

【Java21】在spring boot中使用虚拟线程

文章目录 0.环境说明1.原理解析2.spring boot的方案3.注意事项&#xff08;施工中&#xff0c;欢迎补充&#xff09; 前置知识 虚拟线程VT&#xff08;Virtual Thread&#xff09; 0.环境说明 用于验证的版本&#xff1a; spring boot: 3.3.3jdk: OpenJDK 21.0.5 spring boot…

利器:NPM和YARN及其他

文章目录**1. 安装 Yarn&#xff08;推荐方法&#xff09;****2. 验证安装****3. 常见问题及解决方法****① 权限不足&#xff08;Error: EPERM&#xff09;****② 网络问题&#xff08;连接超时或下载失败&#xff09;****③ 环境变量未正确配置****4. 替代安装方法&#xff0…

跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能

众所周知&#xff0c;直播平台与短视频平台的贴纸功能不仅是用户表达个性的方式&#xff0c;更是平台提高用户粘性和互动转化的法宝。 可问题来了&#xff1a;如何让一个贴纸功能&#xff0c;在Android和iOS两大平台上表现一致、运行流畅、加载稳定&#xff1f;这背后&#xff…

JavaWeb(苍穹外卖)--学习笔记04(前端:HTML,CSS,JavaScript)

前言 本片文章是学习B站黑马程序员苍穹外卖的学习笔记。因为最近期末周&#xff0c;一直在应付考试所以就学的很少&#xff0c;恰好视频中在讲Nginx反向代理和负载均衡&#xff08;写着对前端的内容做一个复习&#xff09; 概述&#xff1a; 1.web前端主要由三部分组成&…

智能学号抽取系统 V5.4.3.2 —— Vue.js 实现的多功能课堂随机抽签工具

智能学号抽取系统 V5.4.3.2 —— Vue.js 实现的多功能课堂随机抽签工具 在教学或会议场景中&#xff0c;我们经常需要随机抽取一个或多个学号/编号来决定发言者、答题者或者参与者。为了提高效率和公平性&#xff0c;我们可以使用一些智能化的小工具来实现这一过程。 今天介绍…

从0开始学习R语言--Day39--Spearman 秩相关

在非参数统计中&#xff0c;不看数据的实际数值&#xff0c;单纯比较两组变量的值的排名是通用的基本方法&#xff0c;但在客观数据中&#xff0c;很多变量的关系都是非线性的&#xff0c;其他的方法不是对样本数据的大小和线性有要求&#xff0c;就是只能对比数据的差异性&…

WSL - Linux 安装 Anaconda3-2025.06-0 详细教程 [WSL 分发版均适用]

一、检查系统状态 安装前先确认 WSL - Linxu 已正常启动&#xff08;比如 Ubuntu&#xff09;&#xff0c;网络连接稳定&#xff0c;并且系统磁盘有足够空间&#xff0c;一般建议预留至少 5GB 以上的可用空间&#xff0c;避免因空间不足导致安装失败。 二、下载安装包 Anacond…

热血三国建筑攻略表格

<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>热血三国建筑攻略表格</title><style>…

SpringBoot+MySQL医院挂号系统源码

概述 基于SpringBootMySQL开发的医院挂号系统完整源码&#xff0c;该系统功能完善&#xff0c;包含从患者挂号到医生管理的全流程解决方案&#xff0c;采用主流技术栈开发&#xff0c;代码规范易于二次开发。 主要内容 系统包含完整的前后台功能模块&#xff1a; ​​前台功…

Linux系统之MySQL数据库基础

目录 一、概述 数据库概念 数据库的类型 关系型数据库模型 关系数据库相关概念 二、安装 1、mariadb安装 2、mysql安装 3、启动并开机自启 4、本地连接&#xff08;本地登录&#xff09; 三、mysqld数据库配置与命令 yum安装后生成的目录 mysqld服务器的启动脚本 …

MySQL--InnoDB存储引擎--页结构

目录 一、页的大小 二、页的分类 三、页头和页尾 3.1 页头--File Header 3.2 页尾--File Trailer 3.3 LSN 四、数据行 五、页中数据的查询 六、事务和索引在页中的记录 一、页的大小 前面介绍了每个数据页默认大小为16KB&#xff0c;是操作系统“数据块” 4KB 的整数倍…

卡车检测数据集-700张图片交通运输管理 智能监控系统 道路安全监测

跌倒检测数据集-4500张图片&#x1f4e6; 已发布目标检测数据集合集&#xff08;持续更新&#xff09;&#x1f69b; Deteccin de carpa 2 Computer Vision Project&#x1f4cc; 数据集概览包含类别&#x1f3af; 应用场景&#x1f5bc; 数据样本展示&#x1f527; 使用建议&a…

Python爬虫实战:研究pangu库相关技术

1. 引言 1.1 研究背景与意义 在数字化信息传播时代,中文文本排版质量直接影响信息传达效果。规范的排版要求中文与西文、数字间保持合理空格间距,但人工处理不仅效率低,且易出现一致性问题。随着互联网中文内容爆发式增长,传统人工排版已无法满足需求。Python 作为高效的…

day48-考试系统项目集群部署

1. ✅考试系统项目集群架构图负载均衡说明7层负载通过nginx对http请求进行转发&#xff08;uri,ua,类型&#xff09;4层负载对端口负载均衡&#xff08;后端&#xff09;2. &#x1f4dd;环境准备角色主机ip负载均衡lb01/lb02172.16.1.5/172.16.1.6前端web集群web01/web02172.1…

Redis+Caffeine双层缓存策略对比与实践指南

RedisCaffeine双层缓存策略对比与实践指南在高并发场景下&#xff0c;缓存是提升系统性能和并发处理能力的关键手段。常见的缓存方案包括远程缓存&#xff08;如Redis&#xff09;和本地缓存&#xff08;如Caffeine&#xff09;。单层缓存各有优劣&#xff0c;结合两者优势的双…

FastAPI+React19 ERP系统实战 第02期

一、搭建环境 1.1 创建Python虚拟环境 切换Python版本: pyenv local 3.12创建虚拟环境: python -m venv venv激活虚拟环境: venv\Scripts\activate1.2 安装FastAPI项目依赖 requirements.txt fastapi==0.109.1

百度AI文心大模型4.5系列开源模型评测,从安装部署到应用体验

2025年6月30日&#xff0c;百度突然宣布&#xff0c;将旗下最新的大语言模型文心大模型4.5&#xff08;ERNIE 4.5&#xff09;全系列开源&#xff0c;震动整个AI行业。百度在GitCode平台上开源了文心大模型4.5系列&#xff0c;包括ERNIE-4.5-VL-424B-A47B-Base-PT等多个型号。此…

windows安装maven环境

在maven官网下载安装包 https://maven.apache.org/download.cgi 下载完成后安装maven&#xff0c;一般下载编辑好的 创建个maven目录解压出来即可 配置环境变量 根据刚刚的安装路径&#xff0c;新建一个命名为MAVEN_HOME的系统变量 新建完成点开系统变量的Path项&#xff0c;…