193 lines
5.6 KiB
Markdown
193 lines
5.6 KiB
Markdown
# 关注列表、粉丝列表
|
|
|
|
---
|
|
|
|
业务层:
|
|
|
|
- 查询某个用户关注的人,支持分页
|
|
- 查询某个用户的粉丝,支持分页
|
|
|
|
表现层:
|
|
|
|
- 处理 “查询关注的人”、“查询粉丝” 的请求
|
|
- 编写 “查询关注的人”、“查询粉丝” 模板
|
|
|
|
## Service
|
|
|
|
```java
|
|
/**
|
|
* 分页查询某个用户关注的人(偷个懒,此处没有做对其他实体的关注)
|
|
* @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
|
|
|
|
```java
|
|
/**
|
|
* 某个用户的关注列表(人)
|
|
* @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);
|
|
}
|
|
```
|
|
|
|
## 前端
|
|
|
|
```html
|
|
<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` 为例:
|
|
|
|
```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>
|
|
```
|
|
|