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

170 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 我收到的赞
---
- 重构点赞功能(使用 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<String, Object> map = new HashMap<>();
map.put("likeCount", likeCount);
map.put("likeStatus", likeStatus);
return CommunityUtil.getJSONString(0, null, map);
}
```
## 前端
添加一个被赞帖子/评论的作者 id 即可
```java
<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`
```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
<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>
```