实现功能
业务层
- 查询某个用户关注的人,支持分页。
- 查询某个用户的粉丝,支持分页。
表现层
- 处理“查询关注的人”、“查询粉丝”请求。
- 编写“查询关注的人”、“查询粉丝”模板
controller
//用户关注的人
@RequestMapping(value = "/followees/{userId}",method = RequestMethod.GET)
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";
}
//用户的粉丝
@RequestMapping(value = "/followers/{userId}",method = RequestMethod.GET)
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";
}
//查看当前登录用户是否关注用户关注的人
private boolean hasFollowed(int userId){
if(hostHolder.getUser()==null){
return false;
}
return followService.hasFollowed(hostHolder.getUser().getId(),ENTITY_TYPE_USER,userId);
}
service
//查询实体关注的人
public List<Map<String,Object>> findFollowees(int userId,int offset,int limit){
//构造followeeKey
String followeeKey = RedisKeyUtil.getFolloweeKey(userId, ENTITY_TYPE_USER);
//找到关注的人的id列表---->倒叙显示
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<>();
//通过id查到对应用户
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;
}
//查询用户的粉丝
public List<Map<String,Object>> findFollowers(int userId,int offset,int limit){
//构造followerKey
String followerKey = RedisKeyUtil.getFollowerKey(ENTITY_TYPE_USER, userId);
//找到关注的人的id列表---->倒叙显示
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<>();
//通过id查到对应用户
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;
}
html
followee.html
<!-- 内容 -->
<div class="main">
<div class="container">
<div class="position-relative">
<!-- 选项 -->
<ul class="nav nav-tabs mb-3">
<li class="nav-item">
<a class="nav-link position-relative active" th:href="@{|/followees/${user.id}|}">
<i class="text-info" th:utext="${user.userName}">Nowcoder</i> 关注的人</a>
</li>
<li class="nav-item">
<a class="nav-link position-relative" th:href="@{|/followers/${user.id}|}">关注
<i class="text-info" th:utext="${user.userName}">Nowcoder</i> 的人</a>
</li>
</ul>
<a th:href="@{|/user/profile/${user.id}|}" class="text-muted position-absolute rt-0">返回个人主页></a>
</div>
<!-- 关注列表 -->
<ul class="list-unstyled">
<li class="media pb-3 pt-3 mb-3 border-bottom position-relative" th:each="map:${users}">
<a th:href="@{|/user/profile/${map.user.id}|}">
<img th:src="${map.user.headerUrl}" class="mr-4 rounded-circle user-header" alt="用户头像" >
</a>
<div class="media-body">
<h6 class="mt-0 mb-3">
<span class="text-success" th:utext="${map.user.userName}">落基山脉下的闲人</span>
<span class="float-right text-muted font-size-12">关注于
<i th:text="${#dates.format(map.followTime,'yyyy-MM-dd HH:mm:ss')}">2019-04-28 14:13:25</i></span>
</h6>
<div>
<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 follow-btn|"
th:if="${LoginUser!=null && LoginUser!=map.user.id}" th:text="${map.hasFollowed?'已关注':'关注TA'}">
关注TA
</button>
</div>
</div>
</li>
</ul>
follower.html
<!-- 内容 -->
<div class="main">
<div class="container">
<div class="position-relative">
<!-- 选项 -->
<ul class="nav nav-tabs mb-3">
<li class="nav-item">
<a class="nav-link position-relative" th:href="@{|/followees/${user.id}|}">
<i class="text-info" th:utext="${user.userName}">Nowcoder</i> 关注的人</a>
</li>
<li class="nav-item">
<a class="nav-link position-relative active" th:href="@{|/followers/${user.id}|}">
关注 <i class="text-info" th:utext="${user.userName}">Nowcoder</i> 的人</a>
</li>
</ul>
<a th:href="@{|/user/profile/${user.id}|}" class="text-muted position-absolute rt-0">返回个人主页></a>
</div>
<!-- 粉丝列表 -->
<ul class="list-unstyled">
<li class="media pb-3 pt-3 mb-3 border-bottom position-relative" th:each="map:${users}">
<a th:href="@{|/user/profile/${map.user.id}|}">
<img th:src="${map.user.headerUrl}" class="mr-4 rounded-circle user-header" alt="用户头像" >
</a>
<div class="media-body">
<h6 class="mt-0 mb-3">
<span class="text-success" th:utext="${map.user.userName}">落基山脉下的闲人</span>
<span class="float-right text-muted font-size-12">关注于
<i th:text="${#dates.format(map.followTime,'yyyy-MM-dd HH:mm:ss')}">2019-04-28 14:13:25</i></span>
</h6>
<div>
<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 follow-btn|"
th:text="${map.hasFollowed?'已关注':'关注TA'}" th:if="${LoginUser!=null&&LoginUser.id!=map.user.id}">
关注TA
</button>
</div>
</div>
</li>
</ul>
profile.html
<!-- 个人信息 -->
<div class="media mt-5">
<img th:src="${user.headerUrl}" class="align-self-start mr-4 rounded-circle" alt="用户头像" style="width:50px;">
<div class="media-body">
<h5 class="mt-0 text-warning">
<span th:utext="${user.userName}">nowcoder</span>
<input type="hidden" id="entityId" th:value="${user.id}">
<button type="button" th:class="|btn ${hasFollowed?'btn-secondary':'btn-info'} btn-sm float-right mr-5 follow-btn|"
th:text="${hasFollowed?'已关注':'关注TA'}" th:if="${LoginUser!=null&&LoginUser.id!=user.id}">关注TA</button>
</h5>
<div class="text-muted mt-3">
<span>注册于 <i class="text-muted" th:text="${#dates.format(user.createTime,'yyyy-MM-dd HH:mm:ss')}">2015-06-12 15:20:12</i></span>
</div>
<div class="text-muted mt-3 mb-5">
<span>关注了 <a class="text-primary"th:href="@{|/followees/${user.id}|}" th:text="${followeeCount}">5</a> 人</span>
<span class="ml-4">关注者 <a class="text-primary" th:href="@{|/followers/${user.id}|}" th:text="${followerCount}">123</a> 人</span>
<span class="ml-4">获得了 <i class="text-danger" th:text="${likeCount}">87</i> 个赞</span>
</div>
</div>
</div>