# 点赞 --- 点赞: - 支持对帖子、评论/回复点赞 - 第 1 次点赞,第 2 次取消点赞 - 首页统计帖子的点赞数量 - 详情页统计帖子和评论/回复的点赞数量 - 详情页显示用户的点赞状态(赞过了则显示已赞) ## Redis 配置 导包、配置端口等 ```properties # Redis spring.redis.database = 11 spring.redis.host = localhost spring.redis.port = 6379 ``` Redis 配置类 ```java /** * Redis 配置类 */ @Configuration public class RedisConfig { @Bean public RedisTemplate redisTemplate(RedisConnectionFactory factory) { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(factory); // 设置 key 的序列化的方式 template.setKeySerializer(RedisSerializer.string()); // 设置 value 的序列化的方式 template.setValueSerializer(RedisSerializer.json()); // 设置 hash 的 key 的序列化的方式 template.setHashKeySerializer(RedisSerializer.string()); // 设置 hash 的 value 的序列化的方式 template.setHashValueSerializer(RedisSerializer.json()); template.afterPropertiesSet(); return template; } } ``` 动态生成 Redis 的 key: 我们将点赞相关信息存入 set 中。其中,key 命名为 `like:entity:entityType:entityId`,value 即存储点赞用户的 id。比如 key = `like:entity:2:246` value = `11` 表示用户 11 对实体类型 2 即评论进行了点赞,该评论的 id 是 246 ```java /** * 生成 Redis 的 key */ public class RedisKeyUtil { private static final String SPLIT = ":"; private static final String PREFIX_ENTITY_LIKE = "like:entity"; // 某个实体(帖子、评论/回复)的赞 // like:entity:entityType:entityId -> set(userId) // 谁给这个实体点了赞,就将这个用户的id存到这个实体对应的集合里 public static String getEntityLikeKey(int entityType, int entityId) { return PREFIX_ENTITY_LIKE + SPLIT + entityType + SPLIT + entityId; } } ``` ## Service ```java /** * 点赞相关 */ @Service public class LikeService { @Autowired private RedisTemplate redisTemplate; /** * 点赞 * @param userId * @param entityType * @param entityId */ public void like(int userId, int entityType, int entityId) { String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId); // 判断用户是否已经点过赞了 boolean isMember = redisTemplate.opsForSet().isMember(entityLikeKey, userId); if (isMember) { // 如果用户已经点过赞,点第二次则取消赞 redisTemplate.opsForSet().remove(entityLikeKey, userId); } else { redisTemplate.opsForSet().add(entityLikeKey, userId); } } /** * 查询某实体被点赞的数量 * @param entityType * @param entityId * @return */ public long findEntityLikeCount(int entityType, int entityId) { String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId); return redisTemplate.opsForSet().size(entityLikeKey); } /** * 查询某个用户对某个实体的点赞状态(是否已赞) * @param userId * @param entityType * @param entityId * @return 1:已赞,0:未赞 */ public int findEntityLikeStatus(int userId, int entityType, int entityId) { String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId); return redisTemplate.opsForSet().isMember(entityLikeKey, userId) ? 1 : 0; } } ``` ## 表现层(Controller 和前端) 在首页进行查询的时候,添加对帖子点赞数量查询 `HomeController` ```java long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, post.getId()); map.put("likeCount", likeCount); ``` 在消息列表进行查询的时候,添加点赞功能,并对帖子、评论的点赞数量以及目前登录用户的点赞状态进行查询 `LikeController` ```java /** * 点赞 */ @Controller public class LikeController { @Autowired private HostHolder hostHolder; @Autowired private LikeService likeService; @PostMapping("/like") @ResponseBody public String like(int entityType, int entityId) { User user = hostHolder.getUser(); // 点赞 likeService.like(user.getId(), entityType, entityId); // 点赞数量 long likeCount = likeService.findEntityLikeCount(entityType, entityId); // 点赞状态 int likeStatus = likeService.findEntityLikeStatus(user.getId(), entityType, entityId); Map map = new HashMap<>(); map.put("likeCount", likeCount); map.put("likeStatus", likeStatus); return CommunityUtil.getJSONString(0, null, map); } } ``` 前端消息列表界面 `discuss-detail.html`: ```html ``` 对应的 `discuss.js` ```java function like(btn, entityType, entityId) { $.post( CONTEXT_PATH + "/like", {"entityType":entityType, "entityId":entityId}, function(data) { data = $.parseJSON(data); if (data.code == 0) { $(btn).children("i").text(data.likeCount); $(btn).children("b").text(data.likeStatus == 1 ? '已赞' : '赞'); } else { alert(data.msg); } } ) } ``` 对应的 `DiscussPostController` : ```java // 点赞数量 long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, discussPostId); model.addAttribute("likeCount", likeCount); // 当前登录用户的点赞状态 int likeStatus = hostHolder.getUser() == null ? 0 : likeService.findEntityLikeStatus(hostHolder.getUser().getId(), ENTITY_TYPE_POST, discussPostId); model.addAttribute("likeStatus", likeStatus); ```