├── .gitignore
├── README.md
├── chathub-common
├── pom.xml
└── src
│ └── main
│ └── java
│ └── bupt
│ └── edu
│ └── jhc
│ └── chathub
│ └── common
│ ├── aspect
│ └── ReqLogRecord.java
│ ├── config
│ ├── CorsConfig.java
│ ├── MvcConfig.java
│ ├── MybatisPlusConfig.java
│ ├── SwaggerConfig.java
│ └── ThreadPoolConfig.java
│ ├── domain
│ ├── constants
│ │ ├── MDCKeys.java
│ │ ├── MqConstants.java
│ │ ├── RedisConstants.java
│ │ └── SystemConstants.java
│ ├── enums
│ │ └── ErrorStatus.java
│ └── vo
│ │ ├── request
│ │ └── CursorPageBaseReq.java
│ │ └── resp
│ │ ├── CursorPageBaseResp.java
│ │ └── Response.java
│ ├── interceptor
│ ├── CheckTokenInterceptor.java
│ └── RefreshTokenInterceptor.java
│ ├── service
│ └── cache
│ │ ├── AbstractRedisStringCache.java
│ │ └── BatchCache.java
│ └── utils
│ ├── CursorUtils.java
│ ├── JsonUtils.java
│ ├── PasswordEncoder.java
│ ├── RedisUtils.java
│ ├── context
│ ├── RequestHolder.java
│ └── RequestInfo.java
│ ├── exception
│ ├── BizException.java
│ ├── GlobalExceptionHandler.java
│ └── ThrowUtils.java
│ └── regex
│ ├── RegexPatterns.java
│ └── RegexUtils.java
├── chathub-server
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── bupt
│ │ └── edu
│ │ └── jhc
│ │ └── chathub
│ │ └── server
│ │ ├── ChathubApplication.java
│ │ ├── chat
│ │ ├── controller
│ │ │ └── MessageController.java
│ │ ├── domain
│ │ │ ├── dto
│ │ │ │ ├── FileMsgDTO.java
│ │ │ │ ├── ImgMsgDTO.java
│ │ │ │ ├── MessageExtra.java
│ │ │ │ ├── MsgPageReq.java
│ │ │ │ ├── SendMsgDTO.java
│ │ │ │ └── TextMsgDTO.java
│ │ │ ├── entity
│ │ │ │ ├── Message.java
│ │ │ │ ├── Room.java
│ │ │ │ └── UserRoom.java
│ │ │ ├── enums
│ │ │ │ └── MsgTypeEnum.java
│ │ │ └── vo
│ │ │ │ ├── RoomVO.java
│ │ │ │ └── ShowMsgVO.java
│ │ ├── event
│ │ │ ├── MessageSendEvent.java
│ │ │ └── listener
│ │ │ │ └── MessageSendListener.java
│ │ ├── mapper
│ │ │ ├── MessageMapper.java
│ │ │ ├── RoomMapper.java
│ │ │ └── UserRoomMapper.java
│ │ └── service
│ │ │ ├── IMessageService.java
│ │ │ ├── IRoomService.java
│ │ │ ├── adapter
│ │ │ └── MsgAdapter.java
│ │ │ ├── cache
│ │ │ ├── RoomLatestMsgCache.java
│ │ │ └── UserRoomCache.java
│ │ │ ├── impl
│ │ │ ├── MessageServiceImpl.java
│ │ │ └── RoomServiceImpl.java
│ │ │ └── strategy
│ │ │ ├── AbstractMsgHandler.java
│ │ │ ├── FileMsgHandler.java
│ │ │ ├── ImgMsgHandler.java
│ │ │ ├── MsgHandlerFactory.java
│ │ │ └── TextMsgHandler.java
│ │ ├── friend
│ │ ├── controller
│ │ │ ├── FriendController.java
│ │ │ └── NoticeController.java
│ │ ├── domain
│ │ │ ├── dto
│ │ │ │ ├── FriendApplication.java
│ │ │ │ └── FriendApplicationReply.java
│ │ │ ├── entity
│ │ │ │ ├── FriendNotice.java
│ │ │ │ └── FriendRelation.java
│ │ │ └── vo
│ │ │ │ └── FriendNoticeVO.java
│ │ ├── mapper
│ │ │ ├── FriendNoticeMapper.java
│ │ │ └── FriendRelationMapper.java
│ │ └── service
│ │ │ ├── IFriendNoticeService.java
│ │ │ ├── IFriendService.java
│ │ │ └── impl
│ │ │ ├── FriendNoticeServiceImpl.java
│ │ │ └── FriendServiceImpl.java
│ │ ├── group
│ │ ├── controller
│ │ │ └── GroupController.java
│ │ ├── domain
│ │ │ ├── dto
│ │ │ │ ├── CreateGroupDTO.java
│ │ │ │ └── InvitationRespDTO.java
│ │ │ ├── entity
│ │ │ │ ├── Group.java
│ │ │ │ ├── GroupNotice.java
│ │ │ │ └── GroupRelation.java
│ │ │ └── vo
│ │ │ │ ├── GroupNoticeVO.java
│ │ │ │ └── GroupVO.java
│ │ ├── mapper
│ │ │ ├── GroupMapper.java
│ │ │ ├── GroupNoticeMapper.java
│ │ │ └── GroupRelationMapper.java
│ │ └── service
│ │ │ ├── IGroupNoticeService.java
│ │ │ ├── IGroupService.java
│ │ │ ├── adapter
│ │ │ ├── GroupAdapter.java
│ │ │ └── GroupNoticeAdapter.java
│ │ │ └── impl
│ │ │ ├── GroupNoticeServiceImpl.java
│ │ │ └── GroupServiceImpl.java
│ │ ├── sse
│ │ ├── controller
│ │ │ └── SseController.java
│ │ ├── domain
│ │ │ ├── enums
│ │ │ │ └── SseRespType.java
│ │ │ └── vo
│ │ │ │ └── SseResponse.java
│ │ ├── manager
│ │ │ └── SseSessionManager.java
│ │ └── service
│ │ │ ├── ISseService.java
│ │ │ └── impl
│ │ │ └── SseServiceImpl.java
│ │ ├── trend
│ │ ├── controller
│ │ │ ├── CommentController.java
│ │ │ └── TrendController.java
│ │ ├── domain
│ │ │ ├── dto
│ │ │ │ ├── comment
│ │ │ │ │ └── PostCommentDTO.java
│ │ │ │ └── talk
│ │ │ │ │ ├── CreateTalkDTO.java
│ │ │ │ │ ├── ImgDTO.java
│ │ │ │ │ ├── LikeInfoDTO.java
│ │ │ │ │ ├── TalkExtra.java
│ │ │ │ │ └── VideoDTO.java
│ │ │ ├── entity
│ │ │ │ ├── Comment.java
│ │ │ │ ├── Feeds.java
│ │ │ │ ├── Like.java
│ │ │ │ └── Talk.java
│ │ │ └── vo
│ │ │ │ ├── CommentVO.java
│ │ │ │ └── TalkVO.java
│ │ ├── mapper
│ │ │ ├── CommentMapper.java
│ │ │ ├── FeedsMapper.java
│ │ │ ├── LikeMapper.java
│ │ │ └── TalkMapper.java
│ │ ├── mq
│ │ │ ├── feeds
│ │ │ │ ├── FeedsInitMain.java
│ │ │ │ ├── FeedsMessage.java
│ │ │ │ ├── FeedsMessageConsumer.java
│ │ │ │ └── FeedsMessageProducer.java
│ │ │ └── like
│ │ │ │ ├── LikeInitMain.java
│ │ │ │ ├── LikeMessage.java
│ │ │ │ ├── LikeMessageConsumer.java
│ │ │ │ └── LikeMessageProducer.java
│ │ └── service
│ │ │ ├── ICommentService.java
│ │ │ ├── ITrendService.java
│ │ │ └── impl
│ │ │ ├── CommentServiceImpl.java
│ │ │ ├── FeedsServiceImpl.java
│ │ │ └── TrendServiceImpl.java
│ │ ├── user
│ │ ├── controller
│ │ │ ├── OSSController.java
│ │ │ └── UserController.java
│ │ ├── domain
│ │ │ ├── dto
│ │ │ │ ├── LoginFormDTO.java
│ │ │ │ ├── PhoneLoginFormDTO.java
│ │ │ │ ├── RegisterFormDTO.java
│ │ │ │ └── UserDTO.java
│ │ │ ├── entity
│ │ │ │ └── User.java
│ │ │ └── vo
│ │ │ │ ├── ForceLogoutInfo.java
│ │ │ │ └── UserVO.java
│ │ ├── mapper
│ │ │ └── UserMapper.java
│ │ └── service
│ │ │ ├── IUserService.java
│ │ │ └── impl
│ │ │ └── UserServiceImpl.java
│ │ └── websocket
│ │ ├── NettyWebSocketServer.java
│ │ ├── domain
│ │ ├── enums
│ │ │ └── WSReqEnum.java
│ │ ├── req
│ │ │ └── WSReqDTO.java
│ │ └── resp
│ │ │ └── WSResponse.java
│ │ ├── handler
│ │ ├── HttpHeaderHandler.java
│ │ └── NettyWebSocketServerHandler.java
│ │ ├── service
│ │ ├── IWebSocketService.java
│ │ └── impl
│ │ │ └── WebSocketServiceImpl.java
│ │ └── utils
│ │ └── NettyUtils.java
│ └── resources
│ ├── application.yaml
│ └── logback.xml
├── chathub-tools
├── chathub-frequency-control
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ └── java
│ │ └── bupt
│ │ └── edu
│ │ └── jhc
│ │ └── chathub
│ │ └── frequency_control
│ │ ├── annotation
│ │ ├── FrequencyControl.java
│ │ └── FrequencyControlContainer.java
│ │ ├── aspect
│ │ └── FrequencyControlAspect.java
│ │ ├── domain
│ │ └── FrequencyControlDTO.java
│ │ ├── service
│ │ ├── AbstractFrequencyControlService.java
│ │ ├── FrequencyControlStrategyFactory.java
│ │ └── strategy
│ │ │ └── TotalCountWithInFixTimeFrequencyController.java
│ │ └── utils
│ │ ├── FrequencyControlUtils.java
│ │ ├── JsonUtils.java
│ │ ├── RedisUtils2.java
│ │ └── SpElUtils.java
├── chathub-oss-starter
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ ├── java
│ │ └── bupt
│ │ │ └── edu
│ │ │ └── jhc
│ │ │ └── chathub
│ │ │ └── oss
│ │ │ ├── FileUtils.java
│ │ │ ├── OssProperties.java
│ │ │ ├── OssType.java
│ │ │ └── minio
│ │ │ ├── MinioConfig.java
│ │ │ └── MinioTemplate.java
│ │ └── resources
│ │ └── META-INF
│ │ └── spring.factories
└── pom.xml
├── docs
├── chathub.sql
├── deployment
│ ├── java.sh
│ ├── minio
│ │ └── docker-compose.yml
│ ├── mysql
│ │ └── docker-compose.yml
│ ├── rabbitmq
│ │ └── docker-compose.yml
│ └── redis
│ │ └── docker-compose.yml
└── images
│ ├── 图片1.jpg
│ ├── 图片2.jpg
│ ├── 图片3.jpg
│ ├── 图片4.jpg
│ └── 系统架构图.jpg
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea
8 | *.iws
9 | *.iml
10 | *.ipr
11 |
12 | ### Eclipse ###
13 | .apt_generated
14 | .classpath
15 | .factorypath
16 | .project
17 | .settings
18 | .springBeans
19 | .sts4-cache
20 |
21 | ### NetBeans ###
22 | /nbproject/private/
23 | /nbbuild/
24 | /dist/
25 | /nbdist/
26 | /.nb-gradle/
27 | build/
28 | !**/src/main/**/build/
29 | !**/src/test/**/build/
30 |
31 | ### VS Code ###
32 | .vscode/
33 |
34 | ### Mac OS ###
35 | .DS_Store
36 |
37 | ### data ###
38 | data/
39 |
40 | ### application-prod.properties ###
41 | chathub-server/src/main/resources/application-prod.properties
42 | chathub-server/src/main/resources/application-dev.properties
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # chathub - 一个简化版qq的移动端项目
2 |
3 | >聊天中心项目:仿照 qq 移动端的 UI 页面,实现了 qq 相关的核心功能!
4 | >
5 | >前后端全栈项目 By [JollyCorivuG](https://github.com/JollyCorivuG)
6 |
7 | 上线地址:[chathub.love](http://www.chathub.love/)
8 |
9 | ## 效果展示
10 |
11 | 
12 |
13 | 
14 |
15 | 
16 |
17 | 
18 |
19 | ## 功能大全
20 |
21 | ### 用户
22 | - 用户注册、登录(含账号、手机验证码两种登录方式)
23 | - 用户可以通过关键字搜索用户,并发送好友申请
24 | - 用户可以查看通知,同意或拒绝好友申请
25 | - 同一个账号只能在一个浏览器登录,否则原有账号会被强制下线
26 | - 用户可以修改头像、用户名等个人信息
27 |
28 | ### 消息
29 | - 用户可以发送消息给自己的好友(支持表情包、图片、文件等多种类型)
30 | - 用户可以实时接收消息
31 | - 消息面板自动刷新,会更新消息未读数
32 | - 用户可以删除会话信息,并在有消息时重新显示
33 |
34 | ### 群组
35 | - 用户可以创建群组,并指定群组相关信息(头像,最大人数限制等)
36 | - 用户可以邀请自己的好友加入群组
37 | - 用户可以在群组内发送消息,同属一个群组的人都能实时收到消息
38 | - 用户可以同意、拒绝入群邀请
39 |
40 | ### 动态
41 | - 用户可以发送动态,并可以选取相应的图片
42 | - 用户可以点赞动态,并看到最新点赞的人和点赞总数
43 | - 用户可以评论好友发送的动态,也可以进行评论的回复
44 |
45 | ## 技术栈
46 | ### 前端
47 | - vue3 + ts
48 | - Vant4 UI
49 | - axios 请求库
50 | - pinia 状态管理
51 | - pinia 持久化插件
52 | - Vue Router 路由管理
53 |
54 | ### 后端
55 | - Java 8 + Spring Boot 框架(spring boot 2.6.7)
56 | - Spring MVC + Mybatis Plus 框架
57 | - Knife4j + Swagger 生成接口文档
58 | - MySQL 8.x (数据存储) + Redis(缓存)
59 | - Netty + WebSocket 实现即时通讯
60 | - SSE 实现消息列表实时刷新
61 | - RabbitMQ 消息队列
62 | - MinIO 实现文件存储
63 |
64 | ## 系统架构
65 |
66 | 
67 |
68 |
--------------------------------------------------------------------------------
/chathub-common/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | bupt.edu.jhc
8 | chathub
9 | 1.0-SNAPSHOT
10 |
11 |
12 | chathub-common
13 |
14 |
15 | 8
16 | 8
17 | UTF-8
18 |
19 |
20 |
21 |
22 | org.projectlombok
23 | lombok
24 |
25 |
26 | cn.hutool
27 | hutool-all
28 |
29 |
30 | org.apache.commons
31 | commons-lang3
32 |
33 |
34 | org.springframework.boot
35 | spring-boot-starter
36 |
37 |
38 | org.springframework.boot
39 | spring-boot-starter-actuator
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-aop
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-starter-web
48 |
49 |
50 | org.springframework.boot
51 | spring-boot-starter-data-redis
52 |
53 |
54 | com.baomidou
55 | mybatis-plus-boot-starter
56 |
57 |
58 | com.github.xiaoymin
59 | knife4j-spring-boot-starter
60 |
61 |
62 |
63 |
64 |
65 |
66 | org.springframework.boot
67 | spring-boot-maven-plugin
68 |
69 | none
70 | execute
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/chathub-common/src/main/java/bupt/edu/jhc/chathub/common/aspect/ReqLogRecord.java:
--------------------------------------------------------------------------------
1 | package bupt.edu.jhc.chathub.common.aspect;
2 |
3 | import bupt.edu.jhc.chathub.common.domain.constants.MDCKeys;
4 | import cn.hutool.core.lang.UUID;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.aspectj.lang.ProceedingJoinPoint;
7 | import org.aspectj.lang.annotation.Around;
8 | import org.aspectj.lang.annotation.Aspect;
9 | import org.slf4j.MDC;
10 | import org.springframework.stereotype.Component;
11 | import org.springframework.util.StopWatch;
12 | import org.springframework.web.context.request.RequestAttributes;
13 | import org.springframework.web.context.request.RequestContextHolder;
14 | import org.springframework.web.context.request.ServletRequestAttributes;
15 | import org.apache.commons.lang3.StringUtils;
16 |
17 | import javax.servlet.http.HttpServletRequest;
18 |
19 | /**
20 | * @Description: 接口请求日志记录
21 | * @Author: JollyCorivuG
22 | * @CreateTime: 2024/1/18
23 | */
24 | @Aspect
25 | @Component
26 | @Slf4j
27 | public class ReqLogRecord {
28 | @Around("execution(* bupt.edu.jhc.chathub.server.*.controller..*.*(..))")
29 | public Object doInterceptor(ProceedingJoinPoint point) throws Throwable {
30 | // 1.开启一个计时器
31 | StopWatch stopWatch = new StopWatch();
32 | stopWatch.start();
33 |
34 | // 2.输出请求日志
35 | // 2.1获取请求路径
36 | RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
37 | HttpServletRequest httpServletRequest = ((ServletRequestAttributes) requestAttributes).getRequest();
38 | // 2.2生成链路唯一 id
39 | String tId = UUID.randomUUID().toString();
40 | MDC.put(MDCKeys.TID, tId);
41 | String url = httpServletRequest.getRequestURI();
42 | // 2.3获取请求参数
43 | Object[] args = point.getArgs();
44 | String reqParam = "[" + StringUtils.join(args, ", ") + "]";
45 | // 2.4打印日志
46 | log.info("request start, path: {}, ip: {}, params: {}", url,
47 | httpServletRequest.getRemoteHost(), reqParam);
48 |
49 | // 3.执行原方法
50 | Object result = point.proceed();
51 | MDC.remove(MDCKeys.TID);
52 |
53 | // 4.输出响应日志
54 | stopWatch.stop();
55 | long totalTimeMillis = stopWatch.getTotalTimeMillis();
56 | log.info("request end, cost: {} ms", totalTimeMillis);
57 | return result;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/chathub-common/src/main/java/bupt/edu/jhc/chathub/common/config/CorsConfig.java:
--------------------------------------------------------------------------------
1 | package bupt.edu.jhc.chathub.common.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.web.cors.CorsConfiguration;
6 | import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
7 | import org.springframework.web.filter.CorsFilter;
8 |
9 | /**
10 | * @Description: 跨域配置类
11 | * @Author: JollyCorivuG
12 | * @CreateTime: 2024/1/16
13 | */
14 | @Configuration
15 | public class CorsConfig {
16 | @Bean
17 | public CorsFilter corsFilter() {
18 | // 1.创建 CORS 配置对象
19 | CorsConfiguration config = new CorsConfiguration();
20 | // 支持域
21 | config.addAllowedOriginPattern("*");
22 | // 是否发送 Cookie
23 | config.setAllowCredentials(true);
24 | // 支持请求方式
25 | config.addAllowedMethod("*");
26 | // 允许的原始请求头部信息
27 | config.addAllowedHeader("*");
28 | // 暴露的头部信息
29 | config.addExposedHeader("*");
30 | // 2.添加地址映射
31 | UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
32 | corsConfigurationSource.registerCorsConfiguration("/**", config);
33 | // 3.返回 CorsFilter 对象
34 | return new CorsFilter(corsConfigurationSource);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/chathub-common/src/main/java/bupt/edu/jhc/chathub/common/config/MvcConfig.java:
--------------------------------------------------------------------------------
1 | package bupt.edu.jhc.chathub.common.config;
2 |
3 | import bupt.edu.jhc.chathub.common.interceptor.CheckTokenInterceptor;
4 | import bupt.edu.jhc.chathub.common.interceptor.RefreshTokenInterceptor;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.data.redis.core.StringRedisTemplate;
7 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
8 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
9 |
10 | import javax.annotation.Resource;
11 |
12 | /**
13 | * @Description: Mvc 配置
14 | * @Author: JollyCorivuG
15 | * @CreateTime: 2024/1/16
16 | */
17 | @Configuration
18 | public class MvcConfig implements WebMvcConfigurer {
19 | @Resource
20 | private StringRedisTemplate stringRedisTemplate;
21 |
22 | @Override
23 | public void addInterceptors(InterceptorRegistry registry) {
24 | // 刷新token的拦截器
25 | registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns("/**").order(0);
26 |
27 | // 需要校验token的拦截器
28 | registry.addInterceptor(new CheckTokenInterceptor())
29 | .addPathPatterns("/api/**")
30 | .excludePathPatterns(
31 | "/api/upload/**",
32 | "/api/users/login",
33 | "/api/users/register",
34 | "/api/users/phone_code/**",
35 | "/api/users/phone_login",
36 | "/api/sse/unsubscribe"
37 | ).order(1);
38 | }
39 | }
--------------------------------------------------------------------------------
/chathub-common/src/main/java/bupt/edu/jhc/chathub/common/config/MybatisPlusConfig.java:
--------------------------------------------------------------------------------
1 | package bupt.edu.jhc.chathub.common.config;
2 |
3 | import com.baomidou.mybatisplus.annotation.DbType;
4 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
5 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.transaction.annotation.EnableTransactionManagement;
9 |
10 | /**
11 | * @Description: Mybatis Plus 配置类
12 | * @Author: JollyCorivuG
13 | * @CreateTime: 2024/1/16
14 | */
15 | @Configuration
16 | @EnableTransactionManagement
17 | public class MybatisPlusConfig {
18 | /**
19 | * 新增分页拦截器,并设置数据库类型为mysql
20 | * @return MybatisPlusInterceptor
21 | */
22 | @Bean
23 | public MybatisPlusInterceptor mybatisPlusInterceptor() {
24 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
25 | interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
26 | return interceptor;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/chathub-common/src/main/java/bupt/edu/jhc/chathub/common/config/ThreadPoolConfig.java:
--------------------------------------------------------------------------------
1 | package bupt.edu.jhc.chathub.common.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.context.annotation.Primary;
6 | import org.springframework.scheduling.annotation.AsyncConfigurer;
7 | import org.springframework.scheduling.annotation.EnableAsync;
8 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
9 |
10 | import java.util.concurrent.Executor;
11 | import java.util.concurrent.ThreadPoolExecutor;
12 |
13 | /**
14 | * @Description: 线程池配置
15 | * @Author: JollyCorivuG
16 | * @CreateTime: 2024/1/16
17 | */
18 | @Configuration
19 | @EnableAsync
20 | public class ThreadPoolConfig implements AsyncConfigurer {
21 | /**
22 | * 项目共用线程池
23 | */
24 | public static final String CHATHUB_EXECUTOR = "chathubExecutor";
25 | /**
26 | * websocket通信线程池
27 | */
28 | public static final String WS_EXECUTOR = "websocketExecutor";
29 |
30 | @Override
31 | public Executor getAsyncExecutor() {
32 | return chathubExecutor();
33 | }
34 |
35 | @Bean(CHATHUB_EXECUTOR)
36 | @Primary
37 | public ThreadPoolTaskExecutor chathubExecutor() {
38 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
39 | executor.setCorePoolSize(16); // 核心线程数
40 | executor.setMaxPoolSize(16); // 最大线程数
41 | executor.setQueueCapacity(200); // 队列大小
42 | executor.setThreadNamePrefix("chathub-executor-");
43 | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 满了调用线程执行,认为重要任务
44 | executor.initialize();
45 | return executor;
46 | }
47 |
48 | @Bean(WS_EXECUTOR)
49 | public ThreadPoolTaskExecutor websocketExecutor() {
50 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
51 | executor.setCorePoolSize(16);
52 | executor.setMaxPoolSize(16);
53 | executor.setQueueCapacity(1000); // 支持同时推送1000人
54 | executor.setThreadNamePrefix("websocket-executor-");
55 | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); //满了直接丢弃,默认为不重要消息推送
56 | executor.initialize();
57 | return executor;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/chathub-common/src/main/java/bupt/edu/jhc/chathub/common/domain/constants/MDCKeys.java:
--------------------------------------------------------------------------------
1 | package bupt.edu.jhc.chathub.common.domain.constants;
2 |
3 | /**
4 | * @Description: MDC 的 key 常量
5 | * @Author: JollyCorivuG
6 | * @CreateTime: 2024/1/16
7 | */
8 | public class MDCKeys {
9 | public static final String TID = "tid";
10 | public static final String UID = "uid";
11 | }
12 |
--------------------------------------------------------------------------------
/chathub-common/src/main/java/bupt/edu/jhc/chathub/common/domain/constants/MqConstants.java:
--------------------------------------------------------------------------------
1 | package bupt.edu.jhc.chathub.common.domain.constants;
2 |
3 | /**
4 | * @Description: MQ 常量
5 | * @Author: JollyCorivuG
6 | * @CreateTime: 2024/1/22
7 | */
8 | public class MqConstants {
9 | // 跟feeds流相关消息队列的常量
10 | public static final String FEEDS_EXCHANGE = "feeds_exchange";
11 | public static final String FEEDS_QUEUE = "feeds_queue";
12 | public static final String FEEDS_ROUTING_KEY = "feeds_routing_key";
13 |
14 | // 跟点赞相关消息队列的常量
15 | public static final String LIKE_EXCHANGE = "like_exchange";
16 | public static final String LIKE_QUEUE = "like_queue";
17 | public static final String LIKE_ROUTING_KEY = "like_routing_key";
18 | }
19 |
--------------------------------------------------------------------------------
/chathub-common/src/main/java/bupt/edu/jhc/chathub/common/domain/constants/RedisConstants.java:
--------------------------------------------------------------------------------
1 | package bupt.edu.jhc.chathub.common.domain.constants;
2 |
3 | /**
4 | * @Description: redis 常量
5 | * @Author: JollyCorivuG
6 | * @CreateTime: 2024/1/16
7 | */
8 | public class RedisConstants {
9 | // token保存30min
10 | public static final String USER_TOKEN_KEY = "user:token:";
11 | public static final Integer USER_TOKEN_KEY_TTL = 30;
12 |
13 | // 手机验证码保存1min
14 | public static final String PHONE_CODE_KEY = "phone:code:";
15 | public static final Integer PHONE_CODE_KEY_TTL = 1;
16 |
17 | // 记录在线用户
18 | public static final String ID_TO_TOKEN = "token:id:";
19 | public static final String ONLINE_USER_KEY = "online:user";
20 |
21 | // 记录用户的好友
22 | public static final String USER_FRIEND_KEY = "user:friend:";
23 |
24 | // 缓存查询用户
25 | public static final String CACHE_QUERY_USER_KET = "cache:users:";
26 | public static final Integer CACHE_QUERY_USER_KEY_TTL = 2;
27 |
28 | // 记录用户对于一个房间最新的已读消息id, key为用户id:房间id
29 | public static final String USER_READ_LATEST_MESSAGE = "user:read:latest:message:";
30 |
31 | // 记录每个房间最新的消息id, key为房间id
32 | public static final String ROOM_LATEST_MESSAGE = "room:latest:message:";
33 |
34 | // 记录用户删除一个会话时, 当前会话的最新消息id, key为用户id:会话id
35 | public static final String USER_DELETE_LATEST_MESSAGE = "user:delete:latest:message:";
36 |
37 | public static final String USER_ROOM_INFO = "user:room:info:";
38 |
39 |
40 | // 记录某个说说最新点赞的用户id, key为说说id
41 | public static final String TALK_LATEST_LIKE = "talk:latest:like:";
42 | }
43 |
--------------------------------------------------------------------------------
/chathub-common/src/main/java/bupt/edu/jhc/chathub/common/domain/constants/SystemConstants.java:
--------------------------------------------------------------------------------
1 | package bupt.edu.jhc.chathub.common.domain.constants;
2 |
3 | /**
4 | * @Description: 系统常量
5 | * @Author: JollyCorivuG
6 | * @CreateTime: 2024/1/18
7 | */
8 | public class SystemConstants {
9 | // 响应码 0:成功 1:失败
10 | public static final Integer SUCCESS_REQUEST = 0;
11 | public static final Integer COMMON_ERROR = 1;
12 |
13 | // 默认用户前缀名
14 | public static final String DEFAULT_NICK_NAME_PREFIX = "user_";
15 |
16 | // 默认用户头像
17 | public static final String DEV_DEFAULT_USER_AVATAR_URL = "/src/assets/images/avatar/default_user_avatar.jpg";
18 | public static final String PROD_DEFAULT_USER_AVATAR_URL = "/assets/images/avatar/default_user_avatar.jpg";
19 |
20 | // 查询用户的默认分页参数
21 | public static final Integer DEFAULT_PAGE_SIZE = 20;
22 |
23 | // 好友通知的一些常量
24 | public static final Integer NOTICE_TYPE_ADD_OTHER = 0; // 申请添加好友
25 | public static final Integer NOTICE_TYPE_OTHER_ADD_ME = 1; // 对方申请添加好友
26 | public static final Integer NOTICE_STATUS_WAIT = 0; // 待处理
27 | public static final Integer NOTICE_STATUS_PASS = 1; // 已通过
28 | public static final Integer NOTICE_STATUS_NOT_PASS = 2; // 未通过
29 | public static final Integer NOTICE_STATUS_REFUSE = 3; // 已拒绝
30 | public static final Integer NOTICE_STATUS_ACCEPT = 4; // 已接受
31 | public static final Integer NOTICE_STATUS_PENDING = 5; // 等待处理
32 |
33 | // 群组通知的一些常量
34 | public static final Integer GROUP_NOTICE_STATUS_PENDING = 0; // 等待处理
35 | public static final Integer GROUP_NOTICE_STATUS_AGREE = 1; // 已同意
36 | public static final Integer GROUP_NOTICE_STATUS_REFUSE = 2; // 已拒绝
37 |
38 | // 消息类型
39 | public static final Integer TEXT_MSG = 0;
40 | public static final Integer IMG_MSG = 1;
41 | public static final Integer FILE_MSG = 2;
42 |
43 | // WS响应消息类型
44 | public static final Integer WS_NORMAL_MSG = 0; // 普通消息
45 | public static final Integer WS_HEAD_SHAKE_SUCCESS_MSG = 1; // 握手成功消息
46 | public static final Integer WS_HEAD_SHAKE_FAIL_MSG = 2; // 握手失败消息
47 |
48 | // room类型
49 | public static final Integer ROOM_TYPE_SINGLE = 0; // 单聊
50 | public static final Integer ROOM_TYPE_GROUP = 1; // 群聊
51 |
52 | // 说说的额外内容的类型, 0表示图片, 1表示视频
53 | public static final Integer TALK_EXTRA_TYPE_IMG = 0;
54 | public static final Integer TALK_EXTRA_TYPE_VIDEO = 1;
55 | }
56 |
--------------------------------------------------------------------------------
/chathub-common/src/main/java/bupt/edu/jhc/chathub/common/domain/enums/ErrorStatus.java:
--------------------------------------------------------------------------------
1 | package bupt.edu.jhc.chathub.common.domain.enums;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 |
6 | /**
7 | * @Description: 错误状态枚举
8 | * @Author: JollyCorivuG
9 | * @CreateTime: 2024/1/18
10 | */
11 | @Getter
12 | @AllArgsConstructor
13 | public enum ErrorStatus {
14 | PARAMS_ERROR(40000, "请求参数错误"),
15 | NOT_LOGIN_ERROR(40100, "未登录"),
16 | NO_AUTH_ERROR(40101, "无权限"),
17 | NOT_FOUND_ERROR(40400, "请求数据不存在"),
18 | FORBIDDEN_ERROR(40300, "禁止访问"),
19 | SYSTEM_ERROR(50000, "系统内部异常"),
20 | OPERATION_ERROR(50001, "操作失败"),
21 | ;
22 |
23 | private final Integer code;
24 | private final String message;
25 | }
26 |
--------------------------------------------------------------------------------
/chathub-common/src/main/java/bupt/edu/jhc/chathub/common/domain/vo/request/CursorPageBaseReq.java:
--------------------------------------------------------------------------------
1 | package bupt.edu.jhc.chathub.common.domain.vo.request;
2 |
3 | import cn.hutool.core.util.StrUtil;
4 | import com.fasterxml.jackson.annotation.JsonIgnore;
5 | import io.swagger.annotations.ApiModel;
6 | import io.swagger.annotations.ApiModelProperty;
7 | import lombok.Data;
8 | import lombok.experimental.Accessors;
9 |
10 | /**
11 | * @Description: 游标分页基础请求
12 | * @Author: JollyCorivuG
13 | * @CreateTime: 2024/1/18
14 | */
15 | @Data
16 | @Accessors(chain = true)
17 | @ApiModel("游标分页基础请求")
18 | public class CursorPageBaseReq {
19 | @ApiModelProperty("每页大小")
20 | private Integer pageSize = 20; // 每页大小默认 20
21 | @ApiModelProperty("游标")
22 | private String cursor; // 游标
23 |
24 | @JsonIgnore
25 | public Boolean isFirstPage() {
26 | return StrUtil.isBlank(cursor);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/chathub-common/src/main/java/bupt/edu/jhc/chathub/common/domain/vo/resp/CursorPageBaseResp.java:
--------------------------------------------------------------------------------
1 | package bupt.edu.jhc.chathub.common.domain.vo.resp;
2 |
3 | import cn.hutool.core.collection.CollectionUtil;
4 | import com.fasterxml.jackson.annotation.JsonIgnore;
5 | import io.swagger.annotations.ApiModel;
6 | import io.swagger.annotations.ApiModelProperty;
7 | import lombok.AllArgsConstructor;
8 | import lombok.Data;
9 | import lombok.NoArgsConstructor;
10 | import lombok.experimental.Accessors;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | /**
16 | * @Description: 游标分页响应类
17 | * @Author: JollyCorivuG
18 | * @CreateTime: 2024/1/18
19 | */
20 | @Data
21 | @Accessors(chain = true)
22 | @ApiModel("游标分页响应")
23 | @AllArgsConstructor
24 | @NoArgsConstructor
25 | public class CursorPageBaseResp {
26 | @ApiModelProperty("是否最后一页")
27 | private Boolean isLast = Boolean.FALSE; // 是否最后一页
28 | @ApiModelProperty("游标 (下次翻页时需要带上的参数)")
29 | private String cursor; // 游标 (下次翻页时需要带上的参数)
30 | @ApiModelProperty("数据列表")
31 | private List list; // 数据列表
32 |
33 | public static CursorPageBaseResp change(CursorPageBaseResp> cursorPage, List list) {
34 | CursorPageBaseResp cursorPageBaseResp = new CursorPageBaseResp<>();
35 | cursorPageBaseResp
36 | .setIsLast(cursorPage.getIsLast())
37 | .setList(list)
38 | .setCursor(cursorPage.getCursor());
39 | return cursorPageBaseResp;
40 | }
41 |
42 | @JsonIgnore
43 | public Boolean isEmpty() {
44 | return CollectionUtil.isEmpty(list);
45 | }
46 |
47 | public static CursorPageBaseResp empty() {
48 | CursorPageBaseResp cursorPageBaseResp = new CursorPageBaseResp<>();
49 | cursorPageBaseResp
50 | .setIsLast(true)
51 | .setList(new ArrayList<>());
52 | return cursorPageBaseResp;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/chathub-common/src/main/java/bupt/edu/jhc/chathub/common/domain/vo/resp/Response.java:
--------------------------------------------------------------------------------
1 | package bupt.edu.jhc.chathub.common.domain.vo.resp;
2 |
3 | import bupt.edu.jhc.chathub.common.domain.constants.SystemConstants;
4 | import bupt.edu.jhc.chathub.common.domain.enums.ErrorStatus;
5 | import io.swagger.annotations.ApiModel;
6 | import io.swagger.annotations.ApiModelProperty;
7 | import lombok.Data;
8 | import lombok.experimental.Accessors;
9 |
10 | /**
11 | * @Description: 通用响应类
12 | * @Author: JollyCorivuG
13 | * @CreateTime: 2024/1/18
14 | */
15 | @Data
16 | @Accessors(chain = true)
17 | @ApiModel("基础响应体")
18 | public class Response {
19 | @ApiModelProperty("状态码 0-成功 其他值-失败")
20 | private Integer statusCode;
21 | @ApiModelProperty("状态信息")
22 | private String statusMsg;
23 | @ApiModelProperty("响应数据")
24 | private T data;
25 | public static Response success(T data) {
26 | Response response = new Response<>();
27 | return response
28 | .setStatusCode(SystemConstants.SUCCESS_REQUEST)
29 | .setStatusMsg("成功")
30 | .setData(data);
31 | }
32 | public static Response fail(ErrorStatus errorStatus) {
33 | Response response = new Response<>();
34 | return response
35 | .setStatusCode(errorStatus.getCode())
36 | .setStatusMsg(errorStatus.getMessage());
37 | }
38 | public static Response fail(Integer code, String message) {
39 | Response response = new Response<>();
40 | return response
41 | .setStatusCode(code)
42 | .setStatusMsg(message);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/chathub-common/src/main/java/bupt/edu/jhc/chathub/common/interceptor/CheckTokenInterceptor.java:
--------------------------------------------------------------------------------
1 | package bupt.edu.jhc.chathub.common.interceptor;
2 |
3 | import bupt.edu.jhc.chathub.common.domain.constants.MDCKeys;
4 | import bupt.edu.jhc.chathub.common.utils.context.RequestHolder;
5 | import org.slf4j.MDC;
6 | import org.springframework.lang.NonNull;
7 | import org.springframework.stereotype.Component;
8 | import org.springframework.web.servlet.HandlerInterceptor;
9 |
10 | import javax.servlet.http.HttpServletRequest;
11 | import javax.servlet.http.HttpServletResponse;
12 | import java.util.Objects;
13 |
14 | /**
15 | * @Description: 校验 token 拦截器
16 | * @Author: JollyCorivuG
17 | * @CreateTime: 2024/1/16
18 | */
19 | @Component
20 | public class CheckTokenInterceptor implements HandlerInterceptor {
21 | @Override
22 | public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
23 | if (Objects.isNull(RequestHolder.get())) {
24 | response.setStatus(401);
25 | return false;
26 | }
27 | return true;
28 | }
29 |
30 | @Override
31 | public void afterCompletion(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler, Exception ex) {
32 | MDC.remove(MDCKeys.UID);
33 | RequestHolder.remove();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/chathub-common/src/main/java/bupt/edu/jhc/chathub/common/interceptor/RefreshTokenInterceptor.java:
--------------------------------------------------------------------------------
1 | package bupt.edu.jhc.chathub.common.interceptor;
2 |
3 | import bupt.edu.jhc.chathub.common.utils.context.RequestInfo;
4 | import bupt.edu.jhc.chathub.common.domain.constants.MDCKeys;
5 | import bupt.edu.jhc.chathub.common.domain.constants.RedisConstants;
6 | import bupt.edu.jhc.chathub.common.utils.context.RequestHolder;
7 | import cn.hutool.core.bean.BeanUtil;
8 | import cn.hutool.core.util.StrUtil;
9 | import org.slf4j.MDC;
10 | import org.springframework.data.redis.core.StringRedisTemplate;
11 | import org.springframework.lang.NonNull;
12 | import org.springframework.stereotype.Component;
13 | import org.springframework.web.servlet.HandlerInterceptor;
14 |
15 | import javax.servlet.http.HttpServletRequest;
16 | import javax.servlet.http.HttpServletResponse;
17 | import java.util.Map;
18 | import java.util.concurrent.TimeUnit;
19 |
20 | /**
21 | * @Description: 刷新 token 拦截器
22 | * @Author: JollyCorivuG
23 | * @CreateTime: 2024/1/16
24 | */
25 | @Component
26 | public class RefreshTokenInterceptor implements HandlerInterceptor {
27 | private final StringRedisTemplate stringRedisTemplate;
28 |
29 | public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {
30 | this.stringRedisTemplate = stringRedisTemplate;
31 | }
32 |
33 | private static final String TOKEN_KET = "token";
34 |
35 | @Override
36 | public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
37 | // 1.获取请求头中的 token 或者 url 中的 token
38 | String token = request.getHeader(TOKEN_KET);
39 | if (StrUtil.isBlank(token)) {
40 | token = request.getParameter(TOKEN_KET);
41 | }
42 | if (StrUtil.isBlank(token)) {
43 | return true;
44 | }
45 |
46 | // 2.基于 token 从 redis 中获取请求信息
47 | Map