2021-01-25 17:49:40 +08:00
|
|
|
|
# 我收到的赞
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
- 重构点赞功能(使用 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) {
|
2021-01-28 22:09:02 +08:00
|
|
|
|
return PREFIX_USER_LIKE + SPLIT + userId;
|
2021-01-25 17:49:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 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>
|
|
|
|
|
```
|
|
|
|
|
|