├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── document ├── deploy │ └── 线上部署 │ │ ├── Dockerfile-Backend-8888 │ │ ├── Dockerfile-Backend-8889 │ │ ├── docker-compose.yml │ │ ├── k8s │ │ ├── Dockerfile-Frontend │ │ ├── deploy-backend.yml │ │ ├── deploy-frontend.yml │ │ ├── ingress-nginx.yml │ │ ├── nginx.conf │ │ ├── svc-backend.yml │ │ └── svc-frontend.yml │ │ └── nginx.conf ├── guide │ ├── images │ │ ├── 04ae31df9b954bd5877454c719b738ec.png │ │ ├── 14a33ba7ba3a405c8b87cba53e121911.png │ │ ├── 1549a7a682614972883c48990c4c0dab.png │ │ ├── 277021c85e544bc190b560cd823a7b29.png │ │ ├── 278a9aff1cff417b87dfe3f014245066.png │ │ ├── 32383e2ca264426ca4e8e394c973d10d.png │ │ ├── 351392fb5b384e89b4d8dff057b65e07.png │ │ ├── 37a1e2f11dc642559c031b6168f9f286.png │ │ ├── 37ebf53c03284b319337b59676d50ce2.png │ │ ├── 47f282031d7347c78c02dba83ac31197.png │ │ ├── 4f81a25ecca74e9fabbd7172e971a73b.png │ │ ├── 52c07e2a2244435ea28cb91918da03b8.png │ │ ├── 52da01c64038499a9c617e1e31162236.png │ │ ├── 59215af56edc4aa89a8dda8a57decc23.png │ │ ├── 5c06d38bdbb3487cb4e2def9cd0fe869.png │ │ ├── 6cc48c2e8fda450cb78914506b18d575.png │ │ ├── 912a885fc1a3459d8dcd67c328c5d87c.png │ │ ├── 93e53e3ae2bd4490a7e0455240d63aa5.png │ │ ├── 9f8fec04d4d44b17a643416a2b2e0319.png │ │ ├── a5b808af78454c8c90fd036c2946eca9.png │ │ ├── b0b1977cfab24fdcb2724a5b720c2b08.png │ │ ├── b27f255816854074b8afdaa1c9ebbcad.png │ │ ├── c0e3367d12d84f7e99ef89a769d7952f.png │ │ ├── cae11a506c2a4c018e5b7ba3538a4f12.png │ │ ├── cfa7e96cb48c4ddf9b9a49119bf84057.png │ │ ├── e28f3ec401224d5cbcc0e6479201f04e.png │ │ ├── e31a2f1e468b41bc987d55ddb30c0415.png │ │ ├── f0559af942e64c5f8f4b4815f50da882.png │ │ ├── image-20240414191745575.png │ │ ├── image-20241019202710916.png │ │ ├── image-20241019204035779.png │ │ ├── image-20241019205009094.png │ │ ├── image-20241019205146845.png │ │ ├── image-20241019205223613.png │ │ └── image-20241027210413708.png │ ├── quick_chat.sql │ ├── 启动MQ.md │ └── 提交PR流程.md ├── image │ └── logo.png └── 待完成需求.md ├── pom.xml └── src └── main ├── java └── com │ └── quick │ ├── QuickChatApplication.java │ ├── api │ ├── controller │ │ ├── QuickChatApplyController.java │ │ ├── QuickChatContactController.java │ │ ├── QuickChatFileController.java │ │ ├── QuickChatGroupController.java │ │ ├── QuickChatGroupMemberController.java │ │ ├── QuickChatMsgController.java │ │ ├── QuickChatSearchController.java │ │ ├── QuickChatSessionController.java │ │ └── QuickChatUserController.java │ ├── mapper │ │ ├── QuickChatApplyMapper.java │ │ ├── QuickChatArchiveRecordMapper.java │ │ ├── QuickChatContactMapper.java │ │ ├── QuickChatEmojiMapper.java │ │ ├── QuickChatGroupMapper.java │ │ ├── QuickChatGroupMemberMapper.java │ │ ├── QuickChatMsgDorisMapper.java │ │ ├── QuickChatMsgMapper.java │ │ ├── QuickChatSessionMapper.java │ │ └── QuickChatUserMapper.java │ ├── service │ │ ├── QuickChatApplyService.java │ │ ├── QuickChatContactService.java │ │ ├── QuickChatEmojiService.java │ │ ├── QuickChatFileService.java │ │ ├── QuickChatGroupMemberService.java │ │ ├── QuickChatGroupService.java │ │ ├── QuickChatMsgService.java │ │ ├── QuickChatSessionService.java │ │ ├── QuickUserService.java │ │ └── impl │ │ │ ├── QuickChatApplyServiceImpl.java │ │ │ ├── QuickChatContactServiceImpl.java │ │ │ ├── QuickChatEmojiServiceImpl.java │ │ │ ├── QuickChatFileServiceImpl.java │ │ │ ├── QuickChatGroupMemberServiceImpl.java │ │ │ ├── QuickChatGroupServiceImpl.java │ │ │ ├── QuickChatMsgServiceImpl.java │ │ │ ├── QuickChatSessionServiceImpl.java │ │ │ └── QuickUserServiceImpl.java │ └── store │ │ ├── QuickChatApplyStore.java │ │ ├── QuickChatArchiveRecordStore.java │ │ ├── QuickChatContactStore.java │ │ ├── QuickChatEmojiStore.java │ │ ├── QuickChatGroupMemberStore.java │ │ ├── QuickChatGroupStore.java │ │ ├── QuickChatMsgStore.java │ │ ├── QuickChatSessionStore.java │ │ ├── QuickChatUserStore.java │ │ ├── doris │ │ ├── QuickChatMsgDorisStore.java │ │ └── impl │ │ │ └── QuickChatMsgDorisStoreImpl.java │ │ └── impl │ │ ├── QuickChatApplyStoreImpl.java │ │ ├── QuickChatArchiveRecordStoreImpl.java │ │ ├── QuickChatEmojiStoreImpl.java │ │ ├── QuickChatFriendContactStoreImpl.java │ │ ├── QuickChatGroupMemberStoreImpl.java │ │ ├── QuickChatGroupStoreImpl.java │ │ ├── QuickChatMsgStoreImpl.java │ │ ├── QuickChatSessionStoreImpl.java │ │ └── QuickChatUserStoreImpl.java │ └── common │ ├── adapter │ ├── ApplyAdapter.java │ ├── ContactAdapter.java │ ├── EmojiAdapter.java │ ├── FileExtraAdapter.java │ ├── GroupAdapter.java │ ├── GroupMemberAdapter.java │ ├── MsgAdapter.java │ ├── SessionAdapter.java │ └── UserAdapter.java │ ├── annotation │ └── RateLimiter.java │ ├── aspect │ ├── RateLimiterAspect.java │ └── WebLogAspect.java │ ├── config │ ├── BeanPostProcessorConfig.java │ ├── KaptchaConfig.java │ ├── LuaScriptConfig.java │ ├── MetaObjectConfig.java │ ├── MinioConfig.java │ ├── MybatisPlusConfig.java │ ├── RedisConfig.java │ ├── RocketMQConfig.java │ ├── SensitiveConfig.java │ ├── SwaggerConfiguration.java │ ├── WebMvcConfig.java │ └── XxlJobConfig.java │ ├── constant │ ├── RedisConstant.java │ └── RocketMQConstant.java │ ├── enums │ ├── ApplyTypeEnum.java │ ├── BucketEnum.java │ ├── ChatMsgEnum.java │ ├── EmailEnum.java │ ├── GenderEnum.java │ ├── LimitTypeEnum.java │ ├── ResponseEnum.java │ ├── SessionTypeEnum.java │ ├── WsPushEnum.java │ └── YesNoEnum.java │ ├── exception │ ├── GlobalExceptionHandler.java │ ├── QuickException.java │ └── QuickValidationException.java │ ├── interceptor │ └── LoginTokenInterceptor.java │ ├── job │ └── ChatSessionMsgJob.java │ ├── mq │ ├── consumer │ │ ├── apply │ │ │ ├── FriendApplyConsumer.java │ │ │ └── GroupApplyConsumer.java │ │ ├── msg │ │ │ ├── SendFriendMsgConsumer.java │ │ │ ├── SendGroupMsgConsumer.java │ │ │ └── SendMsgLoadingConsumer.java │ │ └── notice │ │ │ ├── GroupAddMemberConsumer.java │ │ │ ├── GroupDeleteMemberConsumer.java │ │ │ └── GroupReleaseConsumer.java │ └── producer │ │ └── MyRocketMQTemplate.java │ ├── netty │ ├── NettyChannelHandler.java │ ├── NettyWebSocketServer.java │ └── UserChannelRelation.java │ ├── pojo │ ├── dto │ │ ├── ChatMsgDTO.java │ │ ├── ChatMsgQueryDTO.java │ │ ├── EmailDTO.java │ │ ├── FileExtraDTO.java │ │ ├── FindBackFormDTO.java │ │ ├── GroupDTO.java │ │ ├── LoginFormDTO.java │ │ ├── RegisterFormDTO.java │ │ └── UserInfoDTO.java │ ├── entity │ │ └── WsPushEntity.java │ ├── po │ │ ├── QuickChatApply.java │ │ ├── QuickChatArchiveRecord.java │ │ ├── QuickChatContact.java │ │ ├── QuickChatEmoji.java │ │ ├── QuickChatGroup.java │ │ ├── QuickChatGroupMember.java │ │ ├── QuickChatMsg.java │ │ ├── QuickChatSession.java │ │ └── QuickChatUser.java │ └── vo │ │ ├── ChatMsgVO.java │ │ ├── ChatSessionVO.java │ │ └── ChatUserVO.java │ ├── response │ ├── BaseResponse.java │ └── R.java │ ├── sensitive │ ├── MySensitiveWordReplace.java │ ├── MyWordAllow.java │ └── MyWordDeny.java │ ├── strategy │ ├── email │ │ ├── AbstractEmailStrategy.java │ │ ├── EmailStrategyFactory.java │ │ └── handler │ │ │ ├── FindBackHandler.java │ │ │ ├── SendCodeHandler.java │ │ │ └── WarnUserHandler.java │ ├── file │ │ ├── AbstractFileStrategy.java │ │ ├── FileStrategyFactory.java │ │ └── handler │ │ │ ├── AvatarHandler.java │ │ │ ├── FileHandler.java │ │ │ └── VoiceHandler.java │ └── msg │ │ ├── AbstractChatMsgStrategy.java │ │ ├── ChatMsgStrategyFactory.java │ │ └── handler │ │ ├── AtMsgHandler.java │ │ ├── EmojiHandler.java │ │ ├── FileMsgHandler.java │ │ ├── FontMsgHandler.java │ │ ├── RecallMsgHandler.java │ │ ├── ReplyMsgHandler.java │ │ ├── VideoCallHandler.java │ │ ├── VoiceCallHandler.java │ │ └── VoiceMsgHandler.java │ ├── threadpool │ ├── MyThreadFactory.java │ ├── MyThreadPoolExecutor.java │ └── MyUncaughtExceptionHandler.java │ └── utils │ ├── AESUtil.java │ ├── AddressUtil.java │ ├── CookieUtil.java │ ├── EmailUtil.java │ ├── HttpServletUtil.java │ ├── IpUtil.java │ ├── JwtUtil.java │ ├── MinioUtil.java │ ├── RandomUtil.java │ ├── RedisUtil.java │ ├── RedissonLockUtil.java │ ├── RequestContextUtil.java │ └── SensitiveWordUtil.java └── resources ├── application-dev.yml ├── application.yml ├── banner.txt ├── email ├── findBack.html └── sendCode.html ├── ip2region └── ip2region.xdb ├── logback-spring.xml ├── lua └── RateLimit.lua ├── mapper ├── QuickChatApplyMapper.xml ├── QuickChatArchiveRecordMapper.xml ├── QuickChatContactMapper.xml ├── QuickChatEmojiMapper.xml ├── QuickChatGroupMapper.xml ├── QuickChatGroupMemberMapper.xml ├── QuickChatMsgDorisMapper.xml ├── QuickChatMsgMapper.xml ├── QuickChatSessionMapper.xml └── QuickChatUserMapper.xml └── sensitive ├── myNotSensitiveWords.txt └── mySensitiveWords.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific stuff 2 | .idea/**/workspace.xml 3 | .idea/**/tasks.xml 4 | .idea/**/dictionaries 5 | .idea/**/shelf 6 | 7 | # Sensitive or high-churn files 8 | .idea/**/dataSources/ 9 | .idea/**/dataSources.ids 10 | .idea/**/dataSources.local.xml 11 | .idea/**/sqlDataSources.xml 12 | .idea/**/dynamic.xml 13 | .idea/**/uiDesigner.xml 14 | .idea/**/dbnavigator.xml 15 | .idea 16 | 17 | # Gradle 18 | .idea/**/gradle.xml 19 | .idea/**/libraries 20 | 21 | # CMake 22 | cmake-build-debug/ 23 | cmake-build-release/ 24 | 25 | # Mongo Explorer plugin 26 | .idea/**/mongoSettings.xml 27 | 28 | # File-based project format 29 | *.iws 30 | 31 | # IntelliJ 32 | out/ 33 | 34 | # mpeltonen/sbt-idea plugin 35 | .idea_modules/ 36 | 37 | # JIRA plugin 38 | atlassian-ide-plugin.xml 39 | 40 | # Cursive Clojure plugin 41 | .idea/replstate.xml 42 | 43 | # Crashlytics plugin (for Android Studio and IntelliJ) 44 | com_crashlytics_export_strings.xml 45 | crashlytics.properties 46 | crashlytics-build.properties 47 | fabric.properties 48 | 49 | # Editor-based Rest Client 50 | .idea/httpRequests 51 | 52 | ### Java template 53 | # Compiled class file 54 | *.class 55 | 56 | # Log file 57 | *.log 58 | 59 | # BlueJ files 60 | *.ctxt 61 | 62 | # Mobile Tools for Java (J2ME) 63 | .mtj.tmp/ 64 | 65 | # Package Files # 66 | *.jar 67 | *.war 68 | *.nar 69 | *.ear 70 | *.zip 71 | *.tar.gz 72 | *.rar 73 | 74 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 75 | hs_err_pid* 76 | *.iml 77 | /.idea/ 78 | */target/ 79 | */*/target/ 80 | */*/*/target/ 81 | */*.iml 82 | */*/*.iml 83 | 84 | # 自定义 85 | application-prod.yml 86 | CodeGenerator.java -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |
6 | 7 | 8 | 9 | 10 |
11 |

麻烦您帮忙点个Star⭐

12 |
13 | 14 | ## ✨系统介绍 15 | 16 | 基于SpringBoot2 + JDK11的IM实时通讯聊天系统,通过Netty构建高性能WebSocket服务器。
17 | 具有单聊、群聊、文件传输、音频消息、实时通话视频等强大功能。
18 | 支持任意联网设备直接通过浏览器随时随地访问,消息多端系统实时同步。
19 | 20 | ## 🚀技术架构 21 | 22 | 23 | ## ✋加入我们 24 | 25 | - [🚢本地启动流程](https://github.com/Binx98/QuickChat/blob/master/docs/guide/%E6%9C%AC%E5%9C%B0%E7%8E%AF%E5%A2%83%E9%83%A8%E7%BD%B2.md) 26 | - [✍提交PR流程](https://github.com/Binx98/QuickChat/blob/master/docs/guide/%E6%8F%90%E4%BA%A4PR%E6%B5%81%E7%A8%8B.md) 27 | 28 | ## 🎉贡献名单 29 | 30 |
31 | 32 | 33 | 34 | | 姓名 | Github | 公司 | 35 | |:---:|:----------------------------------:|:-------------:| 36 | | 徐志斌 | https://github.com/Binx98 | PARAVERSE 平行云 | 37 | | 陈辰 | https://github.com/GeforceLite | SBI BITS | 38 | | 刘东辉 | https://github.com/gentlemanJiu | 中科院信工所 | 39 | -------------------------------------------------------------------------------- /document/deploy/线上部署/Dockerfile-Backend-8888: -------------------------------------------------------------------------------- 1 | FROM openjdk:17 2 | MAINTAINER 徐志斌 3 | ADD quick-chat.jar /quick-chat.jar 4 | EXPOSE 8888 5 | ENTRYPOINT ["java", "-jar", "quick-chat.jar"] -------------------------------------------------------------------------------- /document/deploy/线上部署/Dockerfile-Backend-8889: -------------------------------------------------------------------------------- 1 | FROM openjdk:17 2 | MAINTAINER 徐志斌 3 | ADD quick-chat.jar /quick-chat.jar 4 | EXPOSE 8889 5 | ENTRYPOINT ["java", "-jar", "quick-chat.jar"] -------------------------------------------------------------------------------- /document/deploy/线上部署/k8s/Dockerfile-Frontend: -------------------------------------------------------------------------------- 1 | # 基础镜像 Nginx 2 | FROM nginx:1.24.0 3 | 4 | # 拷贝当前目录的文件到指定文件夹下,改文件夹为镜像中的文件夹 5 | COPY ./dist /usr/share/nginx/html 6 | 7 | # 拷贝nginx.conf文件到镜像下,替换掉原有的nginx.conf 8 | COPY nginx.conf /etc/nginx/nginx.conf 9 | -------------------------------------------------------------------------------- /document/deploy/线上部署/k8s/deploy-backend.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: backend-deployment 5 | namespace: prod-env 6 | labels: 7 | app: backend-label 8 | spec: 9 | replicas: 3 10 | selector: 11 | matchLabels: 12 | app: backend-label 13 | template: 14 | metadata: 15 | labels: 16 | app: backend-label 17 | spec: 18 | containers: 19 | - name: backend 20 | image: 镜像仓库内网IP:9999/test/backend-project:1.0 21 | imagePullPolicy: Always 22 | ports: 23 | - containerPort: 8080 24 | resources: 25 | requests: 26 | memory: 300Mi 27 | cpu: 200m 28 | limits: 29 | memory: 500Mi 30 | cpu: 400m -------------------------------------------------------------------------------- /document/deploy/线上部署/k8s/deploy-frontend.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: frontend-deployment 5 | namespace: prod-env 6 | labels: 7 | app: frontend-label 8 | spec: 9 | replicas: 3 10 | selector: 11 | matchLabels: 12 | app: frontend-label 13 | template: 14 | metadata: 15 | labels: 16 | app: frontend-label 17 | spec: 18 | containers: 19 | - name: frontend 20 | image: 镜像仓库内网IP:9999/test/frontend-project:1.0 21 | imagePullPolicy: Always 22 | ports: 23 | - containerPort: 80 24 | resources: 25 | requests: 26 | memory: 300Mi 27 | cpu: 200m 28 | limits: 29 | memory: 500Mi 30 | cpu: 400m 31 | -------------------------------------------------------------------------------- /document/deploy/线上部署/k8s/ingress-nginx.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: my-ingress 5 | namespace: prod-env 6 | spec: 7 | ingressClassName: nginx 8 | rules: 9 | - host: 域名 10 | http: 11 | paths: 12 | - path: / 13 | pathType: Prefix 14 | backend: 15 | service: 16 | name: frontend-service 17 | port: 18 | number: 80 19 | 20 | # 后端服务 Service 就不用暴露了,不需要直接把后端接口给别人调用啊! 21 | # - path: /api 22 | # pathType: Prefix 23 | # backend: 24 | # service: 25 | # name: backend-service 26 | # port: 27 | # number: 8080 -------------------------------------------------------------------------------- /document/deploy/线上部署/k8s/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | events { 4 | worker_connections 1024; 5 | } 6 | 7 | http { 8 | include mime.types; 9 | default_type application/octet-stream; 10 | sendfile on; 11 | keepalive_timeout 65; 12 | 13 | server { 14 | listen 80; 15 | server_name localhost; 16 | 17 | location / { 18 | root /usr/share/nginx/html; 19 | try_files $uri $uri/ /index.html; 20 | index index.html index.htm; 21 | } 22 | 23 | location /api/ { 24 | proxy_http_version 1.1; 25 | proxy_set_header Host $host; 26 | proxy_set_header X-Real-IP $remote_addr; 27 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 28 | proxy_set_header Connection ""; 29 | # 这里用的是 K8S Service 服务名访问方式 30 | proxy_pass http://backend-service.prod-env.svc.cluster.local:8080; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /document/deploy/线上部署/k8s/svc-backend.yml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: backend-service 5 | namespace: prod-env 6 | labels: 7 | app: backend-label 8 | spec: 9 | selector: 10 | app: backend-label 11 | type: ClusterIP 12 | ports: 13 | - protocol: TCP 14 | port: 8080 15 | targetPort: 8080 16 | -------------------------------------------------------------------------------- /document/deploy/线上部署/k8s/svc-frontend.yml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: frontend-service 5 | namespace: prod-env 6 | labels: 7 | app: frontend-label 8 | spec: 9 | selector: 10 | app: frontend-label 11 | type: ClusterIP 12 | ports: 13 | - protocol: TCP 14 | port: 80 15 | targetPort: 80 16 | -------------------------------------------------------------------------------- /document/deploy/线上部署/nginx.conf: -------------------------------------------------------------------------------- 1 | upstream backend { 2 | server JAR内网ip:8888 max_fails=3 fail_timeout=30s; 3 | server JAR内网ip:8889 max_fails=3 fail_timeout=30s; 4 | } 5 | 6 | upstream websocket { 7 | server JAR内网ip:8888 max_fails=3 fail_timeout=30s; 8 | server JAR内网ip:8889 max_fails=3 fail_timeout=30s; 9 | } 10 | 11 | server { 12 | listen 80; 13 | server_name localhost; 14 | 15 | location / { 16 | root /usr/share/nginx/html/pc; 17 | if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') { 18 | root /usr/share/nginx/html/mobile; 19 | } 20 | index index.html index.htm; 21 | } 22 | 23 | location /api/ { 24 | proxy_http_version 1.1; 25 | proxy_set_header Host $host; 26 | proxy_set_header Connection ""; 27 | proxy_set_header X-Real-IP $remote_addr; 28 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 29 | proxy_pass http://backend; 30 | } 31 | 32 | location /ws/ { 33 | proxy_http_version 1.1; 34 | proxy_set_header Host $host; 35 | proxy_set_header Upgrade $http_upgrade"; 36 | proxy_set_header Connection "Upgrade"; 37 | proxy_pass http://websocket; 38 | } 39 | } -------------------------------------------------------------------------------- /document/guide/images/04ae31df9b954bd5877454c719b738ec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/04ae31df9b954bd5877454c719b738ec.png -------------------------------------------------------------------------------- /document/guide/images/14a33ba7ba3a405c8b87cba53e121911.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/14a33ba7ba3a405c8b87cba53e121911.png -------------------------------------------------------------------------------- /document/guide/images/1549a7a682614972883c48990c4c0dab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/1549a7a682614972883c48990c4c0dab.png -------------------------------------------------------------------------------- /document/guide/images/277021c85e544bc190b560cd823a7b29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/277021c85e544bc190b560cd823a7b29.png -------------------------------------------------------------------------------- /document/guide/images/278a9aff1cff417b87dfe3f014245066.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/278a9aff1cff417b87dfe3f014245066.png -------------------------------------------------------------------------------- /document/guide/images/32383e2ca264426ca4e8e394c973d10d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/32383e2ca264426ca4e8e394c973d10d.png -------------------------------------------------------------------------------- /document/guide/images/351392fb5b384e89b4d8dff057b65e07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/351392fb5b384e89b4d8dff057b65e07.png -------------------------------------------------------------------------------- /document/guide/images/37a1e2f11dc642559c031b6168f9f286.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/37a1e2f11dc642559c031b6168f9f286.png -------------------------------------------------------------------------------- /document/guide/images/37ebf53c03284b319337b59676d50ce2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/37ebf53c03284b319337b59676d50ce2.png -------------------------------------------------------------------------------- /document/guide/images/47f282031d7347c78c02dba83ac31197.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/47f282031d7347c78c02dba83ac31197.png -------------------------------------------------------------------------------- /document/guide/images/4f81a25ecca74e9fabbd7172e971a73b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/4f81a25ecca74e9fabbd7172e971a73b.png -------------------------------------------------------------------------------- /document/guide/images/52c07e2a2244435ea28cb91918da03b8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/52c07e2a2244435ea28cb91918da03b8.png -------------------------------------------------------------------------------- /document/guide/images/52da01c64038499a9c617e1e31162236.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/52da01c64038499a9c617e1e31162236.png -------------------------------------------------------------------------------- /document/guide/images/59215af56edc4aa89a8dda8a57decc23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/59215af56edc4aa89a8dda8a57decc23.png -------------------------------------------------------------------------------- /document/guide/images/5c06d38bdbb3487cb4e2def9cd0fe869.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/5c06d38bdbb3487cb4e2def9cd0fe869.png -------------------------------------------------------------------------------- /document/guide/images/6cc48c2e8fda450cb78914506b18d575.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/6cc48c2e8fda450cb78914506b18d575.png -------------------------------------------------------------------------------- /document/guide/images/912a885fc1a3459d8dcd67c328c5d87c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/912a885fc1a3459d8dcd67c328c5d87c.png -------------------------------------------------------------------------------- /document/guide/images/93e53e3ae2bd4490a7e0455240d63aa5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/93e53e3ae2bd4490a7e0455240d63aa5.png -------------------------------------------------------------------------------- /document/guide/images/9f8fec04d4d44b17a643416a2b2e0319.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/9f8fec04d4d44b17a643416a2b2e0319.png -------------------------------------------------------------------------------- /document/guide/images/a5b808af78454c8c90fd036c2946eca9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/a5b808af78454c8c90fd036c2946eca9.png -------------------------------------------------------------------------------- /document/guide/images/b0b1977cfab24fdcb2724a5b720c2b08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/b0b1977cfab24fdcb2724a5b720c2b08.png -------------------------------------------------------------------------------- /document/guide/images/b27f255816854074b8afdaa1c9ebbcad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/b27f255816854074b8afdaa1c9ebbcad.png -------------------------------------------------------------------------------- /document/guide/images/c0e3367d12d84f7e99ef89a769d7952f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/c0e3367d12d84f7e99ef89a769d7952f.png -------------------------------------------------------------------------------- /document/guide/images/cae11a506c2a4c018e5b7ba3538a4f12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/cae11a506c2a4c018e5b7ba3538a4f12.png -------------------------------------------------------------------------------- /document/guide/images/cfa7e96cb48c4ddf9b9a49119bf84057.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/cfa7e96cb48c4ddf9b9a49119bf84057.png -------------------------------------------------------------------------------- /document/guide/images/e28f3ec401224d5cbcc0e6479201f04e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/e28f3ec401224d5cbcc0e6479201f04e.png -------------------------------------------------------------------------------- /document/guide/images/e31a2f1e468b41bc987d55ddb30c0415.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/e31a2f1e468b41bc987d55ddb30c0415.png -------------------------------------------------------------------------------- /document/guide/images/f0559af942e64c5f8f4b4815f50da882.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/f0559af942e64c5f8f4b4815f50da882.png -------------------------------------------------------------------------------- /document/guide/images/image-20240414191745575.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/image-20240414191745575.png -------------------------------------------------------------------------------- /document/guide/images/image-20241019202710916.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/image-20241019202710916.png -------------------------------------------------------------------------------- /document/guide/images/image-20241019204035779.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/image-20241019204035779.png -------------------------------------------------------------------------------- /document/guide/images/image-20241019205009094.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/image-20241019205009094.png -------------------------------------------------------------------------------- /document/guide/images/image-20241019205146845.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/image-20241019205146845.png -------------------------------------------------------------------------------- /document/guide/images/image-20241019205223613.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/image-20241019205223613.png -------------------------------------------------------------------------------- /document/guide/images/image-20241027210413708.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/guide/images/image-20241027210413708.png -------------------------------------------------------------------------------- /document/guide/启动MQ.md: -------------------------------------------------------------------------------- 1 | RocketMQ 需要先启动 NameServer 再启动 Broker,RocketMQ安装4.9.3版本即可 2 | 3 | 参考文档:[【RocketMQ】安装与部署(Windows)_rocketmq windows-CSDN博客](https://blog.csdn.net/m0_52777015/article/details/130928378) 4 | 5 | 启动nameServer 6 | 7 | ```text 8 | start mqnamesrv.cmd 9 | ``` 10 | 11 | ![image-20241019202710916](./images/image-20241019202710916.png) 12 | 13 | **启动Broker**:继续在同一命令提示符窗口中执行下面的命令来启动Broker 14 | 15 | ```text 16 | start mqbroker.cmd -n 127.0.0.1:9876 17 | ``` 18 | 19 | ![image-20241019204035779](./images/image-20241019204035779.png) 20 | 21 | 22 | 23 | 启动MQ的web管理端,这个自行百度即可,不做特别详细介绍:[RockeMQ Admin DashBoard](https://github.com/apache/rocketmq-dashboard) 24 | 25 | ``` 26 | mvn spring-boot:run 27 | ``` 28 | 29 | 30 | 31 | **启动时可能遇到的问题:** 32 | 33 | 如果你的电脑默认JDK不是8的情况下,那么默认就需要修改一下启动变量,比如我默认是11 34 | ![image-20241027210413708](./images/image-20241027210413708.png) 35 | 36 | 版本不对,XXX类已经过时,一般就是JAVA_HOME的版本不对,右键打开启动脚本,单独设置JDK8的路径即可 37 | 38 | ![image-20241019205223613](./images/image-20241019205223613.png) 39 | 40 | ![image-20241019205009094](./images/image-20241019205009094.png) 41 | 42 | ![image-20241019205146845](./images/image-20241019205146845.png) -------------------------------------------------------------------------------- /document/image/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/document/image/logo.png -------------------------------------------------------------------------------- /document/待完成需求.md: -------------------------------------------------------------------------------- 1 | - XXL-JOB整合 2 | - RocketMQ整合 3 | - 本地部署文档 -------------------------------------------------------------------------------- /src/main/java/com/quick/QuickChatApplication.java: -------------------------------------------------------------------------------- 1 | package com.quick; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.mybatis.spring.annotation.MapperScan; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.CommandLineRunner; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.core.env.Environment; 10 | import org.springframework.scheduling.annotation.EnableAsync; 11 | 12 | @Slf4j 13 | @EnableAsync 14 | @MapperScan("com.quick.api.mapper") 15 | @SpringBootApplication 16 | public class QuickChatApplication implements CommandLineRunner { 17 | @Autowired 18 | private Environment environment; 19 | 20 | public static void main(String[] args) { 21 | SpringApplication.run(QuickChatApplication.class, args); 22 | } 23 | 24 | public void run(String... args) { 25 | String applicationName = environment.getProperty("spring.application.name"); 26 | String serverPort = environment.getProperty("server.port"); 27 | String active = environment.getProperty("spring.profiles.active"); 28 | System.setProperty("rocketmq.client.logUseSlf4j", "true"); 29 | log.info("----------------------------项目名称:[{}]----------------------------", applicationName); 30 | log.info("----------------------------项目环境:[{}]----------------------------", active); 31 | log.info("----------------------------项目端口:[{}]----------------------------", serverPort); 32 | log.info("----------------------------QuickChat启动成功!----------------------------"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/controller/QuickChatApplyController.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.controller; 2 | 3 | import com.quick.common.enums.ResponseEnum; 4 | import com.quick.common.pojo.po.QuickChatApply; 5 | import com.quick.common.response.R; 6 | import com.quick.api.service.QuickChatApplyService; 7 | import io.swagger.annotations.Api; 8 | import io.swagger.annotations.ApiOperation; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.PathVariable; 11 | import org.springframework.web.bind.annotation.PostMapping; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | * @Author: 徐志斌 19 | * @CreateTime: 2024-07-04 15:45 20 | * @Description: 申请通知 21 | * @Version: 1.0 22 | */ 23 | @Api(tags = "申请通知") 24 | @RestController 25 | @RequestMapping("/apply") 26 | public class QuickChatApplyController { 27 | @Autowired 28 | private QuickChatApplyService applyService; 29 | 30 | @ApiOperation("查询列表") 31 | @PostMapping("/list") 32 | public R getApplyList() { 33 | List list = applyService.getApplyList(); 34 | return R.out(ResponseEnum.SUCCESS, list); 35 | } 36 | 37 | @ApiOperation("同意申请") 38 | @PostMapping("/agree/{applyId}") 39 | public R agreeApply(@PathVariable Long applyId) { 40 | applyService.agreeApply(applyId); 41 | return R.out(ResponseEnum.SUCCESS); 42 | } 43 | 44 | @ApiOperation("删除申请") 45 | @PostMapping("/delete/{applyId}") 46 | public R deleteApply(@PathVariable Long applyId) { 47 | applyService.deleteApply(applyId); 48 | return R.out(ResponseEnum.SUCCESS); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/controller/QuickChatContactController.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.controller; 2 | 3 | import com.quick.common.enums.ResponseEnum; 4 | import com.quick.common.pojo.vo.ChatUserVO; 5 | import com.quick.common.response.R; 6 | import com.quick.api.service.QuickChatContactService; 7 | import io.swagger.annotations.Api; 8 | import io.swagger.annotations.ApiOperation; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.PathVariable; 11 | import org.springframework.web.bind.annotation.PostMapping; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | * @Author: 徐志斌 19 | * @CreateTime: 2024-07-04 15:45 20 | * @Description: 通讯录(好友 + 群组) 21 | * @Version: 1.0 22 | */ 23 | @Api(tags = "通讯录") 24 | @RestController 25 | @RequestMapping("/contact") 26 | public class QuickChatContactController { 27 | @Autowired 28 | private QuickChatContactService contactService; 29 | 30 | @ApiOperation("查询列表") 31 | @PostMapping("/list") 32 | public R getFriendList() { 33 | List result = contactService.getContactList(); 34 | return R.out(ResponseEnum.SUCCESS, result); 35 | } 36 | 37 | @ApiOperation("添加好友") 38 | @PostMapping("/add/{accountId}") 39 | public R addFriend(@PathVariable String accountId, String applyInfo) { 40 | contactService.addFriend(accountId, applyInfo); 41 | return R.out(ResponseEnum.SUCCESS); 42 | } 43 | 44 | @ApiOperation("删除好友") 45 | @PostMapping("/delete/{accountId}") 46 | public R deleteFriend(@PathVariable String accountId) { 47 | contactService.deleteFriend(accountId); 48 | return R.out(ResponseEnum.SUCCESS); 49 | } 50 | 51 | @ApiOperation("备注昵称") 52 | @PostMapping("/note/{accountId}/{noteName}") 53 | public R noteFriend(@PathVariable String accountId, 54 | @PathVariable String noteName) { 55 | contactService.noteFriend(accountId, noteName); 56 | return R.out(ResponseEnum.SUCCESS); 57 | } 58 | 59 | @ApiOperation("拉黑好友") 60 | @PostMapping("/black") 61 | public R blackFriend() { 62 | return R.out(ResponseEnum.SUCCESS); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/controller/QuickChatFileController.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.controller; 2 | 3 | import com.quick.common.enums.ResponseEnum; 4 | import com.quick.common.response.R; 5 | import com.quick.api.service.QuickChatFileService; 6 | import io.swagger.annotations.Api; 7 | import io.swagger.annotations.ApiOperation; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Controller; 10 | import org.springframework.web.bind.annotation.*; 11 | import org.springframework.web.multipart.MultipartFile; 12 | 13 | import java.util.Map; 14 | 15 | /** 16 | * @Author 徐志斌 17 | * @Date: 2024/3/3 16:29 18 | * @Version 1.0 19 | * @Description: 文件控制器 20 | */ 21 | @Api(tags = "文件相关") 22 | @Controller 23 | @RequestMapping("/file") 24 | public class QuickChatFileController { 25 | @Autowired 26 | private QuickChatFileService fileService; 27 | 28 | @ResponseBody 29 | @ApiOperation("上传文件") 30 | @PostMapping("/upload/{type}") 31 | public R uploadFile(@PathVariable Integer type, MultipartFile file) throws Exception { 32 | Map resultMap = fileService.uploadFile(type, file); 33 | return R.out(ResponseEnum.SUCCESS, resultMap); 34 | } 35 | 36 | @ApiOperation("下载文件") 37 | @GetMapping("/download/{type}") 38 | public void downloadFile(@PathVariable Integer type, String url) { 39 | fileService.downloadFile(type, url); 40 | } 41 | 42 | @ApiOperation("删除文件") 43 | @DeleteMapping("/delete/{type}") 44 | public void deleteFile(@PathVariable Integer type, String url) throws Exception { 45 | fileService.deleteFile(type, url); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/controller/QuickChatGroupController.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.controller; 2 | 3 | import com.quick.common.enums.ResponseEnum; 4 | import com.quick.common.pojo.dto.GroupDTO; 5 | import com.quick.common.response.R; 6 | import com.quick.api.service.QuickChatGroupService; 7 | import io.swagger.annotations.Api; 8 | import io.swagger.annotations.ApiOperation; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.validation.annotation.Validated; 11 | import org.springframework.web.bind.annotation.*; 12 | 13 | /** 14 | * @Author: 徐志斌 15 | * @CreateTime: 2023-11-21 10:05 16 | * @Description: 群组信息 17 | * @Version: 1.0 18 | */ 19 | @Api(tags = "群组信息") 20 | @RestController 21 | @RequestMapping("/group") 22 | public class QuickChatGroupController { 23 | @Autowired 24 | private QuickChatGroupService groupService; 25 | 26 | @ApiOperation("创建群组") 27 | @PostMapping("/create") 28 | public R create(@Validated @RequestBody GroupDTO group) { 29 | groupService.createGroup(group); 30 | return R.out(ResponseEnum.SUCCESS); 31 | } 32 | 33 | @ApiOperation("修改群组信息") 34 | @GetMapping("/update") 35 | public R updateInfo(@Validated @RequestBody GroupDTO group) { 36 | groupService.updateInfo(group); 37 | return R.out(ResponseEnum.SUCCESS); 38 | } 39 | 40 | @ApiOperation("解散群聊") 41 | @DeleteMapping("/release/{groupId}") 42 | public R releaseGroup(@PathVariable Long groupId) { 43 | groupService.releaseGroup(groupId); 44 | return R.out(ResponseEnum.SUCCESS); 45 | } 46 | 47 | @ApiOperation("退出群聊") 48 | @GetMapping("/exit/{groupId}") 49 | public R exitGroup(@PathVariable Long groupId) { 50 | groupService.exitGroup(groupId); 51 | return R.out(ResponseEnum.SUCCESS); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/controller/QuickChatGroupMemberController.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.controller; 2 | 3 | import com.quick.common.enums.ResponseEnum; 4 | import com.quick.common.pojo.vo.ChatUserVO; 5 | import com.quick.common.response.R; 6 | import com.quick.api.service.QuickChatGroupMemberService; 7 | import io.swagger.annotations.Api; 8 | import io.swagger.annotations.ApiOperation; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * @Author: 徐志斌 16 | * @CreateTime: 2024-07-05 16:45 17 | * @Description: 群成员 18 | * @Version: 1.0 19 | */ 20 | @Api(tags = "群成员") 21 | @RestController 22 | @RequestMapping("/member") 23 | public class QuickChatGroupMemberController { 24 | @Autowired 25 | private QuickChatGroupMemberService memberService; 26 | 27 | @ApiOperation("查询群成员") 28 | @PostMapping("/list/{groupId}") 29 | public R getMemberList(@PathVariable Long groupId) { 30 | List members = memberService.getGroupMemberList(groupId); 31 | return R.out(ResponseEnum.SUCCESS, members); 32 | } 33 | 34 | @ApiOperation("批量添加成员") 35 | @GetMapping("/add/{groupId}") 36 | public R addMember(@PathVariable Long groupId, 37 | @RequestBody List accountIdList) { 38 | memberService.addMember(groupId, accountIdList); 39 | return R.out(ResponseEnum.SUCCESS); 40 | } 41 | 42 | @ApiOperation("移除群成员") 43 | @GetMapping("/delete/{groupId}/{accountId}") 44 | public R deleteMember(@PathVariable Long groupId, 45 | @PathVariable String accountId) { 46 | memberService.deleteMember(groupId, accountId); 47 | return R.out(ResponseEnum.SUCCESS); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/controller/QuickChatSearchController.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.controller; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | /** 7 | * @Author: 徐志斌 8 | * @CreateTime: 2024-12-03 12:06 9 | * @Description: 搜索框 10 | * @Version: 1.0 11 | */ 12 | @RestController 13 | @RequestMapping("/search") 14 | public class QuickChatSearchController { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/mapper/QuickChatApplyMapper.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.quick.common.pojo.po.QuickChatApply; 5 | 6 | /** 7 | *

8 | * 系统通知 Mapper 接口 9 | *

10 | * 11 | * @author 徐志斌 12 | * @since 2024-03-12 13 | */ 14 | public interface QuickChatApplyMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/mapper/QuickChatArchiveRecordMapper.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.quick.common.pojo.po.QuickChatArchiveRecord; 5 | 6 | /** 7 | *

8 | * Mapper 接口 9 | *

10 | * 11 | * @author 徐志斌 12 | * @since 2024-11-13 13 | */ 14 | public interface QuickChatArchiveRecordMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/mapper/QuickChatContactMapper.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.quick.common.pojo.po.QuickChatContact; 5 | 6 | /** 7 | *

8 | * 聊天好友 Mapper 接口 9 | *

10 | * 11 | * @author 徐志斌 12 | * @since 2023-11-30 13 | */ 14 | public interface QuickChatContactMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/mapper/QuickChatEmojiMapper.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.quick.common.pojo.po.QuickChatEmoji; 5 | 6 | /** 7 | *

8 | * 表情包 Mapper 接口 9 | *

10 | * 11 | * @author 徐志斌 12 | * @since 2023-11-30 13 | */ 14 | public interface QuickChatEmojiMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/mapper/QuickChatGroupMapper.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.quick.common.pojo.po.QuickChatGroup; 5 | 6 | /** 7 | *

8 | * 群聊 Mapper 接口 9 | *

10 | * 11 | * @author 徐志斌 12 | * @since 2024-01-08 13 | */ 14 | public interface QuickChatGroupMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/mapper/QuickChatGroupMemberMapper.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.quick.common.pojo.po.QuickChatGroupMember; 5 | 6 | /** 7 | *

8 | * 群成员 Mapper 接口 9 | *

10 | * 11 | * @author 徐志斌 12 | * @since 2024-01-08 13 | */ 14 | public interface QuickChatGroupMemberMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/mapper/QuickChatMsgDorisMapper.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.quick.common.pojo.po.QuickChatMsg; 5 | 6 | /** 7 | *

8 | * 聊天信息 Mapper 接口 9 | *

10 | * 11 | * @author 徐志斌 12 | * @since 2023-11-25 13 | */ 14 | public interface QuickChatMsgDorisMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/mapper/QuickChatMsgMapper.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.quick.common.pojo.po.QuickChatMsg; 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | *

11 | * 聊天信息 Mapper 接口 12 | *

13 | * 14 | * @author 徐志斌 15 | * @since 2023-11-25 16 | */ 17 | public interface QuickChatMsgMapper extends BaseMapper { 18 | /** 19 | * 根据 消息id列表 物理删除聊天记录 20 | * 21 | * @param ids 消息id列表 22 | * @return 执行结果 23 | */ 24 | Boolean physicalDeleteMsgList(@Param("ids") List ids); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/mapper/QuickChatSessionMapper.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.quick.common.pojo.po.QuickChatSession; 5 | 6 | /** 7 | *

8 | * 聊天会话(针对单聊) Mapper 接口 9 | *

10 | * 11 | * @author 徐志斌 12 | * @since 2023-11-25 13 | */ 14 | public interface QuickChatSessionMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/mapper/QuickChatUserMapper.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.quick.common.pojo.po.QuickChatUser; 5 | 6 | /** 7 | *

8 | * Mapper 接口 9 | *

10 | * 11 | * @author 徐志斌 12 | * @since 2023-11-13 13 | */ 14 | public interface QuickChatUserMapper extends BaseMapper { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/service/QuickChatApplyService.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.quick.common.pojo.po.QuickChatApply; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | *

10 | * 申请通知 服务类 11 | *

12 | * 13 | * @author 徐志斌 14 | * @since 2024-03-12 15 | */ 16 | public interface QuickChatApplyService extends IService { 17 | 18 | /** 19 | * 查询申请通知列表 20 | * 21 | * @return 通知列表 22 | */ 23 | List getApplyList(); 24 | 25 | /** 26 | * 同意申请 27 | * 28 | * @param applyId 申请id 29 | * @return 执行结果 30 | */ 31 | void agreeApply(Long applyId); 32 | 33 | /** 34 | * 删除申请 35 | * 36 | * @param applyId 申请id 37 | * @return 执行结果 38 | */ 39 | void deleteApply(Long applyId); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/service/QuickChatContactService.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.quick.common.pojo.po.QuickChatContact; 5 | import com.quick.common.pojo.vo.ChatUserVO; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | *

11 | * 通讯录 服务类 12 | *

13 | * 14 | * @author 徐志斌 15 | * @since 2023-11-30 16 | */ 17 | public interface QuickChatContactService extends IService { 18 | 19 | /** 20 | * 查询通讯录好友 21 | * 22 | * @return 通讯录好友列表 23 | */ 24 | List getContactList(); 25 | 26 | /** 27 | * 添加好友 28 | * 29 | * @param accountId 用户id 30 | * @param applyInfo 申请信息 31 | * @return 执行结果 32 | */ 33 | void addFriend(String accountId, String applyInfo); 34 | 35 | /** 36 | * 删除好友 37 | * 38 | * @param accountId 用户id 39 | * @return 执行结果 40 | */ 41 | void deleteFriend(String accountId); 42 | 43 | /** 44 | * 备注昵称 45 | * 46 | * @param accountId 账户id 47 | * @param noteName 昵称 48 | */ 49 | void noteFriend(String accountId, String noteName); 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/service/QuickChatEmojiService.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.quick.common.pojo.po.QuickChatEmoji; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | *

10 | * 表情包 服务类 11 | *

12 | * 13 | * @author 徐志斌 14 | * @since 2023-11-30 15 | */ 16 | public interface QuickChatEmojiService extends IService { 17 | /** 18 | * 获取表情包列表 19 | * 20 | * @param accountId 账号id 21 | * @return 表情包列表 22 | */ 23 | List getEmojiList(String accountId); 24 | 25 | /** 26 | * 添加表情包 27 | * 28 | * @param url 表情包URL 29 | * @return 执行结果 30 | */ 31 | Boolean addEmoji(String url); 32 | 33 | /** 34 | * 删除表情包 35 | * 36 | * @param id 主键id 37 | * @return 执行结果 38 | */ 39 | Boolean deleteEmoji(Long id); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/service/QuickChatFileService.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.service; 2 | 3 | import org.springframework.web.multipart.MultipartFile; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | *

9 | * 表情包 服务类 10 | *

11 | * 12 | * @author 徐志斌 13 | * @since 2024-04-04 14 | */ 15 | public interface QuickChatFileService { 16 | /** 17 | * 上传文件 18 | * 19 | * @param type Bucket类型 20 | * @param file 文件对象 21 | * @return 文件信息 22 | */ 23 | Map uploadFile(int type, MultipartFile file) throws Exception; 24 | 25 | /** 26 | * 下载文件 27 | * 28 | * @param type Bucket类型 29 | * @param url 文件url 30 | */ 31 | void downloadFile(int type, String url); 32 | 33 | /** 34 | * 删除文件 35 | * 36 | * @param type Bucket类型 37 | * @param url 文件url 38 | */ 39 | void deleteFile(int type, String url) throws Exception; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/service/QuickChatGroupMemberService.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.quick.common.pojo.po.QuickChatGroupMember; 5 | import com.quick.common.pojo.vo.ChatUserVO; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | *

11 | * 群成员 服务类 12 | *

13 | * 14 | * @author 徐志斌 15 | * @since 2024-01-08 16 | */ 17 | public interface QuickChatGroupMemberService extends IService { 18 | /** 19 | * 查询群成员列表 20 | * 21 | * @param groupId 群id 22 | * @return 群成员列表 23 | */ 24 | List getGroupMemberList(Long groupId); 25 | 26 | /** 27 | * 添加群成员 28 | * 29 | * @param groupId 群组id 30 | * @param accountIdList 账户id列表 31 | */ 32 | void addMember(Long groupId, List accountIdList); 33 | 34 | /** 35 | * 移除群成员 36 | * 37 | * @param groupId 群组id 38 | * @param accountId 账户id 39 | * @return 执行结果 40 | */ 41 | void deleteMember(Long groupId, String accountId); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/service/QuickChatGroupService.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.quick.common.pojo.dto.GroupDTO; 5 | import com.quick.common.pojo.po.QuickChatGroup; 6 | 7 | /** 8 | *

9 | * 群聊 服务类 10 | *

11 | * 12 | * @author 徐志斌 13 | * @since 2024-01-08 14 | */ 15 | public interface QuickChatGroupService extends IService { 16 | /** 17 | * 创建群聊 18 | * 19 | * @param group 群聊参数 20 | * @return 执行结果 21 | */ 22 | void createGroup(GroupDTO group); 23 | 24 | /** 25 | * 解散群聊 26 | * 27 | * @param groupId 群聊id 28 | */ 29 | void releaseGroup(Long groupId); 30 | 31 | /** 32 | * 退出群聊 33 | * 34 | * @param groupId 群聊id 35 | * @return 执行结果 36 | */ 37 | void exitGroup(Long groupId); 38 | 39 | /** 40 | * 修改群组信息 41 | * 42 | * @param group 群组信息 43 | * @return 执行结果 44 | */ 45 | void updateInfo(GroupDTO group); 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/service/QuickChatMsgService.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.quick.common.pojo.dto.ChatMsgDTO; 5 | import com.quick.common.pojo.po.QuickChatMsg; 6 | import com.quick.common.pojo.vo.ChatMsgVO; 7 | 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | *

13 | * 聊天信息 服务类 14 | *

15 | * 16 | * @author 徐志斌 17 | * @since 2023-11-25 18 | */ 19 | public interface QuickChatMsgService extends IService { 20 | /** 21 | * 根据 relation_id 分页查询聊天信息 22 | * 23 | * @param relationId 关联id 24 | * @param current 当前页 25 | * @param size 每页条数 26 | * @return 聊天信息集合 27 | */ 28 | Map> getPageByRelationId(Long relationId, Integer current, Integer size); 29 | 30 | /** 31 | * 根据 relation_id 分页查询历史聊天信息 32 | * 33 | * @param relationId 关联id 34 | * @param current 当前页 35 | * @param size 每页条数 36 | * @return 聊天信息集合 37 | */ 38 | Map> getHisPageByRelationId(Long relationId, Integer current, Integer size); 39 | 40 | /** 41 | * 根据 account_id 集合批量查询聊天记录 42 | * 43 | * @param relationIds 会话列表 44 | * @return 聊天信息 45 | */ 46 | Map> getMsgByRelationIds(List relationIds, Integer size); 47 | 48 | 49 | /** 50 | * 发送聊天信息 51 | * 52 | * @param msgDTO 聊天信息实体 53 | * @throws Throwable 54 | */ 55 | void sendMsg(ChatMsgDTO msgDTO) throws Throwable; 56 | 57 | /** 58 | * 对方正在输入... 59 | * 60 | * @param fromId 发送方 61 | * @param toId 接收方 62 | */ 63 | void writing(String fromId, String toId); 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/service/QuickChatSessionService.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.quick.common.pojo.po.QuickChatSession; 5 | import com.quick.common.pojo.vo.ChatSessionVO; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | *

12 | * 聊天会话(针对单聊) 服务类 13 | *

14 | * 15 | * @author 徐志斌 16 | * @since 2023-11-25 17 | */ 18 | public interface QuickChatSessionService extends IService { 19 | /** 20 | * 查询会话列表 21 | * 22 | * @return 会话列表信息 23 | */ 24 | List getSessionList(); 25 | 26 | /** 27 | * 根据 sessionId 删除会话 28 | * 29 | * @param sessionId 会话主键id 30 | * @return 执行结果 31 | */ 32 | void deleteSession(Long sessionId); 33 | 34 | /** 35 | * 更新最后会话读取时间 36 | * 37 | * @param sessionId 会话id 38 | * @return 执行结果 39 | */ 40 | void updateReadTime(Long sessionId); 41 | 42 | /** 43 | * 获取会话未读数 44 | * 45 | * @param sessionList 会话列表 46 | * @return 未读数结果Map 47 | */ 48 | Map getUnreadCountMap(List sessionList); 49 | 50 | /** 51 | * 查询会话信息 52 | * 53 | * @param fromId 发送方 54 | * @param toId 接收方 55 | * @return 会话信息 56 | */ 57 | ChatSessionVO getByFromIdAndToId(String fromId, String toId); 58 | 59 | /** 60 | * 置顶会话 61 | * 62 | * @param sessionId 63 | * @return 执行结果 64 | */ 65 | void topSession(Long sessionId); 66 | 67 | /** 68 | * 恢复会话信息 69 | * 70 | * @param toId 用户id 71 | * @return 执行结果 72 | */ 73 | void activeSession(String toId); 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/service/QuickUserService.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.quick.common.pojo.dto.*; 5 | import com.quick.common.pojo.po.QuickChatUser; 6 | import com.quick.common.pojo.vo.ChatUserVO; 7 | 8 | import java.io.IOException; 9 | import java.util.Map; 10 | 11 | /** 12 | *

13 | * 服务类 14 | *

15 | * 16 | * @author 徐志斌 17 | * @since 2023-11-13 18 | */ 19 | public interface QuickUserService extends IService { 20 | /** 21 | * 根据 account_id 查询用户信息 22 | * 23 | * @param accountId 账户id 24 | * @return 用户信息VO 25 | * @throws Exception 26 | */ 27 | ChatUserVO getByAccountId(String accountId) throws Exception; 28 | 29 | /** 30 | * 账号注册 31 | * 32 | * @param registerDTO 注册表单DTO 33 | * @return 执行结果 34 | * @throws Exception 35 | */ 36 | void register(RegisterFormDTO registerDTO) throws Exception; 37 | 38 | /** 39 | * 登录功能 40 | * 41 | * @param loginDTO 登录表单DTO 42 | * @return Token和账户信息 43 | * @throws Exception 44 | */ 45 | Map login(LoginFormDTO loginDTO) throws Exception; 46 | 47 | /** 48 | * 图片验证码 49 | * 50 | * @throws IOException 51 | */ 52 | void captcha() throws IOException; 53 | 54 | /** 55 | * 发送邮件 56 | * 57 | * @param emailDTO 邮件入参DTO 58 | * @return 执行结果 59 | * @throws Throwable 60 | */ 61 | void sendEmail(EmailDTO emailDTO) throws Throwable; 62 | 63 | /** 64 | * 修改用户信息 65 | * 66 | * @param userDTO 修改表单DTO 67 | * @return 执行结果 68 | */ 69 | void updateUser(UserInfoDTO userDTO); 70 | 71 | /** 72 | * 根据请求头Token解析用户信息 73 | * 74 | * @return 用户信息PO 75 | */ 76 | QuickChatUser getByToken(); 77 | 78 | /** 79 | * 用户找回密码 80 | * 81 | * @param findBackDTO 找回密码DTO 82 | * @return 执行结果 83 | * @throws Exception 84 | */ 85 | void findBack(FindBackFormDTO findBackDTO) throws Exception; 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/service/impl/QuickChatEmojiServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.service.impl; 2 | 3 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 4 | import com.quick.api.mapper.QuickChatEmojiMapper; 5 | import com.quick.api.service.QuickChatEmojiService; 6 | import com.quick.api.store.QuickChatEmojiStore; 7 | import com.quick.common.adapter.EmojiAdapter; 8 | import com.quick.common.pojo.po.QuickChatEmoji; 9 | import com.quick.common.utils.RequestContextUtil; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | *

17 | * 表情包 服务实现类 18 | *

19 | * 20 | * @author 徐志斌 21 | * @since 2023-11-30 22 | */ 23 | @Service 24 | public class QuickChatEmojiServiceImpl extends ServiceImpl implements QuickChatEmojiService { 25 | @Autowired 26 | private QuickChatEmojiStore emojiStore; 27 | 28 | @Override 29 | public List getEmojiList(String accountId) { 30 | return emojiStore.getEmojiList(accountId); 31 | } 32 | 33 | @Override 34 | public Boolean addEmoji(String url) { 35 | String accountId = (String) RequestContextUtil.getData(RequestContextUtil.ACCOUNT_ID); 36 | QuickChatEmoji chatEmoji = EmojiAdapter.buildEmojiPO(url, accountId); 37 | return emojiStore.saveEmoji(chatEmoji); 38 | } 39 | 40 | @Override 41 | public Boolean deleteEmoji(Long id) { 42 | String accountId = (String) RequestContextUtil.getData(RequestContextUtil.ACCOUNT_ID); 43 | return emojiStore.deleteByEmojiId(id, accountId); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/service/impl/QuickChatFileServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.service.impl; 2 | 3 | import com.quick.api.service.QuickChatFileService; 4 | import com.quick.common.strategy.file.AbstractFileStrategy; 5 | import com.quick.common.strategy.file.FileStrategyFactory; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.web.multipart.MultipartFile; 8 | 9 | import java.util.Map; 10 | 11 | /** 12 | *

13 | * 表情包 服务实现类 14 | *

15 | * 16 | * @author 徐志斌 17 | * @since 2024-04-04 18 | */ 19 | @Service 20 | public class QuickChatFileServiceImpl implements QuickChatFileService { 21 | @Override 22 | public Map uploadFile(int type, MultipartFile file) throws Exception { 23 | AbstractFileStrategy fileStrategy = FileStrategyFactory.getStrategyHandler(type); 24 | return fileStrategy.uploadFile(file); 25 | } 26 | 27 | @Override 28 | public void downloadFile(int type, String url) { 29 | AbstractFileStrategy fileStrategy = FileStrategyFactory.getStrategyHandler(type); 30 | fileStrategy.downloadFile(url); 31 | } 32 | 33 | @Override 34 | public void deleteFile(int type, String url) throws Exception { 35 | AbstractFileStrategy fileStrategy = FileStrategyFactory.getStrategyHandler(type); 36 | fileStrategy.deleteFile(url); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/store/QuickChatApplyStore.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.store; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.quick.common.pojo.po.QuickChatApply; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | *

10 | * 好友/群聊申请 服务类 11 | *

12 | * 13 | * @author 徐志斌 14 | * @since 2024-03-12 15 | */ 16 | public interface QuickChatApplyStore extends IService { 17 | /** 18 | * 保存申请信息 19 | * 20 | * @param apply 申请信息 21 | * @return 执行结果 22 | */ 23 | Boolean saveApply(QuickChatApply apply); 24 | 25 | /** 26 | * 根据 to_id 查询申请列表 27 | * 28 | * @param toId 接收方 29 | * @return 申请列表 30 | */ 31 | List getListByToId(String toId); 32 | 33 | /** 34 | * 修改申请状态 35 | * 36 | * @param applyId 申请id 37 | * @param toId 接收账号 38 | * @param status 状态 39 | * @return 执行结果 40 | */ 41 | Boolean updateApplyStatus(Long applyId, String toId, Integer status); 42 | 43 | /** 44 | * 根据 申请id 删除申请记录 45 | * 46 | * @param applyId 申请id 47 | * @param toId 接收方账号 48 | * @return 执行结果 49 | */ 50 | Boolean deleteByApplyId(Long applyId, String toId); 51 | 52 | /** 53 | * 根据 申请id 查询申请记录 54 | * 55 | * @param applyId 申请id 56 | * @return 申请记录 57 | */ 58 | QuickChatApply getByApplyId(Long applyId); 59 | 60 | /** 61 | * 批量保存申请记录 62 | * 63 | * @param applyList 申请列表 64 | * @return 65 | */ 66 | Boolean saveAll(List applyList); 67 | 68 | /** 69 | * 根据 apply_id 删除 Redis 缓存 70 | * 71 | * @param applyId 申请id 72 | */ 73 | void deleteCacheByApplyId(Long applyId); 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/store/QuickChatArchiveRecordStore.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.store; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.quick.common.pojo.po.QuickChatArchiveRecord; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | *

10 | * 服务类 11 | *

12 | * 13 | * @author 徐志斌 14 | * @since 2024-11-13 15 | */ 16 | public interface QuickChatArchiveRecordStore extends IService { 17 | /** 18 | * 保存数据迁移记录 19 | * 20 | * @param record 迁移记录 21 | * @return 执行结果 22 | */ 23 | Boolean saveArchiveRecord(QuickChatArchiveRecord record); 24 | 25 | /** 26 | * 修改迁移记录 27 | * 28 | * @param record 迁移记录 29 | * @return 执行结果 30 | */ 31 | Boolean updateArchiveRecord(QuickChatArchiveRecord record); 32 | 33 | /** 34 | * 根据状态查询迁移记录 35 | * 36 | * @param status 状态 37 | * @return 迁移记录 38 | */ 39 | List getListByStatus(Integer status); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/store/QuickChatContactStore.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.store; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.quick.common.pojo.po.QuickChatContact; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | *

10 | * 通讯录 服务类 11 | *

12 | * 13 | * @author 徐志斌 14 | * @since 2023-11-30 15 | */ 16 | public interface QuickChatContactStore extends IService { 17 | /** 18 | * 根据 from_id 查询通讯录列表 19 | * 20 | * @param fromId 用户id 21 | * @return 通讯录列表 22 | */ 23 | List getListByFromId(String fromId); 24 | 25 | /** 26 | * 根据 from_id to_id 查询好友信息 27 | * 28 | * @param fromId 账号id 29 | * @param toId 账号id 30 | * @return 通讯录信息 31 | */ 32 | QuickChatContact getByFromIdAndToId(String fromId, String toId); 33 | 34 | /** 35 | * 根据 from_id to_id 删除好友信息 36 | * 37 | * @param fromId 账号id 38 | * @param toId 账号id 39 | * @return 执行结果 40 | */ 41 | Boolean deleteByFromIdAndToId(String fromId, String toId); 42 | 43 | /** 44 | * 保存通讯录 45 | * 46 | * @param contact 通讯录信息 47 | * @return 执行结果 48 | */ 49 | Boolean saveContact(QuickChatContact contact); 50 | 51 | /** 52 | * 批量保存通讯录 53 | * 54 | * @param contacts 通讯录列表 55 | * @return 执行结果 56 | */ 57 | Boolean saveContactList(List contacts); 58 | 59 | /** 60 | * 修改通讯录 61 | * 62 | * @param friendPO 通讯录实体 63 | * @return 执行结果 64 | */ 65 | Boolean updateContact(QuickChatContact friendPO); 66 | 67 | /** 68 | * 删除 Redis 缓存 69 | * 70 | * @param fromId 账号id 71 | * @param toId 账号id 72 | */ 73 | void deleteCacheByFromIdAndToId(String fromId, String toId); 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/store/QuickChatEmojiStore.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.store; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.quick.common.pojo.po.QuickChatEmoji; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | *

10 | * 表情包 服务类 11 | *

12 | * 13 | * @author 徐志斌 14 | * @since 2023-11-30 15 | */ 16 | public interface QuickChatEmojiStore extends IService { 17 | /** 18 | * 根据 account_id 查询表情包列表 19 | * 20 | * @param accountId 账号id 21 | * @return 表情包List 22 | */ 23 | List getEmojiList(String accountId); 24 | 25 | /** 26 | * 保存表情包 27 | * 28 | * @param chatEmoji 表情包实体 29 | * @return 执行结果 30 | */ 31 | Boolean saveEmoji(QuickChatEmoji chatEmoji); 32 | 33 | /** 34 | * 删除表情包 35 | * 36 | * @param emojiId 表情包id 37 | * @param accountId 账户id 38 | * @return 执行结果 39 | */ 40 | Boolean deleteByEmojiId(Long emojiId, String accountId); 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/store/QuickChatGroupMemberStore.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.store; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.quick.common.pojo.po.QuickChatGroupMember; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | *

10 | * 群成员 服务类 11 | *

12 | * 13 | * @author 徐志斌 14 | * @since 2024-01-08 15 | */ 16 | public interface QuickChatGroupMemberStore extends IService { 17 | 18 | /** 19 | * 根据 group_id 查询群成员列表 20 | * 21 | * @param groupId 群聊id 22 | * @return 群成员列表 23 | */ 24 | List getListByGroupId(Long groupId); 25 | 26 | /** 27 | * 进入群聊 28 | * 29 | * @param memberPO 群成员信息 30 | * @return 执行结果 31 | */ 32 | Boolean saveMember(QuickChatGroupMember memberPO); 33 | 34 | /** 35 | * 根据 group_id account_id 移出群聊 36 | * 37 | * @param groupId 群聊id 38 | * @param accountId 账号id 39 | * @return 执行结果 40 | */ 41 | Boolean deleteByGroupIdAndAccountId(Long groupId, String accountId); 42 | 43 | /** 44 | * 查询成员否在群中 45 | * 46 | * @param groupId 群组id 47 | * @param accountId 账户id 48 | * @return 群成员信息 49 | */ 50 | QuickChatGroupMember getMemberByAccountId(Long groupId, String accountId); 51 | 52 | /** 53 | * 根据 groupId,accountIdList 查询成员 54 | * 55 | * @param groupId 群id 56 | * @param accountIdList 成员id列表 57 | * @return 58 | */ 59 | List getGroupMemberByAccountIdList(Long groupId, List accountIdList); 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/store/QuickChatGroupStore.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.store; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.quick.common.pojo.po.QuickChatGroup; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | *

10 | * 群聊 服务类 11 | *

12 | * 13 | * @author 徐志斌 14 | * @since 2024-01-08 15 | */ 16 | public interface QuickChatGroupStore extends IService { 17 | /** 18 | * 根据 group_id 查询 19 | * 20 | * @param groupId 群组id 21 | * @return 群组信息 22 | */ 23 | QuickChatGroup getByGroupId(Long groupId); 24 | 25 | /** 26 | * 修改群组信息 27 | * 28 | * @param group 群组信息 29 | * @return 执行结果 30 | */ 31 | Boolean updateInfo(QuickChatGroup group); 32 | 33 | /** 34 | * 根据 group_id 列表批量查询群组信息列表 35 | * 36 | * @param groupIds 群组id列表 37 | * @return 群组信息列表 38 | */ 39 | List getListByGroupIds(List groupIds); 40 | 41 | /** 42 | * 根据 group_id 解散群聊 43 | * 44 | * @param groupId 群组id 45 | * @return 执行结果 46 | */ 47 | Boolean dismissByGroupId(Long groupId); 48 | 49 | /** 50 | * 创建群聊 51 | * 52 | * @param groupPO 群聊信息实体 53 | * @return 执行结果 54 | */ 55 | Boolean saveGroup(QuickChatGroup groupPO); 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/store/QuickChatMsgStore.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.store; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | import com.quick.common.pojo.po.QuickChatMsg; 6 | 7 | import java.time.LocalDateTime; 8 | import java.util.List; 9 | 10 | /** 11 | *

12 | * 聊天信息 服务类 13 | *

14 | * 15 | * @author 徐志斌 16 | * @since 2023-11-25 17 | */ 18 | public interface QuickChatMsgStore extends IService { 19 | /** 20 | * 保存聊天消息 21 | * 22 | * @param chatMsg 消息实体 23 | * @return 执行结果 24 | */ 25 | Boolean saveMsg(QuickChatMsg chatMsg); 26 | 27 | /** 28 | * 根据 relation_id 分页查询聊天信息 29 | * 30 | * @param relationId 关联id 31 | * @param current 起始页 32 | * @param size 每页条数 33 | * @return 聊天信息结果 34 | */ 35 | Page getPageByRelationId(Long relationId, Integer current, Integer size); 36 | 37 | /** 38 | * 根据 relation_id集合 查询聊天信息 39 | * 40 | * @param relationIds relation_id集合 41 | * @param size 数据条数 42 | * @return 聊天信息列表 43 | */ 44 | List getByRelationIds(List relationIds, Integer size); 45 | 46 | /** 47 | * 根据 msg_id 查询单条聊天信息 48 | * 49 | * @param msgId 消息id 50 | * @return 消息实体 51 | */ 52 | QuickChatMsg getByMsgId(Long msgId); 53 | 54 | /** 55 | * 根据 msg_id 修改聊天信息 56 | * 57 | * @param chatMsg 消息实体 58 | * @return 执行结果 59 | */ 60 | Boolean updateByMsgId(QuickChatMsg chatMsg); 61 | 62 | /** 63 | * 获取消息未读数量 64 | * 65 | * @param loginAccountId 登录账号id 66 | * @param relationId 关联id 67 | * @param lastReadTime 上次已读时间 68 | * @return 未读数量 69 | */ 70 | Long getUnreadCount(String loginAccountId, Long relationId, LocalDateTime lastReadTime); 71 | 72 | /** 73 | * 根据时间范围,查询聊天信息 74 | * 75 | * @param startTime 开始时间 76 | * @param endTime 结束时间 77 | * @return 聊天信息列表 78 | */ 79 | List getMsgByTime(LocalDateTime startTime, LocalDateTime endTime); 80 | 81 | /** 82 | * 物理删除聊天消息(数据迁移使用) 83 | * 84 | * @param ids 聊天信息id列表 85 | * @return 执行结果 86 | */ 87 | Boolean deleteNoLogicMsgListByIds(List ids); 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/store/QuickChatUserStore.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.store; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.quick.common.pojo.po.QuickChatUser; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | *

10 | * 服务类 11 | *

12 | * 13 | * @author 徐志斌 14 | * @since 2023-11-13 15 | */ 16 | public interface QuickChatUserStore extends IService { 17 | /** 18 | * 根据 account_id 查询用户信息 19 | * 20 | * @param accountId 账户id 21 | * @return 用户信息 22 | */ 23 | QuickChatUser getByAccountId(String accountId); 24 | 25 | /** 26 | * 保存用户信息 27 | * 28 | * @param userPO 用户信息 29 | * @return 执行结果 30 | */ 31 | Boolean saveUser(QuickChatUser userPO); 32 | 33 | /** 34 | * 根据 account_id 列表查询用户列表 35 | * 36 | * @param accountIds account_id列表 37 | * @return 用户列表 38 | */ 39 | List getListByAccountIds(List accountIds); 40 | 41 | /** 42 | * 修改用户信息 43 | * 44 | * @param userPO 用户信息 45 | * @return 执行结果 46 | */ 47 | Boolean updateUserById(QuickChatUser userPO); 48 | 49 | /** 50 | * 根据 email 查询用户信息 51 | * @param email 52 | * @return 53 | */ 54 | QuickChatUser getByEmail(String email); 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/store/doris/QuickChatMsgDorisStore.java: -------------------------------------------------------------------------------- 1 | //package com.quick.store.doris; 2 | // 3 | //import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 4 | //import com.baomidou.mybatisplus.extension.service.IService; 5 | //import com.quick.pojo.po.QuickChatMsg; 6 | // 7 | //import java.util.List; 8 | // 9 | ///** 10 | // *

11 | // * 聊天信息 服务类 12 | // *

13 | // * 14 | // * @author 徐志斌 15 | // * @since 2024-11-06 16 | // */ 17 | //public interface QuickChatMsgDorisStore extends IService { 18 | // /** 19 | // * 批量保存聊天记录 20 | // * 21 | // * @param msgList 消息列表 22 | // * @return 执行结果 23 | // */ 24 | // Boolean saveBatchMsg(List msgList); 25 | // 26 | // 27 | // /** 28 | // * 根据 relation_id 分页查询聊天记录 29 | // * 30 | // * @param relationId 关联id 31 | // * @param current 当前页 32 | // * @param size 每页条数 33 | // * @return 分页聊天记录 34 | // */ 35 | // Page getHisPageByRelationId(Long relationId, Integer current, Integer size); 36 | //} 37 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/store/doris/impl/QuickChatMsgDorisStoreImpl.java: -------------------------------------------------------------------------------- 1 | //package com.quick.store.doris.impl; 2 | // 3 | //import com.baomidou.dynamic.datasource.annotation.DS; 4 | //import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 5 | //import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 6 | //import com.quick.mapper.QuickChatMsgDorisMapper; 7 | //import com.quick.mapper.QuickChatMsgMapper; 8 | //import com.quick.pojo.po.QuickChatMsg; 9 | //import com.quick.store.doris.QuickChatMsgDorisStore; 10 | //import org.springframework.stereotype.Service; 11 | // 12 | //import java.util.List; 13 | // 14 | ///** 15 | // *

16 | // * 聊天信息 服务实现类 17 | // *

18 | // * 19 | // * @author 徐志斌 20 | // * @since 2024-11-06 21 | // */ 22 | //@Service 23 | //@DS("doris") 24 | //public class QuickChatMsgDorisStoreImpl extends ServiceImpl implements QuickChatMsgDorisStore { 25 | // @Override 26 | // public Boolean saveBatchMsg(List msgList) { 27 | // return this.saveBatch(msgList); 28 | // } 29 | // 30 | // @Override 31 | // public Page getHisPageByRelationId(Long relationId, Integer current, Integer size) { 32 | // return null; 33 | // } 34 | //} 35 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/store/impl/QuickChatArchiveRecordStoreImpl.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.store.impl; 2 | 3 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 4 | import com.quick.api.mapper.QuickChatArchiveRecordMapper; 5 | import com.quick.api.store.QuickChatArchiveRecordStore; 6 | import com.quick.common.pojo.po.QuickChatArchiveRecord; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | *

13 | * 服务实现类 14 | *

15 | * 16 | * @author 徐志斌 17 | * @since 2024-11-13 18 | */ 19 | @Service 20 | public class QuickChatArchiveRecordStoreImpl extends ServiceImpl implements QuickChatArchiveRecordStore { 21 | @Override 22 | public Boolean saveArchiveRecord(QuickChatArchiveRecord record) { 23 | return this.save(record); 24 | } 25 | 26 | @Override 27 | public Boolean updateArchiveRecord(QuickChatArchiveRecord record) { 28 | return this.updateById(record); 29 | } 30 | 31 | @Override 32 | public List getListByStatus(Integer status) { 33 | return this.lambdaQuery() 34 | .eq(QuickChatArchiveRecord::getStatus, status) 35 | .list(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/store/impl/QuickChatEmojiStoreImpl.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.store.impl; 2 | 3 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 4 | import com.quick.api.mapper.QuickChatEmojiMapper; 5 | import com.quick.common.pojo.po.QuickChatEmoji; 6 | import com.quick.api.store.QuickChatEmojiStore; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | *

13 | * 表情包 服务实现类 14 | *

15 | * 16 | * @author 徐志斌 17 | * @since 2023-11-30 18 | */ 19 | @Service 20 | public class QuickChatEmojiStoreImpl extends ServiceImpl implements QuickChatEmojiStore { 21 | @Override 22 | public List getEmojiList(String accountId) { 23 | return this.lambdaQuery() 24 | .eq(QuickChatEmoji::getAccountId, accountId) 25 | .list(); 26 | } 27 | 28 | @Override 29 | public Boolean saveEmoji(QuickChatEmoji chatEmoji) { 30 | return this.save(chatEmoji); 31 | } 32 | 33 | @Override 34 | public Boolean deleteByEmojiId(Long emojiId, String accountId) { 35 | return this.removeById(emojiId); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/store/impl/QuickChatGroupStoreImpl.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.store.impl; 2 | 3 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 4 | import com.quick.api.mapper.QuickChatGroupMapper; 5 | import com.quick.common.constant.RedisConstant; 6 | import com.quick.common.pojo.po.QuickChatGroup; 7 | import com.quick.api.store.QuickChatGroupStore; 8 | import org.springframework.cache.annotation.CacheEvict; 9 | import org.springframework.cache.annotation.Cacheable; 10 | import org.springframework.cache.annotation.Caching; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | *

17 | * 群聊 服务实现类 18 | *

19 | * 20 | * @author 徐志斌 21 | * @since 2024-01-08 22 | */ 23 | @Service 24 | public class QuickChatGroupStoreImpl extends ServiceImpl implements QuickChatGroupStore { 25 | @Override 26 | @Cacheable(value = RedisConstant.QUICK_CHAT_GROUP, key = "'getByGroupId:' + #p0", unless = "#result == null") 27 | public QuickChatGroup getByGroupId(Long groupId) { 28 | return this.getById(groupId); 29 | } 30 | 31 | @Override 32 | @Caching(evict = { 33 | @CacheEvict(value = RedisConstant.QUICK_CHAT_GROUP, key = "'getByGroupId:' + p0.id") 34 | }) 35 | public Boolean updateInfo(QuickChatGroup chatGroup) { 36 | return this.updateById(chatGroup); 37 | } 38 | 39 | @Override 40 | public List getListByGroupIds(List groupIds) { 41 | return this.lambdaQuery() 42 | .in(QuickChatGroup::getId, groupIds) 43 | .list(); 44 | } 45 | 46 | @Override 47 | @Caching(evict = { 48 | @CacheEvict(value = RedisConstant.QUICK_CHAT_GROUP, key = "'getByGroupId:' + p0") 49 | }) 50 | public Boolean dismissByGroupId(Long groupId) { 51 | return this.lambdaUpdate() 52 | .eq(QuickChatGroup::getId, groupId) 53 | .remove(); 54 | } 55 | 56 | @Override 57 | public Boolean saveGroup(QuickChatGroup groupPO) { 58 | return this.save(groupPO); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/quick/api/store/impl/QuickChatUserStoreImpl.java: -------------------------------------------------------------------------------- 1 | package com.quick.api.store.impl; 2 | 3 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 4 | import com.quick.api.mapper.QuickChatUserMapper; 5 | import com.quick.common.constant.RedisConstant; 6 | import com.quick.common.pojo.po.QuickChatUser; 7 | import com.quick.api.store.QuickChatUserStore; 8 | import org.springframework.cache.annotation.CacheEvict; 9 | import org.springframework.cache.annotation.Cacheable; 10 | import org.springframework.cache.annotation.Caching; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | *

17 | * 服务实现类 18 | *

19 | * 20 | * @author 徐志斌 21 | * @since 2023-11-13 22 | */ 23 | @Service 24 | public class QuickChatUserStoreImpl extends ServiceImpl implements QuickChatUserStore { 25 | @Override 26 | @Cacheable(value = RedisConstant.QUICK_CHAT_USER, key = "'getByAccountId:' + #p0", unless = "#result == null") 27 | public QuickChatUser getByAccountId(String accountId) { 28 | return this.lambdaQuery() 29 | .eq(QuickChatUser::getAccountId, accountId) 30 | .one(); 31 | } 32 | 33 | @Override 34 | public List getListByAccountIds(List accountIds) { 35 | return this.lambdaQuery() 36 | .in(QuickChatUser::getAccountId, accountIds) 37 | .list(); 38 | } 39 | 40 | @Override 41 | public Boolean saveUser(QuickChatUser userPO) { 42 | return this.save(userPO); 43 | } 44 | 45 | @Override 46 | @Caching(evict = { 47 | @CacheEvict(value = RedisConstant.QUICK_CHAT_USER, key = "'getByEmail:' + #p0.accountId"), 48 | @CacheEvict(value = RedisConstant.QUICK_CHAT_USER, key = "'getByAccountId:' + #p0.email") 49 | }) 50 | public Boolean updateUserById(QuickChatUser userPO) { 51 | return this.updateById(userPO); 52 | } 53 | 54 | @Override 55 | @Cacheable(value = RedisConstant.QUICK_CHAT_USER, key = "'getByEmail:' + #p0", unless = "#result == null") 56 | public QuickChatUser getByEmail(String email) { 57 | return this.lambdaQuery() 58 | .eq(QuickChatUser::getEmail, email) 59 | .one(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/adapter/ApplyAdapter.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.adapter; 2 | 3 | import com.quick.common.pojo.po.QuickChatApply; 4 | 5 | /** 6 | * @Author: 徐志斌 7 | * @CreateTime: 2024-07-05 13:35 8 | * @Description: 好友/群聊申请适配器 9 | * @Version: 1.0 10 | */ 11 | public class ApplyAdapter { 12 | public static QuickChatApply buildFriendApplyPO(String fromId, String toId, 13 | String applyInfo, Integer type, 14 | Long groupId, Integer status) { 15 | QuickChatApply apply = new QuickChatApply(); 16 | apply.setFromId(fromId); 17 | apply.setToId(toId); 18 | apply.setApplyInfo(applyInfo); 19 | apply.setType(type); 20 | apply.setGroupId(groupId); 21 | apply.setStatus(status); 22 | return apply; 23 | } 24 | 25 | public static QuickChatApply buildFriendApplyPO(String fromId, String toId, 26 | String applyInfo, Integer type, Integer status) { 27 | QuickChatApply apply = new QuickChatApply(); 28 | apply.setFromId(fromId); 29 | apply.setToId(toId); 30 | apply.setApplyInfo(applyInfo); 31 | apply.setType(type); 32 | apply.setStatus(status); 33 | return apply; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/adapter/ContactAdapter.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.adapter; 2 | 3 | import com.quick.common.pojo.po.QuickChatContact; 4 | 5 | /** 6 | * @Author: 徐志斌 7 | * @CreateTime: 2024-07-08 10:20 8 | * @Description: 通讯录-适配器 9 | * @Version: 1.0 10 | */ 11 | public class ContactAdapter { 12 | 13 | public static QuickChatContact buildContactPO(String accountId, Long groupId, Integer type, String noteName) { 14 | QuickChatContact contact = new QuickChatContact(); 15 | contact.setFromId(accountId); 16 | contact.setToId(groupId.toString()); 17 | contact.setType(type); 18 | contact.setNoteName(noteName); 19 | return contact; 20 | } 21 | 22 | public static QuickChatContact buildContactPO(String accountId, Long groupId, Integer type) { 23 | QuickChatContact contact = new QuickChatContact(); 24 | contact.setFromId(accountId); 25 | contact.setToId(groupId.toString()); 26 | contact.setType(type); 27 | return contact; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/adapter/EmojiAdapter.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.adapter; 2 | 3 | import com.quick.common.pojo.po.QuickChatEmoji; 4 | 5 | /** 6 | * @Author: 徐志斌 7 | * @CreateTime: 2023-12-01 09:18 8 | * @Description: 表情包适配器 9 | * @Version: 1.0 10 | */ 11 | public class EmojiAdapter { 12 | 13 | public static QuickChatEmoji buildEmojiPO(String url, String accountId) { 14 | QuickChatEmoji chatEmoji = new QuickChatEmoji(); 15 | chatEmoji.setAccountId(accountId); 16 | chatEmoji.setUrl(url); 17 | return chatEmoji; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/adapter/FileExtraAdapter.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.adapter; 2 | 3 | import com.quick.common.pojo.dto.FileExtraDTO; 4 | 5 | /** 6 | * @Author 徐志斌 7 | * @Date: 2024/4/4 15:42 8 | * @Version 1.0 9 | * @Description: 文件信息适配器 10 | */ 11 | public class FileExtraAdapter { 12 | 13 | public static FileExtraDTO buildFileExtraPO(String fileName, long size) { 14 | FileExtraDTO extraDTO = new FileExtraDTO(); 15 | extraDTO.setName(fileName); 16 | extraDTO.setSize(size); 17 | return extraDTO; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/adapter/GroupAdapter.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.adapter; 2 | 3 | import com.quick.common.pojo.dto.GroupDTO; 4 | import com.quick.common.pojo.po.QuickChatGroup; 5 | 6 | /** 7 | * @Author 徐志斌 8 | * @Date: 2024/5/25 8:29 9 | * @Version 1.0 10 | * @Description: 群组适配器 11 | */ 12 | public class GroupAdapter { 13 | public static QuickChatGroup buildGroupPO(GroupDTO groupDTO) { 14 | QuickChatGroup group = new QuickChatGroup(); 15 | group.setAccountId(groupDTO.getAccountId()); 16 | group.setGroupName(groupDTO.getGroupName()); 17 | return group; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/adapter/GroupMemberAdapter.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.adapter; 2 | 3 | import com.quick.common.pojo.po.QuickChatGroupMember; 4 | 5 | /** 6 | * @Author 徐志斌 7 | * @Date: 2024/1/8 21:22 8 | * @Version 1.0 9 | * @Description: 群成员适配器 10 | */ 11 | public class GroupMemberAdapter { 12 | public static QuickChatGroupMember buildMemberPO(Long groupId, String accountId) { 13 | QuickChatGroupMember groupMember = new QuickChatGroupMember(); 14 | groupMember.setGroupId(groupId); 15 | groupMember.setAccountId(accountId); 16 | return groupMember; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/annotation/RateLimiter.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.annotation; 2 | 3 | import com.quick.common.enums.LimitTypeEnum; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * @Author 徐志斌 9 | * @Date: 2024/2/14 20:40 10 | * @Version 1.0 11 | * @Description: 限流注解 12 | */ 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Documented 16 | public @interface RateLimiter { 17 | /** 18 | * 限流 KEY 19 | */ 20 | String key() default "rate_limit:"; 21 | 22 | /** 23 | * 限流时间,单位秒 24 | */ 25 | int time() default 60; 26 | 27 | /** 28 | * 请求次数 29 | */ 30 | int count() default 100; 31 | 32 | /** 33 | * 限流类型 34 | */ 35 | LimitTypeEnum limitType() default LimitTypeEnum.DEFAULT; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/aspect/WebLogAspect.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.aspect; 2 | 3 | import cn.hutool.core.date.StopWatch; 4 | import com.quick.common.utils.HttpServletUtil; 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.springframework.stereotype.Component; 10 | 11 | import javax.servlet.ServletRequest; 12 | import javax.servlet.ServletResponse; 13 | import javax.servlet.http.HttpServletRequest; 14 | import java.util.List; 15 | import java.util.stream.Collectors; 16 | import java.util.stream.Stream; 17 | 18 | /** 19 | * @Author: 徐志斌 20 | * @CreateTime: 2023-09-13 16:22 21 | * @Description: 统计接口调用日志 22 | * @Version: 1.0 23 | */ 24 | @Slf4j 25 | @Aspect 26 | @Component 27 | public class WebLogAspect { 28 | @Around("execution(* com.quick.api.controller..*.*(..))") 29 | public Object saveLog(ProceedingJoinPoint joinPoint) throws Throwable { 30 | HttpServletRequest request = HttpServletUtil.getRequest(); 31 | String method = request.getMethod(); 32 | String uri = request.getRequestURI(); 33 | 34 | List paramList = Stream.of(joinPoint.getArgs()) 35 | .filter(args -> !(args instanceof ServletRequest)) 36 | .filter(args -> !(args instanceof ServletResponse)) 37 | .collect(Collectors.toList()); 38 | log.info("-------------method:[{}],url:[{}],params:[{}]-------------", method, uri, paramList); 39 | 40 | StopWatch stopWatch = new StopWatch(); 41 | stopWatch.start(); 42 | Object result = joinPoint.proceed(); 43 | stopWatch.stop(); 44 | long cost = stopWatch.getTotalTimeMillis(); 45 | log.info("-------------url:[{}],response:[{}],time:[{}ms]-------------", uri, result, cost); 46 | return result; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/config/KaptchaConfig.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.config; 2 | 3 | import com.google.code.kaptcha.impl.DefaultKaptcha; 4 | import com.google.code.kaptcha.util.Config; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | import java.util.Properties; 9 | 10 | 11 | /** 12 | * @Author 徐志斌 13 | * @Date: 2023/9/12 21:57 14 | * @Description: Kaptcha验证码配置类 15 | * @Version 1.0 16 | */ 17 | @Configuration 18 | public class KaptchaConfig { 19 | @Bean 20 | public DefaultKaptcha getDefaultKaptcha() { 21 | Properties properties = new Properties(); 22 | properties.setProperty("kaptcha.border", "no"); 23 | properties.setProperty("kaptcha.textproducer.char.string", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"); 24 | properties.setProperty("kaptcha.textproducer.char.length", "4"); 25 | properties.setProperty("kaptcha.textproducer.font.names", "Arial, Courier, Georgia"); 26 | properties.setProperty("kaptcha.textproducer.font.size", "30"); 27 | properties.setProperty("kaptcha.textproducer.font.color", "0,102,204"); 28 | properties.setProperty("kaptcha.textproducer.char.space", "2"); 29 | properties.setProperty("kaptcha.image.width", "85"); 30 | properties.setProperty("kaptcha.image.height", "41"); 31 | properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.WaterRipple"); 32 | properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise"); 33 | DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); 34 | defaultKaptcha.setConfig(new Config(properties)); 35 | return defaultKaptcha; 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/com/quick/common/config/LuaScriptConfig.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.core.io.ClassPathResource; 6 | import org.springframework.data.redis.core.script.DefaultRedisScript; 7 | import org.springframework.scripting.support.ResourceScriptSource; 8 | 9 | /** 10 | * @Author 徐志斌 11 | * @Date: 2024/02/14 20:42:33 12 | * @Version 1.0 13 | * @Description: Redis Lua脚本配置类 14 | */ 15 | @Configuration 16 | public class LuaScriptConfig { 17 | public static final String RATE_LIMIT_LUA = "RATE_LIMIT_LUA"; 18 | 19 | /** 20 | * RateLimiter.lua 限流脚本 21 | */ 22 | @Bean(RATE_LIMIT_LUA) 23 | public DefaultRedisScript rateLimitScript() { 24 | DefaultRedisScript script = new DefaultRedisScript<>(); 25 | script.setScriptSource(new ResourceScriptSource(new ClassPathResource("src/main/resources/lua/RateLimit.lua"))); 26 | script.setResultType(Long.class); 27 | return script; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/config/MetaObjectConfig.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.config; 2 | 3 | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.apache.ibatis.reflection.MetaObject; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.time.LocalDateTime; 9 | 10 | /** 11 | * @Author: 徐志斌 12 | * @CreateTime: 2023-10-24 11:48 13 | * @Description: MyBatis-Plus自动填充 14 | * @Version: 1.0 15 | */ 16 | @Slf4j 17 | @Component 18 | public class MetaObjectConfig implements MetaObjectHandler { 19 | @Override 20 | public void insertFill(MetaObject metaObject) { 21 | this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); 22 | this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); 23 | this.strictInsertFill(metaObject, "deleted", Boolean.class, false); 24 | } 25 | 26 | @Override 27 | public void updateFill(MetaObject metaObject) { 28 | this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); 29 | } 30 | } -------------------------------------------------------------------------------- /src/main/java/com/quick/common/config/MinioConfig.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.config; 2 | 3 | import io.minio.MinioClient; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * @Author 徐志斌 11 | * @Date: 2023/7/23 18:27 12 | * @Version 1.0 13 | * @Description: Minio配置 14 | */ 15 | @Slf4j 16 | @Component 17 | public class MinioConfig { 18 | @Value("${minio.endpoint}") 19 | private String endpoint; 20 | @Value("${minio.accessKey}") 21 | private String accessKey; 22 | @Value("${minio.secretKey}") 23 | private String secretKey; 24 | 25 | @Bean 26 | public MinioClient minioClient() { 27 | return MinioClient.builder() 28 | .endpoint(endpoint) 29 | .credentials(accessKey, secretKey) 30 | .build(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/config/MybatisPlusConfig.java: -------------------------------------------------------------------------------- 1 | //package com.quick.config; 2 | // 3 | //import com.baomidou.mybatisplus.annotation.DbType; 4 | //import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; 5 | //import org.springframework.context.annotation.Bean; 6 | //import org.springframework.context.annotation.Configuration; 7 | // 8 | ///** 9 | // * @Author 徐志斌 10 | // * @Date: 2023/11/12 12:44 11 | // * @Version 1.0 12 | // * @Description: MyBatisPlus配置类 13 | // */ 14 | //@Configuration 15 | //public class MybatisPlusConfig { 16 | // @Bean 17 | // public MybatisPlusInterceptor mybatisPlusInterceptor() { 18 | // MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); 19 | // interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); 20 | // interceptor.addInnerInterceptor(new (DbType.MYSQL)); 21 | // return interceptor; 22 | // } 23 | //} -------------------------------------------------------------------------------- /src/main/java/com/quick/common/config/RocketMQConfig.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.config; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 5 | import org.apache.rocketmq.spring.support.RocketMQMessageConverter; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.context.annotation.Primary; 9 | import org.springframework.messaging.converter.CompositeMessageConverter; 10 | import org.springframework.messaging.converter.MappingJackson2MessageConverter; 11 | import org.springframework.messaging.converter.MessageConverter; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * @Author 徐志斌 17 | * @Date: 2024/10/09 10:03 18 | * @Version 1.0 19 | * @Description: RocketMQ 配置类 20 | */ 21 | @Configuration 22 | public class RocketMQConfig { 23 | /** 24 | * 解决RocketMQ Jackson不支持Java时间类型配置 25 | */ 26 | @Bean 27 | @Primary 28 | public RocketMQMessageConverter enhanceRocketMQMessageConverter() { 29 | RocketMQMessageConverter converter = new RocketMQMessageConverter(); 30 | CompositeMessageConverter compositeMessageConverter = (CompositeMessageConverter) converter.getMessageConverter(); 31 | List messageConverterList = compositeMessageConverter.getConverters(); 32 | for (MessageConverter messageConverter : messageConverterList) { 33 | if (messageConverter instanceof MappingJackson2MessageConverter) { 34 | MappingJackson2MessageConverter jackson2MessageConverter = (MappingJackson2MessageConverter) messageConverter; 35 | ObjectMapper objectMapper = jackson2MessageConverter.getObjectMapper(); 36 | objectMapper.registerModules(new JavaTimeModule()); 37 | } 38 | } 39 | return converter; 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/java/com/quick/common/config/SensitiveConfig.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.config; 2 | 3 | import com.github.houbb.sensitive.word.api.IWordAllow; 4 | import com.github.houbb.sensitive.word.api.IWordDeny; 5 | import com.github.houbb.sensitive.word.bs.SensitiveWordBs; 6 | import com.github.houbb.sensitive.word.core.SensitiveWordHelper; 7 | import com.github.houbb.sensitive.word.support.allow.WordAllows; 8 | import com.github.houbb.sensitive.word.support.deny.WordDenys; 9 | import com.quick.common.sensitive.MyWordAllow; 10 | import com.quick.common.sensitive.MyWordDeny; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.context.annotation.Configuration; 13 | 14 | /** 15 | * @Author: 徐志斌 16 | * @CreateTime: 2024-03-19 11:01 17 | * @Description: Sensitive 敏感词配置 18 | * @Version: 1.0 19 | */ 20 | @Configuration 21 | public class SensitiveConfig { 22 | IWordDeny wordDeny = WordDenys.chains(WordDenys.system(), new MyWordDeny()); 23 | IWordAllow wordAllow = WordAllows.chains(WordAllows.system(), new MyWordAllow()); 24 | 25 | @Bean 26 | public SensitiveWordBs sensitiveWordBs() { 27 | return SensitiveWordBs.newInstance() 28 | // 忽略大小写 29 | .ignoreCase(true) 30 | // 忽略半角圆角 31 | .ignoreWidth(true) 32 | // 忽略数字的写法 33 | .ignoreNumStyle(true) 34 | // 忽略中文的书写格式:简繁体 35 | .ignoreChineseStyle(true) 36 | // 忽略英文的书写格式 37 | .ignoreEnglishStyle(true) 38 | // 忽略重复词 39 | .ignoreRepeat(false) 40 | // 是否启用数字检测 41 | .enableNumCheck(true) 42 | // 是否启用邮箱检测 43 | .enableEmailCheck(true) 44 | // 是否启用链接检测 45 | .enableUrlCheck(true) 46 | // 配置自定义敏感词 47 | .wordDeny(wordDeny) 48 | // 配置自定义非敏感词 49 | .wordAllow(wordAllow) 50 | // 数字检测,自定义指定长度 51 | .numCheckLen(8) 52 | .init(); 53 | } 54 | 55 | public static void main(String[] args) { 56 | String str = "五星红旗迎风飘扬,毛主席的画像屹立在天安门前。"; 57 | System.out.println(SensitiveWordHelper.contains(str)); 58 | System.out.println(SensitiveWordHelper.findAll(str)); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/config/XxlJobConfig.java: -------------------------------------------------------------------------------- 1 | //package com.quick.common.config; 2 | // 3 | //import com.xxl.job.core.executor.impl.XxlJobSpringExecutor; 4 | //import org.springframework.beans.factory.annotation.Value; 5 | //import org.springframework.context.annotation.Bean; 6 | //import org.springframework.context.annotation.Configuration; 7 | // 8 | ///** 9 | // * @Author: 徐志斌 10 | // * @CreateTime: 2024-11-01 15:15 11 | // * @Description: XXL-JOB 配置类 12 | // * @Version: 1.0 13 | // */ 14 | //@Configuration 15 | //public class XxlJobConfig { 16 | // @Value("${xxl.job.admin.addresses}") 17 | // private String adminAddresses; 18 | // @Value("${xxl.job.accessToken}") 19 | // private String accessToken; 20 | // @Value("${xxl.job.executor.appname}") 21 | // private String appname; 22 | // @Value("${xxl.job.executor.address}") 23 | // private String address; 24 | // @Value("${xxl.job.executor.ip}") 25 | // private String ip; 26 | // @Value("${xxl.job.executor.port}") 27 | // private int port; 28 | // @Value("${xxl.job.executor.logpath}") 29 | // private String logPath; 30 | // @Value("${xxl.job.executor.logretentiondays}") 31 | // private int logRetentionDays; 32 | // 33 | // @Bean 34 | // public XxlJobSpringExecutor xxlJobExecutor() { 35 | // XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor(); 36 | // xxlJobSpringExecutor.setAdminAddresses(adminAddresses); 37 | // xxlJobSpringExecutor.setAppname(appname); 38 | // xxlJobSpringExecutor.setAddress(address); 39 | // xxlJobSpringExecutor.setIp(ip); 40 | // xxlJobSpringExecutor.setPort(port); 41 | // xxlJobSpringExecutor.setAccessToken(accessToken); 42 | // xxlJobSpringExecutor.setLogPath(logPath); 43 | // xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays); 44 | // return xxlJobSpringExecutor; 45 | // } 46 | //} -------------------------------------------------------------------------------- /src/main/java/com/quick/common/constant/RedisConstant.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.constant; 2 | 3 | /** 4 | * @Author: 徐志斌 5 | * @CreateTime: 2023-11-17 16:19 6 | * @Description: Redis常量类 7 | * @Version: 1.0 8 | */ 9 | public class RedisConstant { 10 | /** 11 | * 缓存 Key 12 | */ 13 | public static final String CAPTCHA_KEY = "captcha_key"; 14 | public static final String EMAIL_KEY = "EMAIL_KEY:"; 15 | public static final String PAGE_CURRENT_KEY = "PAGE_CURRENT_KEY:"; 16 | 17 | 18 | /** 19 | * 缓存分区 20 | */ 21 | public static final String QUICK_CHAT_USER = "quick_chat_user"; 22 | public static final String QUICK_CHAT_FRIEND_CONTACT = "quick_chat_friend_contact"; 23 | public static final String QUICK_CHAT_MSG = "quick_chat_msg"; 24 | public static final String QUICK_CHAT_EMOJI = "quick_chat_emoji"; 25 | public static final String QUICK_CHAT_SESSION = "quick_chat_session"; 26 | public static final String QUICK_CHAT_GROUP = "quick_chat_group"; 27 | public static final String QUICK_CHAT_GROUP_MEMBER = "quick_chat_group_member"; 28 | public static final String QUICK_CHAT_APPLY = "quick_chat_apply"; 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/constant/RocketMQConstant.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.constant; 2 | 3 | /** 4 | * @Author: 徐志斌 5 | * @CreateTime: 2023-11-20 18:15 6 | * @Description: RocketMQ 常量 7 | * @Version: 1.0 8 | */ 9 | public class RocketMQConstant { 10 | /** 11 | * 发送消息 Topic 12 | */ 13 | public static final String SEND_CHAT_SINGLE_MSG = "SEND_CHAT_SINGLE_MSG"; 14 | public static final String SEND_CHAT_GROUP_MSG = "SEND_CHAT_GROUP_MSG"; 15 | 16 | /** 17 | * 好友、群组申请 Topic 18 | */ 19 | public static final String FRIEND_APPLY_TOPIC = "FRIEND_APPLY_TOPIC"; 20 | public static final String GROUP_APPLY_TOPIC = "GROUP_APPLY_TOPIC"; 21 | 22 | /** 23 | * 群内通知 Topic 24 | */ 25 | public static final String GROUP_ADD_MEMBER_NOTICE = "GROUP_ADD_MEMBER_NOTICE"; 26 | public static final String GROUP_DELETE_MEMBER_NOTICE = "GROUP_DELETE_MEMBER_NOTICE"; 27 | public static final String GROUP_RELEASE_NOTICE = "GROUP_RELEASE_NOTICE"; 28 | 29 | /** 30 | * 对方正在输入 Topic 31 | */ 32 | public static final String SEND_CHAT_ENTERING = "SEND_CHAT_ENTERING"; 33 | 34 | // ----------------------------------------------------------------------------------------------------------------- 35 | 36 | /** 37 | * 消费组 38 | */ 39 | public static final String CHAT_SEND_GROUP_ID = "CHAT_SEND_GROUP_ID"; 40 | public static final String APPLY_GROUP_ID = "CHAT_SEND_GROUP_ID"; 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/enums/ApplyTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * @Author: 徐志斌 8 | * @CreateTime: 2024-07-05 13:39 9 | * @Description: 申请类型枚举 10 | * @Version: 1.0 11 | */ 12 | @Getter 13 | @AllArgsConstructor 14 | public enum ApplyTypeEnum { 15 | FRIEND(1, "好友申请"), 16 | GROUP(2, "群聊申请"); 17 | 18 | private Integer code; 19 | private String msg; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/enums/BucketEnum.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * @Author: 徐志斌 8 | * @CreateTime: 2023-11-21 10:31 9 | * @Description: 文件类型枚举 10 | * @Version: 1.0 11 | */ 12 | @Getter 13 | @AllArgsConstructor 14 | public enum BucketEnum { 15 | AVATAR(1, "avatar-bucket", "头像"), 16 | VOICE(2, "voice-bucket", "语音"), 17 | FILE(3, "file-bucket", "文件"), 18 | ; 19 | 20 | private Integer code; 21 | private String bucketName; 22 | private String desc; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/enums/ChatMsgEnum.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * @Author: 徐志斌 8 | * @CreateTime: 2023-11-17 14:46 9 | * @Description: 聊天消息类型枚举 10 | * @Version: 1.0 11 | */ 12 | @Getter 13 | @AllArgsConstructor 14 | public enum ChatMsgEnum { 15 | RECALL(0, "撤回"), 16 | FONT(1, "文字"), 17 | VOICE(2, "语音"), 18 | EMOJI(3, "表情包"), 19 | FILE(4, "文件(图片、视频)"), 20 | VOICE_CALL(5, "语音通话"), 21 | VIDEO_CALL(6, "视频通话"), 22 | AT(8, "艾特用户"), 23 | REPLY(9, "引用(回复)"), 24 | ; 25 | 26 | private Integer code; 27 | private String msg; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/enums/EmailEnum.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * @Author: 徐志斌 8 | * @CreateTime: 2023-11-17 14:46 9 | * @Description: 邮件类型枚举 10 | * @Version: 1.0 11 | */ 12 | @Getter 13 | @AllArgsConstructor 14 | public enum EmailEnum { 15 | VERIFY_CODE(1, "验证码"), 16 | FIND_BACK(2, "找回密码"), 17 | ; 18 | 19 | private Integer type; 20 | private String desc; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/enums/GenderEnum.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * @Author: 徐志斌 8 | * @CreateTime: 2023-11-17 16:37 9 | * @Description: 性别枚举 10 | * @Version: 1.0 11 | */ 12 | @Getter 13 | @AllArgsConstructor 14 | public enum GenderEnum { 15 | GIRL(0, "女"), 16 | BOY(1, "男"); 17 | 18 | private Integer type; 19 | private String desc; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/enums/LimitTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.enums; 2 | 3 | /** 4 | * @Author 徐志斌 5 | * @Date: 2024/2/14 20:48 6 | * @Version 1.0 7 | * @Description: 限流类型枚举 8 | */ 9 | public enum LimitTypeEnum { 10 | /** 11 | * 默认策略全局限流 12 | */ 13 | DEFAULT, 14 | 15 | /** 16 | * 根据请求者IP进行限流 17 | */ 18 | IP 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/enums/ResponseEnum.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | /** 8 | * @Author 徐志斌 9 | * @Date: 2023/11/13 22:00 10 | * @Version 1.0 11 | * @Description: 响应封装类状态码 12 | */ 13 | @Getter 14 | @AllArgsConstructor 15 | public enum ResponseEnum { 16 | SUCCESS(200, "操作成功"), 17 | FAIL(500, "操作失败"), 18 | 19 | // --------------------账户--------------------- 20 | ACCOUNT_ID_NOT_EXIST(500, "该用户信息不存在"), 21 | ACCOUNT_ID_EXIST(500, "该账号信息已存在,请勿重复注册!"), 22 | PASSWORD_DIFF(500, "两次密码输入不一致,请重试!"), 23 | PASSWORD_ERROR(500, "密码输入错误,请重试!"), 24 | IMG_CODE_ERROR(500, "图片验证码输入错误,请重试!"), 25 | EMAIL_CODE_ERROR(500, "邮箱验证码输入错误,请重试!"), 26 | EMAIL_HAS_REGISTERED(500, "邮箱已经被注册,请重试!"), 27 | EMAIL_NOT_REGISTERED(500, "邮箱尚未注册账号,请重试!"), 28 | TOKEN_EXPIRE(510, "登录身份已过期,请重新登录!"), 29 | NICK_NAME_NOT_ALLOW(510, "昵称存在违规信息,不可使用!"), 30 | 31 | // --------------------会话--------------------- 32 | SESSION_INFO_ERROR(500, "聊天会话信息异常,请联系废物作者"), 33 | SESSION_NOT_EXIST(500, "聊天会话信息不存在,请重新加载后操作"), 34 | 35 | // --------------------聊天消息--------------------- 36 | FILE_OVER_SIZE(500, "文件大小不可超过:%s"), 37 | VOICE_TIME_NOT_ALLOW(500, "语音消息时长不可超过%s秒!"), 38 | FONT_MSG_NOT_EXIST(500, "输入框内容为空,不可进行发送"), 39 | CAN_NOT_RECALL(500, "信息发送已超过2分钟,不可撤回"), 40 | SEND_MSG_FAST(500, "慢点发消息嘛,别急..."), 41 | 42 | 43 | // --------------------通讯录--------------------- 44 | YOUR_FRIEND(500, "对方已经是您的好友,不可重复添加"), 45 | NOT_YOUR_FRIEND(500, "对方不是您的好友,不可进行当前操作!"), 46 | 47 | // --------------------群组--------------------- 48 | GROUP_NOT_EXIST(500, "群组信息不存在!"), 49 | NOT_GROUP_OWNER(500, "您不是群主,不可进行当前操作!"), 50 | NOT_GROUP_MEMBER(500, "您不在该群组中,不可进行当前操作!"), 51 | GROUP_MEMBER_ADD_COUNT_NOT_ALLOW(500, "单次添加群成员数量不可超过20"), 52 | GROUP_MEMBER_COUNT_NOT_EXIST(500, "添加群成员参数不能为空!"), 53 | GROUP_MEMBER_NOT_ALLOW(500, "群成员不可进行当前操作"), 54 | GROUP_SIZE_OVER(500, "群成员数量已满,不可以进入群聊"), 55 | 56 | 57 | // --------------------系统申请--------------------- 58 | APPLY_NOT_EXIST(500, "该申请信息不存在"), 59 | APPLY_IS_FINISH(500, "该申请信息已处理,请勿继续操作"), 60 | ; 61 | 62 | @Setter 63 | private Integer code; 64 | @Setter 65 | private String msg; 66 | } -------------------------------------------------------------------------------- /src/main/java/com/quick/common/enums/SessionTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * @Author: 徐志斌 8 | * @CreateTime: 2024-01-09 09:57 9 | * @Description: 会话类型枚举 10 | * @Version: 1.0 11 | */ 12 | @Getter 13 | @AllArgsConstructor 14 | public enum SessionTypeEnum { 15 | SINGLE(1, "单聊"), 16 | GROUP(2, "群聊"); 17 | 18 | private Integer code; 19 | private String msg; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/enums/WsPushEnum.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * @Author: 徐志斌 8 | * @CreateTime: 2024-03-11 10:19 9 | * @Description: WebSocket 推送消息类型 10 | * @Version: 1.0 11 | */ 12 | @Getter 13 | @AllArgsConstructor 14 | public enum WsPushEnum { 15 | /** 16 | * 通用 17 | */ 18 | SYSTEM_NOTICE(0, "系统通知:账号重复登录"), 19 | CHAT_MSG(1, "发送消息"), 20 | WRITING(2, "对方正在输入"), 21 | ONLINE_STATUS(3, "登陆状态"), 22 | 23 | /** 24 | * 好友、群聊申请 25 | */ 26 | FRIEND_APPLY_NOTICE(20, "好友申请"), 27 | GROUP_APPLY_NOTICE(21, "群聊申请"), 28 | 29 | /** 30 | * 群聊内部通知 31 | */ 32 | GROUP_RELEASE_NOTICE(30, "群内通知:解散群聊"), 33 | GROUP_ADD_MEMBER_NOTICE(31, "群内通知:加入新成员"), 34 | GROUP_DELETE_MEMBER_NOTICE(32, "群内通知:删除成员"), 35 | ; 36 | 37 | private Integer code; 38 | private String msg; 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/enums/YesNoEnum.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * @Author 徐志斌 8 | * @Date: 2023/11/25 13:13 9 | * @Version 1.0 10 | * @Description: 判断枚举 11 | */ 12 | @Getter 13 | @AllArgsConstructor 14 | public enum YesNoEnum { 15 | NO(0), 16 | YES(1); 17 | 18 | private Integer code; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/exception/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.exception; 2 | 3 | import com.quick.common.enums.ResponseEnum; 4 | import com.quick.common.response.R; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.commons.lang3.exception.ExceptionUtils; 7 | import org.springframework.validation.BindException; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.RestControllerAdvice; 10 | 11 | /** 12 | * @Author 徐志斌 13 | * @Date: 2023/6/30 21:22 14 | * @Version 1.0 15 | * @Description: 全局统一异常处理 16 | */ 17 | @Slf4j 18 | @RestControllerAdvice 19 | public class GlobalExceptionHandler { 20 | /** 21 | * 自定义异常 QuickException 22 | */ 23 | @ExceptionHandler(QuickException.class) 24 | public R quickException(QuickException e) { 25 | log.error("========================QuickException:{}========================", e); 26 | return R.out(e.getResponseEnum()); 27 | } 28 | 29 | /** 30 | * 注解校验异常 BindException 31 | */ 32 | @ExceptionHandler(BindException.class) 33 | public R validationException(BindException b) { 34 | log.error("========================BindException:{}========================", b); 35 | final StringBuilder sb = new StringBuilder(); 36 | b.getBindingResult().getAllErrors().forEach(e -> sb.append(e.getDefaultMessage()).append("\r\n")); 37 | return R.out(ResponseEnum.FAIL, sb); 38 | } 39 | 40 | /** 41 | * 自定义注解校验异常 QuickValidationException 42 | */ 43 | @ExceptionHandler({QuickValidationException.class}) 44 | public R quickValidationException(QuickValidationException e) { 45 | log.error("========================QuickValidationException:{}========================", e); 46 | return R.out(ResponseEnum.FAIL, ExceptionUtils.getMessage(e)); 47 | } 48 | 49 | /** 50 | * 所有异常 51 | */ 52 | @ExceptionHandler(Exception.class) 53 | public R bindException(Exception e) { 54 | log.error("========================Exception:{}========================", e); 55 | return R.out(ResponseEnum.FAIL, e); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/exception/QuickException.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.exception; 2 | 3 | import com.quick.common.enums.ResponseEnum; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | 7 | /** 8 | * @Author 徐志斌 9 | * @Date: 2023/11/13 21:19 10 | * @Version 1.0 11 | * @Description: 自定义通用异常 12 | */ 13 | @Getter 14 | @AllArgsConstructor 15 | public class QuickException extends RuntimeException { 16 | private ResponseEnum responseEnum; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/exception/QuickValidationException.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.exception; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | import java.net.BindException; 7 | 8 | /** 9 | * @Author 陈辰 10 | * @Date: 2024/7/10 20:27 11 | * @Version 1.0 12 | * @Description: 自定义注解校验异常 13 | */ 14 | @Getter 15 | @AllArgsConstructor 16 | public class QuickValidationException extends BindException { 17 | private String errorMsg; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/interceptor/LoginTokenInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.interceptor; 2 | 3 | import com.quick.common.enums.ResponseEnum; 4 | import com.quick.common.exception.QuickException; 5 | import com.quick.common.utils.JwtUtil; 6 | import com.quick.common.utils.RequestContextUtil; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.stereotype.Component; 9 | import org.springframework.web.servlet.HandlerInterceptor; 10 | import org.springframework.web.servlet.ModelAndView; 11 | 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | import java.util.Map; 15 | 16 | /** 17 | * @Author: 徐志斌 18 | * @CreateTime: 2023-11-20 18:06 19 | * @Description: 登录Token拦截器 20 | * @Version: 1.0 21 | */ 22 | @Slf4j 23 | @Component 24 | public class LoginTokenInterceptor implements HandlerInterceptor { 25 | @Override 26 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { 27 | String httpMethod = "OPTIONS"; 28 | if (httpMethod.equals(request.getMethod())) { 29 | response.setStatus(HttpServletResponse.SC_OK); 30 | return true; 31 | } 32 | 33 | String token = request.getHeader("token"); 34 | if (!JwtUtil.check(token)) { 35 | throw new QuickException(ResponseEnum.TOKEN_EXPIRE); 36 | } 37 | 38 | Map tokenMap = JwtUtil.resolve(token); 39 | RequestContextUtil.setData(tokenMap); 40 | return true; 41 | } 42 | 43 | @Override 44 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { 45 | 46 | } 47 | 48 | @Override 49 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { 50 | RequestContextUtil.removeData(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/mq/consumer/apply/FriendApplyConsumer.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.mq.consumer.apply; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.quick.common.constant.RocketMQConstant; 5 | import com.quick.common.enums.WsPushEnum; 6 | import com.quick.common.netty.UserChannelRelation; 7 | import com.quick.common.pojo.entity.WsPushEntity; 8 | import com.quick.common.pojo.po.QuickChatApply; 9 | import io.netty.channel.Channel; 10 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 11 | import org.apache.commons.lang3.ObjectUtils; 12 | import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; 13 | import org.apache.rocketmq.spring.core.RocketMQListener; 14 | import org.springframework.messaging.Message; 15 | import org.springframework.stereotype.Component; 16 | 17 | /** 18 | * @Author: 徐志斌 19 | * @CreateTime: 2024-03-13 16:07 20 | * @Description: 好友申请-消费者 21 | * @Version: 1.0 22 | */ 23 | @Component 24 | @RocketMQMessageListener(topic = RocketMQConstant.FRIEND_APPLY_TOPIC, consumerGroup = RocketMQConstant.CHAT_SEND_GROUP_ID) 25 | public class FriendApplyConsumer implements RocketMQListener> { 26 | @Override 27 | public void onMessage(Message message) { 28 | QuickChatApply apply = message.getPayload(); 29 | Channel channel = UserChannelRelation.getUserChannelMap().get(apply.getToId()); 30 | if (ObjectUtils.isNotEmpty(channel)) { 31 | WsPushEntity pushEntity = new WsPushEntity<>(); 32 | pushEntity.setPushType(WsPushEnum.FRIEND_APPLY_NOTICE.getCode()); 33 | pushEntity.setMessage(apply); 34 | channel.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(pushEntity))); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/mq/consumer/apply/GroupApplyConsumer.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.mq.consumer.apply; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; 5 | import com.quick.common.constant.RocketMQConstant; 6 | import com.quick.common.enums.WsPushEnum; 7 | import com.quick.common.netty.UserChannelRelation; 8 | import com.quick.common.pojo.entity.WsPushEntity; 9 | import com.quick.common.pojo.po.QuickChatApply; 10 | import com.quick.common.pojo.po.QuickChatGroupMember; 11 | import com.quick.api.store.QuickChatGroupMemberStore; 12 | import io.netty.channel.Channel; 13 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 14 | import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; 15 | import org.apache.rocketmq.spring.core.RocketMQListener; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.messaging.Message; 18 | import org.springframework.stereotype.Component; 19 | 20 | import java.util.List; 21 | 22 | /** 23 | * @Author: 徐志斌 24 | * @CreateTime: 2024-03-13 16:07 25 | * @Description: 群聊申请-消费者 26 | * @Version: 1.0 27 | */ 28 | @Component 29 | @RocketMQMessageListener(topic = RocketMQConstant.GROUP_APPLY_TOPIC, consumerGroup = RocketMQConstant.CHAT_SEND_GROUP_ID) 30 | public class GroupApplyConsumer implements RocketMQListener> { 31 | @Autowired 32 | private QuickChatGroupMemberStore memberStore; 33 | 34 | @Override 35 | public void onMessage(Message message) { 36 | QuickChatApply apply = message.getPayload(); 37 | List members = memberStore.getListByGroupId(apply.getGroupId()); 38 | for (QuickChatGroupMember member : members) { 39 | Channel channel = UserChannelRelation.getUserChannelMap().get(member.getAccountId()); 40 | if (ObjectUtils.isNotEmpty(channel)) { 41 | WsPushEntity pushEntity = new WsPushEntity<>(); 42 | pushEntity.setPushType(WsPushEnum.GROUP_APPLY_NOTICE.getCode()); 43 | pushEntity.setMessage(apply); 44 | channel.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(pushEntity))); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/mq/consumer/msg/SendFriendMsgConsumer.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.mq.consumer.msg; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; 5 | import com.quick.common.constant.RocketMQConstant; 6 | import com.quick.common.enums.WsPushEnum; 7 | import com.quick.common.netty.UserChannelRelation; 8 | import com.quick.common.pojo.entity.WsPushEntity; 9 | import com.quick.common.pojo.po.QuickChatMsg; 10 | import io.netty.channel.Channel; 11 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 12 | import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; 13 | import org.apache.rocketmq.spring.core.RocketMQListener; 14 | import org.springframework.messaging.Message; 15 | import org.springframework.stereotype.Component; 16 | 17 | /** 18 | * @Author 徐志斌 19 | * @Date: 2024/10/6 8:52 20 | * @Version 1.0 21 | * @Description: 发送信息(单聊)-消费者 22 | */ 23 | @Component 24 | @RocketMQMessageListener(topic = RocketMQConstant.SEND_CHAT_SINGLE_MSG, consumerGroup = RocketMQConstant.CHAT_SEND_GROUP_ID) 25 | public class SendFriendMsgConsumer implements RocketMQListener> { 26 | @Override 27 | public void onMessage(Message message) { 28 | QuickChatMsg chatMsg = message.getPayload(); 29 | Channel channel = UserChannelRelation.getUserChannelMap().get(chatMsg.getToId()); 30 | if (ObjectUtils.isNotEmpty(channel)) { 31 | WsPushEntity pushEntity = new WsPushEntity<>(); 32 | pushEntity.setPushType(WsPushEnum.CHAT_MSG.getCode()); 33 | pushEntity.setMessage(chatMsg); 34 | channel.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(pushEntity))); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/mq/consumer/msg/SendGroupMsgConsumer.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.mq.consumer.msg; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; 5 | import com.quick.common.constant.RocketMQConstant; 6 | import com.quick.common.enums.WsPushEnum; 7 | import com.quick.common.netty.UserChannelRelation; 8 | import com.quick.common.pojo.entity.WsPushEntity; 9 | import com.quick.common.pojo.po.QuickChatGroupMember; 10 | import com.quick.common.pojo.po.QuickChatMsg; 11 | import com.quick.api.store.QuickChatGroupMemberStore; 12 | import io.netty.channel.Channel; 13 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 14 | import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; 15 | import org.apache.rocketmq.spring.core.RocketMQListener; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.messaging.Message; 18 | import org.springframework.stereotype.Component; 19 | 20 | import java.util.List; 21 | 22 | /** 23 | * @Author 徐志斌 24 | * @Date: 2024/10/6 8:52 25 | * @Version 1.0 26 | * @Description: 发送信息(群聊)-消费者 27 | */ 28 | @Component 29 | @RocketMQMessageListener(topic = RocketMQConstant.SEND_CHAT_GROUP_MSG, consumerGroup = RocketMQConstant.CHAT_SEND_GROUP_ID) 30 | public class SendGroupMsgConsumer implements RocketMQListener> { 31 | @Autowired 32 | private QuickChatGroupMemberStore memberStore; 33 | 34 | @Override 35 | public void onMessage(Message message) { 36 | QuickChatMsg chatMsg = message.getPayload(); 37 | List memberList = memberStore.getListByGroupId(chatMsg.getRelationId()); 38 | for (QuickChatGroupMember member : memberList) { 39 | if (member.getAccountId().equals(chatMsg.getFromId())) { 40 | continue; 41 | } 42 | Channel channel = UserChannelRelation.getUserChannelMap().get(member.getAccountId()); 43 | if (ObjectUtils.isNotEmpty(channel)) { 44 | WsPushEntity pushEntity = new WsPushEntity<>(); 45 | pushEntity.setPushType(WsPushEnum.CHAT_MSG.getCode()); 46 | pushEntity.setMessage(chatMsg); 47 | channel.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(chatMsg))); 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/mq/consumer/msg/SendMsgLoadingConsumer.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.mq.consumer.msg; 2 | 3 | import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; 4 | import com.quick.common.constant.RocketMQConstant; 5 | import com.quick.common.enums.WsPushEnum; 6 | import com.quick.common.netty.UserChannelRelation; 7 | import com.quick.common.pojo.entity.WsPushEntity; 8 | import io.netty.channel.Channel; 9 | import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; 10 | import org.apache.rocketmq.spring.core.RocketMQListener; 11 | import org.springframework.messaging.Message; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.util.Map; 15 | 16 | /** 17 | * @Author 徐志斌 18 | * @Date: 2024/10/6 8:52 19 | * @Version 1.0 20 | * @Description: 消息发送中-消费者 21 | */ 22 | @Component 23 | @RocketMQMessageListener(topic = RocketMQConstant.SEND_CHAT_ENTERING, consumerGroup = RocketMQConstant.CHAT_SEND_GROUP_ID) 24 | public class SendMsgLoadingConsumer implements RocketMQListener>> { 25 | @Override 26 | public void onMessage(Message> message) { 27 | Map param = message.getPayload(); 28 | Channel channel = UserChannelRelation.getUserChannelMap().get(param.get("toId")); 29 | if (ObjectUtils.isNotEmpty(channel)) { 30 | WsPushEntity> pushEntity = new WsPushEntity(); 31 | pushEntity.setPushType(WsPushEnum.WRITING.getCode()); 32 | pushEntity.setMessage(param); 33 | channel.writeAndFlush(pushEntity); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/mq/consumer/notice/GroupAddMemberConsumer.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.mq.consumer.notice; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; 5 | import com.quick.common.constant.RocketMQConstant; 6 | import com.quick.common.enums.WsPushEnum; 7 | import com.quick.common.netty.UserChannelRelation; 8 | import com.quick.common.pojo.entity.WsPushEntity; 9 | import com.quick.common.pojo.po.QuickChatApply; 10 | import com.quick.common.pojo.po.QuickChatGroupMember; 11 | import com.quick.api.store.QuickChatGroupMemberStore; 12 | import io.netty.channel.Channel; 13 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 14 | import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; 15 | import org.apache.rocketmq.spring.core.RocketMQListener; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.messaging.Message; 18 | import org.springframework.stereotype.Component; 19 | 20 | import java.util.List; 21 | 22 | /** 23 | * @Author 徐志斌 24 | * @Date: 2024/10/6 14:42 25 | * @Version 1.0 26 | * @Description: 添加群成员-消费者 27 | */ 28 | @Component 29 | @RocketMQMessageListener(topic = RocketMQConstant.GROUP_ADD_MEMBER_NOTICE, consumerGroup = RocketMQConstant.CHAT_SEND_GROUP_ID) 30 | public class GroupAddMemberConsumer implements RocketMQListener> { 31 | @Autowired 32 | private QuickChatGroupMemberStore memberStore; 33 | 34 | @Override 35 | public void onMessage(Message message) { 36 | QuickChatApply apply = message.getPayload(); 37 | List members = memberStore.getListByGroupId(apply.getGroupId()); 38 | for (QuickChatGroupMember member : members) { 39 | Channel channel = UserChannelRelation.getUserChannelMap().get(member.getAccountId()); 40 | if (ObjectUtils.isNotEmpty(channel)) { 41 | WsPushEntity pushEntity = new WsPushEntity<>(); 42 | pushEntity.setPushType(WsPushEnum.GROUP_ADD_MEMBER_NOTICE.getCode()); 43 | pushEntity.setMessage(apply); 44 | channel.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(pushEntity))); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/mq/consumer/notice/GroupDeleteMemberConsumer.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.mq.consumer.notice; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; 5 | import com.quick.common.constant.RocketMQConstant; 6 | import com.quick.common.enums.WsPushEnum; 7 | import com.quick.common.netty.UserChannelRelation; 8 | import com.quick.common.pojo.entity.WsPushEntity; 9 | import com.quick.common.pojo.po.QuickChatGroupMember; 10 | import io.netty.channel.Channel; 11 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 12 | import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; 13 | import org.apache.rocketmq.spring.core.RocketMQListener; 14 | import org.springframework.messaging.Message; 15 | import org.springframework.stereotype.Component; 16 | 17 | /** 18 | * @Author 徐志斌 19 | * @Date: 2024/10/6 14:42 20 | * @Version 1.0 21 | * @Description: 移除群成员-消费者 22 | */ 23 | @Component 24 | @RocketMQMessageListener(topic = RocketMQConstant.GROUP_DELETE_MEMBER_NOTICE, consumerGroup = RocketMQConstant.CHAT_SEND_GROUP_ID) 25 | public class GroupDeleteMemberConsumer implements RocketMQListener> { 26 | @Override 27 | public void onMessage(Message message) { 28 | QuickChatGroupMember member = message.getPayload(); 29 | Channel channel = UserChannelRelation.getUserChannelMap().get(member.getAccountId()); 30 | if (ObjectUtils.isNotEmpty(channel)) { 31 | WsPushEntity pushEntity = new WsPushEntity<>(); 32 | pushEntity.setPushType(WsPushEnum.GROUP_DELETE_MEMBER_NOTICE.getCode()); 33 | pushEntity.setMessage(member); 34 | channel.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(pushEntity))); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/mq/consumer/notice/GroupReleaseConsumer.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.mq.consumer.notice; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; 5 | import com.quick.common.constant.RocketMQConstant; 6 | import com.quick.common.enums.WsPushEnum; 7 | import com.quick.common.netty.UserChannelRelation; 8 | import com.quick.common.pojo.entity.WsPushEntity; 9 | import io.netty.channel.Channel; 10 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 11 | import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; 12 | import org.apache.rocketmq.spring.core.RocketMQListener; 13 | import org.springframework.messaging.Message; 14 | import org.springframework.stereotype.Component; 15 | 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | /** 20 | * @Author 徐志斌 21 | * @Date: 2024/10/6 14:42 22 | * @Version 1.0 23 | * @Description: 解散群组-消费者 24 | */ 25 | @Component 26 | @RocketMQMessageListener(topic = RocketMQConstant.GROUP_RELEASE_NOTICE, consumerGroup = RocketMQConstant.CHAT_SEND_GROUP_ID) 27 | public class GroupReleaseConsumer implements RocketMQListener>> { 28 | 29 | @Override 30 | public void onMessage(Message> message) { 31 | Map params = message.getPayload(); 32 | List accountIds = (List) params.get("accountIds"); 33 | for (String accountId : accountIds) { 34 | Channel channel = UserChannelRelation.getUserChannelMap().get(accountId); 35 | if (ObjectUtils.isNotEmpty(channel)) { 36 | WsPushEntity pushEntity = new WsPushEntity<>(); 37 | pushEntity.setPushType(WsPushEnum.GROUP_RELEASE_NOTICE.getCode()); 38 | pushEntity.setMessage((Long) params.get("groupId")); 39 | channel.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(pushEntity))); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/mq/producer/MyRocketMQTemplate.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.mq.producer; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.apache.rocketmq.client.producer.SendCallback; 6 | import org.apache.rocketmq.client.producer.SendResult; 7 | import org.apache.rocketmq.spring.core.RocketMQTemplate; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.messaging.Message; 10 | import org.springframework.messaging.support.MessageBuilder; 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * @Author: 徐志斌 15 | * @CreateTime: 2024-11-19 11:05 16 | * @Description: 自定义 RocketMQTemplate 17 | * @Version: 1.0 18 | */ 19 | @Slf4j 20 | @Component 21 | public class MyRocketMQTemplate { 22 | @Autowired 23 | private RocketMQTemplate rocketMQTemplate; 24 | 25 | /** 26 | * 同步消息 27 | * 28 | * @param topic 主题 29 | * @param message 消息实体 30 | * @return 执行结果 31 | */ 32 | public SendResult syncSend(String topic, T message) { 33 | Message sendMessage = MessageBuilder.withPayload(message).build(); 34 | SendResult sendResult = rocketMQTemplate.syncSend(topic, sendMessage); 35 | log.info("[{}]同步消息[{}]发送结果[{}]", topic, JSONObject.toJSON(message), JSONObject.toJSON(sendResult)); 36 | return sendResult; 37 | } 38 | 39 | /** 40 | * 异步消息 41 | * 42 | * @param topic 主题 43 | * @param message 消息实体 44 | */ 45 | public void asyncSend(String topic, T message) { 46 | Message sendMessage = MessageBuilder.withPayload(message).build(); 47 | rocketMQTemplate.asyncSend(topic, sendMessage, new SendCallback() { 48 | @Override 49 | public void onSuccess(SendResult sendResult) { 50 | log.info("[asyncSend] msg send Success, topic:[{}], message: [{}], result: [{}]", 51 | topic, JSONObject.toJSON(message), JSONObject.toJSON(sendResult)); 52 | } 53 | 54 | @Override 55 | public void onException(Throwable throwable) { 56 | log.error("[asyncSend] msg send Failed, topic:[{}], message: [{}]", 57 | topic, JSONObject.toJSON(message)); 58 | } 59 | }); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/netty/NettyChannelHandler.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.netty; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelHandler; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.SimpleChannelInboundHandler; 7 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * @Author 徐志斌 13 | * @Date: 2023/11/12 20:10 14 | * @Version 1.0 15 | * @Description: WebSocket Channel处理器 16 | */ 17 | @Slf4j 18 | @Component 19 | @ChannelHandler.Sharable 20 | public class NettyChannelHandler extends SimpleChannelInboundHandler { 21 | /** 22 | * 读取客户端 Channel 数据:建立 account_id 和 Channel 的关联 23 | */ 24 | @Override 25 | protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) { 26 | log.info("-----------channelRead0()调用:{}-----------", frame.text()); 27 | String accountId = frame.text(); 28 | Channel channel = ctx.channel(); 29 | UserChannelRelation.getUserChannelMap().put(accountId, channel); 30 | } 31 | 32 | /** 33 | * 断开连接 34 | */ 35 | @Override 36 | public void handlerRemoved(ChannelHandlerContext ctx) { 37 | 38 | log.info("--------------WebSocket连接断开:{}--------------", ctx); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/netty/UserChannelRelation.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.netty; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.group.ChannelGroup; 5 | import io.netty.channel.group.DefaultChannelGroup; 6 | import io.netty.util.concurrent.GlobalEventExecutor; 7 | 8 | import java.util.concurrent.ConcurrentHashMap; 9 | 10 | /** 11 | * @Author 徐志斌 12 | * @Date: 2023/5/28 19:29 13 | * @Description: account_id & Channel 关系 14 | */ 15 | public class UserChannelRelation { 16 | private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); 17 | private static ConcurrentHashMap userChannelMap = new ConcurrentHashMap<>(); 18 | 19 | public static ChannelGroup getChannelGroup() { 20 | return channelGroup; 21 | } 22 | 23 | public static ConcurrentHashMap getUserChannelMap() { 24 | return userChannelMap; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/dto/ChatMsgDTO.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.dto; 2 | 3 | import com.quick.common.enums.ChatMsgEnum; 4 | import com.quick.common.enums.SessionTypeEnum; 5 | import lombok.Data; 6 | import org.hibernate.validator.constraints.Length; 7 | 8 | import javax.validation.constraints.NotBlank; 9 | import javax.validation.constraints.NotNull; 10 | 11 | 12 | /** 13 | * @Author: 徐志斌 14 | * @CreateTime: 2023-11-17 15:15 15 | * @Description: 聊天消息DTO 16 | * @Version: 1.0 17 | */ 18 | @Data 19 | public class ChatMsgDTO { 20 | /** 21 | * 发送方 22 | */ 23 | @NotBlank(message = "发送方不能为空") 24 | private String fromId; 25 | 26 | /** 27 | * 接收方 28 | */ 29 | @NotBlank(message = "接收方不能为空") 30 | private String toId; 31 | 32 | /** 33 | * 关联id 34 | */ 35 | @NotNull(message = "关联id不能为空") 36 | private Long relationId; 37 | 38 | /** 39 | * 发送人昵称 40 | */ 41 | @NotBlank(message = "发送账号昵称不能为空") 42 | private String nickName; 43 | 44 | /** 45 | * 消息类型 46 | * 47 | * @see ChatMsgEnum 48 | */ 49 | @NotNull(message = "消息类型不能为空") 50 | private Integer msgType; 51 | 52 | /** 53 | * 会话类型 54 | * 55 | * @see SessionTypeEnum 56 | */ 57 | @NotNull(message = "会话类型不能为空") 58 | private Integer sessionType; 59 | 60 | /** 61 | * 消息内容 62 | */ 63 | @NotBlank(message = "消息内容不能为空") 64 | @Length(max = 20, message = "输入框内容长度不能超过300字符") 65 | private String content; 66 | 67 | /** 68 | * 消息id:撤回消息、回复消息 69 | */ 70 | private Long msgId; 71 | 72 | /** 73 | * 文件消息 74 | */ 75 | private FileExtraDTO extraInfo; 76 | 77 | /** 78 | * 引用id 79 | */ 80 | private Long quoteId; 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/dto/ChatMsgQueryDTO.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.dto; 2 | 3 | import lombok.Data; 4 | 5 | import javax.validation.constraints.NotBlank; 6 | 7 | 8 | /** 9 | * @Author: 徐志斌 10 | * @CreateTime: 2023-11-17 15:15 11 | * @Description: 聊天消息查询DTO 12 | * @Version: 1.0 13 | */ 14 | @Data 15 | public class ChatMsgQueryDTO { 16 | /** 17 | * 发送方 18 | */ 19 | @NotBlank(message = "发送方账号不能为空") 20 | private String accountId; 21 | 22 | /** 23 | * 接收方 24 | */ 25 | @NotBlank(message = "接收方账号不能为空") 26 | private String receiveId; 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/dto/EmailDTO.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.dto; 2 | 3 | import com.quick.common.enums.EmailEnum; 4 | import lombok.Data; 5 | 6 | import javax.validation.constraints.NotBlank; 7 | import javax.validation.constraints.NotNull; 8 | 9 | 10 | /** 11 | * @Author 徐志斌 12 | * @Date: 2023/11/25 15:05 13 | * @Version 1.0 14 | * @Description: 邮箱DTO 15 | */ 16 | @Data 17 | public class EmailDTO { 18 | /** 19 | * 邮件类型 20 | * 21 | * @see EmailEnum 22 | */ 23 | @NotNull(message = "邮件类型不能为空") 24 | private Integer type; 25 | 26 | /** 27 | * 接收方邮箱 28 | */ 29 | @NotBlank(message = "接收方邮箱不能为空") 30 | private String toEmail; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/dto/FileExtraDTO.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.dto; 2 | 3 | import lombok.Data; 4 | 5 | import javax.validation.constraints.Min; 6 | import javax.validation.constraints.NotBlank; 7 | 8 | 9 | /** 10 | * @Author 徐志斌 11 | * @Date: 2024/3/3 20:00 12 | * @Version 1.0 13 | * @Description: 文件信息 14 | */ 15 | @Data 16 | public class FileExtraDTO { 17 | /** 18 | * 文件名 19 | */ 20 | @NotBlank(message = "文件名不能为空") 21 | private String name; 22 | 23 | /** 24 | * 文件大小:Byte 25 | */ 26 | @Min(value = 0, message = "文件大小不能小于0") 27 | private Long size; 28 | 29 | /** 30 | * 文件类型 31 | */ 32 | @NotBlank(message = "文件类型参数不能为空") 33 | private String type; 34 | 35 | /** 36 | * 语音文件时长 37 | */ 38 | private Long voiceTime; 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/dto/FindBackFormDTO.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.dto; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author 刘东辉 7 | * @Date 2024/7/8 17:32 8 | * @Description: 找回密码DTO 9 | * @Version: 1.0 10 | */ 11 | @Data 12 | public class FindBackFormDTO { 13 | 14 | /** 15 | * 邮件 16 | */ 17 | private String email; 18 | 19 | /** 20 | * 邮箱验证码 21 | */ 22 | private String emailCode; 23 | 24 | /** 25 | * 密码 26 | */ 27 | private String password1; 28 | 29 | /** 30 | * 再次输入密码 31 | */ 32 | private String password2; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/dto/GroupDTO.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.dto; 2 | 3 | import com.quick.common.enums.YesNoEnum; 4 | import lombok.Data; 5 | 6 | /** 7 | * @Author: 徐志斌 8 | * @CreateTime: 2024-05-23 10:49 9 | * @Description: 群聊入参 10 | * @Version: 1.0 11 | */ 12 | @Data 13 | public class GroupDTO { 14 | /** 15 | * 群组id 16 | */ 17 | private Long groupId; 18 | 19 | /** 20 | * 群主账户id 21 | */ 22 | private String accountId; 23 | 24 | /** 25 | * 群名 26 | */ 27 | private String groupName; 28 | 29 | /** 30 | * 群头像 31 | */ 32 | private String groupAvatar; 33 | 34 | /** 35 | * 群员邀请权限(0不可以,1可以) 36 | * 37 | * @see YesNoEnum 38 | */ 39 | private Integer invitePermission; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/dto/LoginFormDTO.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.dto; 2 | 3 | import lombok.Data; 4 | 5 | import javax.validation.constraints.NotBlank; 6 | 7 | 8 | /** 9 | * @Author: 徐志斌 10 | * @CreateTime: 2023-11-17 15:15 11 | * @Description: 登录表单入参 DTO 12 | * @Version: 1.0 13 | */ 14 | @Data 15 | public class LoginFormDTO { 16 | /** 17 | * 账号 18 | */ 19 | @NotBlank(message = "账号不能为空") 20 | private String accountId; 21 | 22 | /** 23 | * 密码 24 | */ 25 | @NotBlank(message = "密码不能为空") 26 | private String passWord; 27 | 28 | /** 29 | * 图片验证码 30 | */ 31 | @NotBlank(message = "图片验证码不能为空") 32 | private String verifyCode; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/dto/RegisterFormDTO.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.dto; 2 | 3 | import com.quick.common.enums.GenderEnum; 4 | import lombok.Data; 5 | import org.hibernate.validator.constraints.Length; 6 | 7 | import javax.validation.constraints.NotBlank; 8 | 9 | 10 | /** 11 | * @Author 徐志斌 12 | * @Date: 2023/11/14 21:12 13 | * @Version 1.0 14 | * @Description: 注册账户表单DTO 15 | */ 16 | @Data 17 | public class RegisterFormDTO { 18 | /** 19 | * 账号 20 | */ 21 | @NotBlank(message = "账号不能为空") 22 | @Length(min = 6, max = 15, message = "账号id长度是6-15位") 23 | private String accountId; 24 | 25 | /** 26 | * 昵称 27 | */ 28 | @NotBlank(message = "昵称不能为空") 29 | @Length(min = 6, max = 15, message = "昵称长度是6-15位") 30 | private String nickName; 31 | 32 | /** 33 | * 性别 34 | * 35 | * @see GenderEnum 36 | */ 37 | @NotBlank(message = "性别信息不能为空") 38 | private Integer gender; 39 | 40 | /** 41 | * 密码 42 | */ 43 | @NotBlank(message = "密码不能为空") 44 | @Length(min = 6, max = 15, message = "密码长度是6-15位") 45 | private String password1; 46 | 47 | /** 48 | * 再次输入密码 49 | */ 50 | @NotBlank(message = "确认密码不能为空") 51 | @Length(min = 6, max = 15, message = "账号id长度是6-15位") 52 | private String password2; 53 | 54 | /** 55 | * 邮件 56 | */ 57 | @NotBlank(message = "邮件信息不能为空") 58 | private String email; 59 | 60 | /** 61 | * 邮箱验证码 62 | */ 63 | @NotBlank(message = "发送方账号不能为空") 64 | private String emailCode; 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/dto/UserInfoDTO.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.dto; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: 徐志斌 7 | * @CreateTime: 2023-11-29 09:08 8 | * @Description: 账户信息DTO 9 | * @Version: 1.0 10 | */ 11 | @Data 12 | public class UserInfoDTO { 13 | /** 14 | * 账号 15 | */ 16 | private String accountId; 17 | 18 | /** 19 | * 昵称 20 | */ 21 | private String nickName; 22 | 23 | /** 24 | * 头像 25 | */ 26 | private String avatar; 27 | 28 | /** 29 | * 性别(0:女,1:男) 30 | */ 31 | private Integer gender; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/entity/WsPushEntity.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.entity; 2 | 3 | import com.quick.common.enums.WsPushEnum; 4 | import lombok.Data; 5 | 6 | /** 7 | * @Author: 徐志斌 8 | * @CreateTime: 2024-03-11 11:37 9 | * @Description: WebSocket推送消息实体 10 | * @Version: 1.0 11 | */ 12 | @Data 13 | public class WsPushEntity { 14 | /** 15 | * 推送消息类型 16 | * 17 | * @see WsPushEnum 18 | */ 19 | private Integer pushType; 20 | 21 | /** 22 | * 消息内容 23 | */ 24 | private T message; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/po/QuickChatApply.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.po; 2 | 3 | import com.baomidou.mybatisplus.annotation.*; 4 | import com.fasterxml.jackson.annotation.JsonFormat; 5 | import com.quick.common.enums.YesNoEnum; 6 | import lombok.Data; 7 | import lombok.EqualsAndHashCode; 8 | 9 | import java.io.Serializable; 10 | import java.time.LocalDateTime; 11 | 12 | /** 13 | *

14 | * 好友/群申请 15 | *

16 | * 17 | * @author 徐志斌 18 | * @since 2024-03-12 19 | */ 20 | @Data 21 | @EqualsAndHashCode(callSuper = false) 22 | @TableName("quick_chat_apply") 23 | public class QuickChatApply implements Serializable { 24 | 25 | private static final long serialVersionUID = 1L; 26 | 27 | /** 28 | * 主键id 29 | */ 30 | @TableId(value = "id", type = IdType.ASSIGN_ID) 31 | private Long id; 32 | 33 | /** 34 | * 发起人 35 | */ 36 | @TableField("from_id") 37 | private String fromId; 38 | 39 | /** 40 | * 接收人 41 | */ 42 | @TableField("to_id") 43 | private String toId; 44 | 45 | /** 46 | * 申请信息 47 | */ 48 | @TableField("apply_info") 49 | private String applyInfo; 50 | 51 | /** 52 | * 类型(1:好友,2:群聊) 53 | */ 54 | @TableField("type") 55 | private Integer type; 56 | 57 | /** 58 | * 群聊id 59 | */ 60 | @TableField(value = "group_id") 61 | private Long groupId; 62 | 63 | /** 64 | * 状态(0:未处理,1:已通过) 65 | * 66 | * @see YesNoEnum 67 | */ 68 | @TableField("status") 69 | private Integer status; 70 | 71 | /** 72 | * 创建时间 73 | */ 74 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 75 | @TableField(value = "create_time", fill = FieldFill.INSERT) 76 | private LocalDateTime createTime; 77 | 78 | /** 79 | * 修改时间 80 | */ 81 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 82 | @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) 83 | private LocalDateTime updateTime; 84 | 85 | /** 86 | * 删除标识 87 | */ 88 | @TableField(value = "deleted", fill = FieldFill.INSERT) 89 | @TableLogic 90 | private Boolean deleted; 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/po/QuickChatArchiveRecord.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.po; 2 | 3 | import com.baomidou.mybatisplus.annotation.*; 4 | import com.fasterxml.jackson.annotation.JsonFormat; 5 | import com.quick.common.enums.YesNoEnum; 6 | import lombok.Data; 7 | import lombok.EqualsAndHashCode; 8 | 9 | import java.io.Serializable; 10 | import java.time.LocalDateTime; 11 | 12 | /** 13 | *

14 | * 用户 15 | *

16 | * 17 | * @author 徐志斌 18 | * @since 2024-11-11 19 | */ 20 | @Data 21 | @EqualsAndHashCode(callSuper = false) 22 | @TableName("quick_chat_archive_record") 23 | public class QuickChatArchiveRecord implements Serializable { 24 | 25 | private static final long serialVersionUID = 1L; 26 | 27 | /** 28 | * 主键 29 | */ 30 | @TableId(value = "id", type = IdType.ASSIGN_ID) 31 | private Long id; 32 | 33 | /** 34 | * 起始主键 35 | */ 36 | @TableField("begin_id") 37 | private Long beginId; 38 | 39 | /** 40 | * 结束主键 41 | */ 42 | @TableField("end_id") 43 | private Long endId; 44 | 45 | /** 46 | * 开始时间 47 | */ 48 | @TableField("start_time") 49 | private LocalDateTime startTime; 50 | 51 | /** 52 | * 结束时间 53 | */ 54 | @TableField("end_time") 55 | private LocalDateTime endTime; 56 | 57 | /** 58 | * 迁移数据总条数 59 | */ 60 | @TableField("count") 61 | private Long count; 62 | 63 | /** 64 | * 状态 65 | * 66 | * @see YesNoEnum 67 | */ 68 | @TableField("status") 69 | private Integer status; 70 | 71 | /** 72 | * 创建时间 73 | */ 74 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 75 | @TableField(value = "create_time", fill = FieldFill.INSERT) 76 | private LocalDateTime createTime; 77 | 78 | /** 79 | * 修改时间 80 | */ 81 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 82 | @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) 83 | private LocalDateTime updateTime; 84 | 85 | /** 86 | * 删除标识 87 | */ 88 | @TableField(value = "deleted", fill = FieldFill.INSERT) 89 | @TableLogic 90 | private Boolean deleted; 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/po/QuickChatContact.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.po; 2 | 3 | import com.baomidou.mybatisplus.annotation.*; 4 | import com.fasterxml.jackson.annotation.JsonFormat; 5 | import com.quick.common.enums.SessionTypeEnum; 6 | import lombok.Data; 7 | import lombok.EqualsAndHashCode; 8 | 9 | import java.io.Serializable; 10 | import java.time.LocalDateTime; 11 | 12 | /** 13 | *

14 | * 通讯录 15 | *

16 | * 17 | * @author 徐志斌 18 | * @since 2023-11-30 19 | */ 20 | @Data 21 | @EqualsAndHashCode(callSuper = false) 22 | @TableName("quick_chat_contact") 23 | public class QuickChatContact implements Serializable { 24 | 25 | private static final long serialVersionUID = 1L; 26 | 27 | /** 28 | * 主键id 29 | */ 30 | @TableId(value = "id", type = IdType.ASSIGN_ID) 31 | private Long id; 32 | 33 | /** 34 | * 账号id 35 | */ 36 | @TableField("from_id") 37 | private String fromId; 38 | 39 | /** 40 | * 账号id 41 | */ 42 | @TableField("to_id") 43 | private String toId; 44 | 45 | /** 46 | * 类型 47 | * 48 | * @see SessionTypeEnum 49 | */ 50 | @TableField("type") 51 | private Integer type; 52 | 53 | /** 54 | * 备注 55 | */ 56 | @TableField("note_name") 57 | private String noteName; 58 | 59 | /** 60 | * 创建时间 61 | */ 62 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 63 | @TableField(value = "create_time", fill = FieldFill.INSERT) 64 | private LocalDateTime createTime; 65 | 66 | /** 67 | * 修改时间 68 | */ 69 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 70 | @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) 71 | private LocalDateTime updateTime; 72 | 73 | /** 74 | * 删除标识 75 | */ 76 | @TableField(value = "deleted", fill = FieldFill.INSERT) 77 | @TableLogic 78 | private Boolean deleted; 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/po/QuickChatEmoji.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.po; 2 | 3 | import com.baomidou.mybatisplus.annotation.*; 4 | import com.fasterxml.jackson.annotation.JsonFormat; 5 | import lombok.Data; 6 | import lombok.EqualsAndHashCode; 7 | 8 | import java.io.Serializable; 9 | import java.time.LocalDateTime; 10 | 11 | /** 12 | *

13 | * 表情包 14 | *

15 | * 16 | * @author 徐志斌 17 | * @since 2023-11-30 18 | */ 19 | @Data 20 | @EqualsAndHashCode(callSuper = false) 21 | @TableName("quick_chat_emoji") 22 | public class QuickChatEmoji implements Serializable { 23 | 24 | private static final long serialVersionUID = 1L; 25 | 26 | /** 27 | * 主键id 28 | */ 29 | @TableId(value = "id", type = IdType.ASSIGN_ID) 30 | private Long id; 31 | 32 | /** 33 | * 账户id 34 | */ 35 | @TableField("account_id") 36 | private String accountId; 37 | 38 | /** 39 | * 图片url 40 | */ 41 | @TableField("url") 42 | private String url; 43 | 44 | /** 45 | * 创建时间 46 | */ 47 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 48 | @TableField(value = "create_time", fill = FieldFill.INSERT) 49 | private LocalDateTime createTime; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/po/QuickChatGroup.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.po; 2 | 3 | import com.baomidou.mybatisplus.annotation.*; 4 | import com.fasterxml.jackson.annotation.JsonFormat; 5 | import com.quick.common.enums.YesNoEnum; 6 | import lombok.Data; 7 | import lombok.EqualsAndHashCode; 8 | 9 | import java.io.Serializable; 10 | import java.time.LocalDateTime; 11 | 12 | /** 13 | *

14 | * 群组信息 15 | *

16 | * 17 | * @author 徐志斌 18 | * @since 2024-01-08 19 | */ 20 | @Data 21 | @EqualsAndHashCode(callSuper = false) 22 | @TableName("quick_chat_group") 23 | public class QuickChatGroup implements Serializable { 24 | 25 | private static final long serialVersionUID = 1L; 26 | 27 | /** 28 | * 群id 29 | */ 30 | @TableId(value = "id", type = IdType.ASSIGN_ID) 31 | private Long id; 32 | 33 | /** 34 | * 群主id 35 | */ 36 | @TableField("account_id") 37 | private String accountId; 38 | 39 | /** 40 | * 群名 41 | */ 42 | @TableField("group_name") 43 | private String groupName; 44 | 45 | /** 46 | * 群头像 47 | */ 48 | @TableField("group_avatar") 49 | private String groupAvatar; 50 | 51 | /** 52 | * 群员邀请权限(0不可以,1可以) 53 | * 54 | * @see YesNoEnum 55 | */ 56 | @TableField("invite_permission") 57 | private Integer invitePermission; 58 | 59 | /** 60 | * 创建时间 61 | */ 62 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 63 | @TableField(value = "create_time", fill = FieldFill.INSERT) 64 | private LocalDateTime createTime; 65 | 66 | /** 67 | * 修改时间 68 | */ 69 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 70 | @TableField(value = "update_time", fill = FieldFill.UPDATE) 71 | private LocalDateTime updateTime; 72 | 73 | /** 74 | * 删除标识 75 | */ 76 | @TableField(value = "deleted", fill = FieldFill.INSERT) 77 | @TableLogic 78 | private Boolean deleted; 79 | 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/po/QuickChatGroupMember.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.po; 2 | 3 | import com.baomidou.mybatisplus.annotation.*; 4 | import com.fasterxml.jackson.annotation.JsonFormat; 5 | import lombok.Data; 6 | import lombok.EqualsAndHashCode; 7 | 8 | import java.io.Serializable; 9 | import java.time.LocalDateTime; 10 | 11 | /** 12 | *

13 | * 群成员 14 | *

15 | * 16 | * @author 徐志斌 17 | * @since 2024-01-08 18 | */ 19 | @Data 20 | @EqualsAndHashCode(callSuper = false) 21 | @TableName("quick_chat_group_member") 22 | public class QuickChatGroupMember implements Serializable { 23 | 24 | private static final long serialVersionUID = 1L; 25 | 26 | /** 27 | * 主键id 28 | */ 29 | @TableId(value = "id", type = IdType.ASSIGN_ID) 30 | private Long id; 31 | 32 | /** 33 | * 群组id 34 | */ 35 | @TableField("group_id") 36 | private Long groupId; 37 | 38 | /** 39 | * 账户id 40 | */ 41 | @TableField("account_id") 42 | private String accountId; 43 | 44 | /** 45 | * 创建时间(入群时间) 46 | */ 47 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 48 | @TableField(value = "create_time", fill = FieldFill.INSERT) 49 | private LocalDateTime createTime; 50 | 51 | /** 52 | * 修改时间 53 | */ 54 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 55 | @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) 56 | private LocalDateTime updateTime; 57 | 58 | /** 59 | * 删除标识 60 | */ 61 | @TableField(value = "deleted", fill = FieldFill.INSERT) 62 | @TableLogic 63 | private Boolean deleted; 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/po/QuickChatMsg.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.po; 2 | 3 | import com.baomidou.mybatisplus.annotation.*; 4 | import com.fasterxml.jackson.annotation.JsonFormat; 5 | import com.quick.common.enums.ChatMsgEnum; 6 | import lombok.Data; 7 | import lombok.EqualsAndHashCode; 8 | 9 | import java.io.Serializable; 10 | import java.time.LocalDateTime; 11 | 12 | /** 13 | *

14 | * 聊天信息 15 | *

16 | * 17 | * @author 徐志斌 18 | * @since 2023-11-25 19 | */ 20 | @Data 21 | @EqualsAndHashCode(callSuper = false) 22 | @TableName("quick_chat_msg") 23 | public class QuickChatMsg implements Serializable { 24 | 25 | private static final long serialVersionUID = 1L; 26 | 27 | /** 28 | * 主键id 29 | */ 30 | @TableId(value = "id", type = IdType.ASSIGN_ID) 31 | private Long id; 32 | 33 | /** 34 | * 账户id(发送人) 35 | */ 36 | @TableField("from_id") 37 | private String fromId; 38 | 39 | /** 40 | * 账户id(接收人) 41 | */ 42 | @TableField("to_id") 43 | private String toId; 44 | 45 | /** 46 | * 关联id 47 | */ 48 | @TableField("relation_id") 49 | private Long relationId; 50 | 51 | /** 52 | * 昵称 53 | */ 54 | @TableField("nick_name") 55 | private String nickName; 56 | 57 | /** 58 | * 消息内容 59 | */ 60 | @TableField("content") 61 | private String content; 62 | 63 | /** 64 | * 引用id 65 | */ 66 | @TableField("quote_id") 67 | private Long quoteId; 68 | 69 | /** 70 | * 消息类型 71 | * 72 | * @see ChatMsgEnum 73 | */ 74 | @TableField("msg_type") 75 | private Integer msgType; 76 | 77 | /** 78 | * 文件信息 79 | */ 80 | @TableField("extra_info") 81 | private String extraInfo; 82 | 83 | /** 84 | * 创建时间 85 | */ 86 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 87 | @TableField(value = "create_time", fill = FieldFill.INSERT) 88 | private LocalDateTime createTime; 89 | 90 | /** 91 | * 修改时间 92 | */ 93 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 94 | @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) 95 | private LocalDateTime updateTime; 96 | 97 | /** 98 | * 删除标识 99 | */ 100 | @TableField(value = "deleted", fill = FieldFill.INSERT) 101 | @TableLogic 102 | private Boolean deleted; 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/vo/ChatMsgVO.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.vo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import com.quick.common.enums.ChatMsgEnum; 5 | import com.quick.common.pojo.dto.FileExtraDTO; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Builder; 8 | import lombok.Data; 9 | import lombok.NoArgsConstructor; 10 | 11 | import java.time.LocalDateTime; 12 | 13 | /** 14 | * @Author 徐志斌 15 | * @Date: 2024/1/13 19:24 16 | * @Version 1.0 17 | * @Description: 聊天信息VO 18 | */ 19 | @Data 20 | @Builder 21 | @AllArgsConstructor 22 | @NoArgsConstructor 23 | public class ChatMsgVO { 24 | /** 25 | * 账户id 26 | */ 27 | private String accountId; 28 | 29 | /** 30 | * 昵称 31 | */ 32 | private String nickName; 33 | 34 | /** 35 | * 内容 36 | */ 37 | private String content; 38 | 39 | /** 40 | * 关联id 41 | */ 42 | private Long relationId; 43 | 44 | /** 45 | * 消息类型 46 | * 47 | * @see ChatMsgEnum 48 | */ 49 | private Integer msgType; 50 | 51 | /** 52 | * 额外信息 53 | */ 54 | private FileExtraDTO extraInfo; 55 | 56 | /** 57 | * 发送时间 58 | */ 59 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 60 | private LocalDateTime createTime; 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/vo/ChatSessionVO.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.vo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import com.quick.common.enums.SessionTypeEnum; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | 10 | import java.time.LocalDateTime; 11 | 12 | /** 13 | * @Author 徐志斌 14 | * @Date: 2023/11/25 12:47 15 | * @Version 1.0 16 | * @Description: 聊天会话VO 17 | */ 18 | @Data 19 | @Builder 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | public class ChatSessionVO { 23 | /** 24 | * 主键id 25 | */ 26 | private Long sessionId; 27 | 28 | /** 29 | * 发送方账号id 30 | */ 31 | private String fromId; 32 | 33 | /** 34 | * 接收方账号id 35 | */ 36 | private String toId; 37 | 38 | /** 39 | * 关联id 40 | */ 41 | private Long relationId; 42 | 43 | /** 44 | * 名称 45 | */ 46 | private String sessionName; 47 | 48 | /** 49 | * 头像 50 | */ 51 | private String avatar; 52 | 53 | /** 54 | * 未读数量 55 | */ 56 | private Long unreadCount; 57 | 58 | /** 59 | * 在线状态(针对用户) 60 | */ 61 | private Integer loginStatus; 62 | 63 | /** 64 | * 性别(针对用户) 65 | */ 66 | private Integer gender; 67 | 68 | /** 69 | * 类型 70 | * 71 | * @see SessionTypeEnum 72 | */ 73 | private Integer type; 74 | 75 | /** 76 | * 最后已读时间 77 | */ 78 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 79 | private LocalDateTime lastReadTime; 80 | 81 | /** 82 | * 修改时间(发送消息) 83 | */ 84 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 85 | private LocalDateTime updateTime; 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/pojo/vo/ChatUserVO.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.pojo.vo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import lombok.Data; 5 | 6 | import java.time.LocalDateTime; 7 | 8 | /** 9 | * @Author 徐志斌 10 | * @Date: 2023/11/13 20:58 11 | * @Version 1.0 12 | * @Description: 用户信息VO 13 | */ 14 | @Data 15 | public class ChatUserVO { 16 | /** 17 | * 账号 18 | */ 19 | private String accountId; 20 | 21 | /** 22 | * 昵称 23 | */ 24 | private String nickName; 25 | 26 | /** 27 | * 性别(1:男,0:女) 28 | */ 29 | private Integer gender; 30 | 31 | /** 32 | * 位置 33 | */ 34 | private String location; 35 | 36 | /** 37 | * 邮箱 38 | */ 39 | private String email; 40 | 41 | /** 42 | * 创建时间 43 | */ 44 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 45 | private LocalDateTime createTime; 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/response/BaseResponse.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.response; 2 | 3 | import com.quick.common.enums.ResponseEnum; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | /** 8 | * @Author 徐志斌 9 | * @Date: 2023/5/8 21:59 10 | * @Version 1.0 11 | * @Description: BaseResponse 12 | */ 13 | @Getter 14 | @Setter 15 | public class BaseResponse { 16 | private Integer code; 17 | private String msg; 18 | 19 | protected BaseResponse(ResponseEnum code) { 20 | this.code = code.getCode(); 21 | this.msg = code.getMsg(); 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/java/com/quick/common/response/R.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.response; 2 | 3 | import com.quick.common.enums.ResponseEnum; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | /** 8 | * @Author 徐志斌 9 | * @Date: 2023/11/13 21:59 10 | * @Version 1.0 11 | * @Description: 响应封装类 12 | */ 13 | @Getter 14 | @Setter 15 | public class R extends BaseResponse { 16 | private T data; 17 | 18 | private R(ResponseEnum respEnum) { 19 | super(respEnum); 20 | } 21 | 22 | private R(ResponseEnum respEnum, T data) { 23 | super(respEnum); 24 | this.data = data; 25 | } 26 | 27 | public static R out(ResponseEnum respEnum) { 28 | return new R<>(respEnum); 29 | } 30 | 31 | public static R out(ResponseEnum respEnum, T data) { 32 | return new R<>(respEnum, data); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/sensitive/MySensitiveWordReplace.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.sensitive; 2 | 3 | import com.github.houbb.heaven.util.lang.CharUtil; 4 | import com.github.houbb.sensitive.word.api.ISensitiveWordReplace; 5 | import com.github.houbb.sensitive.word.api.ISensitiveWordReplaceContext; 6 | 7 | 8 | public class MySensitiveWordReplace implements ISensitiveWordReplace { 9 | @Override 10 | public String replace(ISensitiveWordReplaceContext context) { 11 | String sensitiveWord = context.sensitiveWord(); 12 | // 自定义不同的敏感词替换策略,可以从数据库等地方读取 13 | if ("五星红旗".equals(sensitiveWord)) { 14 | return "国家旗帜"; 15 | } 16 | if ("毛主席".equals(sensitiveWord)) { 17 | return "教员"; 18 | } 19 | // 其他默认使用 * 代替 20 | int wordLength = context.wordLength(); 21 | return CharUtil.repeat('*', wordLength); 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/java/com/quick/common/sensitive/MyWordAllow.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.sensitive; 2 | 3 | import com.github.houbb.sensitive.word.api.IWordAllow; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.core.io.ClassPathResource; 6 | import org.springframework.core.io.Resource; 7 | 8 | import java.io.IOException; 9 | import java.nio.charset.StandardCharsets; 10 | import java.nio.file.Files; 11 | import java.nio.file.Path; 12 | import java.nio.file.Paths; 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * @Author: 徐志斌 18 | * @CreateTime: 2024-03-19 11:40 19 | * @Description: 自定义【非敏感词】 20 | * @Version: 1.0 21 | */ 22 | @Slf4j 23 | public class MyWordAllow implements IWordAllow { 24 | @Override 25 | public List allow() { 26 | List list = new ArrayList<>(); 27 | try { 28 | Resource myAllowWords = new ClassPathResource("/src/main/resources/sensitive/myNotSensitiveWords.txt"); 29 | Path myAllowWordsPath = Paths.get(myAllowWords.getFile().getPath()); 30 | list = Files.readAllLines(myAllowWordsPath, StandardCharsets.UTF_8); 31 | } catch (IOException ioException) { 32 | log.error("读取非敏感词文件错误!" + ioException.getMessage()); 33 | } 34 | return list; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/sensitive/MyWordDeny.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.sensitive; 2 | 3 | import com.github.houbb.sensitive.word.api.IWordDeny; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.core.io.ClassPathResource; 6 | import org.springframework.core.io.Resource; 7 | 8 | import java.io.IOException; 9 | import java.nio.charset.StandardCharsets; 10 | import java.nio.file.Files; 11 | import java.nio.file.Path; 12 | import java.nio.file.Paths; 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * @Author: 徐志斌 18 | * @CreateTime: 2024-03-19 11:40 19 | * @Description: 自定义【敏感词】 20 | * @Version: 1.0 21 | */ 22 | @Slf4j 23 | public class MyWordDeny implements IWordDeny { 24 | @Override 25 | public List deny() { 26 | List list = new ArrayList<>(); 27 | try { 28 | Resource mySensitiveWords = new ClassPathResource("/src/main/resources/sensitive/mySensitiveWords.txt"); 29 | Path mySensitiveWordsPath = Paths.get(mySensitiveWords.getFile().getPath()); 30 | list = Files.readAllLines(mySensitiveWordsPath, StandardCharsets.UTF_8); 31 | } catch (IOException ioException) { 32 | log.error("读取敏感词文件错误!" + ioException.getMessage()); 33 | } 34 | return list; 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/email/AbstractEmailStrategy.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.email; 2 | 3 | import com.quick.common.enums.EmailEnum; 4 | import com.quick.common.pojo.dto.EmailDTO; 5 | import org.springframework.messaging.MessagingException; 6 | import org.springframework.stereotype.Component; 7 | 8 | import javax.annotation.PostConstruct; 9 | import java.io.IOException; 10 | 11 | /** 12 | * @Author: 徐志斌 13 | * @CreateTime: 2023-11-17 16:58 14 | * @Description: 邮件策略抽象类 15 | * @Version: 1.0 16 | */ 17 | @Component 18 | public abstract class AbstractEmailStrategy { 19 | /** 20 | * 策略 Handler 注册到策略工厂 21 | */ 22 | @PostConstruct 23 | private void initStrategyHandler() { 24 | EmailStrategyFactory.register(this.getEnum().getType(), this); 25 | } 26 | 27 | /** 28 | * 获取当前实现类对应 Handler 枚举 29 | */ 30 | protected abstract EmailEnum getEnum(); 31 | 32 | /** 33 | * 发送邮件 34 | */ 35 | public abstract void sendEmail(EmailDTO emailDTO) throws IOException, MessagingException, javax.mail.MessagingException; 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/email/EmailStrategyFactory.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.email; 2 | 3 | import com.quick.common.enums.ResponseEnum; 4 | import com.quick.common.exception.QuickException; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.commons.lang3.ObjectUtils; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * @Author: 徐志斌 13 | * @CreateTime: 2023-11-17 16:59 14 | * @Description: 聊天信息策略工厂 15 | * @Version: 1.0 16 | */ 17 | @Slf4j 18 | public class EmailStrategyFactory { 19 | private static final Map STRATEGY_MAP = new HashMap<>(); 20 | 21 | public static void register(Integer type, AbstractEmailStrategy orderStrategy) { 22 | STRATEGY_MAP.put(type, orderStrategy); 23 | } 24 | 25 | public static AbstractEmailStrategy getStrategyHandler(Integer code) { 26 | AbstractEmailStrategy strategyHandler = STRATEGY_MAP.get(code); 27 | if (ObjectUtils.isEmpty(strategyHandler)) { 28 | throw new QuickException(ResponseEnum.FAIL); 29 | } 30 | return strategyHandler; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/email/handler/FindBackHandler.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.email.handler; 2 | 3 | import com.quick.common.constant.RedisConstant; 4 | import com.quick.common.enums.EmailEnum; 5 | import com.quick.common.pojo.dto.EmailDTO; 6 | import com.quick.common.strategy.email.AbstractEmailStrategy; 7 | import com.quick.common.utils.EmailUtil; 8 | import com.quick.common.utils.RandomUtil; 9 | import com.quick.common.utils.RedisUtil; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Component; 12 | 13 | import javax.mail.MessagingException; 14 | import java.io.IOException; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | /** 18 | * @Author 刘东辉 19 | * @Version 1.0 20 | * @Date 2024/7/9 15:24 21 | * @Description: 找回密码处理器 22 | */ 23 | @Component 24 | public class FindBackHandler extends AbstractEmailStrategy { 25 | @Autowired 26 | private RedisUtil redisUtil; 27 | @Autowired 28 | private EmailUtil emailUtil; 29 | 30 | @Override 31 | protected EmailEnum getEnum() { 32 | return EmailEnum.FIND_BACK; 33 | } 34 | 35 | @Override 36 | public void sendEmail(EmailDTO emailDTO) throws IOException, MessagingException { 37 | // 生成验证码,有效期 3min 38 | String code = RandomUtil.generate(4, 1); 39 | String emailKey = RedisConstant.EMAIL_KEY + emailDTO.getToEmail(); 40 | redisUtil.setCacheObject(emailKey, code, 3, TimeUnit.MINUTES); 41 | 42 | // 读取HTML文本,替换%s 43 | String htmlContent = emailUtil.readHtmlText("/src/main/resources/email/findBack.html"); 44 | htmlContent = String.format(htmlContent, code); 45 | 46 | // 发送HTML邮件 47 | emailUtil.sendHtmlMail(emailDTO.getToEmail(), "找回QuickChat密码", htmlContent); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/email/handler/SendCodeHandler.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.email.handler; 2 | 3 | import com.quick.common.constant.RedisConstant; 4 | import com.quick.common.enums.EmailEnum; 5 | import com.quick.common.pojo.dto.EmailDTO; 6 | import com.quick.common.strategy.email.AbstractEmailStrategy; 7 | import com.quick.common.threadpool.MyThreadPoolExecutor; 8 | import com.quick.common.utils.EmailUtil; 9 | import com.quick.common.utils.RandomUtil; 10 | import com.quick.common.utils.RedisUtil; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.scheduling.annotation.Async; 13 | import org.springframework.stereotype.Component; 14 | 15 | import javax.mail.MessagingException; 16 | import java.io.IOException; 17 | import java.util.concurrent.TimeUnit; 18 | 19 | /** 20 | * @Author 徐志斌 21 | * @Date: 2023/12/31 13:48 22 | * @Version 1.0 23 | * @Description: 发送验证码 24 | */ 25 | @Component 26 | public class SendCodeHandler extends AbstractEmailStrategy { 27 | @Autowired 28 | private RedisUtil redisUtil; 29 | @Autowired 30 | private EmailUtil emailUtil; 31 | 32 | @Override 33 | protected EmailEnum getEnum() { 34 | return EmailEnum.VERIFY_CODE; 35 | } 36 | 37 | @Override 38 | @Async(MyThreadPoolExecutor.EMAIL_POOL_NAME) 39 | public void sendEmail(EmailDTO emailDTO) throws MessagingException, IOException { 40 | // 生成验证码,有效期 3min 41 | String code = RandomUtil.generate(4, 1); 42 | String emailKey = RedisConstant.EMAIL_KEY + emailDTO.getToEmail(); 43 | redisUtil.setCacheObject(emailKey, code, 3, TimeUnit.MINUTES); 44 | 45 | // 读取HTML文本,替换%s 46 | String htmlContent = emailUtil.readHtmlText("/src/main/resources/email/sendCode.html"); 47 | htmlContent = String.format(htmlContent, code); 48 | 49 | // 发送HTML邮件 50 | emailUtil.sendHtmlMail(emailDTO.getToEmail(), "注册QuickChat账号", htmlContent); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/email/handler/WarnUserHandler.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.email.handler; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | /** 6 | * @Author 徐志斌 7 | * @Date: 2024/4/4 14:40 8 | * @Version 1.0 9 | * @Description: 提示用户 10 | */ 11 | @Component 12 | public class WarnUserHandler { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/file/AbstractFileStrategy.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.file; 2 | 3 | import com.quick.common.enums.BucketEnum; 4 | import org.springframework.stereotype.Component; 5 | import org.springframework.web.multipart.MultipartFile; 6 | 7 | import javax.annotation.PostConstruct; 8 | import java.util.Map; 9 | 10 | /** 11 | * @Author: 徐志斌 12 | * @CreateTime: 2024-04-04 13:58 13 | * @Description: 上传文件策略抽象类 14 | * @Version: 1.0 15 | */ 16 | @Component 17 | public abstract class AbstractFileStrategy { 18 | @PostConstruct 19 | private void initStrategyHandler() { 20 | FileStrategyFactory.register(this.getEnum().getCode(), this); 21 | } 22 | 23 | /** 24 | * 获取当前策略枚举 25 | * 26 | * @return Bucket桶枚举 27 | */ 28 | protected abstract BucketEnum getEnum(); 29 | 30 | /** 31 | * 上传文件 32 | * 33 | * @param file 文件对象 34 | * @return 文件信息 35 | */ 36 | public abstract Map uploadFile(MultipartFile file) throws Exception; 37 | 38 | /** 39 | * 下载文件 40 | * 41 | * @param url 文件url 42 | */ 43 | public abstract void downloadFile(String url); 44 | 45 | 46 | /** 47 | * 删除文件 48 | * 49 | * @param url 文件url 50 | */ 51 | public abstract void deleteFile(String url) throws Exception; 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/file/FileStrategyFactory.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.file; 2 | 3 | import com.quick.common.enums.ResponseEnum; 4 | import com.quick.common.exception.QuickException; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.commons.lang3.ObjectUtils; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * @Author: 徐志斌 13 | * @CreateTime: 2023-11-17 16:59 14 | * @Description: 聊天信息策略工厂 15 | * @Version: 1.0 16 | */ 17 | @Slf4j 18 | public class FileStrategyFactory { 19 | private static final Map STRATEGY_MAP = new HashMap<>(); 20 | 21 | public static void register(Integer type, AbstractFileStrategy orderStrategy) { 22 | STRATEGY_MAP.put(type, orderStrategy); 23 | } 24 | 25 | public static AbstractFileStrategy getStrategyHandler(Integer code) { 26 | AbstractFileStrategy strategyHandler = STRATEGY_MAP.get(code); 27 | if (ObjectUtils.isEmpty(strategyHandler)) { 28 | throw new QuickException(ResponseEnum.FAIL); 29 | } 30 | return strategyHandler; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/file/handler/AvatarHandler.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.file.handler; 2 | 3 | import com.quick.common.adapter.FileExtraAdapter; 4 | import com.quick.common.enums.BucketEnum; 5 | import com.quick.common.enums.ResponseEnum; 6 | import com.quick.common.exception.QuickException; 7 | import com.quick.common.pojo.dto.FileExtraDTO; 8 | import com.quick.common.strategy.file.AbstractFileStrategy; 9 | import com.quick.common.utils.MinioUtil; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.stereotype.Component; 13 | import org.springframework.web.multipart.MultipartFile; 14 | 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | /** 19 | * @Author 徐志斌 20 | * @Date: 2024/4/4 14:10 21 | * @Version 1.0 22 | * @Description: 头像上传 23 | */ 24 | @Component 25 | public class AvatarHandler extends AbstractFileStrategy { 26 | @Autowired 27 | private MinioUtil minioUtil; 28 | @Value("${quick-chat.size.avatar}") 29 | private Integer avatarSize; 30 | 31 | @Override 32 | protected BucketEnum getEnum() { 33 | return BucketEnum.AVATAR; 34 | } 35 | 36 | @Override 37 | public Map uploadFile(MultipartFile file) throws Exception { 38 | // 文件大小校验 39 | long fileSize = file.getSize() / 1024 / 1024; 40 | if (fileSize > avatarSize) { 41 | ResponseEnum responseEnum = ResponseEnum.FILE_OVER_SIZE; 42 | responseEnum.setMsg(String.format(responseEnum.getMsg(), avatarSize + "MB")); 43 | throw new QuickException(responseEnum); 44 | } 45 | 46 | // 上传文件至 Minio 47 | String url = minioUtil.upload(file, this.getEnum().getBucketName()); 48 | 49 | // 封装结果 50 | FileExtraDTO extraDTO = FileExtraAdapter.buildFileExtraPO(file.getOriginalFilename(), file.getSize()); 51 | Map resultMap = new HashMap<>(); 52 | resultMap.put("url", url); 53 | resultMap.put("extraInfo", extraDTO); 54 | return resultMap; 55 | } 56 | 57 | @Override 58 | public void downloadFile(String url) { 59 | minioUtil.download(this.getEnum().getBucketName(), url); 60 | } 61 | 62 | @Override 63 | public void deleteFile(String url) throws Exception { 64 | minioUtil.delete(this.getEnum().getBucketName(), url); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/file/handler/FileHandler.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.file.handler; 2 | 3 | import com.quick.common.adapter.FileExtraAdapter; 4 | import com.quick.common.enums.BucketEnum; 5 | import com.quick.common.enums.ResponseEnum; 6 | import com.quick.common.exception.QuickException; 7 | import com.quick.common.pojo.dto.FileExtraDTO; 8 | import com.quick.common.strategy.file.AbstractFileStrategy; 9 | import com.quick.common.utils.MinioUtil; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.stereotype.Component; 13 | import org.springframework.web.multipart.MultipartFile; 14 | 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | /** 19 | * @Author 徐志斌 20 | * @Date: 2024/4/4 14:10 21 | * @Version 1.0 22 | * @Description: 文件上传 23 | */ 24 | @Component 25 | public class FileHandler extends AbstractFileStrategy { 26 | @Autowired 27 | private MinioUtil minioUtil; 28 | @Value("${quick-chat.size.file}") 29 | private Integer fileSize; 30 | 31 | @Override 32 | protected BucketEnum getEnum() { 33 | return BucketEnum.FILE; 34 | } 35 | 36 | @Override 37 | public Map uploadFile(MultipartFile file) throws Exception { 38 | // 文件大小校验 39 | long size = file.getSize() / 1024 / 1024; 40 | if (size > fileSize) { 41 | ResponseEnum responseEnum = ResponseEnum.FILE_OVER_SIZE; 42 | responseEnum.setMsg(String.format(responseEnum.getMsg(), fileSize + "MB")); 43 | throw new QuickException(responseEnum); 44 | } 45 | 46 | // 上传文件至 Minio 47 | String url = minioUtil.upload(file, this.getEnum().getBucketName()); 48 | 49 | // 封装结果集 50 | FileExtraDTO extraDTO = FileExtraAdapter.buildFileExtraPO(file.getOriginalFilename(), file.getSize()); 51 | Map resultMap = new HashMap<>(); 52 | resultMap.put("url", url); 53 | resultMap.put("extraInfo", extraDTO); 54 | return resultMap; 55 | } 56 | 57 | @Override 58 | public void downloadFile(String url) { 59 | minioUtil.download(this.getEnum().getBucketName(), url); 60 | } 61 | 62 | @Override 63 | public void deleteFile(String url) throws Exception { 64 | minioUtil.delete(this.getEnum().getBucketName(), url); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/msg/AbstractChatMsgStrategy.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.msg; 2 | 3 | import com.quick.common.enums.ChatMsgEnum; 4 | import com.quick.common.pojo.dto.ChatMsgDTO; 5 | import com.quick.common.pojo.po.QuickChatMsg; 6 | import org.springframework.stereotype.Component; 7 | 8 | import javax.annotation.PostConstruct; 9 | 10 | 11 | /** 12 | * @Author: 徐志斌 13 | * @CreateTime: 2023-11-17 16:58 14 | * @Description: 聊天信息策略抽象类 15 | * @Version: 1.0 16 | */ 17 | @Component 18 | public abstract class AbstractChatMsgStrategy { 19 | @PostConstruct 20 | private void initStrategyHandler() { 21 | ChatMsgStrategyFactory.register(this.getEnum().getCode(), this); 22 | } 23 | 24 | /** 25 | * 获取当前策略对应聊天消息枚举 26 | * 27 | * @return 聊天消息枚举 28 | */ 29 | protected abstract ChatMsgEnum getEnum(); 30 | 31 | /** 32 | * 发送聊天消息 33 | * 34 | * @param msgDTO 消息参数 35 | * @return 消息实体PO 36 | * @throws Throwable 顶级异常 37 | */ 38 | public abstract QuickChatMsg sendMsg(ChatMsgDTO msgDTO) throws Throwable; 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/msg/ChatMsgStrategyFactory.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.msg; 2 | 3 | import com.quick.common.enums.ResponseEnum; 4 | import com.quick.common.exception.QuickException; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.commons.lang3.ObjectUtils; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * @Author: 徐志斌 13 | * @CreateTime: 2023-11-17 16:59 14 | * @Description: 聊天信息策略工厂 15 | * @Version: 1.0 16 | */ 17 | @Slf4j 18 | public class ChatMsgStrategyFactory { 19 | private static final Map STRATEGY_MAP = new HashMap<>(); 20 | 21 | public static void register(Integer type, AbstractChatMsgStrategy orderStrategy) { 22 | STRATEGY_MAP.put(type, orderStrategy); 23 | } 24 | 25 | public static AbstractChatMsgStrategy getStrategyHandler(Integer code) { 26 | AbstractChatMsgStrategy strategyHandler = STRATEGY_MAP.get(code); 27 | if (ObjectUtils.isEmpty(strategyHandler)) { 28 | throw new QuickException(ResponseEnum.FAIL); 29 | } 30 | return strategyHandler; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/msg/handler/AtMsgHandler.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.msg.handler; 2 | 3 | import com.quick.common.enums.ChatMsgEnum; 4 | import com.quick.common.pojo.dto.ChatMsgDTO; 5 | import com.quick.common.pojo.po.QuickChatMsg; 6 | import com.quick.api.store.QuickChatMsgStore; 7 | import com.quick.common.strategy.msg.AbstractChatMsgStrategy; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * @Author: 刘东辉 13 | * @CreateTime: 14 | * @Description: 艾特消息 15 | * @Version: 1.0 16 | */ 17 | @Component 18 | public class AtMsgHandler extends AbstractChatMsgStrategy { 19 | @Autowired 20 | private QuickChatMsgStore msgStore; 21 | 22 | @Override 23 | protected ChatMsgEnum getEnum() { 24 | return ChatMsgEnum.AT; 25 | } 26 | 27 | @Override 28 | public QuickChatMsg sendMsg(ChatMsgDTO msgDTO) throws Throwable { 29 | return null; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/msg/handler/EmojiHandler.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.msg.handler; 2 | 3 | import com.quick.common.enums.ChatMsgEnum; 4 | import com.quick.common.pojo.dto.ChatMsgDTO; 5 | import com.quick.common.pojo.po.QuickChatMsg; 6 | import com.quick.common.strategy.msg.AbstractChatMsgStrategy; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * @Author: 徐志斌 11 | * @CreateTime: 2023-11-17 17:06 12 | * @Description: 表情包消息 13 | * @Version: 1.0 14 | */ 15 | @Component 16 | public class EmojiHandler extends AbstractChatMsgStrategy { 17 | @Override 18 | protected ChatMsgEnum getEnum() { 19 | return ChatMsgEnum.EMOJI; 20 | } 21 | 22 | @Override 23 | public QuickChatMsg sendMsg(ChatMsgDTO msgDTO) { 24 | return null; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/msg/handler/FontMsgHandler.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.msg.handler; 2 | 3 | import com.baomidou.mybatisplus.core.toolkit.StringUtils; 4 | import com.quick.common.adapter.MsgAdapter; 5 | import com.quick.common.enums.ChatMsgEnum; 6 | import com.quick.common.enums.ResponseEnum; 7 | import com.quick.common.exception.QuickException; 8 | import com.quick.common.pojo.dto.ChatMsgDTO; 9 | import com.quick.common.pojo.po.QuickChatMsg; 10 | import com.quick.api.store.QuickChatMsgStore; 11 | import com.quick.common.strategy.msg.AbstractChatMsgStrategy; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.stereotype.Component; 14 | 15 | /** 16 | * @Author: 徐志斌 17 | * @CreateTime: 2023-11-17 17:02 18 | * @Description: 文字消息 19 | * @Version: 1.0 20 | */ 21 | @Component 22 | public class FontMsgHandler extends AbstractChatMsgStrategy { 23 | @Autowired 24 | private QuickChatMsgStore msgStore; 25 | 26 | @Override 27 | protected ChatMsgEnum getEnum() { 28 | return ChatMsgEnum.FONT; 29 | } 30 | 31 | @Override 32 | public QuickChatMsg sendMsg(ChatMsgDTO msgDTO) throws Throwable { 33 | String fromId = msgDTO.getFromId(); 34 | String toId = msgDTO.getToId(); 35 | String nickName = msgDTO.getNickName(); 36 | String content = msgDTO.getContent(); 37 | Long relationId = msgDTO.getRelationId(); 38 | Long quoteId = msgDTO.getQuoteId(); 39 | 40 | if (StringUtils.isBlank(content)) { 41 | throw new QuickException(ResponseEnum.FONT_MSG_NOT_EXIST); 42 | } 43 | 44 | QuickChatMsg chatMsg = MsgAdapter.buildChatMsgPO(fromId, toId, relationId, 45 | nickName, content, quoteId, null, this.getEnum().getCode()); 46 | msgStore.saveMsg(chatMsg); 47 | return chatMsg; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/msg/handler/ReplyMsgHandler.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.msg.handler; 2 | 3 | import com.quick.common.enums.ChatMsgEnum; 4 | import com.quick.common.pojo.dto.ChatMsgDTO; 5 | import com.quick.common.pojo.po.QuickChatMsg; 6 | import com.quick.api.store.QuickChatMsgStore; 7 | import com.quick.common.strategy.msg.AbstractChatMsgStrategy; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * @Author: 刘东辉 13 | * @CreateTime: 14 | * @Description: 引用、回复消息 15 | * @Version: 1.0 16 | */ 17 | @Component 18 | public class ReplyMsgHandler extends AbstractChatMsgStrategy { 19 | @Autowired 20 | private QuickChatMsgStore msgStore; 21 | 22 | @Override 23 | protected ChatMsgEnum getEnum() { 24 | return ChatMsgEnum.AT; 25 | } 26 | 27 | @Override 28 | public QuickChatMsg sendMsg(ChatMsgDTO msgDTO) throws Throwable { 29 | return null; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/msg/handler/VideoCallHandler.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.msg.handler; 2 | 3 | import com.quick.common.enums.ChatMsgEnum; 4 | import com.quick.common.pojo.dto.ChatMsgDTO; 5 | import com.quick.common.pojo.po.QuickChatMsg; 6 | import com.quick.common.strategy.msg.AbstractChatMsgStrategy; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * @Author: 徐志斌 11 | * @CreateTime: 2023-11-17 17:08 12 | * @Description: 视频通话消息 13 | * @Version: 1.0 14 | */ 15 | @Component 16 | public class VideoCallHandler extends AbstractChatMsgStrategy { 17 | 18 | @Override 19 | protected ChatMsgEnum getEnum() { 20 | return ChatMsgEnum.VIDEO_CALL; 21 | } 22 | 23 | // TODO 视频电话 24 | @Override 25 | public QuickChatMsg sendMsg(ChatMsgDTO msgDTO) { 26 | return null; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/strategy/msg/handler/VoiceCallHandler.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.strategy.msg.handler; 2 | 3 | import com.quick.common.enums.ChatMsgEnum; 4 | import com.quick.common.pojo.dto.ChatMsgDTO; 5 | import com.quick.common.pojo.po.QuickChatMsg; 6 | import com.quick.common.strategy.msg.AbstractChatMsgStrategy; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * @Author: 徐志斌 11 | * @CreateTime: 2023-11-17 17:07 12 | * @Description: 语音通话消息 13 | * @Version: 1.0 14 | */ 15 | @Component 16 | public class VoiceCallHandler extends AbstractChatMsgStrategy { 17 | @Override 18 | protected ChatMsgEnum getEnum() { 19 | return ChatMsgEnum.VOICE_CALL; 20 | } 21 | 22 | // TODO 语音电话 23 | @Override 24 | public QuickChatMsg sendMsg(ChatMsgDTO msgDTO) { 25 | return null; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/threadpool/MyThreadFactory.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.threadpool; 2 | 3 | import lombok.AllArgsConstructor; 4 | 5 | import java.util.concurrent.ThreadFactory; 6 | 7 | /** 8 | * @Author: 徐志斌 9 | * @CreateTime: 2023-08-29 16:38 10 | * @Description: 自定义线程工厂 11 | * @Version: 1.0 12 | */ 13 | @AllArgsConstructor 14 | public class MyThreadFactory implements ThreadFactory { 15 | private final ThreadFactory factory; 16 | 17 | @Override 18 | public Thread newThread(Runnable r) { 19 | Thread thread = factory.newThread(r); 20 | thread.setUncaughtExceptionHandler(MyUncaughtExceptionHandler.getInstance()); 21 | return thread; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/threadpool/MyThreadPoolExecutor.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.threadpool; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.Primary; 7 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 8 | 9 | import java.util.concurrent.ThreadPoolExecutor; 10 | 11 | /** 12 | * @Author: 徐志斌 13 | * @CreateTime: 2023-08-29 13:43 14 | * @Description: 自定义线程池 15 | * @Version: 1.0 16 | */ 17 | @Slf4j 18 | @Configuration 19 | public class MyThreadPoolExecutor { 20 | public static final String CHAT_POOL_NAME = "CHAT_THREAD_POOL"; 21 | public static final String EMAIL_POOL_NAME = "EMAIL_POOL_NAME"; 22 | 23 | /** 24 | * 聊天专用 25 | */ 26 | @Primary 27 | @Bean(CHAT_POOL_NAME) 28 | public ThreadPoolTaskExecutor chatExecutor() { 29 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 30 | executor.setCorePoolSize(4); 31 | executor.setMaxPoolSize(8); 32 | executor.setQueueCapacity(100); 33 | executor.setKeepAliveSeconds(60); 34 | executor.setThreadNamePrefix("chat-pool-thread-"); 35 | executor.setWaitForTasksToCompleteOnShutdown(true); 36 | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 37 | executor.setThreadFactory(new MyThreadFactory(executor)); 38 | executor.initialize(); 39 | return executor; 40 | } 41 | 42 | /** 43 | * 邮件专用 44 | */ 45 | @Bean(EMAIL_POOL_NAME) 46 | public ThreadPoolTaskExecutor emailExecutor() { 47 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 48 | executor.setCorePoolSize(2); 49 | executor.setMaxPoolSize(4); 50 | executor.setQueueCapacity(20); 51 | executor.setKeepAliveSeconds(60); 52 | executor.setThreadNamePrefix("email-pool-thread-"); 53 | executor.setWaitForTasksToCompleteOnShutdown(true); 54 | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 55 | executor.setThreadFactory(new MyThreadFactory(executor)); 56 | executor.initialize(); 57 | return executor; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/threadpool/MyUncaughtExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.threadpool; 2 | 3 | 4 | import lombok.extern.slf4j.Slf4j; 5 | 6 | /** 7 | * @Author: 徐志斌 8 | * @CreateTime: 2023-08-29 15:01 9 | * @Description: 线程池未捕获异常处理器 10 | * @Version: 1.0 11 | */ 12 | @Slf4j 13 | public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { 14 | private static final MyUncaughtExceptionHandler instance = new MyUncaughtExceptionHandler(); 15 | 16 | public static MyUncaughtExceptionHandler getInstance() { 17 | return instance; 18 | } 19 | 20 | @Override 21 | public void uncaughtException(Thread t, Throwable e) { 22 | log.error("==============thread pool:[{}],error:[{}]==============", t.getName(), e); 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/java/com/quick/common/utils/AESUtil.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.utils; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.apache.tomcat.util.codec.binary.Base64; 5 | 6 | import javax.crypto.Cipher; 7 | import javax.crypto.spec.SecretKeySpec; 8 | import java.nio.charset.StandardCharsets; 9 | 10 | /** 11 | * @Author: 徐志斌 12 | * @CreateTime: 2023-03-24 17:46 13 | * @Description: AES加密工具类 14 | * @Version: 1.0 15 | */ 16 | @Slf4j 17 | public class AESUtil { 18 | // 加密 Key 长度确保 16 位 19 | private static final String KEY = "QuickChat_XZB!!!"; 20 | 21 | public static String encrypt(String content) throws Exception { 22 | byte[] raw = KEY.getBytes(StandardCharsets.UTF_8); 23 | SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); 24 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 25 | cipher.init(Cipher.ENCRYPT_MODE, skeySpec); 26 | byte[] encrypted = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8)); 27 | return new Base64().encodeAsString(encrypted); 28 | } 29 | 30 | public static String decrypt(String content) throws Exception { 31 | byte[] raw = KEY.getBytes(StandardCharsets.UTF_8); 32 | SecretKeySpec keySpec = new SecretKeySpec(raw, "AES"); 33 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 34 | cipher.init(Cipher.DECRYPT_MODE, keySpec); 35 | byte[] encrypted1 = new Base64().decode(content); 36 | byte[] original = cipher.doFinal(encrypted1); 37 | return new String(original, StandardCharsets.UTF_8); 38 | } 39 | 40 | public static void main(String[] args) throws Exception { 41 | String encryptPwd = encrypt("xuzhibin"); 42 | System.out.println(encryptPwd); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/utils/AddressUtil.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.utils; 2 | 3 | import org.apache.commons.io.FileUtils; 4 | import org.lionsoul.ip2region.xdb.Searcher; 5 | 6 | import java.io.File; 7 | import java.io.InputStream; 8 | import java.text.MessageFormat; 9 | import java.util.Objects; 10 | 11 | /** 12 | * @Author: 徐志斌 13 | * @CreateTime: 2024-01-04 09:59 14 | * @Description: ip2region 地址解析工具类 15 | * @Version: 1.0 16 | */ 17 | public class AddressUtil { 18 | private static final String TEMP_FILE_DIR = "/home/admin/app/"; 19 | 20 | /** 21 | * 根据IP地址查询登录来源 22 | */ 23 | public static String getCityInfo(String ip) { 24 | try { 25 | String dbPath = Objects.requireNonNull(AddressUtil.class.getResource("/src/main/resources/ip2region/ip2region.xdb")).getPath(); 26 | File file = new File(dbPath); 27 | //如果当前文件不存在,则从缓存中复制一份 28 | if (!file.exists()) { 29 | dbPath = TEMP_FILE_DIR + "ip.db"; 30 | System.out.println(MessageFormat.format("当前目录为:[{0}]", dbPath)); 31 | file = new File(dbPath); 32 | InputStream inputStream = AddressUtil.class.getClassLoader().getResourceAsStream("classpath:ip2region/ip2region.xdb"); 33 | FileUtils.copyInputStreamToFile(Objects.requireNonNull(inputStream), file); 34 | } 35 | Searcher searcher = Searcher.newWithFileOnly(dbPath); 36 | return searcher.searchByStr(ip); 37 | } catch (Exception e) { 38 | e.printStackTrace(); 39 | } 40 | return ""; 41 | } 42 | 43 | public static void main(String[] args) { 44 | System.out.println(getCityInfo("1.2.3.4")); 45 | System.out.println(getCityInfo("101.42.13.186")); 46 | System.out.println(getCityInfo("127.0.0.1")); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/utils/HttpServletUtil.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.utils; 2 | 3 | 4 | import org.springframework.web.context.request.RequestContextHolder; 5 | import org.springframework.web.context.request.ServletRequestAttributes; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | 10 | /** 11 | * @Author: 徐志斌 12 | * @CreateTime: 2023-03-24 17:46 13 | * @Description: HttpServlet 工具类 14 | * @Version: 1.0 15 | */ 16 | public class HttpServletUtil { 17 | private static ServletRequestAttributes getRequestAttributes() { 18 | return (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 19 | } 20 | 21 | public static HttpServletRequest getRequest() { 22 | return getRequestAttributes().getRequest(); 23 | } 24 | 25 | public static HttpServletResponse getResponse() { 26 | return getRequestAttributes().getResponse(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/utils/IpUtil.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.utils; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | 7 | 8 | /** 9 | * @Author: 徐志斌 10 | * @CreateTime: 2024-01-04 09:23 11 | * @Description: IP 地址解析工具类 12 | * @Version: 1.0 13 | */ 14 | @Slf4j 15 | public class IpUtil { 16 | public static String getIpAddr(HttpServletRequest request) { 17 | String ip = request.getHeader("Ali-CDN-Real-IP"); 18 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 19 | ip = request.getHeader("X-real-ip"); 20 | } 21 | if (ip == null || "".equals(ip) || "null".equals(ip)) { 22 | ip = request.getHeader("X-Forwarded-For"); 23 | } 24 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 25 | ip = request.getHeader("Proxy-Client-IP"); 26 | } 27 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 28 | ip = request.getHeader("WL-Proxy-Client-IP"); 29 | } 30 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 31 | ip = request.getHeader("HTTP_CLIENT_IP"); 32 | } 33 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 34 | ip = request.getHeader("HTTP_X_FORWARDED_FOR"); 35 | } 36 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 37 | ip = request.getRemoteAddr(); 38 | } 39 | return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip; 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/java/com/quick/common/utils/JwtUtil.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.utils; 2 | 3 | import io.jsonwebtoken.Claims; 4 | import io.jsonwebtoken.Jws; 5 | import io.jsonwebtoken.Jwts; 6 | import io.jsonwebtoken.SignatureAlgorithm; 7 | import org.springframework.util.StringUtils; 8 | 9 | import java.util.Date; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | /** 14 | * @Author 徐志斌 15 | * @Date: 2023/11/13 21:46 16 | * @Version 1.0 17 | * @Description: JWT工具类 18 | */ 19 | public class JwtUtil { 20 | public static final long EXPIRE = 86400000; 21 | public static final String JWT_SECRET = "Quick_Chat_XZB1998"; 22 | 23 | public static String generate(String accountId) { 24 | String JwtToken = Jwts.builder() 25 | .setHeaderParam("typ", "JWT") 26 | .setHeaderParam("alg", "HS256") 27 | .setSubject("QuickChat") 28 | .setIssuedAt(new Date()) 29 | .setExpiration(new Date(System.currentTimeMillis() + EXPIRE)) 30 | .claim(RequestContextUtil.ACCOUNT_ID, accountId) 31 | .signWith(SignatureAlgorithm.HS256, JWT_SECRET) 32 | .compact(); 33 | return JwtToken; 34 | } 35 | 36 | public static Map resolve(String token) { 37 | Jws claimsJws = Jwts.parser().setSigningKey(JWT_SECRET).parseClaimsJws(token); 38 | Claims claims = claimsJws.getBody(); 39 | String accountId = (String) claims.get(RequestContextUtil.ACCOUNT_ID); 40 | Map resultMap = new HashMap<>(); 41 | resultMap.put(RequestContextUtil.ACCOUNT_ID, accountId); 42 | return resultMap; 43 | } 44 | 45 | public static boolean check(String jwtToken) { 46 | if (StringUtils.isEmpty(jwtToken)) { 47 | return false; 48 | } 49 | try { 50 | Jwts.parser().setSigningKey(JWT_SECRET).parseClaimsJws(jwtToken); 51 | } catch (Exception e) { 52 | e.printStackTrace(); 53 | return false; 54 | } 55 | return true; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/utils/RandomUtil.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.utils; 2 | 3 | import java.util.Random; 4 | 5 | /** 6 | * @Author 徐志斌 7 | * @Date: 2023/11/25 15:02 8 | * @Version 1.0 9 | * @Description: 随机生成工具类 10 | */ 11 | public class RandomUtil { 12 | private static final String NUMBERS = "0123456789"; 13 | private static final String LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 14 | private static final String NUMBERS_AND_LETTERS = NUMBERS + LETTERS; 15 | 16 | /** 17 | * 生成随机内容 18 | * 19 | * @param length 内容长度 20 | * @param type 内容类型(1:数字,2:字母,3:数字 + 字母) 21 | * @return 生成内容 22 | */ 23 | public static String generate(int length, int type) { 24 | StringBuilder sb = new StringBuilder(); 25 | Random random = new Random(); 26 | String charSet = ""; 27 | switch (type) { 28 | case 1: 29 | charSet = NUMBERS; 30 | break; 31 | case 2: 32 | charSet = LETTERS; 33 | break; 34 | case 3: 35 | charSet = NUMBERS_AND_LETTERS; 36 | break; 37 | default: 38 | return "Invalid type"; 39 | } 40 | for (int i = 0; i < length; i++) { 41 | sb.append(charSet.charAt(random.nextInt(charSet.length()))); 42 | } 43 | return sb.toString(); 44 | } 45 | 46 | public static void main(String[] args) { 47 | System.out.println("Random Numbers: " + generate(5, 1)); 48 | System.out.println("Random Letters: " + generate(5, 2)); 49 | System.out.println("Random Numbers and Letters: " + generate(5, 3)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/utils/RedissonLockUtil.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.utils; 2 | 3 | import com.quick.common.enums.ResponseEnum; 4 | import com.quick.common.exception.QuickException; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.redisson.api.RLock; 7 | import org.redisson.api.RedissonClient; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.concurrent.TimeUnit; 12 | 13 | /** 14 | * @Author 徐志斌 15 | * @Date: 2023/11/9 22:15 16 | * @Version 1.0 17 | * @Description: Redisson 分布式锁工具类 18 | */ 19 | @Slf4j 20 | @Component 21 | public class RedissonLockUtil { 22 | @Autowired 23 | private RedissonClient redissonClient; 24 | 25 | public T executeWithLock(String key, int waitTime, TimeUnit unit, SupplierThrow supplier) throws Throwable { 26 | RLock lock = redissonClient.getLock(key); 27 | boolean lockSuccess = lock.tryLock(waitTime, unit); 28 | if (!lockSuccess) { 29 | throw new QuickException(ResponseEnum.FAIL); 30 | } 31 | try { 32 | return supplier.get(); 33 | } finally { 34 | if (lock.isLocked() && lock.isHeldByCurrentThread()) { 35 | lock.unlock(); 36 | } 37 | } 38 | } 39 | 40 | @FunctionalInterface 41 | public interface SupplierThrow { 42 | T get() throws Throwable; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/utils/RequestContextUtil.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.utils; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * @Author: 徐志斌 7 | * @CreateTime: 2023-08-29 14:53 8 | * @Description: 请求全局上下文 9 | * @Version: 1.0 10 | */ 11 | public class RequestContextUtil { 12 | public static final String ACCOUNT_ID = "account_id"; 13 | private static final ThreadLocal> threadLocal = new ThreadLocal<>(); 14 | 15 | public static void setData(Map map) { 16 | threadLocal.set(map); 17 | } 18 | 19 | public static Object getData(String key) { 20 | return threadLocal.get().get(key); 21 | } 22 | 23 | public static void removeData() { 24 | threadLocal.remove(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/quick/common/utils/SensitiveWordUtil.java: -------------------------------------------------------------------------------- 1 | package com.quick.common.utils; 2 | 3 | import com.github.houbb.sensitive.word.bs.SensitiveWordBs; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @Author: 徐志斌 11 | * @CreateTime: 2024-03-19 11:40 12 | * @Description: 敏感词过滤工具类 13 | * @Version: 1.0 14 | */ 15 | @Component 16 | public class SensitiveWordUtil { 17 | @Autowired 18 | private SensitiveWordBs sensitiveWordBs; 19 | 20 | /** 21 | * 刷新敏感词库与非敏感词库缓存 22 | */ 23 | public void refresh() { 24 | sensitiveWordBs.init(); 25 | } 26 | 27 | /** 28 | * 判断是否含有敏感词 29 | */ 30 | public boolean check(String text) { 31 | return sensitiveWordBs.contains(text); 32 | } 33 | 34 | /** 35 | * 指定替换符进行替换敏感词 36 | */ 37 | public String replace(String text, char replaceChar) { 38 | return sensitiveWordBs.replace(text, replaceChar); 39 | } 40 | 41 | /** 42 | * 使用默认替换符 * 进行替换敏感词 43 | */ 44 | public String replace(String text) { 45 | return sensitiveWordBs.replace(text); 46 | } 47 | 48 | /** 49 | * 返回所有敏感词 50 | */ 51 | public List findAll(String text) { 52 | return sensitiveWordBs.findAll(text); 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/main/resources/application-dev.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | mvc: 3 | pathmatch: 4 | matching-strategy: ant_path_matcher 5 | datasource: 6 | driver-class-name: com.mysql.cj.jdbc.Driver 7 | url: jdbc:mysql://localhost:3306/quick_chat?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&rewriteBatchedStatements=true 8 | username: root 9 | password: 123456 10 | redis: 11 | host: localhost 12 | port: 6379 13 | password: Pxy123456 14 | database: 0 15 | timeout: 1800000 16 | lettuce: 17 | pool: 18 | max-wait: -1 19 | max-idle: 5 20 | min-idle: 0 21 | max-active: 20 22 | mail: 23 | host: smtp.qq.com 24 | port: 465 25 | username: 1262254123@qq.com 26 | password: ocebnufztunlbagc 27 | default-encoding: UTF-8 28 | properties: 29 | mail: 30 | debug: true 31 | smtp: 32 | socketFactory: 33 | class: javax.net.ssl.SSLSocketFactory 34 | rocketmq: 35 | name-server: localhost:9876 36 | consumer: 37 | group: springboot_consumer_group 38 | pull-batch-size: 10 39 | producer: 40 | group: springboot_producer_group 41 | sendMessageTimeout: 10000 42 | retryTimesWhenSendFailed: 2 43 | retryTimesWhenSendAsyncFailed: 2 44 | maxMessageSize: 4096 45 | compressMessageBodyThreshold: 4096 46 | retryNextServer: false 47 | mybatis-plus: 48 | configuration: 49 | log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl 50 | map-underscore-to-camel-case: true 51 | minio: 52 | endpoint: http://localhost:9000 53 | accessKey: minioadmin 54 | secretKey: minioadmin 55 | logging: 56 | level: 57 | RocketmqClient: ERROR 58 | io: 59 | netty: ERROR 60 | #xxl: 61 | # job: 62 | # admin: 63 | # addresses: 127.0.0.1 64 | # accessToken: "Mock Token" 65 | # executor: 66 | # appname: "AppName" 67 | # address: "Address" 68 | # ip: "IP" 69 | # port: 9001 70 | # logpath: /opt/project/backend/myLogs 71 | # logretentiondays: 30 72 | quick-chat: 73 | common-group-id: 1 74 | no-recall-time: 120 75 | voice-time-limit: 60 76 | session-size-limit: 50 77 | size: 78 | avatar: 2 79 | voice: 5 80 | file: 50 81 | group: 82 | size: 100 83 | invite-count: 20 -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8888 3 | servlet: 4 | context-path: /api 5 | spring: 6 | profiles: 7 | active: dev 8 | application: 9 | name: QuickChat -------------------------------------------------------------------------------- /src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ,----, 2 | ,--. ,--, ,/ .`| 3 | ,----.. ,---, ,----.. ,--/ /| ,----.. ,--.'| ,---, ,` .' : 4 | / / \ ,--, ,`--.' | / / \ ,---,': / ' / / \ ,--, | : ' .' \ ; ; / 5 | / . : ,'_ /| | : :| : :: : '/ / | : :,---.'| : ' / ; '. .'___,/ ,' 6 | . / ;. \ .--. | | : : | '. | ;. /| ' , . | ;. /| | : _' |: : \ | : | 7 | . ; / ` ; ,'_ /| : . | | : |. ; /--` ' | / . ; /--` : : |.' |: | /\ \ ; |.'; ; 8 | ; | ; \ ; | | ' | | . . ' ' ;; | ; | ; ; ; | ; | ' ' ; :| : ' ;. :`----' | | 9 | | : | ; | ' | | ' | | | | | || : | : ' \ | : | ' | .'. || | ;/ \ \ ' : ; 10 | . | ' ' ' : : | | : ' ; ' : ;. | '___ | | ' . | '___ | | : | '' : | \ \ ,' | | ' 11 | ' ; \; / | | ; ' | | ' | | '' ; : .'|' : |. \ ' ; : .'|' : | : ;| | ' '--' ' : | 12 | \ \ ', . \ : | : ; ; | ' : |' | '/ :| | '_\.' ' | '/ :| | ' ,/ | : : ; |.' 13 | ; : ; |' : `--' \; |.' | : / ' : | | : / ; : ;--' | | ,' '---' 14 | \ \ .'`--" : , .-./'---' \ \ .' ; |,' \ \ .' | ,/ `--'' 15 | `---` `--`----' `---` '---' `---` '---' 16 | 17 | ${application.title} ${application.version} 18 | Powered by Spring Boot ${spring-boot.version} -------------------------------------------------------------------------------- /src/main/resources/email/findBack.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 43 | 44 | 45 |
46 |

Quick Chat 验证码

47 |

您正在使用邮箱账号找回密码

48 |

本次验证码如下,请勿泄露给其他人,有效期3分钟,请谨慎保管!

49 |
%s
50 |
51 | 52 | 53 | -------------------------------------------------------------------------------- /src/main/resources/email/sendCode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 43 | 44 | 45 |
46 |

注册 Quick Chat 账号

47 |

欢迎您使用 QuickChat 实时通讯系统,感谢您的光临!

48 |

本次验证码如下,请勿泄露给其他人,有效期3分钟,请谨慎保管!

49 |
%s
50 |
51 | 52 | 53 | -------------------------------------------------------------------------------- /src/main/resources/ip2region/ip2region.xdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binx98/QuickChat/f6ad197da44025db491e99b1a3a61a2ea67ef4a8/src/main/resources/ip2region/ip2region.xdb -------------------------------------------------------------------------------- /src/main/resources/lua/RateLimit.lua: -------------------------------------------------------------------------------- 1 | --[[脚本传入参数:限流key、限流次数、限流时间范围]] 2 | local key = KEYS[1] 3 | local count = tonumber(ARGV[1]) 4 | local time = tonumber(ARGV[2]) 5 | 6 | --[[调用get方法,限流Key对应次数]] 7 | local current = redis.call('get', key) 8 | 9 | --[[限流Key对应次数 < 限制次数,放行!]] 10 | --[[限流Key对应次数 > 限制次数,结束!]] 11 | if current and tonumber(current) > count then 12 | return tonumber(current) 13 | end 14 | 15 | --[[限流Key对应次数 + 1]] 16 | current = redis.call('incr', key) 17 | 18 | --[[限流Key对应次数 = 1,设置限流时间为过期时间]] 19 | if tonumber(current) == 1 then 20 | redis.call('expire', key, time) 21 | end 22 | return tonumber(current) -------------------------------------------------------------------------------- /src/main/resources/mapper/QuickChatApplyMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/mapper/QuickChatArchiveRecordMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/mapper/QuickChatContactMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/mapper/QuickChatEmojiMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/mapper/QuickChatGroupMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/mapper/QuickChatGroupMemberMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/mapper/QuickChatMsgDorisMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/mapper/QuickChatMsgMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DELETE 6 | FROM quick_chat_msg 7 | WHERE id IN 8 | 9 | #{id} 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main/resources/mapper/QuickChatSessionMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/mapper/QuickChatUserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/resources/sensitive/myNotSensitiveWords.txt: -------------------------------------------------------------------------------- 1 | 小码哥 -------------------------------------------------------------------------------- /src/main/resources/sensitive/mySensitiveWords.txt: -------------------------------------------------------------------------------- 1 | 国家 2 | --------------------------------------------------------------------------------