Echo/docs/190-我收到的赞.md
2021-01-28 22:09:02 +08:00

4.7 KiB
Raw Blame History

我收到的赞


  • 重构点赞功能(使用 Redis 进行事务管理)

    - 以用户为 key查询点赞数量

    • increment(key) / decrement(key)

    注意 Redis 的事务管理中不要写查询语句,因为 Redis 会把事务存放在队列中,只有当事务提交之后才会进行统一的提交。

  • 开发个人主页

工具类

在生成 Redis 的 key 工具类中添加一个被赞用户的 key

/**
 * 生成 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

重构点赞方法,将被赞的帖子/评论的作者信息添加进去

/**
 * 点赞
 * @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(); // 提交事务
        }
    });
}
/**
 * 查询某个用户获得赞数量
 * @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 即可:

/**
 * 点赞
 * @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<String, Object> map = new HashMap<>();
    map.put("likeCount", likeCount);
    map.put("likeStatus", likeStatus);

    return CommunityUtil.getJSONString(0, null, map);
}

前端

添加一个被赞帖子/评论的作者 id 即可

<a href="javascript:;" th:onclick="|like(this, 1, ${post.id}, ${post.userId});|" class="text-primary">
	<b th:text="${likeStatus == 1 ? '已赞' : '赞'}"></b> <i th:text="${likeCount}"></i>
</a>

修改对应的 discuss.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);
            }

        }
    )
}

修改前端用户头像的链接

<a th:href="@{|/user/profile/${map.user.id}|}">
	<img th:src="${map.user.headerUrl}" class="mr-4 rounded-circle" alt="用户头像" style="width:50px;height:50px;">
</a>