Redis筆記點(diǎn)贊排行榜的實(shí)現(xiàn)示例
一、發(fā)布探店筆記
探店筆記類似點(diǎn)評(píng)網(wǎng)站的評(píng)價(jià),往往是圖文結(jié)合。對(duì)應(yīng)的表有兩個(gè)
- 探店筆記表(主鍵、商戶id、用戶id、標(biāo)題、文字、圖片、探店文字描述、點(diǎn)贊數(shù)量、評(píng)論數(shù)量)
- 評(píng)價(jià)表(筆記的評(píng)價(jià))
先上傳圖片請(qǐng)求一次保存圖片接口,再點(diǎn)發(fā)布請(qǐng)求發(fā)布接口。這兩個(gè)接口已經(jīng)寫(xiě)好

二、實(shí)現(xiàn)查看筆記接口

BlogController
@RestController
@RequestMapping("/blog")
public class BlogController {
@Resource
private IBlogService blogService;
@GetMapping("/hot")
public Result queryHotBlog(@RequestParam(value = "current", defaultValue = "1") Integer current) {
return blogService.queryHotBlog(current);
}
@GetMapping("/{id}")
public Result queryBlogById(@PathVariable("id") String id){
return blogService.queryBlogById(id);
}
}IBlogService
public interface IBlogService extends IService<Blog> {
Result queryBlogById(String id);
Result queryHotBlog(Integer current);
}BlogServiceImpl
@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {
@Autowired
private IUserService userService;
@Override
public Result queryHotBlog(Integer current) {
// 根據(jù)用戶查詢
Page<Blog> page = query()
.orderByDesc("liked")
.page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
// 獲取當(dāng)前頁(yè)數(shù)據(jù)
List<Blog> records = page.getRecords();
// 查詢用戶
records.forEach(this::queryBlogUser);
return Result.ok(records);
}
private void queryBlogUser(Blog blog) {
Long userId = blog.getUserId();
User user = userService.getById(userId);
blog.setName(user.getNickName());
blog.setIcon(user.getIcon());
}
@Override
public Result queryBlogById(String id) {
Blog blog = getById(id);
if(blog == null){
return Result.fail("筆記不存在!");
}
queryBlogUser(blog);
return Result.ok(blog);
}
}三、點(diǎn)贊功能
現(xiàn)在已經(jīng)寫(xiě)好的點(diǎn)贊接口

問(wèn)題:這樣寫(xiě)接口,可以一直按點(diǎn)贊重復(fù)點(diǎn)贊
需求
- 同一個(gè)用戶只能點(diǎn)贊一次,再次點(diǎn)贊則取消點(diǎn)贊
- 如果當(dāng)前用戶已經(jīng)點(diǎn)贊,則點(diǎn)贊按鈕高亮顯(前端已經(jīng)實(shí)現(xiàn),判斷blog類的isLike屬性)
實(shí)現(xiàn)步驟
- 給Blog類中添加一個(gè)isLike字段,表示是否被當(dāng)前用戶點(diǎn)贊
- 修改點(diǎn)贊功能,利用redis的set集合判斷用戶是否贊過(guò),未贊則點(diǎn)贊數(shù)+1,贊過(guò)則-1
- 修改根據(jù)id查詢blog的業(yè)務(wù),判斷當(dāng)前用戶是否點(diǎn)贊過(guò),賦值給isLike字段
- 修改分頁(yè)查詢blog業(yè)務(wù),判斷當(dāng)前用戶是否贊過(guò),賦值isLike字段
業(yè)務(wù)實(shí)現(xiàn)
@RestController
@RequestMapping("/blog")
public class BlogController {
@Resource
private IBlogService blogService;
@PutMapping("/like/{id}")
public Result likeBlog(@PathVariable("id") Long id) {
return blogService.likeBlog(id);
}
@GetMapping("/hot")
public Result queryHotBlog(@RequestParam(value = "current", defaultValue = "1") Integer current) {
return blogService.queryHotBlog(current);
}
@GetMapping("/{id}")
public Result queryBlogById(@PathVariable("id") String id){
return blogService.queryBlogById(id);
}
}編寫(xiě)完點(diǎn)贊操作的接口后還要修改之前的查詢接口,增加查詢是否已經(jīng)點(diǎn)贊
@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {
@Autowired
private IUserService userService;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public Result queryHotBlog(Integer current) {
// 根據(jù)用戶查詢
Page<Blog> page = query()
.orderByDesc("liked")
.page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
// 獲取當(dāng)前頁(yè)數(shù)據(jù)
List<Blog> records = page.getRecords();
// 查詢用戶
records.forEach(blog -> {
this.queryBlogUser(blog);
this.isBlogLiked(blog);
});
return Result.ok(records);
}
@Override
public Result likeBlog(Long id) {
// 1、獲取登錄用戶
UserDTO user = UserHolder.getUser();
// 2、判斷當(dāng)前登錄用戶是否已經(jīng)點(diǎn)贊
Boolean isMember = stringRedisTemplate.opsForSet().isMember(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString());
if(BooleanUtil.isFalse(isMember)) {
// 3、如果未點(diǎn)贊,可以點(diǎn)贊
// 3.1、數(shù)據(jù)庫(kù)點(diǎn)贊數(shù) +1
boolean isSuccess = update().setSql("liked = liked+1").eq("id", id).update();
// 3.2、保存用戶到 Redis 的 set 集合
if(isSuccess){
stringRedisTemplate.opsForSet().add(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString());
}
} else {
// 4、如果已點(diǎn)贊,取消點(diǎn)贊
// 4.1、數(shù)據(jù)庫(kù)點(diǎn)贊數(shù) -1
boolean isSuccess = update().setSql("liked = liked - 1").eq("id", id).update();
// 4.2、把用戶從 Redis 的 set 集合移除
if(isSuccess){
stringRedisTemplate.opsForSet().remove(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString());
}
}
return Result.ok();
}
private void queryBlogUser(Blog blog) {
Long userId = blog.getUserId();
User user = userService.getById(userId);
blog.setName(user.getNickName());
blog.setIcon(user.getIcon());
}
@Override
public Result queryBlogById(String id) {
Blog blog = getById(id);
if(blog == null){
return Result.fail("筆記不存在!");
}
queryBlogUser(blog);
// 查詢 Blog 是否被點(diǎn)贊
isBlogLiked(blog);
return Result.ok(blog);
}
private void isBlogLiked(Blog blog) {
Long userId = blog.getUserId();
String key = RedisConstants.BLOG_LIKED_KEY + blog.getId();
Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, userId.toString());
blog.setIsLike(BooleanUtil.isTrue(isMember));
}
}四、點(diǎn)贊排行榜

查出給這個(gè)筆記點(diǎn)贊的人,類似微信朋友圈的點(diǎn)贊,可以展示誰(shuí)點(diǎn)贊了,而且我們要進(jìn)行排序
所以我們得用SortedSet這種數(shù)據(jù)類型
1、修改點(diǎn)贊邏輯
把原本存入set改為存入zset多加個(gè)分?jǐn)?shù),分?jǐn)?shù)就是時(shí)間戳
@Override
public Result likeBlog(Long id) {
// 1、獲取登錄用戶
UserDTO user = UserHolder.getUser();
// 2、判斷當(dāng)前登錄用戶是否已經(jīng)點(diǎn)贊
Double score = stringRedisTemplate.opsForZSet().score(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString());
if(score == null) {
// 3、如果未點(diǎn)贊,可以點(diǎn)贊
// 3.1、數(shù)據(jù)庫(kù)點(diǎn)贊數(shù) +1
boolean isSuccess = update().setSql("liked = liked+1").eq("id", id).update();
// 3.2、保存用戶到 Redis 的 set 集合
if(isSuccess){
// 時(shí)間作為 key 的 score
stringRedisTemplate.opsForZSet().add(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString(), System.currentTimeMillis());
}
} else {
// 4、如果已點(diǎn)贊,取消點(diǎn)贊
// 4.1、數(shù)據(jù)庫(kù)點(diǎn)贊數(shù) -1
boolean isSuccess = update().setSql("liked = liked - 1").eq("id", id).update();
// 4.2、把用戶從 Redis 的 set 集合移除
if(isSuccess){
stringRedisTemplate.opsForZSet().remove(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString());
}
}
return Result.ok();
}然后是否被點(diǎn)贊的方法也要修改,根據(jù)key取出分?jǐn)?shù),分?jǐn)?shù)不為null就是點(diǎn)贊過(guò)了
private void isBlogLiked(Blog blog) {
UserDTO user = UserHolder.getUser();
if(user == null){
return;
}
Long userId = user.getId();
String key = RedisConstants.BLOG_LIKED_KEY + blog.getId();
Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());
blog.setIsLike(score != null);
}2、點(diǎn)贊排行榜功能
需求:實(shí)現(xiàn)前五個(gè)點(diǎn)贊的用戶返回
我們先用動(dòng)態(tài)id去redis中查詢出前五個(gè)點(diǎn)贊用戶的id
然后根據(jù)id去數(shù)據(jù)庫(kù)中查詢信息封裝到dto再返回
@GetMapping("/likes/{id}")
public Result queryBlogLikes(@PathVariable("id") String id) {
return blogService.queryBlogLikes(id);
} @Override
public Result queryBlogLikes(String id) {
String key = RedisConstants.BLOG_LIKED_KEY + id;
// 查詢 top5 的點(diǎn)贊用戶
Set<String> top5 = stringRedisTemplate.opsForZSet().range(key, 0, 4);
if(top5 == null){
return Result.ok(Collections.emptyList());
}
// 解析出其中的用戶id
List<Long> ids = top5.stream().map(Long::valueOf).collect(Collectors.toList());
String join = StrUtil.join(",", ids);
// 根據(jù)用戶id查詢用戶
List<UserDTO> userDTOS = userService.query().in("id", ids).last("order by filed(id, "+join+")").list()
.stream()
.map(user -> BeanUtil.copyProperties(user, UserDTO.class))
.collect(Collectors.toList());
return Result.ok(userDTOS);
}注意:如果我們mp直接用in來(lái)查詢根本不能保證點(diǎn)贊的順序,因?yàn)閕n查詢出來(lái)的是按照id順序返回的,沒(méi)有排序,我們要按照查詢id的順序來(lái)查,order by field(id,5,1)這樣
到此這篇關(guān)于Redis筆記點(diǎn)贊排行榜的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Redis筆記點(diǎn)贊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis實(shí)現(xiàn)會(huì)話管理和token認(rèn)證的示例代碼
會(huì)話管理和身份認(rèn)證是實(shí)現(xiàn)用戶登錄、權(quán)限管理等功能的基礎(chǔ),本文主就來(lái)介紹一下Redis實(shí)現(xiàn)會(huì)話管理和token認(rèn)證的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下2025-04-04
redis實(shí)現(xiàn)分布式session的解決方案
session存放在服務(wù)器,關(guān)閉瀏覽器不會(huì)失效,本文主要介紹了redis實(shí)現(xiàn)分布式session的解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
redis+mysql+quartz 一種紅包發(fā)送功能的實(shí)現(xiàn)
這篇文章主要介紹了redis+mysql+quartz 一種紅包發(fā)送功能的實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-01-01
redis和rabbitmq實(shí)現(xiàn)延時(shí)隊(duì)列的示例代碼
在高并發(fā)場(chǎng)景下,延遲隊(duì)列顯得尤為重要,本文主要介紹了兩種方式,redis和rabbitmq實(shí)現(xiàn)延時(shí)隊(duì)列,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03
詳解如何利用Redis實(shí)現(xiàn)生成唯一ID
隨著下單流量逐漸上升,為了降低數(shù)據(jù)庫(kù)的訪問(wèn)壓力,需要通過(guò)請(qǐng)求唯一ID+redis分布式鎖來(lái)防止接口重復(fù)提交。今天我們就一起來(lái)看探討一下,如何通過(guò)服務(wù)端來(lái)完成請(qǐng)求唯一?ID?的生成2022-11-11
Redis主從復(fù)制問(wèn)題和擴(kuò)容問(wèn)題的解決思路
這篇文章主要介紹了Redis主從復(fù)制問(wèn)題和擴(kuò)容問(wèn)題的解決思路,其中擴(kuò)容問(wèn)題的解決思路來(lái)自Redis作者,需要的朋友可以參考下2014-06-06
Redis與MySQL數(shù)據(jù)一致性問(wèn)題的策略模式及解決方案
開(kāi)發(fā)中,一般會(huì)使用Redis緩存一些常用的熱點(diǎn)數(shù)據(jù)用來(lái)減少數(shù)據(jù)庫(kù)IO,提高系統(tǒng)的吞吐量,本文將給大家介紹了Redis與MySQL數(shù)據(jù)一致性問(wèn)題的策略模式及解決方案,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2024-07-07
淺析redis cluster介紹與gossip協(xié)議
這篇文章主要介紹了redis cluster介紹與gossip協(xié)議,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09

