Echo/docs/210-关注列表和粉丝列表.md
2021-01-28 22:09:02 +08:00

5.6 KiB

关注列表、粉丝列表


业务层:

  • 查询某个用户关注的人,支持分页
  • 查询某个用户的粉丝,支持分页

表现层:

  • 处理 “查询关注的人”、“查询粉丝” 的请求
  • 编写 “查询关注的人”、“查询粉丝” 模板

Service

/**
 * 分页查询某个用户关注的人(偷个懒,此处没有做对其他实体的关注)
 * @param userId
 * @param offset
 * @param limit
 * @return
 */
public List<Map<String, Object>> findFollowees(int userId, int offset, int limit) {
    String followeeKey = RedisKeyUtil.getFolloweeKey(userId, ENTITY_TYPE_USER);
    Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followeeKey, offset, offset + limit - 1);
    if (targetIds == null) {
        return null;
    }
    List<Map<String, Object>> list = new ArrayList<>();
    for (Integer targetId : targetIds) {
        Map<String, Object> map = new HashMap<>();

        User user = userService.findUserById(targetId);
        map.put("user", user);
        Double score = redisTemplate.opsForZSet().score(followeeKey, targetId);
        map.put("followTime", new Date(score.longValue()));

        list.add(map);
    }

    return list;
}

/**
 * 分页查询某个用户的粉丝(偷个懒,此处没有做对其他实体的粉丝)
 * @param userId
 * @param offset
 * @param limit
 * @return
 */
public List<Map<String, Object>> findFollowers(int userId, int offset, int limit) {
    String followerKey = RedisKeyUtil.getFollowerKey(ENTITY_TYPE_USER, userId);
    Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followerKey, offset, offset + limit - 1);
    if (targetIds == null) {
        return null;
    }
    List<Map<String, Object>> list = new ArrayList<>();
    for (Integer targetId : targetIds) {
        Map<String, Object> map = new HashMap<>();

        User user = userService.findUserById(targetId);
        map.put("user", user);
        Double score = redisTemplate.opsForZSet().score(followerKey, targetId);
        map.put("followTime", new Date(score.longValue()));

        list.add(map);
    }

    return list;

}

Controller

/**
 * 某个用户的关注列表(人)
 * @param userId
 * @param page
 * @param model
 * @return
 */
@GetMapping("/followees/{userId}")
public String getFollowees(@PathVariable("userId") int userId, Page page, Model model) {
    User user = userService.findUserById(userId);
    if (user == null) {
        throw new RuntimeException("该用户不存在");
    }
    model.addAttribute("user", user);

    page.setLimit(5);
    page.setPath("/followees/" + userId);
    page.setRows((int) followService.findFolloweeCount(userId, ENTITY_TYPE_USER));

    // 获取关注列表
    List<Map<String, Object>> userList = followService.findFollowees(userId, page.getOffset(), page.getLimit());

    if (userList != null) {
        for (Map<String, Object> map : userList) {
            User u = (User) map.get("user"); // 被关注的用户
            map.put("hasFollowed", hasFollowed(u.getId())); // 判断当前登录用户是否已关注这个关注列表中的某个用户
        }
    }

    model.addAttribute("users", userList);

    return "/site/followee";
}

/**
 * 某个用户的粉丝列表
 * @param userId
 * @param page
 * @param model
 * @return
 */
@GetMapping("/followers/{userId}")
public String getFollowers(@PathVariable("userId") int userId, Page page, Model model) {
    User user = userService.findUserById(userId);
    if (user == null) {
        throw new RuntimeException("该用户不存在");
    }
    model.addAttribute("user", user);

    page.setLimit(5);
    page.setPath("/followers/" + userId);
    page.setRows((int) followService.findFollowerCount(ENTITY_TYPE_USER, userId));

    // 获取关注列表
    List<Map<String, Object>> userList = followService.findFollowers(userId, page.getOffset(), page.getLimit());

    if (userList != null) {
        for (Map<String, Object> map : userList) {
            User u = (User) map.get("user"); // 被关注的用户
            map.put("hasFollowed", hasFollowed(u.getId())); // 判断当前登录用户是否已关注这个关注列表中的某个用户
        }
    }

    model.addAttribute("users", userList);

    return "/site/follower";
}

/**
 * 判断当前登录用户是否已关注某个用户
 * @param userId 某个用户
 * @return
 */
private boolean hasFollowed(int userId) {
    if (hostHolder.getUser() == null) {
        return false;
    }

    return followService.hasFollowed(hostHolder.getUser().getId(), ENTITY_TYPE_USER, userId);
}

前端

<a th:href="@{|/followees/${user.id}|}" >
      关注了 <span th:text="${followeeCount}"></span></a>
<a th:href="@{|/followers/${user.id}|}">
      关注者 <span th:text="${followerCount}"></span></a>

对应的关注界面 followee.html 和粉丝界面 follower.html,以 followee.html 为例:

<li th:each="map:${users}">
    <a th:href="@{|/user/profile/${map.user.id}|}">
        <img th:src="${map.user.headerUrl}" alt="用户头像" >
    </a>
    
    <span th:text="${map.user.username}"></span>
    <span >
        关注于 <i th:text="${#dates.format(map.followTime, 'yyyy-MM-dd HH:mm:ss')}"></i></span>
        
       
    <input type="hidden" id="entityId" th:value="${map.user.id}">
    <button type="button" th:class="|btn ${map.hasFollowed ? 'btn-secondary' : 'btn-info'} btn-sm float-right mr-5 follow-btn|"
            th:text="${map.hasFollowed ? '已关注' : '关注TA'}"
            th:if="${loginUser!=null && loginUser.id!=map.user.id}"></button>
    </div>
</li>