feat(note): 新增笔记删除功能
- 新增 DeleteNoteReqVO 请求参数类,用于接收笔记删除请求 - 在 NoteController 中添加 /delete 接口,实现笔记删除功能 - 在 NoteService 和 NoteServiceImpl 中实现 deleteNote 方法 - 删除笔记时进行权限校验,仅允许笔记创建者删除 - 删除操作为逻辑删除,更新笔记状态为已删除 - 删除笔记后清除 Redis 缓存,并通过 MQ 广播通知各实例清除本地缓存 -优化更新和可见性接口的权限校验逻辑,避免重复代码 - 添加 MQ 测试类 MQTests,用于批量发送关注/取关消息 - 引入 Guava 的 RateLimiter 实现 MQ 消费端限流- 配置 Nacos 配置中心依赖及动态刷新配置 - 更新 .gitignore 文件,忽略日志文件目录 - 在 application.yml 中添加 MQ 消费者限流配置项 - 在 bootstrap.yml 中完善 Nacos 配置中心相关配置 - 为 FollowUnfollowConsumer 添加限流逻辑,防止消费端压力过大
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
package com.hanserwei.hannote.user.relation.biz.config;
|
||||
|
||||
import com.google.common.util.concurrent.RateLimiter;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@RefreshScope
|
||||
public class FollowUnfollowMqConsumerRateLimitConfig {
|
||||
|
||||
@Value("${mq-consumer.follow-unfollow.rate-limit}")
|
||||
private double rateLimit;
|
||||
|
||||
@Bean
|
||||
@RefreshScope
|
||||
public RateLimiter rateLimiter() {
|
||||
return RateLimiter.create(rateLimit);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.hanserwei.hannote.user.relation.biz.consumer;
|
||||
|
||||
import com.google.common.util.concurrent.RateLimiter;
|
||||
import com.hanserwei.framework.common.utils.JsonUtils;
|
||||
import com.hanserwei.hannote.user.relation.biz.constant.MQConstants;
|
||||
import com.hanserwei.hannote.user.relation.biz.domain.dataobject.FansDO;
|
||||
@@ -7,6 +8,8 @@ import com.hanserwei.hannote.user.relation.biz.domain.dataobject.FollowingDO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.dto.FollowUserMqDTO;
|
||||
import com.hanserwei.hannote.user.relation.biz.service.FansDOService;
|
||||
import com.hanserwei.hannote.user.relation.biz.service.FollowingDOService;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.common.message.Message;
|
||||
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||
@@ -23,19 +26,19 @@ import java.util.Objects;
|
||||
topic = MQConstants.TOPIC_FOLLOW_OR_UNFOLLOW
|
||||
)
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class FollowUnfollowConsumer implements RocketMQListener<Message> {
|
||||
private final TransactionTemplate transactionTemplate;
|
||||
private final FollowingDOService followingDOService;
|
||||
private final FansDOService fansDOService;
|
||||
|
||||
public FollowUnfollowConsumer(TransactionTemplate transactionTemplate, FollowingDOService followingDOService, FansDOService fansDOService) {
|
||||
this.transactionTemplate = transactionTemplate;
|
||||
this.followingDOService = followingDOService;
|
||||
this.fansDOService = fansDOService;
|
||||
}
|
||||
@Resource
|
||||
private RateLimiter rateLimiter;
|
||||
|
||||
@Override
|
||||
public void onMessage(Message message) {
|
||||
// 流量削峰:通过获取令牌,如果没有令牌可用,将阻塞,直到获得
|
||||
rateLimiter.acquire();
|
||||
// 消息体
|
||||
String bodyJsonStr = new String(message.getBody());
|
||||
// 标签
|
||||
|
||||
@@ -28,4 +28,7 @@ mybatis-plus:
|
||||
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
|
||||
global-config:
|
||||
banner: false
|
||||
mapper-locations: classpath*:/mapperxml/*.xml
|
||||
mapper-locations: classpath*:/mapperxml/*.xml
|
||||
mq-consumer: # MQ 消费者
|
||||
follow-unfollow: # 关注、取关
|
||||
rate-limit: 5000 # 每秒限流阈值
|
||||
@@ -10,3 +10,10 @@ spring:
|
||||
group: DEFAULT_GROUP # 所属组
|
||||
namespace: han-note # 命名空间
|
||||
server-addr: 127.0.0.1:8848 # 指定 Nacos 配置中心的服务器地址
|
||||
config:
|
||||
server-addr: http://127.0.0.1:8848 # 指定 Nacos 配置中心的服务器地址
|
||||
prefix: ${spring.application.name} # 配置 Data Id 前缀,这里使用应用名称作为前缀
|
||||
group: DEFAULT_GROUP # 所属组
|
||||
namespace: han-note # 命名空间
|
||||
file-extension: yaml # 配置文件格式
|
||||
refresh-enabled: true # 是否开启动态刷新
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.hanserwei.hannote.user.relation.biz;
|
||||
|
||||
import com.hanserwei.framework.common.utils.JsonUtils;
|
||||
import com.hanserwei.hannote.user.relation.biz.constant.MQConstants;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.dto.FollowUserMqDTO;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.client.producer.SendCallback;
|
||||
import org.apache.rocketmq.client.producer.SendResult;
|
||||
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@SpringBootTest
|
||||
@Slf4j
|
||||
class MQTests {
|
||||
|
||||
@Resource
|
||||
private RocketMQTemplate rocketMQTemplate;
|
||||
|
||||
/**
|
||||
* 测试:发送一万条 MQ
|
||||
*/
|
||||
@Test
|
||||
void testBatchSendMQ() {
|
||||
for (long i = 0; i < 10000; i++) {
|
||||
// 构建消息体 DTO
|
||||
FollowUserMqDTO followUserMqDTO = FollowUserMqDTO.builder()
|
||||
.userId(i)
|
||||
.followUserId(i)
|
||||
.createTime(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
// 构建消息对象,并将 DTO 转成 Json 字符串设置到消息体中
|
||||
Message<String> message = MessageBuilder.withPayload(JsonUtils.toJsonString(followUserMqDTO))
|
||||
.build();
|
||||
|
||||
// 通过冒号连接, 可让 MQ 发送给主题 Topic 时,携带上标签 Tag
|
||||
String destination = MQConstants.TOPIC_FOLLOW_OR_UNFOLLOW + ":" + MQConstants.TAG_FOLLOW;
|
||||
|
||||
log.info("==> 开始发送关注操作 MQ, 消息体: {}", followUserMqDTO);
|
||||
|
||||
// 异步发送 MQ 消息,提升接口响应速度
|
||||
rocketMQTemplate.asyncSend(destination, message, new SendCallback() {
|
||||
@Override
|
||||
public void onSuccess(SendResult sendResult) {
|
||||
log.info("==> MQ 发送成功,SendResult: {}", sendResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Throwable throwable) {
|
||||
log.error("==> MQ 发送异常: ", throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user