基于数据库
表
1 2 3 4 5 6 7 8 9 10 11
| CREATE TABLE IF NOT EXISTS `liked_record` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键id', `user_id` bigint NOT NULL COMMENT '用户id', `biz_id` bigint NOT NULL COMMENT '点赞的业务id', `biz_type` VARCHAR(16) NOT NULL COMMENT '点赞的业务类型', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `idx_biz_user` (`biz_id`,`user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='点赞记录表';
|
图

controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package com.orchids.likepointbyset.web.controller;
import com.orchids.likepointbyset.web.domain.dto.LikeRecordFormDTO; import com.orchids.likepointbyset.web.domain.po.LikedRecord; import com.orchids.likepointbyset.web.domain.result.Result; import com.orchids.likepointbyset.web.domain.vo.LikedRecordVo; import com.orchids.likepointbyset.web.service.ILikedRecordService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
@RestController @RequiredArgsConstructor @RequestMapping("/likes") @Api(tags = "基于数据库的点赞点赞业务相关接口") public class LikedRecordController { private final ILikedRecordService likedRecordService; @PostMapping("points") @ApiOperation("点赞或取消点赞") public Result<LikedRecordVo> addLIkeRecord(@Validated @RequestBody LikeRecordFormDTO recordDTO){
LikedRecordVo record = likedRecordService.addLIkeRecord(recordDTO); return Result.ok(record);
} }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com.orchids.likepointbyset.web.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.orchids.likepointbyset.web.domain.dto.LikeRecordFormDTO; import com.orchids.likepointbyset.web.domain.po.LikedRecord; import com.orchids.likepointbyset.web.domain.result.Result; import com.orchids.likepointbyset.web.domain.vo.LikedRecordVo;
public interface ILikedRecordService extends IService<LikedRecord> {
LikedRecordVo addLIkeRecord(LikeRecordFormDTO recordDTO); }
|
service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| package com.orchids.likepointbyset.web.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.orchids.likepointbyset.web.domain.dto.LikeRecordFormDTO; import com.orchids.likepointbyset.web.domain.po.LikedRecord; import com.orchids.likepointbyset.web.domain.vo.LikedRecordVo; import com.orchids.likepointbyset.web.exception.SignException; import com.orchids.likepointbyset.web.mapper.LikedRecordMapper; import com.orchids.likepointbyset.web.service.ILikedRecordService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service;
@Service public class LikedRecordServiceImpl extends ServiceImpl<LikedRecordMapper, LikedRecord> implements ILikedRecordService {
@Override public LikedRecordVo addLIkeRecord(LikeRecordFormDTO recordDTO) { boolean success = recordDTO.getLiked()?like(recordDTO):unlike(recordDTO); if (!success){ throw new SignException("亲!业务失败了 >︿< 马上好",500); } Long likePoints = lambdaQuery().eq(LikedRecord::getBizId, recordDTO.getBizId()).count(); LikedRecordVo result = new LikedRecordVo(); result.setBizId(recordDTO.getBizId()); result.setLikeCount(likePoints.intValue()); return result; }
private boolean like(LikeRecordFormDTO recordDTO) { Long userId = 138888L; Long count = lambdaQuery() .eq(LikedRecord::getUserId, userId) .eq(LikedRecord::getBizId, recordDTO.getBizId()).count(); if (count>0){ return false; } LikedRecord record = new LikedRecord(); record.setUserId(userId); record.setBizId(recordDTO.getBizId()); record.setBizType(recordDTO.getBizType()); boolean save = save(record); return save; } private boolean unlike(LikeRecordFormDTO recordDTO) { Long userId = 138888L; LambdaQueryWrapper<LikedRecord> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(LikedRecord::getUserId,userId).eq(LikedRecord::getBizId,recordDTO.getBizId()); boolean remove = remove(wrapper); return remove; } }
|
测试结果





基于redis set
使用redis set 先缓存点赞数据然后使用定时任务批量保存点赞数据 key 为业务id value 为点赞用户的id
使用set中的 size方法统计一条评论的点赞总数
使用zset对每一条评论的点赞数进行排序
配合定时任务定时更新评论区点赞数
controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package com.orchids.likepointbyset.web.controller;
import com.orchids.likepointbyset.web.domain.dto.LikeRecordFormDTO; import com.orchids.likepointbyset.web.domain.po.LikedRecord; import com.orchids.likepointbyset.web.domain.result.Result; import com.orchids.likepointbyset.web.domain.vo.LikedRecordVo; import com.orchids.likepointbyset.web.service.ILikedRecordService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
@RestController @RequiredArgsConstructor @RequestMapping("/likes") @Api(tags = "基于数据库的点赞点赞业务相关接口") public class LikedRecordController { private final ILikedRecordService likedRecordService; @PostMapping("points") @ApiOperation("点赞或取消点赞") public Result<LikedRecordVo> addLIkeRecord(@Validated @RequestBody LikeRecordFormDTO recordDTO){
LikedRecordVo record = likedRecordService.addLIkeRecord(recordDTO); return Result.ok(record);
} }
|
service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.orchids.likepointbyset.web.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.orchids.likepointbyset.web.domain.dto.LikeRecordFormDTO; import com.orchids.likepointbyset.web.domain.po.LikedRecord; import com.orchids.likepointbyset.web.domain.result.Result; import com.orchids.likepointbyset.web.domain.vo.LikedRecordVo;
public interface ILikedRecordService extends IService<LikedRecord> {
LikedRecordVo addLIkeRecord(LikeRecordFormDTO recordDTO);
void readLikedTimesAndSendMessage(String bizType, int maxBizSize); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
| package com.orchids.likepointbyset.web.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.orchids.likepointbyset.web.domain.dto.LikeRecordFormDTO; import com.orchids.likepointbyset.web.domain.dto.LikedTimesDTO; import com.orchids.likepointbyset.web.domain.po.LikedRecord; import com.orchids.likepointbyset.web.domain.vo.LikedRecordVo; import com.orchids.likepointbyset.web.exception.SignException; import com.orchids.likepointbyset.web.mapper.LikedRecordMapper; import com.orchids.likepointbyset.web.service.ILikedRecordService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ZSetOperations; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils;
import java.util.ArrayList; import java.util.Set;
@Slf4j @Service @RequiredArgsConstructor public class LikedRecordRedisServiceImpl extends ServiceImpl<LikedRecordMapper, LikedRecord> implements ILikedRecordService { private final StringRedisTemplate redisTemplate; private final String LIKE_SET_BIZ = "like:set:biz"; private final String LIKE_SET_BIZ_SUM = "like:set:biz:type"; private final String LIKE_RECORD_EXCHANGE = "like.record.topic"; private final String LIKED_TIMES_KEY_TEMPLATE = "qa.times.changed"; private final RabbitTemplate rabbitTemplate;
@Override public LikedRecordVo addLIkeRecord(LikeRecordFormDTO recordDTO) { boolean success = recordDTO.getLiked() ? like(recordDTO) : unlike(recordDTO); if (!success){ throw new SignException("亲!业务失败了 >︿< 马上好",500); } Long likeCount = redisTemplate.opsForSet().size(LIKE_SET_BIZ + recordDTO.getBizId()); if (likeCount == null){ throw new SignException("亲 该评论还未被点赞过急需 您的点赞(✿◡‿◡)",203); } Boolean add = redisTemplate.opsForZSet().add(LIKE_SET_BIZ_SUM +":"+ recordDTO.getBizType(), recordDTO.getBizId().toString(), likeCount); LikedRecordVo result = new LikedRecordVo(); result.setBizId(recordDTO.getBizId()); result.setLikeCount(likeCount.intValue()); return result; }
@Override public void readLikedTimesAndSendMessage(String bizType, int maxBizSize) { String key = LIKE_SET_BIZ_SUM + bizType; Set<ZSetOperations.TypedTuple<String>> tuples = redisTemplate.opsForZSet().popMin(key, maxBizSize); if (CollectionUtils.isEmpty(tuples)){ return; } ArrayList<LikedTimesDTO> list = new ArrayList<>(tuples.size()); for (ZSetOperations.TypedTuple<String> tuple : tuples) { LikedTimesDTO dto = new LikedTimesDTO(); String bizId = tuple.getValue(); Double likeCount = tuple.getScore(); if (bizId==null||likeCount==null){ continue; } dto.setBizId(Long.valueOf(bizId)); dto.setLikedCounts(likeCount.intValue()); list.add(dto); } log.error("评论区点赞数据{}",list); if (!CollectionUtils.isEmpty(list)) { rabbitTemplate.convertAndSend(LIKE_RECORD_EXCHANGE, LIKED_TIMES_KEY_TEMPLATE, list); } };
private boolean like(LikeRecordFormDTO recordDTO) { Long userId = 138888L; String key = LIKE_SET_BIZ + recordDTO.getBizId(); Long result = redisTemplate.opsForSet().add(key, userId.toString()); return result !=null && result > 0; }
private boolean unlike(LikeRecordFormDTO recordDTO) { Long userId = 138888L; String key = LIKE_SET_BIZ + recordDTO.getBizId(); Long result = redisTemplate.opsForSet().remove(key, userId.toString()); return result !=null && result > 0; }
}
|
其他类
定时任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.orchids.likepointbyset.web.task;
import com.orchids.likepointbyset.web.service.ILikedRecordService; import lombok.RequiredArgsConstructor; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component;
import java.util.Arrays; import java.util.List;
@Component @RequiredArgsConstructor public class TimesCheckLikedTask { private final ILikedRecordService recordService; private static final List<String> BIZ_TYPES = Arrays.asList("QA","NOTE"); private static final int MAX_BIZ_SIZE = 30;
@Scheduled(cron = "5 * * * * *") public void TimesCheckLiked(){ for (String bizType : BIZ_TYPES) { recordService.readLikedTimesAndSendMessage(bizType, MAX_BIZ_SIZE); } } }
|
启动类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package com.orchids.likepointbyset;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling @SpringBootApplication @ComponentScan(basePackages = "com.orchids.likepointbyset.web") public class LikepointbyzsetApplication {
public static void main(String[] args) { SpringApplication.run(LikepointbyzsetApplication.class, args); }
}
|
测试因为要写其他业务就算了 思想理解了 就行