Compare commits
8 Commits
5e4f9b1203
...
c6ac7193c1
| Author | SHA1 | Date | |
|---|---|---|---|
| c6ac7193c1 | |||
| 31ab7c3d86 | |||
| e17ab857b9 | |||
| ee99654e7c | |||
| 3904e8510e | |||
| 893f52e5aa | |||
| 84d6914b1c | |||
| 9e3c35043e |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -51,3 +51,4 @@ build/
|
||||
/han-note-note/han-note-note-biz/src/main/resources/application-dev.yml
|
||||
/han-note-user-relation/han-note-user-relation-biz/src/main/resources/application-dev.yml
|
||||
/han-note-user-relation/han-note-user-relation-biz/logs/
|
||||
/han-note-count/han-note-count-biz/src/main/resources/application-dev.yml
|
||||
|
||||
6
.idea/encodings.xml
generated
6
.idea/encodings.xml
generated
@@ -3,6 +3,12 @@
|
||||
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
|
||||
<file url="file://$PROJECT_DIR$/han-note-auth/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/han-note-auth/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/han-note-count/han-note-count-api/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/han-note-count/han-note-count-api/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/han-note-count/han-note-count-biz/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/han-note-count/han-note-count-biz/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/han-note-count/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/han-note-count/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/han-note-distributed-id-generator/han-note-distributed-id-generator-api/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/han-note-distributed-id-generator/han-note-distributed-id-generator-api/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/han-note-distributed-id-generator/han-note-distributed-id-generator-biz/src/main/java" charset="UTF-8" />
|
||||
|
||||
3
.idea/inspectionProfiles/Project_Default.xml
generated
3
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -1,6 +1,9 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="ConstantValue" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="REPORT_CONSTANT_REFERENCE_VALUES" value="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<Languages>
|
||||
<language minSize="56" name="Java" />
|
||||
|
||||
25
han-note-count/han-note-count-api/pom.xml
Normal file
25
han-note-count/han-note-count-api/pom.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<!-- 指定父项目 -->
|
||||
<parent>
|
||||
<groupId>com.hanserwei</groupId>
|
||||
<artifactId>han-note-count</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<!-- 打包方式 -->
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<artifactId>han-note-count-api</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>RPC层, 供其他服务调用</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.hanserwei</groupId>
|
||||
<artifactId>hanserwei-common</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
117
han-note-count/han-note-count-biz/pom.xml
Normal file
117
han-note-count/han-note-count-biz/pom.xml
Normal file
@@ -0,0 +1,117 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<!-- 指定父项目 -->
|
||||
<parent>
|
||||
<groupId>com.hanserwei</groupId>
|
||||
<artifactId>han-note-count</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<!-- 打包方式 -->
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<artifactId>han-note-count-biz</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>计数服务业务模块</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.hanserwei</groupId>
|
||||
<artifactId>hanserwei-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 业务接口日志组件 -->
|
||||
<dependency>
|
||||
<groupId>com.hanserwei</groupId>
|
||||
<artifactId>hanserwei-spring-boot-starter-biz-operationlog</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 上下文组件 -->
|
||||
<dependency>
|
||||
<groupId>com.hanserwei</groupId>
|
||||
<artifactId>hanserwei-spring-boot-starter-biz-context</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson 组件 -->
|
||||
<dependency>
|
||||
<groupId>com.hanserwei</groupId>
|
||||
<artifactId>hanserwei-spring-boot-starter-jackson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 服务发现 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Mybatis-plus -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MySQL 驱动 -->
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Druid 数据库连接池 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-3-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 提供 Redis 连接池 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Redis -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Rocket MQ -->
|
||||
<dependency>
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 快手 Buffer Trigger -->
|
||||
<dependency>
|
||||
<groupId>com.github.phantomthief</groupId>
|
||||
<artifactId>buffer-trigger</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.hanserwei.hannote.count.biz;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
@MapperScan("com.hanserwei.hannote.count.biz.domain.mapper")
|
||||
public class HannoteCountBizApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(HannoteCountBizApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.hanserwei.hannote.count.biz.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
@Configuration
|
||||
public class RedisTemplateConfig {
|
||||
|
||||
@Bean
|
||||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
|
||||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
|
||||
// 设置 RedisTemplate 的连接工厂
|
||||
redisTemplate.setConnectionFactory(connectionFactory);
|
||||
|
||||
// 使用 StringRedisSerializer 来序列化和反序列化 redis 的 key 值,确保 key 是可读的字符串
|
||||
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
||||
|
||||
// 使用 Jackson2JsonRedisSerializer 来序列化和反序列化 redis 的 value 值, 确保存储的是 JSON 格式
|
||||
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
|
||||
redisTemplate.setValueSerializer(serializer);
|
||||
redisTemplate.setHashValueSerializer(serializer);
|
||||
|
||||
redisTemplate.afterPropertiesSet();
|
||||
return redisTemplate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.hanserwei.hannote.count.biz.config;
|
||||
|
||||
import org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@Configuration
|
||||
@Import(RocketMQAutoConfiguration.class)
|
||||
public class RocketMQConfig {
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.hanserwei.hannote.count.biz.constant;
|
||||
|
||||
public interface MQConstants {
|
||||
|
||||
/**
|
||||
* Topic: 关注数计数
|
||||
*/
|
||||
String TOPIC_COUNT_FOLLOWING = "CountFollowingTopic";
|
||||
|
||||
/**
|
||||
* Topic: 粉丝数计数
|
||||
*/
|
||||
String TOPIC_COUNT_FANS = "CountFansTopic";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.hanserwei.hannote.count.biz.consumer;
|
||||
|
||||
import com.github.phantomthief.collection.BufferTrigger;
|
||||
import com.hanserwei.framework.common.utils.JsonUtils;
|
||||
import com.hanserwei.hannote.count.biz.constant.MQConstants;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||
import org.apache.rocketmq.spring.core.RocketMQListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@RocketMQMessageListener(
|
||||
consumerGroup = "han_note_group_" + MQConstants.TOPIC_COUNT_FANS,
|
||||
topic = MQConstants.TOPIC_COUNT_FANS
|
||||
)
|
||||
@Slf4j
|
||||
public class CountFansConsumer implements RocketMQListener<String> {
|
||||
private final BufferTrigger<String> bufferTrigger = BufferTrigger.<String>batchBlocking()
|
||||
.bufferSize(50000) // 缓存队列的最大容量
|
||||
.batchSize(1000) // 一批次最多聚合 1000 条
|
||||
.linger(Duration.ofSeconds(1)) // 多久聚合一次
|
||||
.setConsumerEx(this::consumeMessage)
|
||||
.build();
|
||||
@Override
|
||||
public void onMessage(String body) {
|
||||
// 往 bufferTrigger 中添加元素
|
||||
bufferTrigger.enqueue(body);
|
||||
}
|
||||
|
||||
private void consumeMessage(List<String> bodys) {
|
||||
log.info("==> 聚合消息, size: {}", bodys.size());
|
||||
log.info("==> 聚合消息, {}", JsonUtils.toJsonString(bodys));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.hanserwei.hannote.count.biz.consumer;
|
||||
|
||||
import com.hanserwei.hannote.count.biz.constant.MQConstants;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||
import org.apache.rocketmq.spring.core.RocketMQListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RocketMQMessageListener(
|
||||
consumerGroup = "han_note_group_" + MQConstants.TOPIC_COUNT_FOLLOWING,
|
||||
topic = MQConstants.TOPIC_COUNT_FOLLOWING
|
||||
)
|
||||
@Slf4j
|
||||
public class CountFollowingConsumer implements RocketMQListener<String> {
|
||||
@Override
|
||||
public void onMessage(String body) {
|
||||
log.info("## 消费了 MQ [计数:关注数]: {}", body);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.hanserwei.hannote.count.biz.domain.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 笔记计数表
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@TableName(value = "t_note_count")
|
||||
public class NoteCountDO {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 笔记ID
|
||||
*/
|
||||
@TableField(value = "note_id")
|
||||
private Long noteId;
|
||||
|
||||
/**
|
||||
* 获得点赞总数
|
||||
*/
|
||||
@TableField(value = "like_total")
|
||||
private Long likeTotal;
|
||||
|
||||
/**
|
||||
* 获得收藏总数
|
||||
*/
|
||||
@TableField(value = "collect_total")
|
||||
private Long collectTotal;
|
||||
|
||||
/**
|
||||
* 被评论总数
|
||||
*/
|
||||
@TableField(value = "comment_total")
|
||||
private Long commentTotal;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.hanserwei.hannote.count.biz.domain.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 笔记计数表
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@TableName(value = "t_note_count")
|
||||
public class TNoteCount {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 笔记ID
|
||||
*/
|
||||
@TableField(value = "note_id")
|
||||
private Long noteId;
|
||||
|
||||
/**
|
||||
* 获得点赞总数
|
||||
*/
|
||||
@TableField(value = "like_total")
|
||||
private Long likeTotal;
|
||||
|
||||
/**
|
||||
* 获得收藏总数
|
||||
*/
|
||||
@TableField(value = "collect_total")
|
||||
private Long collectTotal;
|
||||
|
||||
/**
|
||||
* 被评论总数
|
||||
*/
|
||||
@TableField(value = "comment_total")
|
||||
private Long commentTotal;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.hanserwei.hannote.count.biz.domain.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 用户计数表
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@TableName(value = "t_user_count")
|
||||
public class UserCountDO {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@TableField(value = "user_id")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 粉丝总数
|
||||
*/
|
||||
@TableField(value = "fans_total")
|
||||
private Long fansTotal;
|
||||
|
||||
/**
|
||||
* 关注总数
|
||||
*/
|
||||
@TableField(value = "following_total")
|
||||
private Long followingTotal;
|
||||
|
||||
/**
|
||||
* 发布笔记总数
|
||||
*/
|
||||
@TableField(value = "note_total")
|
||||
private Long noteTotal;
|
||||
|
||||
/**
|
||||
* 获得点赞总数
|
||||
*/
|
||||
@TableField(value = "like_total")
|
||||
private Long likeTotal;
|
||||
|
||||
/**
|
||||
* 获得收藏总数
|
||||
*/
|
||||
@TableField(value = "collect_total")
|
||||
private Long collectTotal;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.hanserwei.hannote.count.biz.domain.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hanserwei.hannote.count.biz.domain.dataobject.NoteCountDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface NoteCountDOMapper extends BaseMapper<NoteCountDO> {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.hanserwei.hannote.count.biz.domain.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hanserwei.hannote.count.biz.domain.dataobject.UserCountDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface UserCountDOMapper extends BaseMapper<UserCountDO> {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.hanserwei.hannote.count.biz.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hanserwei.hannote.count.biz.domain.dataobject.NoteCountDO;
|
||||
public interface NoteCountDOService extends IService<NoteCountDO>{
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.hanserwei.hannote.count.biz.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hanserwei.hannote.count.biz.domain.dataobject.UserCountDO;
|
||||
public interface UserCountDOService extends IService<UserCountDO>{
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.hanserwei.hannote.count.biz.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hanserwei.hannote.count.biz.domain.dataobject.NoteCountDO;
|
||||
import com.hanserwei.hannote.count.biz.domain.mapper.NoteCountDOMapper;
|
||||
import com.hanserwei.hannote.count.biz.service.NoteCountDOService;
|
||||
import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
public class NoteCountDOServiceImpl extends ServiceImpl<NoteCountDOMapper, NoteCountDO> implements NoteCountDOService{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.hanserwei.hannote.count.biz.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hanserwei.hannote.count.biz.domain.dataobject.UserCountDO;
|
||||
import com.hanserwei.hannote.count.biz.domain.mapper.UserCountDOMapper;
|
||||
import com.hanserwei.hannote.count.biz.service.UserCountDOService;
|
||||
import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
public class UserCountDOServiceImpl extends ServiceImpl<UserCountDOMapper, UserCountDO> implements UserCountDOService{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
server:
|
||||
port: 8090 # 项目启动的端口
|
||||
|
||||
spring:
|
||||
profiles:
|
||||
active: dev # 默认激活 dev 本地开发环境
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 20MB # 单个文件最大大小
|
||||
max-request-size: 100MB # 单次请求最大大小(包含多个文件)
|
||||
data:
|
||||
redis:
|
||||
database: 5 # Redis 数据库索引(默认为 0)
|
||||
host: 127.0.0.1 # Redis 服务器地址
|
||||
port: 6379 # Redis 服务器连接端口
|
||||
password: redis # Redis 服务器连接密码(默认为空)
|
||||
timeout: 5s # 读超时时间
|
||||
connect-timeout: 5s # 链接超时时间
|
||||
lettuce:
|
||||
pool:
|
||||
max-active: 200 # 连接池最大连接数
|
||||
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
min-idle: 0 # 连接池中的最小空闲连接
|
||||
max-idle: 10 # 连接池中的最大空闲连接
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true
|
||||
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
|
||||
global-config:
|
||||
banner: false
|
||||
mapper-locations: classpath*:/mapperxml/*.xml
|
||||
@@ -0,0 +1,19 @@
|
||||
spring:
|
||||
application:
|
||||
name: han-note-count # 应用名称
|
||||
profiles:
|
||||
active: dev # 默认激活 dev 本地开发环境
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
enabled: true # 启用服务发现
|
||||
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,58 @@
|
||||
<configuration>
|
||||
<!-- 引用 Spring Boot 的 logback 基础配置 -->
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
||||
|
||||
<!-- 应用名称 -->
|
||||
<property scope="context" name="appName" value="count"/>
|
||||
<!-- 自定义日志输出路径,以及日志名称前缀 -->
|
||||
<property name="LOG_FILE" value="./logs/${appName}.%d{yyyy-MM-dd}"/>
|
||||
<!-- 每行日志输出的格式 -->
|
||||
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
|
||||
|
||||
<!-- 文件输出 -->
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<!-- 日志文件的命名格式 -->
|
||||
<fileNamePattern>${LOG_FILE}-%i.log</fileNamePattern>
|
||||
<!-- 保留 30 天的日志文件 -->
|
||||
<maxHistory>30</maxHistory>
|
||||
<!-- 单个日志文件最大大小 -->
|
||||
<maxFileSize>10MB</maxFileSize>
|
||||
<!-- 日志文件的总大小,0 表示不限制 -->
|
||||
<totalSizeCap>0</totalSizeCap>
|
||||
<!-- 重启服务时,是否清除历史日志,不推荐清理 -->
|
||||
<cleanHistoryOnStart>false</cleanHistoryOnStart>
|
||||
</rollingPolicy>
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 异步写入日志,提升性能 -->
|
||||
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<!-- 是否丢弃日志, 0 表示不丢弃。默认情况下,如果队列满 80%, 会丢弃 TRACE、DEBUG、INFO 级别的日志 -->
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<!-- 队列大小。默认值为 256 -->
|
||||
<queueSize>256</queueSize>
|
||||
<appender-ref ref="FILE"/>
|
||||
</appender>
|
||||
|
||||
<!-- 本地 dev 开发环境 -->
|
||||
<springProfile name="dev">
|
||||
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE"/> <!-- 输出控制台日志 -->
|
||||
<appender-ref ref="ASYNC_FILE"/> <!-- 打印日志到文件中。PS: 本地环境下,如果不想打印日志到文件,可注释掉此行 -->
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
<!-- 其它环境 -->
|
||||
<springProfile name="prod">
|
||||
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
|
||||
<root level="INFO">
|
||||
<appender-ref ref="ASYNC_FILE"/> <!-- 生产环境下,仅打印日志到文件中 -->
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
</configuration>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.hanserwei.hannote.count.biz.domain.mapper.NoteCountDOMapper">
|
||||
<resultMap id="BaseResultMap" type="com.hanserwei.hannote.count.biz.domain.dataobject.NoteCountDO">
|
||||
<!--@mbg.generated-->
|
||||
<!--@Table t_note_count-->
|
||||
<id column="id" jdbcType="BIGINT" property="id" />
|
||||
<result column="note_id" jdbcType="BIGINT" property="noteId" />
|
||||
<result column="like_total" jdbcType="BIGINT" property="likeTotal" />
|
||||
<result column="collect_total" jdbcType="BIGINT" property="collectTotal" />
|
||||
<result column="comment_total" jdbcType="BIGINT" property="commentTotal" />
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
id, note_id, like_total, collect_total, comment_total
|
||||
</sql>
|
||||
</mapper>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.hanserwei.hannote.count.biz.domain.mapper.UserCountDOMapper">
|
||||
<resultMap id="BaseResultMap" type="com.hanserwei.hannote.count.biz.domain.dataobject.UserCountDO">
|
||||
<!--@mbg.generated-->
|
||||
<!--@Table t_user_count-->
|
||||
<id column="id" jdbcType="BIGINT" property="id" />
|
||||
<result column="user_id" jdbcType="BIGINT" property="userId" />
|
||||
<result column="fans_total" jdbcType="BIGINT" property="fansTotal" />
|
||||
<result column="following_total" jdbcType="BIGINT" property="followingTotal" />
|
||||
<result column="note_total" jdbcType="BIGINT" property="noteTotal" />
|
||||
<result column="like_total" jdbcType="BIGINT" property="likeTotal" />
|
||||
<result column="collect_total" jdbcType="BIGINT" property="collectTotal" />
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
id, user_id, fans_total, following_total, note_total, like_total, collect_total
|
||||
</sql>
|
||||
</mapper>
|
||||
26
han-note-count/pom.xml
Normal file
26
han-note-count/pom.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<!-- 指定父项目 -->
|
||||
<parent>
|
||||
<groupId>com.hanserwei</groupId>
|
||||
<artifactId>han-note</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<!-- 多模块项目需要配置打包方式为 pom -->
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<!-- 子模块管理 -->
|
||||
<modules>
|
||||
<module>han-note-count-api</module>
|
||||
<module>han-note-count-biz</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>han-note-count</artifactId>
|
||||
<!-- 项目名称 -->
|
||||
<name>${project.artifactId}</name>
|
||||
<!-- 项目描述 -->
|
||||
<description>计数服务</description>
|
||||
|
||||
</project>
|
||||
@@ -2,7 +2,6 @@ package com.hanserwei.hannote.distributed.id.generator.biz.config;
|
||||
|
||||
import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceBuilder;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import javax.sql.DataSource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
@@ -11,6 +10,8 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
package com.hanserwei.hannote.distributed.id.generator.biz.core.segment.dao;
|
||||
|
||||
import com.hanserwei.hannote.distributed.id.generator.biz.core.segment.model.LeafAlloc;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Result;
|
||||
import org.apache.ibatis.annotations.Results;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
import org.apache.ibatis.annotations.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.hanserwei.hannote.note.biz.domain.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.util.Date;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 笔记收藏表
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@TableName(value = "t_note_collection")
|
||||
public class NoteCollectionDO {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@TableField(value = "user_id")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 笔记ID
|
||||
*/
|
||||
@TableField(value = "note_id")
|
||||
private Long noteId;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 收藏状态(0:取消收藏 1:收藏)
|
||||
*/
|
||||
@TableField(value = "`status`")
|
||||
private Byte status;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.hanserwei.hannote.note.biz.domain.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.util.Date;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 笔记点赞表
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@TableName(value = "t_note_like")
|
||||
public class NoteLikeDO {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@TableField(value = "user_id")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 笔记ID
|
||||
*/
|
||||
@TableField(value = "note_id")
|
||||
private Long noteId;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 点赞状态(0:取消点赞 1:点赞)
|
||||
*/
|
||||
@TableField(value = "`status`")
|
||||
private Byte status;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.hanserwei.hannote.note.biz.domain.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hanserwei.hannote.note.biz.domain.dataobject.NoteCollectionDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface NoteCollectionDOMapper extends BaseMapper<NoteCollectionDO> {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.hanserwei.hannote.note.biz.domain.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.hanserwei.hannote.note.biz.domain.dataobject.NoteLikeDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface NoteLikeDOMapper extends BaseMapper<NoteLikeDO> {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.hanserwei.hannote.note.biz.service;
|
||||
|
||||
import com.hanserwei.hannote.note.biz.domain.dataobject.NoteCollectionDO;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
public interface NoteCollectionDOService extends IService<NoteCollectionDO>{
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.hanserwei.hannote.note.biz.service;
|
||||
|
||||
import com.hanserwei.hannote.note.biz.domain.dataobject.NoteLikeDO;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
public interface NoteLikeDOService extends IService<NoteLikeDO>{
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.hanserwei.hannote.note.biz.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hanserwei.hannote.note.biz.domain.dataobject.NoteCollectionDO;
|
||||
import com.hanserwei.hannote.note.biz.domain.mapper.NoteCollectionDOMapper;
|
||||
import com.hanserwei.hannote.note.biz.service.NoteCollectionDOService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class NoteCollectionDOServiceImpl extends ServiceImpl<NoteCollectionDOMapper, NoteCollectionDO> implements NoteCollectionDOService {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.hanserwei.hannote.note.biz.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hanserwei.hannote.note.biz.domain.dataobject.NoteLikeDO;
|
||||
import com.hanserwei.hannote.note.biz.domain.mapper.NoteLikeDOMapper;
|
||||
import com.hanserwei.hannote.note.biz.service.NoteLikeDOService;
|
||||
import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
public class NoteLikeDOServiceImpl extends ServiceImpl<NoteLikeDOMapper, NoteLikeDO> implements NoteLikeDOService{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.hanserwei.hannote.note.biz.domain.mapper.NoteCollectionDOMapper">
|
||||
<resultMap id="BaseResultMap" type="com.hanserwei.hannote.note.biz.domain.dataobject.NoteCollectionDO">
|
||||
<!--@mbg.generated-->
|
||||
<!--@Table t_note_collection-->
|
||||
<id column="id" jdbcType="BIGINT" property="id" />
|
||||
<result column="user_id" jdbcType="BIGINT" property="userId" />
|
||||
<result column="note_id" jdbcType="BIGINT" property="noteId" />
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
|
||||
<result column="status" jdbcType="TINYINT" property="status" />
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
id, user_id, note_id, create_time, `status`
|
||||
</sql>
|
||||
</mapper>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.hanserwei.hannote.note.biz.domain.mapper.NoteLikeDOMapper">
|
||||
<resultMap id="BaseResultMap" type="com.hanserwei.hannote.note.biz.domain.dataobject.NoteLikeDO">
|
||||
<!--@mbg.generated-->
|
||||
<!--@Table t_note_like-->
|
||||
<id column="id" jdbcType="BIGINT" property="id" />
|
||||
<result column="user_id" jdbcType="BIGINT" property="userId" />
|
||||
<result column="note_id" jdbcType="BIGINT" property="noteId" />
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
|
||||
<result column="status" jdbcType="TINYINT" property="status" />
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
id, user_id, note_id, create_time, `status`
|
||||
</sql>
|
||||
</mapper>
|
||||
@@ -16,4 +16,14 @@ public interface MQConstants {
|
||||
* 取关标签
|
||||
*/
|
||||
String TAG_UNFOLLOW = "Unfollow";
|
||||
|
||||
/**
|
||||
* Topic: 关注数计数
|
||||
*/
|
||||
String TOPIC_COUNT_FOLLOWING = "CountFollowingTopic";
|
||||
|
||||
/**
|
||||
* Topic: 粉丝数计数
|
||||
*/
|
||||
String TOPIC_COUNT_FANS = "CountFansTopic";
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import com.hanserwei.hannote.user.relation.biz.constant.MQConstants;
|
||||
import com.hanserwei.hannote.user.relation.biz.constant.RedisKeyConstants;
|
||||
import com.hanserwei.hannote.user.relation.biz.domain.dataobject.FansDO;
|
||||
import com.hanserwei.hannote.user.relation.biz.domain.dataobject.FollowingDO;
|
||||
import com.hanserwei.hannote.user.relation.biz.enums.FollowUnfollowTypeEnum;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.dto.CountFollowUnfollowMqDTO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.dto.FollowUserMqDTO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.dto.UnfollowUserMqDTO;
|
||||
import com.hanserwei.hannote.user.relation.biz.service.FansDOService;
|
||||
@@ -15,13 +17,17 @@ import com.hanserwei.hannote.user.relation.biz.util.DateUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.client.producer.SendCallback;
|
||||
import org.apache.rocketmq.client.producer.SendResult;
|
||||
import org.apache.rocketmq.common.message.Message;
|
||||
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
||||
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||
import org.apache.rocketmq.spring.core.RocketMQListener;
|
||||
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.scripting.support.ResourceScriptSource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
@@ -32,8 +38,8 @@ import java.util.Objects;
|
||||
|
||||
@Component
|
||||
@RocketMQMessageListener(
|
||||
consumerGroup = "han_note_group_" + MQConstants.TOPIC_FOLLOW_OR_UNFOLLOW,
|
||||
topic = MQConstants.TOPIC_FOLLOW_OR_UNFOLLOW,
|
||||
consumerGroup = "han_note_group_" + MQConstants.TOPIC_FOLLOW_OR_UNFOLLOW, //han_note_group_FollowUnfollowTopic
|
||||
topic = MQConstants.TOPIC_FOLLOW_OR_UNFOLLOW, //FollowUnfollowTopic
|
||||
consumeMode = ConsumeMode.ORDERLY
|
||||
)
|
||||
@Slf4j
|
||||
@@ -47,6 +53,8 @@ public class FollowUnfollowConsumer implements RocketMQListener<Message> {
|
||||
private RateLimiter rateLimiter;
|
||||
@Resource
|
||||
private RedisTemplate<Object, Object> redisTemplate;
|
||||
@Resource
|
||||
private RocketMQTemplate rocketMQTemplate;
|
||||
|
||||
@Override
|
||||
public void onMessage(Message message) {
|
||||
@@ -114,6 +122,17 @@ public class FollowUnfollowConsumer implements RocketMQListener<Message> {
|
||||
String fansRedisKey = RedisKeyConstants.buildUserFansKey(unfollowUserId);
|
||||
// 删除指定粉丝
|
||||
redisTemplate.opsForZSet().remove(fansRedisKey, userId);
|
||||
|
||||
// 发送MQ消息通知计数服务,统计关注数
|
||||
// 构建DTO对象
|
||||
CountFollowUnfollowMqDTO countFollowUnfollowMqDTO = CountFollowUnfollowMqDTO.builder()
|
||||
.userId(userId)
|
||||
.targetUserId(unfollowUserId)
|
||||
.type(FollowUnfollowTypeEnum.UNFOLLOW.getCode())
|
||||
.build();
|
||||
|
||||
// 发送MQ
|
||||
sendMQ(countFollowUnfollowMqDTO);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,6 +196,53 @@ public class FollowUnfollowConsumer implements RocketMQListener<Message> {
|
||||
|
||||
// 执行Lua脚本
|
||||
redisTemplate.execute(script, Collections.singletonList(fansZSetKey), userId, timestamp);
|
||||
|
||||
// 发送MQ消息通知计数服务,统计关注数
|
||||
// 构建消息体
|
||||
CountFollowUnfollowMqDTO countFollowUnfollowMqDTO = CountFollowUnfollowMqDTO.builder()
|
||||
.userId(userId)
|
||||
.targetUserId(followUserId)
|
||||
.type(FollowUnfollowTypeEnum.FOLLOW.getCode())
|
||||
.build();
|
||||
|
||||
sendMQ(countFollowUnfollowMqDTO);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送MQ消息
|
||||
*
|
||||
* @param countFollowUnfollowMqDTO 消息体
|
||||
*/
|
||||
private void sendMQ(CountFollowUnfollowMqDTO countFollowUnfollowMqDTO) {
|
||||
// 构建MQ消息体
|
||||
org.springframework.messaging.Message<String> message = MessageBuilder.withPayload(JsonUtils.toJsonString(countFollowUnfollowMqDTO))
|
||||
.build();
|
||||
|
||||
// 异步发送 MQ 消息
|
||||
rocketMQTemplate.asyncSend(MQConstants.TOPIC_COUNT_FOLLOWING, message, new SendCallback() {
|
||||
@Override
|
||||
public void onSuccess(SendResult sendResult) {
|
||||
log.info("==> 【计数服务:关注数】MQ 发送成功,SendResult: {}", sendResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Throwable throwable) {
|
||||
log.error("==> 【计数服务:关注数】MQ 发送异常: ", throwable);
|
||||
}
|
||||
});
|
||||
|
||||
// 发送 MQ 通知计数服务:统计粉丝数
|
||||
rocketMQTemplate.asyncSend(MQConstants.TOPIC_COUNT_FANS, message, new SendCallback() {
|
||||
@Override
|
||||
public void onSuccess(SendResult sendResult) {
|
||||
log.info("==> 【计数服务:粉丝数】MQ 发送成功,SendResult: {}", sendResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Throwable throwable) {
|
||||
log.error("==> 【计数服务:粉丝数】MQ 发送异常: ", throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import com.hanserwei.framework.common.response.PageResponse;
|
||||
import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.hannote.user.dto.req.FindFollowingListReqVO;
|
||||
import com.hanserwei.hannote.user.dto.resp.FindFollowingUserRspVO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.dto.FindFansUserRspVO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.vo.FindFansListReqVO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.vo.FollowUserReqVO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.vo.UnfollowUserReqVO;
|
||||
import com.hanserwei.hannote.user.relation.biz.service.RelationService;
|
||||
@@ -41,4 +43,10 @@ public class RelationController {
|
||||
public PageResponse<FindFollowingUserRspVO> findFollowingList(@Validated @RequestBody FindFollowingListReqVO findFollowingListReqVO) {
|
||||
return relationService.findFollowingList(findFollowingListReqVO);
|
||||
}
|
||||
|
||||
@PostMapping("/fans/list")
|
||||
@ApiOperationLog(description = "查询用户粉丝列表")
|
||||
public PageResponse<FindFansUserRspVO> findFansList(@Validated @RequestBody FindFansListReqVO findFansListReqVO) {
|
||||
return relationService.findFansList(findFansListReqVO);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.hanserwei.hannote.user.relation.biz.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum FollowUnfollowTypeEnum {
|
||||
// 关注
|
||||
FOLLOW(1),
|
||||
// 取关
|
||||
UNFOLLOW(0),
|
||||
;
|
||||
|
||||
private final Integer code;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.hanserwei.hannote.user.relation.biz.model.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class CountFollowUnfollowMqDTO {
|
||||
|
||||
/**
|
||||
* 原用户
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 目标用户
|
||||
*/
|
||||
private Long targetUserId;
|
||||
|
||||
/**
|
||||
* 1:关注 0:取关
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.hanserwei.hannote.user.relation.biz.model.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class FindFansUserRspVO {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 头像
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 粉丝总数
|
||||
*/
|
||||
private Long fansTotal;
|
||||
|
||||
/**
|
||||
* 笔记总数
|
||||
*/
|
||||
private Long noteTotal;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.hanserwei.hannote.user.relation.biz.model.vo;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class FindFansListReqVO {
|
||||
|
||||
@NotNull(message = "查询用户 ID 不能为空")
|
||||
private Long userId;
|
||||
|
||||
@NotNull(message = "页码不能为空")
|
||||
private Integer pageNo = 1; // 默认值为第一页
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.hanserwei.hannote.user.relation.biz.service;
|
||||
|
||||
import com.hanserwei.hannote.user.relation.biz.domain.dataobject.FansDO;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hanserwei.hannote.user.relation.biz.domain.dataobject.FansDO;
|
||||
public interface FansDOService extends IService<FansDO>{
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.hanserwei.hannote.user.relation.biz.service;
|
||||
|
||||
import com.hanserwei.hannote.user.relation.biz.domain.dataobject.FollowingDO;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hanserwei.hannote.user.relation.biz.domain.dataobject.FollowingDO;
|
||||
public interface FollowingDOService extends IService<FollowingDO>{
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import com.hanserwei.framework.common.response.PageResponse;
|
||||
import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.hannote.user.dto.req.FindFollowingListReqVO;
|
||||
import com.hanserwei.hannote.user.dto.resp.FindFollowingUserRspVO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.dto.FindFansUserRspVO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.vo.FindFansListReqVO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.vo.FollowUserReqVO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.vo.UnfollowUserReqVO;
|
||||
|
||||
@@ -30,4 +32,13 @@ public interface RelationService {
|
||||
* @return 响应
|
||||
*/
|
||||
PageResponse<FindFollowingUserRspVO> findFollowingList(FindFollowingListReqVO findFollowingListReqVO);
|
||||
|
||||
/**
|
||||
* 查询粉丝列表
|
||||
*
|
||||
* @param findFansListReqVO 查询粉丝列表请求
|
||||
* @return 响应
|
||||
*/
|
||||
PageResponse<FindFansUserRspVO> findFansList(FindFansListReqVO findFansListReqVO);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package com.hanserwei.hannote.user.relation.biz.service.impl;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hanserwei.hannote.user.relation.biz.domain.dataobject.FansDO;
|
||||
import com.hanserwei.hannote.user.relation.biz.domain.mapper.FansDOMapper;
|
||||
import com.hanserwei.hannote.user.relation.biz.service.FansDOService;
|
||||
import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
public class FansDOServiceImpl extends ServiceImpl<FansDOMapper, FansDO> implements FansDOService{
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package com.hanserwei.hannote.user.relation.biz.service.impl;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.hanserwei.hannote.user.relation.biz.domain.mapper.FollowingDOMapper;
|
||||
import com.hanserwei.hannote.user.relation.biz.domain.dataobject.FollowingDO;
|
||||
import com.hanserwei.hannote.user.relation.biz.domain.mapper.FollowingDOMapper;
|
||||
import com.hanserwei.hannote.user.relation.biz.service.FollowingDOService;
|
||||
import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
public class FollowingDOServiceImpl extends ServiceImpl<FollowingDOMapper, FollowingDO> implements FollowingDOService{
|
||||
|
||||
|
||||
@@ -14,14 +14,18 @@ import com.hanserwei.hannote.user.dto.resp.FindFollowingUserRspVO;
|
||||
import com.hanserwei.hannote.user.dto.resp.FindUserByIdRspDTO;
|
||||
import com.hanserwei.hannote.user.relation.biz.constant.MQConstants;
|
||||
import com.hanserwei.hannote.user.relation.biz.constant.RedisKeyConstants;
|
||||
import com.hanserwei.hannote.user.relation.biz.domain.dataobject.FansDO;
|
||||
import com.hanserwei.hannote.user.relation.biz.domain.dataobject.FollowingDO;
|
||||
import com.hanserwei.hannote.user.relation.biz.enums.LuaResultEnum;
|
||||
import com.hanserwei.hannote.user.relation.biz.enums.ResponseCodeEnum;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.dto.FindFansUserRspVO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.dto.FollowUserMqDTO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.dto.UnfollowUserMqDTO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.vo.FindFansListReqVO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.vo.FollowUserReqVO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.vo.UnfollowUserReqVO;
|
||||
import com.hanserwei.hannote.user.relation.biz.rpc.UserRpcService;
|
||||
import com.hanserwei.hannote.user.relation.biz.service.FansDOService;
|
||||
import com.hanserwei.hannote.user.relation.biz.service.FollowingDOService;
|
||||
import com.hanserwei.hannote.user.relation.biz.service.RelationService;
|
||||
import com.hanserwei.hannote.user.relation.biz.util.DateUtils;
|
||||
@@ -59,6 +63,8 @@ public class RelationServiceImpl implements RelationService {
|
||||
private RocketMQTemplate rocketMQTemplate;
|
||||
@Resource(name = "relationTaskExecutor")
|
||||
private ThreadPoolTaskExecutor taskExecutor;
|
||||
@Resource
|
||||
private FansDOService fansDOService;
|
||||
|
||||
@Override
|
||||
public Response<?> follow(FollowUserReqVO followUserReqVO) {
|
||||
@@ -321,7 +327,6 @@ public class RelationServiceImpl implements RelationService {
|
||||
log.info("==> 批量查询用户信息,用户ID: {}", userIds);
|
||||
|
||||
// RPC: 批量查询用户信息
|
||||
//noinspection ConstantValue
|
||||
findFollowingUserRspVOS = rpcUserServiceAndDTO2VO(userIds, findFollowingUserRspVOS);
|
||||
}
|
||||
} else {
|
||||
@@ -358,7 +363,6 @@ public class RelationServiceImpl implements RelationService {
|
||||
List<Long> userIds = followingDOS.stream().map(FollowingDO::getFollowingUserId).toList();
|
||||
|
||||
// RPC: 调用用户服务,并将 DTO 转换为 VO
|
||||
//noinspection ConstantValue
|
||||
findFollowingUserRspVOS = rpcUserServiceAndDTO2VO(userIds, findFollowingUserRspVOS);
|
||||
|
||||
// 异步将关注列表全量同步到 Redis
|
||||
@@ -372,6 +376,157 @@ public class RelationServiceImpl implements RelationService {
|
||||
total);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResponse<FindFansUserRspVO> findFansList(FindFansListReqVO findFansListReqVO) {
|
||||
// 要查询的用户ID
|
||||
Long userId = findFansListReqVO.getUserId();
|
||||
// 页码
|
||||
Integer pageNo = findFansListReqVO.getPageNo();
|
||||
// 先从Redis中查询
|
||||
String fansListRedisKey = RedisKeyConstants.buildUserFansKey(userId);
|
||||
// 查询目标用户粉丝列表 ZSet 的总大小
|
||||
Long total = redisTemplate.opsForZSet().zCard(fansListRedisKey);
|
||||
|
||||
// 构建回参
|
||||
List<FindFansUserRspVO> findFansUserRspVOS = null;
|
||||
// 每页展示10条数据
|
||||
long limit = 10L;
|
||||
|
||||
if (total != null && total > 0) {
|
||||
// 缓存有数据
|
||||
// 计算一共多少页
|
||||
long totalPage = PageResponse.getTotalPage(total, limit);
|
||||
|
||||
// 请求页码超过总页数
|
||||
if (pageNo > totalPage) {
|
||||
log.info("==> 查询粉丝列表请求页码超过总页数,返回空数据");
|
||||
return PageResponse.success(null, pageNo, total);
|
||||
}
|
||||
|
||||
// 准备从 Redis 中查询 ZSet 分页数据
|
||||
// 每页 10 个元素,计算偏移量
|
||||
long offset = PageResponse.getOffset(pageNo, limit);
|
||||
|
||||
// 使用 ZREVRANGEBYSCORE 命令按 score 降序获取元素,同时使用 LIMIT 子句实现分页
|
||||
Set<Object> followingUserIdsSet = redisTemplate.opsForZSet()
|
||||
.reverseRangeByScore(fansListRedisKey, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, offset, limit);
|
||||
|
||||
if (CollUtil.isNotEmpty(followingUserIdsSet)) {
|
||||
// 提取所有用户 ID 到集合中
|
||||
List<Long> userIds = followingUserIdsSet.stream().map(object -> Long.valueOf(object.toString())).toList();
|
||||
|
||||
// RPC: 批量查询用户信息
|
||||
findFansUserRspVOS = rpcUserServiceAndCountServiceAndDTO2VO(userIds, findFansUserRspVOS);
|
||||
}
|
||||
} else {
|
||||
// 若 Redis 中没有数据,则从数据库查询
|
||||
// 先查询记录总量
|
||||
total = fansDOService.count(new LambdaQueryWrapper<>(FansDO.class).eq(FansDO::getUserId, userId));
|
||||
// 获取一共多少页
|
||||
long totalPage = PageResponse.getTotalPage(total, limit);
|
||||
// 请求的页码超出了总页数(只允许查询前 500 页)
|
||||
if (pageNo > totalPage || pageNo > 500) {
|
||||
log.info("==> 查询粉丝列表页码大于总页数或者请求的页码超出了总页数,返回空数据");
|
||||
return PageResponse.success(null, pageNo, total);
|
||||
}
|
||||
// 偏移量
|
||||
long offset = PageResponse.getOffset(pageNo, limit);
|
||||
// 分页查询
|
||||
Page<FansDO> page = fansDOService.page(new Page<>(offset / limit + 1, limit),
|
||||
new LambdaQueryWrapper<>(FansDO.class)
|
||||
.select(FansDO::getFansUserId)
|
||||
.eq(FansDO::getUserId, userId)
|
||||
.orderByDesc(FansDO::getCreateTime));
|
||||
List<FansDO> fansDOS = page.getRecords();
|
||||
|
||||
log.info("==> 查询到粉丝列表:{}", JsonUtils.toJsonString(fansDOS));
|
||||
|
||||
// 若记录不为空
|
||||
if (CollUtil.isNotEmpty(fansDOS)) {
|
||||
// 提取所有用户 ID 到集合中
|
||||
List<Long> userIds = fansDOS.stream().map(FansDO::getFansUserId).toList();
|
||||
|
||||
// RPC: 调用用户服务、计数服务,并将 DTO 转换为 VO
|
||||
findFansUserRspVOS = rpcUserServiceAndCountServiceAndDTO2VO(userIds, findFansUserRspVOS);
|
||||
|
||||
// 异步将粉丝列表同步到 Redis(最多5000条)
|
||||
taskExecutor.submit(() -> syncFansList2Redis(userId));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return PageResponse.success(findFansUserRspVOS, pageNo, total);
|
||||
}
|
||||
|
||||
private void syncFansList2Redis(Long userId) {
|
||||
// 同步粉丝列表到 Redis
|
||||
// 查询粉丝列表,最多5000条
|
||||
Page<FansDO> page = fansDOService.page(new Page<>(1, 5000),
|
||||
new LambdaQueryWrapper<>(FansDO.class)
|
||||
.select(FansDO::getFansUserId, FansDO::getCreateTime)
|
||||
.eq(FansDO::getUserId, userId)
|
||||
.orderByDesc(FansDO::getCreateTime));
|
||||
List<FansDO> fansDOS = page.getRecords();
|
||||
if (CollUtil.isNotEmpty(fansDOS)) {
|
||||
// 用户粉丝列表的Redis Key
|
||||
String fansListRedisKey = RedisKeyConstants.buildUserFansKey(userId);
|
||||
// 随机过期时间,保底一天+随机秒数
|
||||
long expireSeconds = 86400 + RandomUtil.randomLong(0, 86400);
|
||||
// 构建 Lua 参数
|
||||
Object[] luaArgs = buildFansZSetLuaArgs(fansDOS, expireSeconds);
|
||||
|
||||
// 执行 Lua 脚本,批量同步关注关系数据到 Redis 中
|
||||
DefaultRedisScript<Long> script = new DefaultRedisScript<>();
|
||||
script.setScriptSource(new ResourceScriptSource(new ClassPathResource("/lua/follow_batch_add_and_expire.lua")));
|
||||
script.setResultType(Long.class);
|
||||
redisTemplate.execute(script, Collections.singletonList(fansListRedisKey), luaArgs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 Lua 脚本参数 :粉丝列表
|
||||
*
|
||||
* @param fansDOS 粉丝DO列表
|
||||
* @param expireSeconds 过期时间
|
||||
* @return 参数列表
|
||||
*/
|
||||
private Object[] buildFansZSetLuaArgs(List<FansDO> fansDOS, long expireSeconds) {
|
||||
int argsLength = fansDOS.size() * 2 + 1; // 每个粉丝关系有 2 个参数(score 和 value),再加一个过期时间
|
||||
Object[] luaArgs = new Object[argsLength];
|
||||
|
||||
int i = 0;
|
||||
for (FansDO fansDO : fansDOS) {
|
||||
luaArgs[i] = DateUtils.localDateTime2Timestamp(fansDO.getCreateTime()); // 粉丝的关注时间作为 score
|
||||
luaArgs[i + 1] = fansDO.getFansUserId(); // 粉丝的用户 ID 作为 ZSet value
|
||||
i += 2;
|
||||
}
|
||||
|
||||
luaArgs[argsLength - 1] = expireSeconds; // 最后一个参数是 ZSet 的过期时间
|
||||
return luaArgs;
|
||||
}
|
||||
|
||||
private List<FindFansUserRspVO> rpcUserServiceAndCountServiceAndDTO2VO(List<Long> userIds, List<FindFansUserRspVO> findFansUserRspVOS) {
|
||||
// RPC: 批量查询用户信息
|
||||
List<FindUserByIdRspDTO> findUserByIdRspDTOS = userRpcService.findByIds(userIds);
|
||||
|
||||
// TODO RPC: 批量查询用户的计数数据(笔记总数、粉丝总数)
|
||||
|
||||
// 若不为空,DTO 转 VO
|
||||
if (CollUtil.isNotEmpty(findUserByIdRspDTOS)) {
|
||||
findFansUserRspVOS = findUserByIdRspDTOS.stream()
|
||||
.map(dto -> FindFansUserRspVO.builder()
|
||||
.userId(dto.getId())
|
||||
.avatar(dto.getAvatar())
|
||||
.nickname(dto.getNickName())
|
||||
.noteTotal(0L) // TODO: 这块的数据暂无,后续补充
|
||||
.fansTotal(0L) // TODO: 这块的数据暂无,后续补充
|
||||
.build())
|
||||
.toList();
|
||||
}
|
||||
return findFansUserRspVOS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 全量同步关注列表到 Redis
|
||||
*
|
||||
|
||||
@@ -2,6 +2,8 @@ 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.enums.FollowUnfollowTypeEnum;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.dto.CountFollowUnfollowMqDTO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.dto.FollowUserMqDTO;
|
||||
import com.hanserwei.hannote.user.relation.biz.model.dto.UnfollowUserMqDTO;
|
||||
import jakarta.annotation.Resource;
|
||||
@@ -125,4 +127,37 @@ class MQTests {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试:发送计数 MQ, 以统计粉丝数
|
||||
*/
|
||||
@Test
|
||||
void testSendCountFollowUnfollowMQ() {
|
||||
// 循环发送 3200 条 MQ
|
||||
for (long i = 0; i < 3200; i++) {
|
||||
// 构建消息体 DTO
|
||||
CountFollowUnfollowMqDTO countFollowUnfollowMqDTO = CountFollowUnfollowMqDTO.builder()
|
||||
.userId(i + 1) // 关注者用户 ID
|
||||
.targetUserId(27L) // 目标用户
|
||||
.type(FollowUnfollowTypeEnum.FOLLOW.getCode())
|
||||
.build();
|
||||
|
||||
// 构建消息对象,并将 DTO 转成 Json 字符串设置到消息体中
|
||||
org.springframework.messaging.Message<String> message = MessageBuilder.withPayload(JsonUtils.toJsonString(countFollowUnfollowMqDTO))
|
||||
.build();
|
||||
|
||||
// 发送 MQ 通知计数服务:统计粉丝数
|
||||
rocketMQTemplate.asyncSend(MQConstants.TOPIC_COUNT_FANS, message, new SendCallback() {
|
||||
@Override
|
||||
public void onSuccess(SendResult sendResult) {
|
||||
log.info("==> 【计数服务:粉丝数】MQ 发送成功,SendResult: {}", sendResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Throwable throwable) {
|
||||
log.error("==> 【计数服务:粉丝数】MQ 发送异常: ", throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -174,3 +174,13 @@ Authorization: Bearer {{token}}
|
||||
"userId": 100,
|
||||
"pageNo": 1
|
||||
}
|
||||
|
||||
### 查询用户粉丝列表
|
||||
POST http://localhost:8000/relation/relation/fans/list
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"userId": 100,
|
||||
"pageNo": 1
|
||||
}
|
||||
8
pom.xml
8
pom.xml
@@ -21,6 +21,7 @@
|
||||
<module>han-note-note</module>
|
||||
<module>han-note-note/han-note-note-biz</module>
|
||||
<module>han-note-user-relation</module>
|
||||
<module>han-note-count</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
@@ -63,6 +64,7 @@
|
||||
<zookeeper.version>3.9.4</zookeeper.version>
|
||||
<rocketmq-spring-boot.version>2.3.4</rocketmq-spring-boot.version>
|
||||
<rocketmq-client.version>5.3.2</rocketmq-client.version>
|
||||
<buffertrigger.version>0.2.21</buffertrigger.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
@@ -284,6 +286,12 @@
|
||||
<artifactId>rocketmq-acl</artifactId>
|
||||
<version>${rocketmq-client.version}</version>
|
||||
</dependency>
|
||||
<!-- 快手 Buffer Trigger -->
|
||||
<dependency>
|
||||
<groupId>com.github.phantomthief</groupId>
|
||||
<artifactId>buffer-trigger</artifactId>
|
||||
<version>${buffertrigger.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
@@ -179,4 +179,66 @@ ALTER TABLE t_following ADD UNIQUE uk_user_id_following_user_id(user_id, followi
|
||||
|
||||
ALTER TABLE t_fans ADD UNIQUE uk_user_id_fans_user_id(user_id, fans_user_id);
|
||||
|
||||
-- 表:t_note_like
|
||||
CREATE TABLE `t_note_like`
|
||||
(
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`note_id` bigint NOT NULL COMMENT '笔记ID',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`status` tinyint NOT NULL DEFAULT '0' COMMENT '点赞状态(0:取消点赞 1:点赞)',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE KEY `uk_user_id_note_id` (`user_id`, `note_id`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_unicode_ci COMMENT ='笔记点赞表';
|
||||
|
||||
|
||||
-- 表:t_note_collection
|
||||
CREATE TABLE `t_note_collection`
|
||||
(
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`note_id` bigint NOT NULL COMMENT '笔记ID',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`status` tinyint NOT NULL DEFAULT '0' COMMENT '收藏状态(0:取消收藏 1:收藏)',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE KEY `uk_user_id_note_id` (`user_id`, `note_id`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_unicode_ci COMMENT ='笔记收藏表';
|
||||
|
||||
|
||||
-- 表:t_note_count
|
||||
CREATE TABLE `t_note_count`
|
||||
(
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`note_id` bigint unsigned NOT NULL COMMENT '笔记ID',
|
||||
`like_total` bigint DEFAULT '0' COMMENT '获得点赞总数',
|
||||
`collect_total` bigint DEFAULT '0' COMMENT '获得收藏总数',
|
||||
`comment_total` bigint DEFAULT '0' COMMENT '被评论总数',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE KEY `uk_note_id` (`note_id`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_unicode_ci COMMENT ='笔记计数表';
|
||||
|
||||
-- 表:t_user_count
|
||||
CREATE TABLE `t_user_count`
|
||||
(
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`user_id` bigint unsigned NOT NULL COMMENT '用户ID',
|
||||
`fans_total` bigint DEFAULT '0' COMMENT '粉丝总数',
|
||||
`following_total` bigint DEFAULT '0' COMMENT '关注总数',
|
||||
`note_total` bigint DEFAULT '0' COMMENT '发布笔记总数',
|
||||
`like_total` bigint DEFAULT '0' COMMENT '获得点赞总数',
|
||||
`collect_total` bigint DEFAULT '0' COMMENT '获得收藏总数',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE KEY `uk_user_id` (`user_id`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_unicode_ci
|
||||
COMMENT ='用户计数表';
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user