225 lines
6.0 KiB
Markdown
225 lines
6.0 KiB
Markdown
![]() |
# 点赞
|
|||
|
|
|||
|
---
|
|||
|
|
|||
|
点赞:
|
|||
|
|
|||
|
- 支持对帖子、评论/回复点赞
|
|||
|
- 第 1 次点赞,第 2 次取消点赞
|
|||
|
- 首页统计帖子的点赞数量
|
|||
|
- 详情页统计帖子和评论/回复的点赞数量
|
|||
|
- 详情页显示用户的点赞状态(赞过了则显示已赞)
|
|||
|
|
|||
|
## Redis 配置
|
|||
|
|
|||
|
导包、配置端口等
|
|||
|
|
|||
|
```properties
|
|||
|
# Redis
|
|||
|
spring.redis.database = 11
|
|||
|
spring.redis.host = localhost
|
|||
|
spring.redis.port = 6379
|
|||
|
```
|
|||
|
|
|||
|
Redis 配置类
|
|||
|
|
|||
|
```java
|
|||
|
/**
|
|||
|
* Redis 配置类
|
|||
|
*/
|
|||
|
@Configuration
|
|||
|
public class RedisConfig {
|
|||
|
|
|||
|
@Bean
|
|||
|
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
|
|||
|
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
|||
|
template.setConnectionFactory(factory);
|
|||
|
|
|||
|
// 设置 key 的序列化的方式
|
|||
|
template.setKeySerializer(RedisSerializer.string());
|
|||
|
// 设置 value 的序列化的方式
|
|||
|
template.setValueSerializer(RedisSerializer.json());
|
|||
|
// 设置 hash 的 key 的序列化的方式
|
|||
|
template.setHashKeySerializer(RedisSerializer.string());
|
|||
|
// 设置 hash 的 value 的序列化的方式
|
|||
|
template.setHashValueSerializer(RedisSerializer.json());
|
|||
|
|
|||
|
template.afterPropertiesSet();
|
|||
|
|
|||
|
return template;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
动态生成 Redis 的 key:
|
|||
|
|
|||
|
我们将点赞相关信息存入 set 中。其中,key 命名为 `like:entity:entityType:entityId`,value 即存储点赞用户的 id。比如 key = `like:entity:2:246` value = `11` 表示用户 11 对实体类型 2 即评论进行了点赞,该评论的 id 是 246
|
|||
|
|
|||
|
```java
|
|||
|
/**
|
|||
|
* 生成 Redis 的 key
|
|||
|
*/
|
|||
|
public class RedisKeyUtil {
|
|||
|
|
|||
|
private static final String SPLIT = ":";
|
|||
|
private static final String PREFIX_ENTITY_LIKE = "like:entity";
|
|||
|
|
|||
|
// 某个实体(帖子、评论/回复)的赞
|
|||
|
// like:entity:entityType:entityId -> set(userId)
|
|||
|
// 谁给这个实体点了赞,就将这个用户的id存到这个实体对应的集合里
|
|||
|
public static String getEntityLikeKey(int entityType, int entityId) {
|
|||
|
return PREFIX_ENTITY_LIKE + SPLIT + entityType + SPLIT + entityId;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
## Service
|
|||
|
|
|||
|
```java
|
|||
|
/**
|
|||
|
* 点赞相关
|
|||
|
*/
|
|||
|
@Service
|
|||
|
public class LikeService {
|
|||
|
|
|||
|
@Autowired
|
|||
|
private RedisTemplate redisTemplate;
|
|||
|
|
|||
|
/**
|
|||
|
* 点赞
|
|||
|
* @param userId
|
|||
|
* @param entityType
|
|||
|
* @param entityId
|
|||
|
*/
|
|||
|
public void like(int userId, int entityType, int entityId) {
|
|||
|
String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);
|
|||
|
// 判断用户是否已经点过赞了
|
|||
|
boolean isMember = redisTemplate.opsForSet().isMember(entityLikeKey, userId);
|
|||
|
if (isMember) {
|
|||
|
// 如果用户已经点过赞,点第二次则取消赞
|
|||
|
redisTemplate.opsForSet().remove(entityLikeKey, userId);
|
|||
|
}
|
|||
|
else {
|
|||
|
redisTemplate.opsForSet().add(entityLikeKey, userId);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 查询某实体被点赞的数量
|
|||
|
* @param entityType
|
|||
|
* @param entityId
|
|||
|
* @return
|
|||
|
*/
|
|||
|
public long findEntityLikeCount(int entityType, int entityId) {
|
|||
|
String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);
|
|||
|
return redisTemplate.opsForSet().size(entityLikeKey);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 查询某个用户对某个实体的点赞状态(是否已赞)
|
|||
|
* @param userId
|
|||
|
* @param entityType
|
|||
|
* @param entityId
|
|||
|
* @return 1:已赞,0:未赞
|
|||
|
*/
|
|||
|
public int findEntityLikeStatus(int userId, int entityType, int entityId) {
|
|||
|
String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);
|
|||
|
return redisTemplate.opsForSet().isMember(entityLikeKey, userId) ? 1 : 0;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
## 表现层(Controller 和前端)
|
|||
|
|
|||
|
在首页进行查询的时候,添加对帖子点赞数量查询
|
|||
|
|
|||
|
`HomeController`
|
|||
|
|
|||
|
```java
|
|||
|
long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, post.getId());
|
|||
|
map.put("likeCount", likeCount);
|
|||
|
```
|
|||
|
|
|||
|
在消息列表进行查询的时候,添加点赞功能,并对帖子、评论的点赞数量以及目前登录用户的点赞状态进行查询
|
|||
|
|
|||
|
`LikeController`
|
|||
|
|
|||
|
```java
|
|||
|
/**
|
|||
|
* 点赞
|
|||
|
*/
|
|||
|
@Controller
|
|||
|
public class LikeController {
|
|||
|
|
|||
|
@Autowired
|
|||
|
private HostHolder hostHolder;
|
|||
|
|
|||
|
@Autowired
|
|||
|
private LikeService likeService;
|
|||
|
|
|||
|
@PostMapping("/like")
|
|||
|
@ResponseBody
|
|||
|
public String like(int entityType, int entityId) {
|
|||
|
User user = hostHolder.getUser();
|
|||
|
// 点赞
|
|||
|
likeService.like(user.getId(), entityType, entityId);
|
|||
|
// 点赞数量
|
|||
|
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);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
前端消息列表界面 `discuss-detail.html`:
|
|||
|
|
|||
|
```html
|
|||
|
<a href="javascript:;" th:onclick="|like(this, 1, ${post.id});|" class="text-primary">
|
|||
|
<b th:text="${likeStatus == 1 ? '已赞' : '赞'}"></b> <i th:text="${likeCount}"></i>
|
|||
|
</a>
|
|||
|
```
|
|||
|
|
|||
|
对应的 `discuss.js`
|
|||
|
|
|||
|
```java
|
|||
|
function like(btn, entityType, entityId) {
|
|||
|
$.post(
|
|||
|
CONTEXT_PATH + "/like",
|
|||
|
{"entityType":entityType, "entityId":entityId},
|
|||
|
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);
|
|||
|
}
|
|||
|
}
|
|||
|
)
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
对应的 `DiscussPostController` :
|
|||
|
|
|||
|
```java
|
|||
|
// 点赞数量
|
|||
|
long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, discussPostId);
|
|||
|
model.addAttribute("likeCount", likeCount);
|
|||
|
// 当前登录用户的点赞状态
|
|||
|
int likeStatus = hostHolder.getUser() == null ? 0 :
|
|||
|
likeService.findEntityLikeStatus(hostHolder.getUser().getId(), ENTITY_TYPE_POST, discussPostId);
|
|||
|
model.addAttribute("likeStatus", likeStatus);
|
|||
|
```
|
|||
|
|