From 9f56a86116f0dfb6c8c4ec8f297c643ebb34f3c6 Mon Sep 17 00:00:00 2001
From: abu <3109389044@qq.com>
Date: Mon, 10 Mar 2025 15:40:51 +0800
Subject: [PATCH] init
---
.gitignore | 6 +
.idea/.gitignore | 8 +
.idea/compiler.xml | 32 +
.idea/encodings.xml | 16 +
.idea/jarRepositories.xml | 30 +
...batis_generator_for_imooc_1_0_SNAPSHOT.xml | 9 +
.idea/misc.xml | 20 +
.idea/uiDesigner.xml | 124 ++++
.idea/vlog-1.0.0.iml | 9 +
README.md | 16 +
book-api/pom.xml | 71 ++
.../src/main/java/com/imooc/Application.java | 23 +
.../com/imooc/config/InterceptorConfig.java | 32 +
.../java/com/imooc/config/MinIOConfig.java | 33 +
.../java/com/imooc/config/knife4jConfig.java | 40 ++
.../com/imooc/controller/BaseController.java | 15 +
.../imooc/controller/BaseInfoProperties.java | 46 ++
.../imooc/controller/CommentController.java | 114 +++
.../com/imooc/controller/FansController.java | 106 +++
.../com/imooc/controller/FileController.java | 42 ++
.../com/imooc/controller/MsgController.java | 43 ++
.../imooc/controller/PassportController.java | 95 +++
.../imooc/controller/RabbitMQConsumer.java | 66 ++
.../imooc/controller/UserInfoController.java | 136 ++++
.../com/imooc/controller/VlogController.java | 225 ++++++
.../intercepter/PassportInterceptor.java | 47 ++
.../intercepter/UserTokenInterceptor.java | 58 ++
.../src/main/resources/application-dev.yml | 65 ++
.../src/main/resources/application-prod.yml | 65 ++
book-api/src/main/resources/application.yml | 43 ++
book-api/src/main/resources/banner/banner.txt | 22 +
book-api/src/main/resources/banner/cat.png | Bin 0 -> 918517 bytes
book-api/src/main/resources/banner/qiaoba.txt | 57 ++
book-api/src/main/resources/bootstrap.yml | 8 +
book-common/pom.xml | 116 +++
.../java/com/imooc/enums/FileTypeEnum.java | 17 +
.../java/com/imooc/enums/MessageEnum.java | 22 +
.../src/main/java/com/imooc/enums/Sex.java | 18 +
.../com/imooc/enums/UserInfoModifyType.java | 35 +
.../main/java/com/imooc/enums/YesOrNo.java | 17 +
.../com/imooc/exceptions/GraceException.java | 14 +
.../exceptions/GraceExceptionHandler.java | 58 ++
.../imooc/exceptions/MyCustomException.java | 28 +
.../imooc/grace/result/GraceJSONResult.java | 153 ++++
.../imooc/grace/result/IMOOCJSONResult.java | 135 ++++
.../grace/result/ResponseStatusEnum.java | 105 +++
.../main/java/com/imooc/utils/DateUtil.java | 680 ++++++++++++++++++
.../com/imooc/utils/DesensitizationUtil.java | 77 ++
.../src/main/java/com/imooc/utils/IPUtil.java | 37 +
.../main/java/com/imooc/utils/JsonUtils.java | 74 ++
.../main/java/com/imooc/utils/MinIOUtils.java | 432 +++++++++++
.../src/main/java/com/imooc/utils/MyInfo.java | 9 +
.../java/com/imooc/utils/PagedGridResult.java | 49 ++
.../java/com/imooc/utils/RedisOperator.java | 287 ++++++++
.../main/java/com/imooc/utils/SMSUtils.java | 74 ++
.../imooc/utils/TencentCloudProperties.java | 23 +
.../src/main/java/org/n3r/idworker/Code.java | 35 +
.../main/java/org/n3r/idworker/DayCode.java | 19 +
.../src/main/java/org/n3r/idworker/Id.java | 29 +
.../main/java/org/n3r/idworker/IdWorker.java | 91 +++
.../org/n3r/idworker/InvalidSystemClock.java | 7 +
.../org/n3r/idworker/RandomCodeStrategy.java | 11 +
.../src/main/java/org/n3r/idworker/Sid.java | 64 ++
.../src/main/java/org/n3r/idworker/Test.java | 12 +
.../org/n3r/idworker/WorkerIdStrategy.java | 9 +
.../strategy/DayPrefixRandomCodeStrategy.java | 41 ++
.../strategy/DefaultRandomCodeStrategy.java | 197 +++++
.../strategy/DefaultWorkerIdStrategy.java | 205 ++++++
.../org/n3r/idworker/strategy/FileLock.java | 132 ++++
.../java/org/n3r/idworker/utils/HttpReq.java | 113 +++
.../org/n3r/idworker/utils/IPv4Utils.java | 60 ++
.../main/java/org/n3r/idworker/utils/Ip.java | 50 ++
.../java/org/n3r/idworker/utils/Props.java | 70 ++
.../org/n3r/idworker/utils/Serializes.java | 118 +++
.../java/org/n3r/idworker/utils/Utils.java | 114 +++
.../main/resources/tencentcloud.properties | 2 +
book-mapper/pom.xml | 29 +
.../java/com/imooc/mapper/CommentMapper.java | 9 +
.../com/imooc/mapper/CommentMapperCustom.java | 15 +
.../java/com/imooc/mapper/FansMapper.java | 9 +
.../com/imooc/mapper/FansMapperCustom.java | 20 +
.../com/imooc/mapper/MyLikedVlogMapper.java | 9 +
.../java/com/imooc/mapper/UsersMapper.java | 9 +
.../java/com/imooc/mapper/VlogMapper.java | 10 +
.../com/imooc/mapper/VlogMapperCustom.java | 23 +
.../java/com/imooc/my/mapper/MyMapper.java | 34 +
.../imooc/repository/MessageRepository.java | 17 +
.../main/resources/mapper/CommentMapper.xml | 17 +
.../resources/mapper/CommentMapperCustom.xml | 46 ++
.../src/main/resources/mapper/FansMapper.xml | 13 +
.../resources/mapper/FansMapperCustom.xml | 45 ++
.../resources/mapper/MyLikedVlogMapper.xml | 12 +
.../src/main/resources/mapper/UsersMapper.xml | 25 +
.../src/main/resources/mapper/VlogMapper.xml | 21 +
.../resources/mapper/VlogMapperCustom.xml | 161 +++++
book-model/pom.xml | 63 ++
.../src/main/java/com/imooc/bo/CommentBO.java | 32 +
.../main/java/com/imooc/bo/RegistLoginBO.java | 23 +
.../main/java/com/imooc/bo/UpdatedUserBO.java | 28 +
.../src/main/java/com/imooc/bo/VlogBO.java | 22 +
.../src/main/java/com/imooc/mo/MessageMO.java | 41 ++
.../src/main/java/com/imooc/pojo/Comment.java | 191 +++++
.../src/main/java/com/imooc/pojo/Fans.java | 96 +++
.../main/java/com/imooc/pojo/MyLikedVlog.java | 74 ++
.../src/main/java/com/imooc/pojo/Users.java | 374 ++++++++++
.../src/main/java/com/imooc/pojo/Vlog.java | 283 ++++++++
.../src/main/java/com/imooc/vo/CommentVO.java | 28 +
.../src/main/java/com/imooc/vo/FansVO.java | 17 +
.../main/java/com/imooc/vo/IndexVlogVO.java | 28 +
.../src/main/java/com/imooc/vo/UsersVO.java | 42 ++
.../src/main/java/com/imooc/vo/VlogerVO.java | 17 +
book-service/pom.xml | 29 +
.../com/imooc/base/BaseInfoProperties.java | 57 ++
.../java/com/imooc/base/RabbitMQConfig.java | 51 ++
.../com/imooc/service/CommentService.java | 35 +
.../java/com/imooc/service/FansService.java | 35 +
.../java/com/imooc/service/MsgService.java | 27 +
.../java/com/imooc/service/UserService.java | 38 +
.../java/com/imooc/service/VlogService.java | 156 ++++
.../service/impl/CommentServiceImpl.java | 150 ++++
.../imooc/service/impl/FansServiceImpl.java | 173 +++++
.../imooc/service/impl/MsgServiceImpl.java | 89 +++
.../imooc/service/impl/UserServiceImpl.java | 125 ++++
.../imooc/service/impl/VlogServiceImpl.java | 344 +++++++++
pom.xml | 192 +++++
125 files changed, 8945 insertions(+)
create mode 100644 .gitignore
create mode 100644 .idea/.gitignore
create mode 100644 .idea/compiler.xml
create mode 100644 .idea/encodings.xml
create mode 100644 .idea/jarRepositories.xml
create mode 100644 .idea/libraries/mybatis_generator_for_imooc_1_0_SNAPSHOT.xml
create mode 100644 .idea/misc.xml
create mode 100644 .idea/uiDesigner.xml
create mode 100644 .idea/vlog-1.0.0.iml
create mode 100644 README.md
create mode 100644 book-api/pom.xml
create mode 100644 book-api/src/main/java/com/imooc/Application.java
create mode 100644 book-api/src/main/java/com/imooc/config/InterceptorConfig.java
create mode 100644 book-api/src/main/java/com/imooc/config/MinIOConfig.java
create mode 100644 book-api/src/main/java/com/imooc/config/knife4jConfig.java
create mode 100644 book-api/src/main/java/com/imooc/controller/BaseController.java
create mode 100644 book-api/src/main/java/com/imooc/controller/BaseInfoProperties.java
create mode 100644 book-api/src/main/java/com/imooc/controller/CommentController.java
create mode 100644 book-api/src/main/java/com/imooc/controller/FansController.java
create mode 100644 book-api/src/main/java/com/imooc/controller/FileController.java
create mode 100644 book-api/src/main/java/com/imooc/controller/MsgController.java
create mode 100644 book-api/src/main/java/com/imooc/controller/PassportController.java
create mode 100644 book-api/src/main/java/com/imooc/controller/RabbitMQConsumer.java
create mode 100644 book-api/src/main/java/com/imooc/controller/UserInfoController.java
create mode 100644 book-api/src/main/java/com/imooc/controller/VlogController.java
create mode 100644 book-api/src/main/java/com/imooc/intercepter/PassportInterceptor.java
create mode 100644 book-api/src/main/java/com/imooc/intercepter/UserTokenInterceptor.java
create mode 100644 book-api/src/main/resources/application-dev.yml
create mode 100644 book-api/src/main/resources/application-prod.yml
create mode 100644 book-api/src/main/resources/application.yml
create mode 100644 book-api/src/main/resources/banner/banner.txt
create mode 100644 book-api/src/main/resources/banner/cat.png
create mode 100644 book-api/src/main/resources/banner/qiaoba.txt
create mode 100644 book-api/src/main/resources/bootstrap.yml
create mode 100644 book-common/pom.xml
create mode 100644 book-common/src/main/java/com/imooc/enums/FileTypeEnum.java
create mode 100644 book-common/src/main/java/com/imooc/enums/MessageEnum.java
create mode 100644 book-common/src/main/java/com/imooc/enums/Sex.java
create mode 100644 book-common/src/main/java/com/imooc/enums/UserInfoModifyType.java
create mode 100644 book-common/src/main/java/com/imooc/enums/YesOrNo.java
create mode 100644 book-common/src/main/java/com/imooc/exceptions/GraceException.java
create mode 100644 book-common/src/main/java/com/imooc/exceptions/GraceExceptionHandler.java
create mode 100644 book-common/src/main/java/com/imooc/exceptions/MyCustomException.java
create mode 100644 book-common/src/main/java/com/imooc/grace/result/GraceJSONResult.java
create mode 100644 book-common/src/main/java/com/imooc/grace/result/IMOOCJSONResult.java
create mode 100644 book-common/src/main/java/com/imooc/grace/result/ResponseStatusEnum.java
create mode 100644 book-common/src/main/java/com/imooc/utils/DateUtil.java
create mode 100644 book-common/src/main/java/com/imooc/utils/DesensitizationUtil.java
create mode 100644 book-common/src/main/java/com/imooc/utils/IPUtil.java
create mode 100644 book-common/src/main/java/com/imooc/utils/JsonUtils.java
create mode 100644 book-common/src/main/java/com/imooc/utils/MinIOUtils.java
create mode 100644 book-common/src/main/java/com/imooc/utils/MyInfo.java
create mode 100644 book-common/src/main/java/com/imooc/utils/PagedGridResult.java
create mode 100644 book-common/src/main/java/com/imooc/utils/RedisOperator.java
create mode 100644 book-common/src/main/java/com/imooc/utils/SMSUtils.java
create mode 100644 book-common/src/main/java/com/imooc/utils/TencentCloudProperties.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/Code.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/DayCode.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/Id.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/IdWorker.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/InvalidSystemClock.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/RandomCodeStrategy.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/Sid.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/Test.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/WorkerIdStrategy.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/strategy/DayPrefixRandomCodeStrategy.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/strategy/DefaultRandomCodeStrategy.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/strategy/DefaultWorkerIdStrategy.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/strategy/FileLock.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/utils/HttpReq.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/utils/IPv4Utils.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/utils/Ip.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/utils/Props.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/utils/Serializes.java
create mode 100644 book-common/src/main/java/org/n3r/idworker/utils/Utils.java
create mode 100644 book-common/src/main/resources/tencentcloud.properties
create mode 100644 book-mapper/pom.xml
create mode 100644 book-mapper/src/main/java/com/imooc/mapper/CommentMapper.java
create mode 100644 book-mapper/src/main/java/com/imooc/mapper/CommentMapperCustom.java
create mode 100644 book-mapper/src/main/java/com/imooc/mapper/FansMapper.java
create mode 100644 book-mapper/src/main/java/com/imooc/mapper/FansMapperCustom.java
create mode 100644 book-mapper/src/main/java/com/imooc/mapper/MyLikedVlogMapper.java
create mode 100644 book-mapper/src/main/java/com/imooc/mapper/UsersMapper.java
create mode 100644 book-mapper/src/main/java/com/imooc/mapper/VlogMapper.java
create mode 100644 book-mapper/src/main/java/com/imooc/mapper/VlogMapperCustom.java
create mode 100644 book-mapper/src/main/java/com/imooc/my/mapper/MyMapper.java
create mode 100644 book-mapper/src/main/java/com/imooc/repository/MessageRepository.java
create mode 100644 book-mapper/src/main/resources/mapper/CommentMapper.xml
create mode 100644 book-mapper/src/main/resources/mapper/CommentMapperCustom.xml
create mode 100644 book-mapper/src/main/resources/mapper/FansMapper.xml
create mode 100644 book-mapper/src/main/resources/mapper/FansMapperCustom.xml
create mode 100644 book-mapper/src/main/resources/mapper/MyLikedVlogMapper.xml
create mode 100644 book-mapper/src/main/resources/mapper/UsersMapper.xml
create mode 100644 book-mapper/src/main/resources/mapper/VlogMapper.xml
create mode 100644 book-mapper/src/main/resources/mapper/VlogMapperCustom.xml
create mode 100644 book-model/pom.xml
create mode 100644 book-model/src/main/java/com/imooc/bo/CommentBO.java
create mode 100644 book-model/src/main/java/com/imooc/bo/RegistLoginBO.java
create mode 100644 book-model/src/main/java/com/imooc/bo/UpdatedUserBO.java
create mode 100644 book-model/src/main/java/com/imooc/bo/VlogBO.java
create mode 100644 book-model/src/main/java/com/imooc/mo/MessageMO.java
create mode 100644 book-model/src/main/java/com/imooc/pojo/Comment.java
create mode 100644 book-model/src/main/java/com/imooc/pojo/Fans.java
create mode 100644 book-model/src/main/java/com/imooc/pojo/MyLikedVlog.java
create mode 100644 book-model/src/main/java/com/imooc/pojo/Users.java
create mode 100644 book-model/src/main/java/com/imooc/pojo/Vlog.java
create mode 100644 book-model/src/main/java/com/imooc/vo/CommentVO.java
create mode 100644 book-model/src/main/java/com/imooc/vo/FansVO.java
create mode 100644 book-model/src/main/java/com/imooc/vo/IndexVlogVO.java
create mode 100644 book-model/src/main/java/com/imooc/vo/UsersVO.java
create mode 100644 book-model/src/main/java/com/imooc/vo/VlogerVO.java
create mode 100644 book-service/pom.xml
create mode 100644 book-service/src/main/java/com/imooc/base/BaseInfoProperties.java
create mode 100644 book-service/src/main/java/com/imooc/base/RabbitMQConfig.java
create mode 100644 book-service/src/main/java/com/imooc/service/CommentService.java
create mode 100644 book-service/src/main/java/com/imooc/service/FansService.java
create mode 100644 book-service/src/main/java/com/imooc/service/MsgService.java
create mode 100644 book-service/src/main/java/com/imooc/service/UserService.java
create mode 100644 book-service/src/main/java/com/imooc/service/VlogService.java
create mode 100644 book-service/src/main/java/com/imooc/service/impl/CommentServiceImpl.java
create mode 100644 book-service/src/main/java/com/imooc/service/impl/FansServiceImpl.java
create mode 100644 book-service/src/main/java/com/imooc/service/impl/MsgServiceImpl.java
create mode 100644 book-service/src/main/java/com/imooc/service/impl/UserServiceImpl.java
create mode 100644 book-service/src/main/java/com/imooc/service/impl/VlogServiceImpl.java
create mode 100644 pom.xml
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a0595ce
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+# 项目排除路径
+/book-api/target/
+/book-common/target/
+/book-mapper/target/
+/book-model/target/
+/book-service/target/
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..35410ca
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..188c465
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..b734512
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..7628153
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/mybatis_generator_for_imooc_1_0_SNAPSHOT.xml b/.idea/libraries/mybatis_generator_for_imooc_1_0_SNAPSHOT.xml
new file mode 100644
index 0000000..62eb41d
--- /dev/null
+++ b/.idea/libraries/mybatis_generator_for_imooc_1_0_SNAPSHOT.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..d0d019d
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..2b63946
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vlog-1.0.0.iml b/.idea/vlog-1.0.0.iml
new file mode 100644
index 0000000..d6ebd48
--- /dev/null
+++ b/.idea/vlog-1.0.0.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f6e6af3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,16 @@
+# douyin_dome
+SpringBoot+Uniapp仿抖音短视频App
+
+只用修改api模块下面的配置即可运行
+
+Knife4j 接口文档通过访问 http://ip+prot/doc.html#/home 查看api
+# 架构
+
+
+
+# 效果
+
+
+
+
+
diff --git a/book-api/pom.xml b/book-api/pom.xml
new file mode 100644
index 0000000..b699a3a
--- /dev/null
+++ b/book-api/pom.xml
@@ -0,0 +1,71 @@
+
+
+ 4.0.0
+
+ com.imooc
+ imooc-red-book-dev
+ 1.0-SNAPSHOT
+
+
+ jar
+
+
+ book-api
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-config
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-bootstrap
+
+
+
+
+ com.imooc
+ book-service
+ 1.0-SNAPSHOT
+
+
+ com.github.xiaoymin
+ knife4j-spring-boot-starter
+
+
+ com.github.xiaoymin
+ knife4j-springdoc-ui
+
+
+
+
+ ${project.artifactId}
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/book-api/src/main/java/com/imooc/Application.java b/book-api/src/main/java/com/imooc/Application.java
new file mode 100644
index 0000000..d1ba13f
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/Application.java
@@ -0,0 +1,23 @@
+package com.imooc;
+
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+import tk.mybatis.spring.annotation.MapperScan;
+
+/**
+ * @author vercen
+ * @version 1.0
+ * @date 2023/5/20 14:25
+ */
+@SpringBootApplication
+@MapperScan(basePackages = {"com.imooc.mapper"})
+@ComponentScan(basePackages = {"com.imooc","org.n3r.idworker"})
+@EnableMongoRepositories
+public class Application {
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/book-api/src/main/java/com/imooc/config/InterceptorConfig.java b/book-api/src/main/java/com/imooc/config/InterceptorConfig.java
new file mode 100644
index 0000000..51394b0
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/config/InterceptorConfig.java
@@ -0,0 +1,32 @@
+package com.imooc.config;
+
+import com.imooc.intercepter.PassportInterceptor;
+import com.imooc.intercepter.UserTokenInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class InterceptorConfig implements WebMvcConfigurer {
+
+ @Bean
+ public PassportInterceptor passportInterceptor() {
+ return new PassportInterceptor();
+ }
+
+ @Bean
+ public UserTokenInterceptor userTokenInterceptor() {
+ return new UserTokenInterceptor();
+ }
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(passportInterceptor())
+ .addPathPatterns("/passport/getSMSCode");
+
+ registry.addInterceptor(userTokenInterceptor())
+ .addPathPatterns("/userInfo/modifyUserInfo")
+ .addPathPatterns("/userInfo/modifyImage");
+ }
+}
diff --git a/book-api/src/main/java/com/imooc/config/MinIOConfig.java b/book-api/src/main/java/com/imooc/config/MinIOConfig.java
new file mode 100644
index 0000000..0ec55ed
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/config/MinIOConfig.java
@@ -0,0 +1,33 @@
+package com.imooc.config;
+
+import com.imooc.utils.MinIOUtils;
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@Data
+public class MinIOConfig {
+
+ @Value("${minio.endpoint}")
+ private String endpoint;
+ @Value("${minio.fileHost}")
+ private String fileHost;
+ @Value("${minio.bucketName}")
+ private String bucketName;
+ @Value("${minio.accessKey}")
+ private String accessKey;
+ @Value("${minio.secretKey}")
+ private String secretKey;
+
+ @Value("${minio.imgSize}")
+ private Integer imgSize;
+ @Value("${minio.fileSize}")
+ private Integer fileSize;
+
+ @Bean
+ public MinIOUtils creatMinioClient() {
+ return new MinIOUtils(endpoint, bucketName, accessKey, secretKey, imgSize, fileSize);
+ }
+}
diff --git a/book-api/src/main/java/com/imooc/config/knife4jConfig.java b/book-api/src/main/java/com/imooc/config/knife4jConfig.java
new file mode 100644
index 0000000..3b2905e
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/config/knife4jConfig.java
@@ -0,0 +1,40 @@
+package com.imooc.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
+
+/**
+ * @author vercen
+ * @version 1.0
+ * @date 2023/5/20 19:55
+ */
+@Configuration
+@EnableSwagger2WebMvc
+public class knife4jConfig {
+ @Bean
+ public Docket defaultApi2() {
+ Docket docket=new Docket(DocumentationType.SWAGGER_2)
+ .apiInfo(new ApiInfoBuilder()
+ //.title("swagger-bootstrap-ui-demo RESTful APIs")
+ .description("短视频实战接口文档")
+ .termsOfServiceUrl("http://www.xx.com/")
+ .contact(new Contact("lee", "http://www.imooc.com/", "abc@imooc.com"))
+ .version("1.0")
+ .build())
+ //分组名称
+ .groupName("2.X版本")
+ .select()
+ //这里指定Controller扫描包路径
+ .apis(RequestHandlerSelectors.basePackage("com.imooc.controller"))
+ .paths(PathSelectors.any())
+ .build();
+ return docket;
+ }
+}
diff --git a/book-api/src/main/java/com/imooc/controller/BaseController.java b/book-api/src/main/java/com/imooc/controller/BaseController.java
new file mode 100644
index 0000000..e331bd3
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/controller/BaseController.java
@@ -0,0 +1,15 @@
+package com.imooc.controller;
+
+import com.imooc.utils.RedisOperator;
+import org.springframework.beans.factory.annotation.Autowired;
+
+//public class BaseController {
+//
+// @Autowired
+// public RedisOperator redis;
+//
+// public static final String MOBILE_SMSCODE = "mobile:smscode";
+// public static final String REDIS_USER_TOKEN = "redis_user_token";
+// public static final String REDIS_USER_INFO = "redis_user_info";
+//
+//}
diff --git a/book-api/src/main/java/com/imooc/controller/BaseInfoProperties.java b/book-api/src/main/java/com/imooc/controller/BaseInfoProperties.java
new file mode 100644
index 0000000..bd0bbdc
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/controller/BaseInfoProperties.java
@@ -0,0 +1,46 @@
+//package com.imooc.controller;
+//
+//import com.github.pagehelper.PageInfo;
+//import com.imooc.utils.RedisOperator;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.validation.BindingResult;
+//import org.springframework.validation.FieldError;
+//
+//import java.util.HashMap;
+//import java.util.List;
+//import java.util.Map;
+//
+//public class BaseInfoProperties {
+//
+// @Autowired
+// public RedisOperator redis;
+//
+// public static final Integer COMMON_START_PAGE = 1;
+// public static final Integer COMMON_PAGE_SIZE = 10;
+//
+// public static final String MOBILE_SMSCODE = "mobile:smscode";
+// public static final String REDIS_USER_TOKEN = "redis_user_token";
+// public static final String REDIS_USER_INFO = "redis_user_info";
+//
+//
+// //我的关注总数
+// public static final String REDIS_MY_FOLLOWS_COUNTS = "redis_my_follows_counts";
+// // 我的粉丝总数
+// public static final String REDIS_MY_FANS_COUNTS = "redis_my_fans_counts";
+//
+// // 视频和发布者获赞数
+// public static final String REDIS_VLOG_BE_LIKED_COUNTS = "redis_vlog_be_liked_counts";
+// public static final String REDIS_VLOGER_BE_LIKED_COUNTS = "redis_vloger_be_liked_counts";
+//
+// public PagedGridResult setterPagedGrid(List> list,
+// Integer page) {
+// PageInfo> pageList = new PageInfo<>(list);
+// PagedGridResult gridResult = new PagedGridResult();
+// gridResult.setRows(list);
+// gridResult.setPage(page);
+// gridResult.setRecords(pageList.getTotal());
+// gridResult.setTotal(pageList.getPages());
+// return gridResult;
+// }
+//
+//}
diff --git a/book-api/src/main/java/com/imooc/controller/CommentController.java b/book-api/src/main/java/com/imooc/controller/CommentController.java
new file mode 100644
index 0000000..4210401
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/controller/CommentController.java
@@ -0,0 +1,114 @@
+package com.imooc.controller;
+
+import com.imooc.base.BaseInfoProperties;
+import com.imooc.bo.CommentBO;
+import com.imooc.enums.MessageEnum;
+import com.imooc.grace.result.GraceJSONResult;
+import com.imooc.pojo.Comment;
+import com.imooc.pojo.Vlog;
+import com.imooc.service.CommentService;
+import com.imooc.service.MsgService;
+import com.imooc.service.VlogService;
+import com.imooc.vo.CommentVO;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+@Api(tags = "CommentController 评论模块的接口")
+@RequestMapping("comment")
+@RestController
+public class CommentController extends BaseInfoProperties {
+
+ @Autowired
+ private CommentService commentService;
+ @Autowired
+ private MsgService msgService;
+ @Autowired
+ private VlogService vlogService;
+//
+ @PostMapping("create")
+ public GraceJSONResult create(@RequestBody @Valid CommentBO commentBO)
+ throws Exception {
+
+ CommentVO commentVO = commentService.createComment(commentBO);
+ return GraceJSONResult.ok(commentVO);
+ }
+//
+ @GetMapping("counts")
+ public GraceJSONResult counts(@RequestParam String vlogId) {
+
+ String countsStr = redis.get(REDIS_VLOG_COMMENT_COUNTS + ":" + vlogId);
+ if (StringUtils.isBlank(countsStr)) {
+ countsStr = "0";
+ }
+
+ return GraceJSONResult.ok(Integer.valueOf(countsStr));
+ }
+
+ @GetMapping("list")
+ public GraceJSONResult list(@RequestParam String vlogId,
+ @RequestParam(defaultValue = "") String userId,
+ @RequestParam Integer page,
+ @RequestParam Integer pageSize) {
+
+ return GraceJSONResult.ok(
+ commentService.queryVlogComments(
+ vlogId,
+ userId,
+ page,
+ pageSize));
+ }
+
+ @DeleteMapping("delete")
+ public GraceJSONResult delete(@RequestParam String commentUserId,
+ @RequestParam String commentId,
+ @RequestParam String vlogId) {
+ commentService.deleteComment(commentUserId,
+ commentId,
+ vlogId);
+ return GraceJSONResult.ok();
+ }
+
+ @PostMapping("like")
+ public GraceJSONResult like(@RequestParam String commentId,
+ @RequestParam String userId) {
+
+ // 故意犯错,bigkey
+ redis.incrementHash(REDIS_VLOG_COMMENT_LIKED_COUNTS, commentId, 1);
+ redis.setHashValue(REDIS_USER_LIKE_COMMENT, userId + ":" + commentId, "1");
+// redis.hset(REDIS_USER_LIKE_COMMENT, userId, "1");
+
+
+ // 系统消息:点赞评论
+ Comment comment = commentService.getComment(commentId);
+ Vlog vlog = vlogService.getVlog(comment.getVlogId());
+ Map msgContent = new HashMap();
+ msgContent.put("vlogId", vlog.getId());
+ msgContent.put("vlogCover", vlog.getCover());
+ msgContent.put("commentId", commentId);
+ msgService.createMsg(userId,
+ comment.getCommentUserId(),
+ MessageEnum.LIKE_COMMENT.type,
+ msgContent);
+
+
+ return GraceJSONResult.ok();
+ }
+
+ @PostMapping("unlike")
+ public GraceJSONResult unlike(@RequestParam String commentId,
+ @RequestParam String userId) {
+
+ redis.decrementHash(REDIS_VLOG_COMMENT_LIKED_COUNTS, commentId, 1);
+ redis.hdel(REDIS_USER_LIKE_COMMENT, userId + ":" + commentId);
+
+ return GraceJSONResult.ok();
+ }
+}
diff --git a/book-api/src/main/java/com/imooc/controller/FansController.java b/book-api/src/main/java/com/imooc/controller/FansController.java
new file mode 100644
index 0000000..9604118
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/controller/FansController.java
@@ -0,0 +1,106 @@
+package com.imooc.controller;
+
+import com.imooc.base.BaseInfoProperties;
+import com.imooc.grace.result.GraceJSONResult;
+import com.imooc.grace.result.ResponseStatusEnum;
+import com.imooc.pojo.Users;
+import com.imooc.service.FansService;
+import com.imooc.service.UserService;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@Slf4j
+@Api(tags = "FansController 粉丝相关业务功能的接口")
+@RequestMapping("fans")
+@RestController
+public class FansController extends BaseInfoProperties {
+
+ @Autowired
+ private UserService userService;
+ @Autowired
+ private FansService fansService;
+
+ @PostMapping("follow")
+ public GraceJSONResult follow(@RequestParam String myId,
+ @RequestParam String vlogerId) {
+
+ // 判断两个id不能为空
+ if (StringUtils.isBlank(myId) || StringUtils.isBlank(vlogerId)) {
+ return GraceJSONResult.errorCustom(ResponseStatusEnum.SYSTEM_ERROR);
+ }
+
+ // 判断当前用户,自己不能关注自己
+ if (myId.equalsIgnoreCase(vlogerId)) {
+ return GraceJSONResult.errorCustom(ResponseStatusEnum.SYSTEM_RESPONSE_NO_INFO);
+ }
+
+ // 判断两个id对应的用户是否存在
+ Users vloger = userService.getUser(vlogerId);
+ Users myInfo = userService.getUser(myId);
+
+ // fixme: 两个用户id的数据库查询后的判断,是分开好?还是合并判断好?
+ if (myInfo == null || vloger == null) {
+ return GraceJSONResult.errorCustom(ResponseStatusEnum.SYSTEM_RESPONSE_NO_INFO);
+ }
+//
+ // 保存粉丝关系到数据库
+ fansService.doFollow(myId, vlogerId);
+
+ // 博主的粉丝+1,我的关注+1
+ redis.increment(REDIS_MY_FOLLOWS_COUNTS + ":" + myId, 1);
+ redis.increment(REDIS_MY_FANS_COUNTS + ":" + vlogerId, 1);
+
+ // 我和博主的关联关系,依赖redis,不要存储数据库,避免db的性能瓶颈
+ redis.set(REDIS_FANS_AND_VLOGGER_RELATIONSHIP + ":" + myId + ":" + vlogerId, "1");
+//
+ return GraceJSONResult.ok();
+ }
+
+ @PostMapping("cancel")
+ public GraceJSONResult cancel(@RequestParam String myId,
+ @RequestParam String vlogerId) {
+
+ // 删除业务的执行
+ fansService.doCancel(myId, vlogerId);
+
+ // 博主的粉丝-1,我的关注-1
+ redis.decrement(REDIS_MY_FOLLOWS_COUNTS + ":" + myId, 1);
+ redis.decrement(REDIS_MY_FANS_COUNTS + ":" + vlogerId, 1);
+
+ // 我和博主的关联关系,依赖redis,不要存储数据库,避免db的性能瓶颈
+ redis.del(REDIS_FANS_AND_VLOGGER_RELATIONSHIP + ":" + myId + ":" + vlogerId);
+
+ return GraceJSONResult.ok();
+ }
+
+ @GetMapping("queryDoIFollowVloger")
+ public GraceJSONResult queryDoIFollowVloger(@RequestParam String myId,
+ @RequestParam String vlogerId) {
+ return GraceJSONResult.ok(fansService.queryDoIFollowVloger(myId, vlogerId));
+ }
+
+ @GetMapping("queryMyFollows")
+ public GraceJSONResult queryMyFollows(@RequestParam String myId,
+ @RequestParam Integer page,
+ @RequestParam Integer pageSize) {
+ return GraceJSONResult.ok(
+ fansService.queryMyFollows(
+ myId,
+ page,
+ pageSize));
+ }
+
+ @GetMapping("queryMyFans")
+ public GraceJSONResult queryMyFans(@RequestParam String myId,
+ @RequestParam Integer page,
+ @RequestParam Integer pageSize) {
+ return GraceJSONResult.ok(
+ fansService.queryMyFans(
+ myId,
+ page,
+ pageSize));
+ }
+}
diff --git a/book-api/src/main/java/com/imooc/controller/FileController.java b/book-api/src/main/java/com/imooc/controller/FileController.java
new file mode 100644
index 0000000..e808156
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/controller/FileController.java
@@ -0,0 +1,42 @@
+package com.imooc.controller;
+
+
+import com.imooc.config.MinIOConfig;
+import com.imooc.grace.result.GraceJSONResult;
+import com.imooc.utils.MinIOUtils;
+import com.imooc.utils.SMSUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+@Slf4j
+@Api(tags = "FileController 文件上传测试的接口")
+@RestController
+public class FileController {
+
+ @Autowired
+ private MinIOConfig minIOConfig;
+
+ @PostMapping("upload")
+ public GraceJSONResult upload(MultipartFile file) throws Exception {
+
+ String fileName = file.getOriginalFilename();
+
+ MinIOUtils.uploadFile(minIOConfig.getBucketName(),
+ fileName,
+ file.getInputStream());
+
+ String imgUrl = minIOConfig.getFileHost()
+ + "/"
+ + minIOConfig.getBucketName()
+ + "/"
+ + fileName;
+
+ return GraceJSONResult.ok(imgUrl);
+ }
+}
diff --git a/book-api/src/main/java/com/imooc/controller/MsgController.java b/book-api/src/main/java/com/imooc/controller/MsgController.java
new file mode 100644
index 0000000..c684c77
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/controller/MsgController.java
@@ -0,0 +1,43 @@
+package com.imooc.controller;
+
+import com.imooc.base.BaseInfoProperties;
+import com.imooc.grace.result.GraceJSONResult;
+import com.imooc.mo.MessageMO;
+import com.imooc.service.MsgService;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@Slf4j
+@Api(tags = "MsgController 消息功能模块的接口")
+@RequestMapping("msg")
+@RestController
+public class MsgController extends BaseInfoProperties {
+
+ @Autowired
+ private MsgService msgService;
+
+ @GetMapping("list")
+ public GraceJSONResult list(@RequestParam String userId,
+ @RequestParam Integer page,
+ @RequestParam Integer pageSize) {
+
+ // mongodb 从0分页,区别于数据库
+ if (page == null) {
+ page = COMMON_START_PAGE_ZERO;
+ }
+ if (pageSize == null) {
+ pageSize = COMMON_PAGE_SIZE;
+ }
+
+ List list = msgService.queryList(userId, page, pageSize);
+
+ return GraceJSONResult.ok(list);
+ }
+}
diff --git a/book-api/src/main/java/com/imooc/controller/PassportController.java b/book-api/src/main/java/com/imooc/controller/PassportController.java
new file mode 100644
index 0000000..9267618
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/controller/PassportController.java
@@ -0,0 +1,95 @@
+package com.imooc.controller;
+
+import com.imooc.base.BaseInfoProperties;
+import com.imooc.bo.RegistLoginBO;
+import com.imooc.grace.result.GraceJSONResult;
+import com.imooc.grace.result.ResponseStatusEnum;
+import com.imooc.pojo.Users;
+import com.imooc.service.UserService;
+import com.imooc.utils.IPUtil;
+import com.imooc.utils.SMSUtils;
+import com.imooc.vo.UsersVO;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.Valid;
+import java.util.UUID;
+
+/**
+ * @author vercen
+ * @version 1.0
+ * @date 2023/5/25 10:47
+ */
+@Slf4j
+@RestController
+@RequestMapping("passport")
+@Api(tags = "通行证,验证码登录注册")
+public class PassportController extends BaseInfoProperties {
+ @Autowired
+ SMSUtils smsUtils;
+ @Autowired
+ UserService userService;
+ @PostMapping("getSMSCode")
+ public Object getSMSCode(@RequestParam String mobile, HttpServletRequest request) throws Exception {
+ if (StringUtils.isBlank(mobile)){
+ return GraceJSONResult.ok();
+ }
+
+ //TODO 获得用户ip 限制时间60s只能1次
+ String userIp=IPUtil.getRequestIp(request);
+
+ redis.setnx60s(MOBILE_SMSCODE+":"+userIp, userIp);
+ String code=(int)((Math.random()*9+1)*100000)+"";
+
+ smsUtils.sendSMS(mobile,code);
+
+ log.info(code);
+ redis.set(MOBILE_SMSCODE+":"+mobile, code,30*60);
+ //TODO 验证码放入redis
+ return GraceJSONResult.ok();
+ }
+
+ @PostMapping("login")
+ public Object login(@Valid @RequestBody RegistLoginBO registLoginBO){
+
+ String rediscode = redis.get(MOBILE_SMSCODE + ":" + registLoginBO.getMobile());
+
+ if (StringUtils.isBlank(rediscode)|| !rediscode.equalsIgnoreCase(registLoginBO.getSmsCode())){
+ System.out.println("rediscode"+rediscode);
+ System.out.println("registLoginBO.getMobile()"+registLoginBO.getSmsCode());
+ return GraceJSONResult.errorCustom(ResponseStatusEnum.SMS_CODE_ERROR);
+ }
+
+ Users user = userService.queryMobileIsExist(registLoginBO.getMobile());
+ if (user==null){
+ user = userService.createUser(registLoginBO.getMobile());
+ }
+ String uToken = UUID.randomUUID().toString();
+ redis.set(REDIS_USER_TOKEN+":"+user.getId(),uToken);
+
+ //清除验证码
+ redis.del(MOBILE_SMSCODE+":"+user.getMobile());
+
+ //返回给前端
+ UsersVO usersVO = new UsersVO();
+ BeanUtils.copyProperties(user, usersVO);
+ usersVO.setUserToken(uToken);
+
+ return GraceJSONResult.ok(usersVO);
+
+ }
+
+ @PostMapping("logout")
+ public Object logout(@RequestParam String userId){
+
+ redis.del(REDIS_USER_TOKEN+":"+userId);
+
+ return GraceJSONResult.ok();
+ }
+
+}
diff --git a/book-api/src/main/java/com/imooc/controller/RabbitMQConsumer.java b/book-api/src/main/java/com/imooc/controller/RabbitMQConsumer.java
new file mode 100644
index 0000000..b28bd38
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/controller/RabbitMQConsumer.java
@@ -0,0 +1,66 @@
+package com.imooc.controller;
+
+import com.imooc.base.RabbitMQConfig;
+import com.imooc.enums.MessageEnum;
+import com.imooc.exceptions.GraceException;
+import com.imooc.grace.result.ResponseStatusEnum;
+import com.imooc.mo.MessageMO;
+import com.imooc.service.MsgService;
+import com.imooc.utils.JsonUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class RabbitMQConsumer {
+
+ @Autowired
+ private MsgService msgService;
+
+ @RabbitListener(queues = {RabbitMQConfig.QUEUE_SYS_MSG})
+ public void watchQueue(String payload, Message message) {
+ log.info(payload);
+
+ MessageMO messageMO = JsonUtils.jsonToPojo(payload, MessageMO.class);
+
+ String routingKey = message.getMessageProperties().getReceivedRoutingKey();
+ log.info(routingKey);
+
+ // TODO: 下面这段代码可以优化,一个地方是参数优化,另外是枚举的判断优化
+
+ if (routingKey.equalsIgnoreCase("sys.msg." + MessageEnum.FOLLOW_YOU.enValue)) {
+ msgService.createMsg(messageMO.getFromUserId(),
+ messageMO.getToUserId(),
+ MessageEnum.FOLLOW_YOU.type,
+ null);
+ } else if (routingKey.equalsIgnoreCase("sys.msg." + MessageEnum.LIKE_VLOG.enValue)) {
+ msgService.createMsg(messageMO.getFromUserId(),
+ messageMO.getToUserId(),
+ MessageEnum.FOLLOW_YOU.type,
+ messageMO.getMsgContent());
+ } else if (routingKey.equalsIgnoreCase("sys.msg." + MessageEnum.COMMENT_VLOG.enValue)) {
+ msgService.createMsg(messageMO.getFromUserId(),
+ messageMO.getToUserId(),
+ MessageEnum.COMMENT_VLOG.type,
+ messageMO.getMsgContent());
+ } else if (routingKey.equalsIgnoreCase("sys.msg." + MessageEnum.REPLY_YOU.enValue)) {
+ msgService.createMsg(messageMO.getFromUserId(),
+ messageMO.getToUserId(),
+ MessageEnum.REPLY_YOU.type,
+ messageMO.getMsgContent());
+ } else if (routingKey.equalsIgnoreCase("sys.msg." + MessageEnum.LIKE_COMMENT.enValue)) {
+ msgService.createMsg(messageMO.getFromUserId(),
+ messageMO.getToUserId(),
+ MessageEnum.LIKE_COMMENT.type,
+ messageMO.getMsgContent());
+ } else {
+ GraceException.display(ResponseStatusEnum.SYSTEM_OPERATION_ERROR);
+ }
+
+ }
+
+
+}
diff --git a/book-api/src/main/java/com/imooc/controller/UserInfoController.java b/book-api/src/main/java/com/imooc/controller/UserInfoController.java
new file mode 100644
index 0000000..8b68295
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/controller/UserInfoController.java
@@ -0,0 +1,136 @@
+package com.imooc.controller;
+
+import com.imooc.base.BaseInfoProperties;
+import com.imooc.bo.UpdatedUserBO;
+import com.imooc.config.MinIOConfig;
+import com.imooc.enums.FileTypeEnum;
+import com.imooc.enums.UserInfoModifyType;
+import com.imooc.grace.result.GraceJSONResult;
+import com.imooc.grace.result.ResponseStatusEnum;
+import com.imooc.pojo.Users;
+import com.imooc.service.UserService;
+import com.imooc.utils.MinIOUtils;
+import com.imooc.utils.SMSUtils;
+import com.imooc.vo.UsersVO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * @author vercen
+ * @version 1.0
+ * @date 2023/5/20 14:32
+ */
+@RestController
+@Slf4j
+@Api(tags = "UserInfoController用户信息接口模块")
+@RequestMapping("userInfo")
+public class UserInfoController extends BaseInfoProperties {
+
+ @Autowired
+ UserService userService;
+
+// @ResponseBody
+ @ApiOperation(value = "根据userId返回个人信息")
+ @GetMapping("query")
+ public Object query(@RequestParam String userId){
+ Users user = userService.getUser(userId);
+
+ UsersVO usersVO = new UsersVO();
+ BeanUtils.copyProperties(user, usersVO);
+
+
+ // 我的关注博主总数量
+ String myFollowsCountsStr = redis.get(REDIS_MY_FOLLOWS_COUNTS + ":" + userId);
+ // 我的粉丝总数
+ String myFansCountsStr = redis.get(REDIS_MY_FANS_COUNTS + ":" + userId);
+ // 用户获赞总数,视频博主(点赞/喜欢)总和
+// String likedVlogCountsStr = redis.get(REDIS_VLOG_BE_LIKED_COUNTS + ":" + userId);
+ String likedVlogerCountsStr = redis.get(REDIS_VLOGER_BE_LIKED_COUNTS + ":" + userId);
+
+ Integer myFollowsCounts = 0;
+ Integer myFansCounts = 0;
+ Integer likedVlogCounts = 0;
+ Integer likedVlogerCounts = 0;
+ Integer totalLikeMeCounts = 0;
+
+
+ if (StringUtils.isNotBlank(myFollowsCountsStr)) {
+ myFollowsCounts = Integer.valueOf(myFollowsCountsStr);
+ }
+ if (StringUtils.isNotBlank(myFansCountsStr)) {
+ myFansCounts = Integer.valueOf(myFansCountsStr);
+ }
+// if (StringUtils.isNotBlank(likedVlogCountsStr)) {
+// likedVlogCounts = Integer.valueOf(likedVlogCountsStr);
+// }
+ if (StringUtils.isNotBlank(likedVlogerCountsStr)) {
+ likedVlogerCounts = Integer.valueOf(likedVlogerCountsStr);
+ }
+ totalLikeMeCounts = likedVlogCounts + likedVlogerCounts;
+
+ usersVO.setMyFollowsCounts(myFollowsCounts);
+ usersVO.setMyFansCounts(myFansCounts);
+ usersVO.setTotalLikeMeCounts(totalLikeMeCounts);
+
+ //usersVO.setMyFansCounts((Integer) myFansCounts);
+
+ return GraceJSONResult.ok(usersVO);
+ }
+
+ @PostMapping("modifyUserInfo")
+ public GraceJSONResult modifyUserInfo(@RequestBody UpdatedUserBO updatedUserBO, @RequestParam Integer type) throws Exception {
+
+ UserInfoModifyType.checkUserInfoTypeIsRight(type);
+ Users newUserInfo = userService.updateUserInfo(updatedUserBO, type);
+ return GraceJSONResult.ok(newUserInfo);
+ }
+
+ @Autowired
+ private MinIOConfig minIOConfig;
+
+ @PostMapping("modifyImage")
+ public GraceJSONResult modifyImage(@RequestParam String userId,
+ @RequestParam Integer type,
+ MultipartFile file) throws Exception {
+
+ if (type != FileTypeEnum.BGIMG.type && type != FileTypeEnum.FACE.type) {
+ return GraceJSONResult.errorCustom(ResponseStatusEnum.FILE_UPLOAD_FAILD);
+ }
+
+ String fileName = file.getOriginalFilename();
+
+ MinIOUtils.uploadFile(minIOConfig.getBucketName(),
+ fileName,
+ file.getInputStream());
+
+ String imgUrl = minIOConfig.getFileHost()
+ + "/"
+ + minIOConfig.getBucketName()
+ + "/"
+ + fileName;
+
+
+ // 修改图片地址到数据库
+ UpdatedUserBO updatedUserBO = new UpdatedUserBO();
+ updatedUserBO.setId(userId);
+
+ if (type == FileTypeEnum.BGIMG.type) {
+ updatedUserBO.setBgImg(imgUrl);
+ } else {
+ updatedUserBO.setFace(imgUrl);
+ }
+ Users users = userService.updateUserInfo(updatedUserBO);
+
+ return GraceJSONResult.ok(users);
+ }
+
+
+
+}
diff --git a/book-api/src/main/java/com/imooc/controller/VlogController.java b/book-api/src/main/java/com/imooc/controller/VlogController.java
new file mode 100644
index 0000000..b20673b
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/controller/VlogController.java
@@ -0,0 +1,225 @@
+package com.imooc.controller;
+
+import com.imooc.base.BaseInfoProperties;
+import com.imooc.bo.VlogBO;
+import com.imooc.enums.YesOrNo;
+import com.imooc.grace.result.GraceJSONResult;
+import com.imooc.service.VlogService;
+import com.imooc.utils.PagedGridResult;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.web.bind.annotation.*;
+
+@Slf4j
+@Api(tags = "VlogController 短视频相关业务功能的接口")
+@RequestMapping("vlog")
+@RestController
+@RefreshScope
+public class VlogController extends BaseInfoProperties {
+
+ @Autowired
+ private VlogService vlogService;
+
+ @PostMapping("publish")
+ public GraceJSONResult publish(@RequestBody VlogBO vlogBO) {
+ // FIXME 作业,校验VlogBO
+ vlogService.createVlog(vlogBO);
+ return GraceJSONResult.ok();
+ }
+
+ @GetMapping("indexList")
+ public GraceJSONResult indexList(@RequestParam(defaultValue = "") String userId,
+ @RequestParam(defaultValue = "") String search,
+ @RequestParam Integer page,
+ @RequestParam Integer pageSize) {
+
+ if (page == null) {
+ page = COMMON_START_PAGE;
+ }
+ if (pageSize == null) {
+ pageSize = COMMON_PAGE_SIZE;
+ }
+
+ PagedGridResult gridResult = vlogService.getIndexVlogList(userId, search, page, pageSize);
+ return GraceJSONResult.ok(gridResult);
+ }
+
+ @GetMapping("detail")
+ public GraceJSONResult detail(@RequestParam(defaultValue = "") String userId,
+ @RequestParam String vlogId) {
+ return GraceJSONResult.ok(vlogService.getVlogDetailById(userId, vlogId));
+ }
+
+
+ @PostMapping("changeToPrivate")
+ public GraceJSONResult changeToPrivate(@RequestParam String userId,
+ @RequestParam String vlogId) {
+ vlogService.changeToPrivateOrPublic(userId,
+ vlogId,
+ YesOrNo.YES.type);
+ return GraceJSONResult.ok();
+ }
+
+ @PostMapping("changeToPublic")
+ public GraceJSONResult changeToPublic(@RequestParam String userId,
+ @RequestParam String vlogId) {
+ vlogService.changeToPrivateOrPublic(userId,
+ vlogId,
+ YesOrNo.NO.type);
+ return GraceJSONResult.ok();
+ }
+
+
+
+ @GetMapping("myPublicList")
+ public GraceJSONResult myPublicList(@RequestParam String userId,
+ @RequestParam Integer page,
+ @RequestParam Integer pageSize) {
+
+ if (page == null) {
+ page = COMMON_START_PAGE;
+ }
+ if (pageSize == null) {
+ pageSize = COMMON_PAGE_SIZE;
+ }
+
+ PagedGridResult gridResult = vlogService.queryMyVlogList(userId,
+ page,
+ pageSize,
+ YesOrNo.NO.type);
+ return GraceJSONResult.ok(gridResult);
+ }
+
+ @GetMapping("myPrivateList")
+ public GraceJSONResult myPrivateList(@RequestParam String userId,
+ @RequestParam Integer page,
+ @RequestParam Integer pageSize) {
+
+ if (page == null) {
+ page = COMMON_START_PAGE;
+ }
+ if (pageSize == null) {
+ pageSize = COMMON_PAGE_SIZE;
+ }
+
+ PagedGridResult gridResult = vlogService.queryMyVlogList(userId,
+ page,
+ pageSize,
+ YesOrNo.YES.type);
+ return GraceJSONResult.ok(gridResult);
+ }
+
+ @GetMapping("myLikedList")
+ public GraceJSONResult myLikedList(@RequestParam String userId,
+ @RequestParam Integer page,
+ @RequestParam Integer pageSize) {
+
+ if (page == null) {
+ page = COMMON_START_PAGE;
+ }
+ if (pageSize == null) {
+ pageSize = COMMON_PAGE_SIZE;
+ }
+
+ PagedGridResult gridResult = vlogService.getMyLikedVlogList(userId,
+ page,
+ pageSize);
+ return GraceJSONResult.ok(gridResult);
+ }
+
+ @Value(("${nacos.counts}"))
+ private Integer nacosConuts;
+
+
+ @PostMapping("like")
+ public GraceJSONResult like(@RequestParam String userId,
+ @RequestParam String vlogerId,
+ @RequestParam String vlogId) {
+
+ // 我点赞的视频,关联关系保存到数据库
+ vlogService.userLikeVlog(userId, vlogId);
+
+ // 点赞后,视频和视频发布者的获赞都会 +1
+ redis.increment(REDIS_VLOGER_BE_LIKED_COUNTS + ":" + vlogerId, 1);
+ redis.increment(REDIS_VLOG_BE_LIKED_COUNTS + ":" + vlogId, 1);
+
+ // 我点赞的视频,需要在redis中保存关联关系
+ redis.set(REDIS_USER_LIKE_VLOG + ":" + userId + ":" + vlogId, "1");
+
+ log.info("nacosConuts="+nacosConuts);
+
+ String countsStr = redis.get(REDIS_VLOG_BE_LIKED_COUNTS + ":" + vlogId);
+ Integer counts=0;
+ if (StringUtils.isNotBlank(countsStr)){
+
+ counts=Integer.valueOf(countsStr);
+ if (counts>=nacosConuts){
+
+ vlogService.flushCounts(vlogId, counts);
+ }
+ }
+
+ return GraceJSONResult.ok();
+ }
+
+
+ @PostMapping("unlike")
+ public GraceJSONResult unlike(@RequestParam String userId,
+ @RequestParam String vlogerId,
+ @RequestParam String vlogId) {
+
+ // 我取消点赞的视频,关联关系删除
+ vlogService.userUnLikeVlog(userId, vlogId);
+
+ redis.decrement(REDIS_VLOGER_BE_LIKED_COUNTS + ":" + vlogerId, 1);
+ redis.decrement(REDIS_VLOG_BE_LIKED_COUNTS + ":" + vlogId, 1);
+ redis.del(REDIS_USER_LIKE_VLOG + ":" + userId + ":" + vlogId);
+
+ return GraceJSONResult.ok();
+ }
+
+ @PostMapping("totalLikedCounts")
+ public GraceJSONResult totalLikedCounts(@RequestParam String vlogId) {
+ return GraceJSONResult.ok(vlogService.getVlogBeLikedCounts(vlogId));
+ }
+
+ @GetMapping("followList")
+ public GraceJSONResult followList(@RequestParam String myId,
+ @RequestParam Integer page,
+ @RequestParam Integer pageSize) {
+
+ if (page == null) {
+ page = COMMON_START_PAGE;
+ }
+ if (pageSize == null) {
+ pageSize = COMMON_PAGE_SIZE;
+ }
+
+ PagedGridResult gridResult = vlogService.getMyFollowVlogList(myId,
+ page,
+ pageSize);
+ return GraceJSONResult.ok(gridResult);
+ }
+
+ @GetMapping("friendList")
+ public GraceJSONResult friendList(@RequestParam String myId,
+ @RequestParam Integer page,
+ @RequestParam Integer pageSize) {
+
+ if (page == null) {
+ page = COMMON_START_PAGE;
+ }
+ if (pageSize == null) {
+ pageSize = COMMON_PAGE_SIZE;
+ }
+
+ PagedGridResult gridResult = vlogService.getMyFriendVlogList(myId,
+ page,
+ pageSize);
+ return GraceJSONResult.ok(gridResult);
+ }
+}
diff --git a/book-api/src/main/java/com/imooc/intercepter/PassportInterceptor.java b/book-api/src/main/java/com/imooc/intercepter/PassportInterceptor.java
new file mode 100644
index 0000000..cdc0d12
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/intercepter/PassportInterceptor.java
@@ -0,0 +1,47 @@
+package com.imooc.intercepter;
+
+import com.imooc.base.BaseInfoProperties;
+import com.imooc.exceptions.GraceException;
+import com.imooc.grace.result.ResponseStatusEnum;
+import com.imooc.utils.IPUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@Slf4j
+public class PassportInterceptor extends BaseInfoProperties implements HandlerInterceptor {
+
+ @Override
+ public boolean preHandle(HttpServletRequest request,
+ HttpServletResponse response, Object handler) throws Exception {
+
+ // 获得用户的ip
+ String userIp = IPUtil.getRequestIp(request);
+
+ // 得到是否存在的判断
+ boolean keyIsExist = redis.keyIsExist(MOBILE_SMSCODE + ":" + userIp);
+
+ if (keyIsExist) {
+ GraceException.display(ResponseStatusEnum.SMS_NEED_WAIT_ERROR);
+ log.info("短信发送频率太大!");
+ return false;
+ }
+
+ /**
+ * true: 请求放行
+ * false: 请求拦截
+ */
+ return true;
+ }
+
+ @Override
+ public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
+ }
+
+ @Override
+ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+ }
+}
diff --git a/book-api/src/main/java/com/imooc/intercepter/UserTokenInterceptor.java b/book-api/src/main/java/com/imooc/intercepter/UserTokenInterceptor.java
new file mode 100644
index 0000000..e88aff1
--- /dev/null
+++ b/book-api/src/main/java/com/imooc/intercepter/UserTokenInterceptor.java
@@ -0,0 +1,58 @@
+package com.imooc.intercepter;
+
+import com.imooc.base.BaseInfoProperties;
+import com.imooc.exceptions.GraceException;
+import com.imooc.grace.result.ResponseStatusEnum;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@Slf4j
+public class UserTokenInterceptor extends BaseInfoProperties implements HandlerInterceptor {
+
+ @Override
+ public boolean preHandle(HttpServletRequest request,
+ HttpServletResponse response, Object handler) throws Exception {
+
+
+ // 从header中获得用户id和token
+ String userId = request.getHeader("headerUserId");
+ String userToken = request.getHeader("headerUserToken");
+
+ // 判断header中用户id和token不能为空
+ if (StringUtils.isNotBlank(userId) && StringUtils.isNotBlank(userToken)) {
+ String redisToken = redis.get(REDIS_USER_TOKEN + ":" + userId);
+ if (StringUtils.isBlank(redisToken)) {
+ GraceException.display(ResponseStatusEnum.UN_LOGIN);
+ return false;
+ } else {
+ // 比较token是否一致,如果不一致,表示用户在别的手机端登录
+ if (!redisToken.equalsIgnoreCase(userToken)) {
+ GraceException.display(ResponseStatusEnum.TICKET_INVALID);
+ return false;
+ }
+ }
+ } else {
+ GraceException.display(ResponseStatusEnum.UN_LOGIN);
+ return false;
+ }
+
+ /**
+ * true: 请求放行
+ * false: 请求拦截
+ */
+ return true;
+ }
+
+ @Override
+ public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
+ }
+
+ @Override
+ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+ }
+}
diff --git a/book-api/src/main/resources/application-dev.yml b/book-api/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..08a51ec
--- /dev/null
+++ b/book-api/src/main/resources/application-dev.yml
@@ -0,0 +1,65 @@
+server:
+ port: ${port:8099}
+
+spring:
+ datasource: # 数据源的相关配置
+ type: com.zaxxer.hikari.HikariDataSource # 数据源的类型,可以更改为其他的数据源配置,比如druid
+ driver-class-name: com.mysql.cj.jdbc.Driver # mysql/MariaDB 的数据库驱动类名称
+ url: jdbc:mysql://182.92.182.217:3306/tiktok?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
+ username: tiktok
+ password: Bc3T5AA2pBdt2FBk
+ hikari:
+ connection-timeout: 30000 # 等待连接池分配连接的最大时间(毫秒),超过这个时长还没有可用的连接,则会抛出SQLException
+ minimum-idle: 5 # 最小连接数
+ maximum-pool-size: 20 # 最大连接数
+ auto-commit: true # 自动提交
+ idle-timeout: 600000 # 连接超时的最大时长(毫秒),超时则会被释放(retired)
+ pool-name: DataSourceHikariCP # 连接池的名字
+ max-lifetime: 18000000 # 连接池的最大生命时长(毫秒),超时则会被释放(retired)
+ connection-test-query: SELECT 1
+ redis:
+ host: 182.92.182.217
+ port: 6379
+ password: '!aw5)lJf'
+ database: 1 # 使用的数据库编号
+ jedis:
+ pool:
+ max-idle: 6 # 最大空闲连接
+ max-active: 32 # 连接池最大连接数
+ max-wait: 100 # 连接池最大阻塞等待时间, -1表示没有限制
+ min-idle: 4 # 最小空闲连接
+ timeout: 50000
+ data:
+ mongodb:
+# uri: mongodb://root:root@192.168.1.202:27017
+# database: imooc-red-book
+ uri: mongodb://admin:A1969bf8@82.156.121.2:37017/admin
+ rabbitmq:
+ host: 182.92.182.217
+ port: 5672
+ username: admin
+ password: 123123
+ virtual-host: imooc-red-book
+ application:
+ name: imooc-red-book-nacos
+ cloud:
+ nacos:
+ discovery:
+ server-addr: 182.92.182.217:8848 # nacos 所在的地址
+
+# 打开监控
+management:
+ endpoint:
+ web:
+ exposure:
+ include: '*'
+
+# MinIO 配置
+minio:
+ endpoint: http://82.156.121.2:29000 # MinIO服务地址
+ fileHost: http://82.156.121.2:29000 # 文件地址host
+ bucketName: bucket # 存储桶bucket名称
+ accessKey: NJ2GN2wLVkMnyrznbE9t # 用户名
+ secretKey: nrT3e3pRWF5HXQRiIxxDhq20eJ0YrN8lvx5p8bK6 # 密码
+ imgSize: 1024 # 图片大小限制,单位:m
+ fileSize: 1024 # 文件大小限制,单位:m
diff --git a/book-api/src/main/resources/application-prod.yml b/book-api/src/main/resources/application-prod.yml
new file mode 100644
index 0000000..20378e0
--- /dev/null
+++ b/book-api/src/main/resources/application-prod.yml
@@ -0,0 +1,65 @@
+server:
+ port: 8080
+
+spring:
+ datasource: # 数据源的相关配置
+ type: com.zaxxer.hikari.HikariDataSource # 数据源的类型,可以更改为其他的数据源配置,比如druid
+ driver-class-name: com.mysql.cj.jdbc.Driver # mysql/MariaDB 的数据库驱动类名称
+ url: jdbc:mysql://182.92.182.217/tiktok?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
+ username: tiktok
+ password: Bc3T5AA2pBdt2FBk
+ hikari:
+ connection-timeout: 30000 # 等待连接池分配连接的最大时间(毫秒),超过这个时长还没有可用的连接,则会抛出SQLException
+ minimum-idle: 5 # 最小连接数
+ maximum-pool-size: 20 # 最大连接数
+ auto-commit: true # 自动提交
+ idle-timeout: 600000 # 连接超时的最大时长(毫秒),超时则会被释放(retired)
+ pool-name: DataSourceHikariCP # 连接池的名字
+ max-lifetime: 18000000 # 连接池的最大生命时长(毫秒),超时则会被释放(retired)
+ connection-test-query: SELECT 1
+ redis:
+ host: 182.92.182.217
+ port: 6379
+ password: '!aw5)lJf'
+ database: 1 # 使用的数据库编号
+ jedis:
+ pool:
+ max-idle: 6 # 最大空闲连接
+ max-active: 32 # 连接池最大连接数
+ max-wait: 100 # 连接池最大阻塞等待时间, -1表示没有限制
+ min-idle: 4 # 最小空闲连接
+ timeout: 50000
+ data:
+ mongodb:
+ uri: mongodb://admin:A1969bf8@82.156.121.2:37017/admin
+ rabbitmq:
+ host: 182.92.182.217
+ port: 5672
+ username: admin
+ password: 123123
+ virtual-host: imooc-red-book
+ application:
+ name: imooc-red-book-nacos
+ cloud:
+ nacos:
+ discovery:
+ server-addr: 182.92.182.217:8848 # nacos 所在的地址
+
+
+# 打开监控
+management:
+ endpoint:
+ web:
+ exposure:
+ include: '*'
+
+
+# MinIO 配置
+minio:
+ endpoint: http://82.156.121.2:29000 # MinIO服务地址
+ fileHost: http://82.156.121.2:29000 # 文件地址host
+ bucketName: bucket # 存储桶bucket名称
+ accessKey: NJ2GN2wLVkMnyrznbE9t # 用户名
+ secretKey: nrT3e3pRWF5HXQRiIxxDhq20eJ0YrN8lvx5p8bK6 # 密码
+ imgSize: 1024 # 图片大小限制,单位:m
+ fileSize: 1024 # 文件大小限制,单位:m
\ No newline at end of file
diff --git a/book-api/src/main/resources/application.yml b/book-api/src/main/resources/application.yml
new file mode 100644
index 0000000..bd6daaf
--- /dev/null
+++ b/book-api/src/main/resources/application.yml
@@ -0,0 +1,43 @@
+server:
+# port: 8099
+ tomcat:
+ uri-encoding: UTF-8
+ max-swallow-size: -1 # tomcat默认大小2M,超过2M的文件不会被捕获,需要调整此处大小为100MB或者-1即可
+
+spring:
+ application:
+ name: imooc-red-book-nacos
+ profiles:
+ active: dev
+ nacos:
+ counts: 10
+ banner:
+ location: classpath:banner/banner.txt
+ servlet:
+ multipart:
+ max-file-size: 1024MB # 文件上传大小限制,设置最大值,不能超过该值,否则报错
+# max-file-size: 500KB # 文件上传大小限制,设置最大值,不能超过该值,否则报错
+ max-request-size: 1024MB # 文件最大请求限制,用于批量上传
+# max-request-size: 500KB
+nacos:
+ counts: 10
+# 整合mybatis
+mybatis:
+ type-aliases-package: com.imooc.pojo # 所有pojo类所在的包路径
+ mapper-locations: classpath:mapper/*.xml # mapper映射文件
+
+# 通用mapper工具的配置
+mapper:
+ mappers: com.imooc.my.mapper.MyMapper # 配置MyMapper,包含了一些封装好的CRUD方法
+ not-empty: false # 在进行数据库操作的时候,username != null 是否会追加 username != ''
+ identity: MYSQL
+
+# 分页插件助手的配置
+pagehelper:
+ helper-dialect: MYSQL
+ support-methods-arguments: true
+
+# 日志级别
+logging:
+ level:
+ root: info
diff --git a/book-api/src/main/resources/banner/banner.txt b/book-api/src/main/resources/banner/banner.txt
new file mode 100644
index 0000000..3d94420
--- /dev/null
+++ b/book-api/src/main/resources/banner/banner.txt
@@ -0,0 +1,22 @@
+////////////////////////////////////////////////////////////////////
+// _ooOoo_ //
+// o8888888o //
+// 88" . "88 //
+// (| ^_^ |) //
+// O\ = /O //
+// ____/`---'\____ //
+// .' \\| |// `. //
+// / \\||| : |||// \ //
+// / _||||| -:- |||||- \ //
+// | | \\\ - /// | | //
+// | \_| ''\---/'' | | //
+// \ .-\__ `-` ___/-. / //
+// ___`. .' /--.--\ `. . ___ //
+// ."" '< `.___\_<|>_/___.' >'"". //
+// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
+// \ \ `-. \_ __\ /__ _/ .-` / / //
+// ========`-.____`-.___\_____/___.-`____.-'======== //
+// `=---=' //
+// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
+// 佛祖保佑 永无BUG 永不修改 //
+////////////////////////////////////////////////////////////////////
\ No newline at end of file
diff --git a/book-api/src/main/resources/banner/cat.png b/book-api/src/main/resources/banner/cat.png
new file mode 100644
index 0000000000000000000000000000000000000000..f9cece46583a4a2928ded0964dcf9e35c9482030
GIT binary patch
literal 918517
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 Jp!
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