# 我收到的赞 --- - 重构点赞功能(使用 Redis 进行事务管理) - 以用户为 key,查询点赞数量 - increment(key) / decrement(key) > 注意 Redis 的事务管理中不要写查询语句,因为 Redis 会把事务存放在队列中,只有当事务提交之后才会进行统一的提交。 - 开发个人主页 ## 工具类 在生成 Redis 的 key 工具类中添加一个被赞用户的 key ```java /** * 生成 Redis 的 key */ public class RedisKeyUtil { private static final String SPLIT = ":"; private static final String PREFIX_ENTITY_LIKE = "like:entity"; private static final String PREFIX_USER_LIKE = "like:user"; // 某个实体(帖子、评论/回复)的赞 // like:entity:entityType:entityId -> set(userId) // 谁给这个实体点了赞,就将这个用户的id存到这个实体对应的集合里 public static String getEntityLikeKey(int entityType, int entityId) { return PREFIX_ENTITY_LIKE + SPLIT + entityType + SPLIT + entityId; } // 某个用户的赞(被赞) // like:user:userId -> int public static String getUserLikeKey(int userId) { return PREFIX_USER_LIKE + SPLIT + userId; } } ``` ## Service 重构点赞方法,将被赞的帖子/评论的作者信息添加进去 ```java /** * 点赞 * @param userId 点赞的用户 id * @param entityType * @param entityId * @param entityUserId 被赞的帖子/评论的作者 id */ public void like(int userId, int entityType, int entityId, int entityUserId) { redisTemplate.execute(new SessionCallback() { @Override public Object execute(RedisOperations redisOperations) throws DataAccessException { String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId); String userLikeKey = RedisKeyUtil.getUserLikeKey(entityUserId); // 判断用户是否已经点过赞了 boolean isMember = redisOperations.opsForSet().isMember(entityLikeKey, userId); redisOperations.multi(); // 开启事务 if (isMember) { // 如果用户已经点过赞,点第二次则取消赞 redisOperations.opsForSet().remove(entityLikeKey, userId); redisOperations.opsForValue().decrement(userLikeKey); } else { redisTemplate.opsForSet().add(entityLikeKey, userId); redisOperations.opsForValue().increment(userLikeKey); } return redisOperations.exec(); // 提交事务 } }); } ``` ```java /** * 查询某个用户获得赞数量 * @param userId * @return */ public int findUserLikeCount(int userId) { String userLikeKey = RedisKeyUtil.getUserLikeKey(userId); Integer count = (Integer) redisTemplate.opsForValue().get(userLikeKey); return count == null ? 0 : count; } ``` ## Controller 添加一个被赞帖子/评论的作者 id 即可: ```java /** * 点赞 * @param entityType * @param entityId * @param entityUserId 赞的帖子/评论的作者 id * @return */ @PostMapping("/like") @ResponseBody public String like(int entityType, int entityId, int entityUserId) { User user = hostHolder.getUser(); // 点赞 likeService.like(user.getId(), entityType, entityId, entityUserId); // 点赞数量 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); } ``` ## 前端 添加一个被赞帖子/评论的作者 id 即可 ```java ``` 修改对应的 `discuss.js` ```js function like(btn, entityType, entityId, entityUserId) { $.post( CONTEXT_PATH + "/like", {"entityType":entityType, "entityId":entityId, "entityUserId":entityUserId}, 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); } } ) } ``` 修改前端用户头像的链接 ```html 用户头像 ```