Echo/docs/180-点赞.md
2021-01-28 22:09:02 +08:00

227 lines
6.1 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.

# 点赞
---
点赞:
- 支持对帖子、评论/回复点赞
- 第 1 次点赞,第 2 次取消点赞
- 首页统计帖子的点赞数量
- 详情页统计帖子和评论/回复的点赞数量
- 详情页显示用户的点赞状态(赞过了则显示已赞)
> Redis 一般不用 DAO 层,不像 MySQL
## 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);
```