From 8fa5b96104f5960206499f01d41b8d65d982c37c Mon Sep 17 00:00:00 2001
From: wol <1293433164@qq.com>
Date: Sun, 22 Dec 2024 21:44:29 +0800
Subject: [PATCH] 102
---
weblog-springboot-102/pom.xml | 211 ++++++++++++++++++
.../weblog-module-admin/.gitignore | 33 +++
.../weblog-module-admin/pom.xml | 78 +++++++
.../admin/config/Knife4jAdminConfig.java | 53 +++++
.../weblog/admin/config/MinioConfig.java | 27 +++
.../weblog/admin/config/MinioProperties.java | 21 ++
.../admin/config/WebSecurityConfig.java | 65 ++++++
.../controller/AdminArticleController.java | 39 ++++
.../AdminBlogSettingsController.java | 48 ++++
.../controller/AdminCategoryController.java | 67 ++++++
.../admin/controller/AdminFileController.java | 38 ++++
.../admin/controller/AdminTagController.java | 65 ++++++
.../admin/controller/AdminUserController.java | 46 ++++
.../admin/convert/BlogSettingsConvert.java | 36 +++
.../weblog/admin/model/package-info.java | 7 +
.../model/vo/article/PublishArticleReqVO.java | 44 ++++
.../blogsettings/FindBlogSettingsRspVO.java | 40 ++++
.../blogsettings/UpdateBlogSettingsReqVO.java | 47 ++++
.../model/vo/category/AddCategoryReqVO.java | 30 +++
.../vo/category/DeleteCategoryReqVO.java | 29 +++
.../category/FindCategoryPageListReqVO.java | 43 ++++
.../category/FindCategoryPageListRspVO.java | 40 ++++
.../admin/model/vo/file/UploadFileRspVO.java | 27 +++
.../admin/model/vo/tag/AddTagReqVO.java | 30 +++
.../admin/model/vo/tag/DeleteTagReqVO.java | 27 +++
.../model/vo/tag/FindTagPageListReqVO.java | 40 ++++
.../model/vo/tag/FindTagPageListRspVO.java | 37 +++
.../admin/model/vo/tag/SearchTagsReqVO.java | 27 +++
.../model/vo/user/FindUserInfoRspVO.java | 28 +++
.../vo/user/UpdateAdminUserPasswordReqVO.java | 31 +++
.../quanxiaoha/weblog/admin/package-info.java | 7 +
.../admin/service/AdminArticleService.java | 20 ++
.../service/AdminBlogSettingsService.java | 26 +++
.../admin/service/AdminCategoryService.java | 45 ++++
.../admin/service/AdminFileService.java | 20 ++
.../weblog/admin/service/AdminTagService.java | 45 ++++
.../admin/service/AdminUserService.java | 25 +++
.../service/impl/AdminArticleServiceImpl.java | 100 +++++++++
.../impl/AdminBlogSettingsServiceImpl.java | 61 +++++
.../impl/AdminCategoryServiceImpl.java | 157 +++++++++++++
.../service/impl/AdminFileServiceImpl.java | 55 +++++
.../service/impl/AdminTagServiceImpl.java | 139 ++++++++++++
.../service/impl/AdminUserServiceImpl.java | 62 +++++
.../weblog/admin/service/package-info.java | 7 +
.../weblog/admin/utils/MinioUtil.java | 75 +++++++
.../WeblogModuleAdminApplicationTests.java | 25 +++
.../weblog-module-common/.gitignore | 33 +++
.../weblog-module-common/pom.xml | 69 ++++++
.../weblog/common/aspect/ApiOperationLog.java | 17 ++
.../common/aspect/ApiOperationLogAspect.java | 102 +++++++++
.../weblog/common/config/JacksonConfig.java | 60 +++++
.../common/config/MybatisPlusConfig.java | 29 +++
.../domain/dos/ArticleCategoryRelDO.java | 30 +++
.../common/domain/dos/ArticleContentDO.java | 31 +++
.../weblog/common/domain/dos/ArticleDO.java | 42 ++++
.../common/domain/dos/ArticleTagRelDO.java | 30 +++
.../common/domain/dos/BlogSettingsDO.java | 46 ++++
.../weblog/common/domain/dos/CategoryDO.java | 36 +++
.../weblog/common/domain/dos/TagDO.java | 36 +++
.../weblog/common/domain/dos/UserDO.java | 38 ++++
.../weblog/common/domain/dos/UserRoleDO.java | 20 ++
.../mapper/ArticleCategoryRelMapper.java | 14 ++
.../domain/mapper/ArticleContentMapper.java | 14 ++
.../common/domain/mapper/ArticleMapper.java | 14 ++
.../domain/mapper/ArticleTagRelMapper.java | 14 ++
.../domain/mapper/BlogSettingsMapper.java | 18 ++
.../common/domain/mapper/CategoryMapper.java | 54 +++++
.../common/domain/mapper/TagMapper.java | 58 +++++
.../common/domain/mapper/UserMapper.java | 33 +++
.../common/domain/mapper/UserRoleMapper.java | 27 +++
.../weblog/common/domain/package-info.java | 7 +
.../weblog/common/enums/ResponseCodeEnum.java | 40 ++++
.../exception/BaseExceptionInterface.java | 13 ++
.../weblog/common/exception/BizException.java | 24 ++
.../exception/GlobalExceptionHandler.java | 92 ++++++++
.../weblog/common/model/BasePageQuery.java | 23 ++
.../weblog/common/model/package-info.java | 7 +
.../weblog/common/model/vo/SelectRspVO.java | 28 +++
.../weblog/common/package-info.java | 7 +
.../weblog/common/utils/JsonUtil.java | 31 +++
.../weblog/common/utils/PageResponse.java | 60 +++++
.../weblog/common/utils/Response.java | 77 +++++++
.../WeblogModuleCommonApplicationTests.java | 23 ++
.../weblog-module-jwt/.gitignore | 33 +++
.../weblog-module-jwt/pom.xml | 74 ++++++
.../JwtAuthenticationSecurityConfig.java | 58 +++++
.../jwt/config/PasswordEncoderConfig.java | 27 +++
.../UsernameOrPasswordNullException.java | 19 ++
.../jwt/filter/JwtAuthenticationFilter.java | 59 +++++
.../jwt/filter/TokenAuthenticationFilter.java | 107 +++++++++
.../jwt/handler/RestAccessDeniedHandler.java | 32 +++
.../handler/RestAuthenticationEntryPoint.java | 38 ++++
.../RestAuthenticationFailureHandler.java | 43 ++++
.../RestAuthenticationSuccessHandler.java | 47 ++++
.../weblog/jwt/model/LoginRspVO.java | 25 +++
.../jwt/service/UserDetailServiceImpl.java | 63 ++++++
.../weblog/jwt/utils/JwtTokenHelper.java | 146 ++++++++++++
.../weblog/jwt/utils/ResultUtil.java | 73 ++++++
.../jwt/WeblogModuleJwtApplicationTests.java | 16 ++
weblog-springboot-102/weblog-web/.gitignore | 33 +++
weblog-springboot-102/weblog-web/pom.xml | 79 +++++++
.../weblog/web/WeblogWebApplication.java | 15 ++
.../weblog/web/config/Knife4jConfig.java | 53 +++++
.../weblog/web/controller/TestController.java | 54 +++++
.../com/quanxiaoha/weblog/web/model/User.java | 50 +++++
.../src/main/resources/application-dev.yml | 27 +++
.../src/main/resources/application-prod.yml | 27 +++
.../src/main/resources/application.yml | 18 ++
.../src/main/resources/logback-weblog.xml | 46 ++++
.../src/main/resources/spy.properties | 24 ++
.../weblog/web/WeblogWebApplicationTests.java | 86 +++++++
111 files changed, 4892 insertions(+)
create mode 100644 weblog-springboot-102/pom.xml
create mode 100644 weblog-springboot-102/weblog-module-admin/.gitignore
create mode 100644 weblog-springboot-102/weblog-module-admin/pom.xml
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/Knife4jAdminConfig.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/MinioConfig.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/MinioProperties.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/WebSecurityConfig.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminArticleController.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminBlogSettingsController.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminCategoryController.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminFileController.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminTagController.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminUserController.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/convert/BlogSettingsConvert.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/package-info.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/article/PublishArticleReqVO.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/blogsettings/FindBlogSettingsRspVO.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/blogsettings/UpdateBlogSettingsReqVO.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/AddCategoryReqVO.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/DeleteCategoryReqVO.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/FindCategoryPageListReqVO.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/FindCategoryPageListRspVO.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/file/UploadFileRspVO.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/AddTagReqVO.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/DeleteTagReqVO.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/FindTagPageListReqVO.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/FindTagPageListRspVO.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/SearchTagsReqVO.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/user/FindUserInfoRspVO.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/user/UpdateAdminUserPasswordReqVO.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/package-info.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminArticleService.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminBlogSettingsService.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminCategoryService.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminFileService.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminTagService.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminUserService.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminArticleServiceImpl.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminBlogSettingsServiceImpl.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminCategoryServiceImpl.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminFileServiceImpl.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminTagServiceImpl.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminUserServiceImpl.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/package-info.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/utils/MinioUtil.java
create mode 100644 weblog-springboot-102/weblog-module-admin/src/test/java/com/quanxiaoha/weblog/admin/WeblogModuleAdminApplicationTests.java
create mode 100644 weblog-springboot-102/weblog-module-common/.gitignore
create mode 100644 weblog-springboot-102/weblog-module-common/pom.xml
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLog.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLogAspect.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/config/JacksonConfig.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/config/MybatisPlusConfig.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/dos/ArticleCategoryRelDO.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/dos/ArticleContentDO.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/dos/ArticleDO.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/dos/ArticleTagRelDO.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/dos/BlogSettingsDO.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/dos/CategoryDO.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/dos/TagDO.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/dos/UserDO.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/dos/UserRoleDO.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/mapper/ArticleCategoryRelMapper.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/mapper/ArticleContentMapper.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/mapper/ArticleMapper.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/mapper/ArticleTagRelMapper.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/mapper/BlogSettingsMapper.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/mapper/CategoryMapper.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/mapper/TagMapper.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/mapper/UserMapper.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/mapper/UserRoleMapper.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/domain/package-info.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/enums/ResponseCodeEnum.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/exception/BaseExceptionInterface.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/exception/BizException.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/exception/GlobalExceptionHandler.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/model/BasePageQuery.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/model/package-info.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/model/vo/SelectRspVO.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/package-info.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/utils/JsonUtil.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/utils/PageResponse.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/utils/Response.java
create mode 100644 weblog-springboot-102/weblog-module-common/src/test/java/com/quanxiaoha/weblog/common/WeblogModuleCommonApplicationTests.java
create mode 100644 weblog-springboot-102/weblog-module-jwt/.gitignore
create mode 100644 weblog-springboot-102/weblog-module-jwt/pom.xml
create mode 100644 weblog-springboot-102/weblog-module-jwt/src/main/java/com/quanxiaoha/weblog/jwt/config/JwtAuthenticationSecurityConfig.java
create mode 100644 weblog-springboot-102/weblog-module-jwt/src/main/java/com/quanxiaoha/weblog/jwt/config/PasswordEncoderConfig.java
create mode 100644 weblog-springboot-102/weblog-module-jwt/src/main/java/com/quanxiaoha/weblog/jwt/exception/UsernameOrPasswordNullException.java
create mode 100644 weblog-springboot-102/weblog-module-jwt/src/main/java/com/quanxiaoha/weblog/jwt/filter/JwtAuthenticationFilter.java
create mode 100644 weblog-springboot-102/weblog-module-jwt/src/main/java/com/quanxiaoha/weblog/jwt/filter/TokenAuthenticationFilter.java
create mode 100644 weblog-springboot-102/weblog-module-jwt/src/main/java/com/quanxiaoha/weblog/jwt/handler/RestAccessDeniedHandler.java
create mode 100644 weblog-springboot-102/weblog-module-jwt/src/main/java/com/quanxiaoha/weblog/jwt/handler/RestAuthenticationEntryPoint.java
create mode 100644 weblog-springboot-102/weblog-module-jwt/src/main/java/com/quanxiaoha/weblog/jwt/handler/RestAuthenticationFailureHandler.java
create mode 100644 weblog-springboot-102/weblog-module-jwt/src/main/java/com/quanxiaoha/weblog/jwt/handler/RestAuthenticationSuccessHandler.java
create mode 100644 weblog-springboot-102/weblog-module-jwt/src/main/java/com/quanxiaoha/weblog/jwt/model/LoginRspVO.java
create mode 100644 weblog-springboot-102/weblog-module-jwt/src/main/java/com/quanxiaoha/weblog/jwt/service/UserDetailServiceImpl.java
create mode 100644 weblog-springboot-102/weblog-module-jwt/src/main/java/com/quanxiaoha/weblog/jwt/utils/JwtTokenHelper.java
create mode 100644 weblog-springboot-102/weblog-module-jwt/src/main/java/com/quanxiaoha/weblog/jwt/utils/ResultUtil.java
create mode 100644 weblog-springboot-102/weblog-module-jwt/src/test/java/com/quanxiaoha/weblog/jwt/WeblogModuleJwtApplicationTests.java
create mode 100644 weblog-springboot-102/weblog-web/.gitignore
create mode 100644 weblog-springboot-102/weblog-web/pom.xml
create mode 100644 weblog-springboot-102/weblog-web/src/main/java/com/quanxiaoha/weblog/web/WeblogWebApplication.java
create mode 100644 weblog-springboot-102/weblog-web/src/main/java/com/quanxiaoha/weblog/web/config/Knife4jConfig.java
create mode 100644 weblog-springboot-102/weblog-web/src/main/java/com/quanxiaoha/weblog/web/controller/TestController.java
create mode 100644 weblog-springboot-102/weblog-web/src/main/java/com/quanxiaoha/weblog/web/model/User.java
create mode 100644 weblog-springboot-102/weblog-web/src/main/resources/application-dev.yml
create mode 100644 weblog-springboot-102/weblog-web/src/main/resources/application-prod.yml
create mode 100644 weblog-springboot-102/weblog-web/src/main/resources/application.yml
create mode 100644 weblog-springboot-102/weblog-web/src/main/resources/logback-weblog.xml
create mode 100644 weblog-springboot-102/weblog-web/src/main/resources/spy.properties
create mode 100644 weblog-springboot-102/weblog-web/src/test/java/com/quanxiaoha/weblog/web/WeblogWebApplicationTests.java
diff --git a/weblog-springboot-102/pom.xml b/weblog-springboot-102/pom.xml
new file mode 100644
index 0000000..5173976
--- /dev/null
+++ b/weblog-springboot-102/pom.xml
@@ -0,0 +1,211 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+
+ 2.6.3
+
+
+
+ com.quanxiaoha
+ weblog-springboot
+ ${revision}
+ weblog-springboot
+
+ 前后端分离博客 Weblog By 犬小哈
+
+
+ pom
+
+
+
+
+ weblog-web
+
+ weblog-module-admin
+
+ weblog-module-common
+
+ weblog-module-jwt
+
+
+
+
+
+
+ 0.0.1-SNAPSHOT
+ 1.8
+ UTF-8
+
+ ${java.version}
+ ${java.version}
+
+
+ 1.18.28
+ 31.1-jre
+ 3.12.0
+ 2.15.2
+ 4.3.0
+ 3.5.2
+ 3.9.1
+ 0.11.2
+ 8.2.1
+ 1.5.5.Final
+
+
+
+
+
+
+ com.quanxiaoha
+ weblog-module-admin
+ ${revision}
+
+
+
+ com.quanxiaoha
+ weblog-module-common
+ ${revision}
+
+
+
+ com.quanxiaoha
+ weblog-module-jwt
+ ${revision}
+
+
+
+
+ com.google.guava
+ guava
+ ${guava.version}
+
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.version}
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${jackson.version}
+
+
+
+
+
+ com.github.xiaoymin
+ knife4j-openapi2-spring-boot-starter
+ ${knife4j.version}
+
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ ${mybatis-plus.version}
+
+
+
+ p6spy
+ p6spy
+ ${p6spy.version}
+
+
+
+
+ io.jsonwebtoken
+ jjwt-api
+ ${jjwt.version}
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ ${jjwt.version}
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ ${jjwt.version}
+
+
+
+
+ io.minio
+ minio
+ ${minio.version}
+
+
+
+
+ org.mapstruct
+ mapstruct
+ ${mapstruct.version}
+
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ ${java.version}
+ ${java.version}
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+
+
+ org.mapstruct
+ mapstruct-processor
+ ${mapstruct.version}
+
+
+
+
+
+
+
+
+
+
+
+ aliyunmaven
+ aliyun
+ https://maven.aliyun.com/repository/public
+
+
+
diff --git a/weblog-springboot-102/weblog-module-admin/.gitignore b/weblog-springboot-102/weblog-module-admin/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/weblog-springboot-102/weblog-module-admin/pom.xml b/weblog-springboot-102/weblog-module-admin/pom.xml
new file mode 100644
index 0000000..536651a
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/pom.xml
@@ -0,0 +1,78 @@
+
+
+ 4.0.0
+
+
+ com.quanxiaoha
+ weblog-springboot
+ ${revision}
+
+
+ com.quanxiaoha
+ weblog-module-admin
+ weblog-module-admin
+ weblog-admin (负责管理后台相关功能)
+
+
+
+ com.quanxiaoha
+ weblog-module-common
+
+
+
+ com.quanxiaoha
+ weblog-module-jwt
+
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+ com.github.xiaoymin
+ knife4j-openapi2-spring-boot-starter
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+
+ jakarta.validation
+ jakarta.validation-api
+
+
+ org.hibernate.validator
+ hibernate-validator
+
+
+
+
+ io.minio
+ minio
+
+
+
+ org.mapstruct
+ mapstruct
+
+
+
+
+
+
\ No newline at end of file
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/Knife4jAdminConfig.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/Knife4jAdminConfig.java
new file mode 100644
index 0000000..3c2b2da
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/Knife4jAdminConfig.java
@@ -0,0 +1,53 @@
+package com.quanxiaoha.weblog.admin.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-08-16 7:53
+ * @description: Knife4j 配置
+ **/
+@Configuration
+@EnableSwagger2WebMvc
+@Profile("dev") // 只在 dev 环境中开启
+public class Knife4jAdminConfig {
+
+ @Bean("adminApi")
+ public Docket createApiDoc() {
+ Docket docket = new Docket(DocumentationType.SWAGGER_2)
+ .apiInfo(buildApiInfo())
+ // 分组名称
+ .groupName("Admin 后台接口")
+ .select()
+ // 这里指定 Controller 扫描包路径
+ .apis(RequestHandlerSelectors.basePackage("com.quanxiaoha.weblog.admin.controller"))
+ .paths(PathSelectors.any())
+ .build();
+ return docket;
+ }
+
+ /**
+ * 构建 API 信息
+ * @return
+ */
+ private ApiInfo buildApiInfo() {
+ return new ApiInfoBuilder()
+ .title("Weblog 博客 Admin 后台接口文档") // 标题
+ .description("Weblog 是一款由 Spring Boot + Vue 3.2 + Vite 4.3 开发的前后端分离博客。") // 描述
+ .termsOfServiceUrl("https://www.quanxiaoha.com/") // API 服务条款
+ .contact(new Contact("犬小哈", "https://www.quanxiaoha.com", "871361652@qq.com")) // 联系人
+ .version("1.0") // 版本号
+ .build();
+ }
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/MinioConfig.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/MinioConfig.java
new file mode 100644
index 0000000..1083984
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/MinioConfig.java
@@ -0,0 +1,27 @@
+package com.quanxiaoha.weblog.admin.config;
+
+import io.minio.MinioClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-05-11 8:49
+ * @description: TODO
+ **/
+@Configuration
+public class MinioConfig {
+ @Autowired
+ private MinioProperties minioProperties;
+
+ @Bean
+ public MinioClient minioClient() {
+ // 构建 Minio 客户端
+ return MinioClient.builder()
+ .endpoint(minioProperties.getEndpoint())
+ .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
+ .build();
+ }
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/MinioProperties.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/MinioProperties.java
new file mode 100644
index 0000000..c72af04
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/MinioProperties.java
@@ -0,0 +1,21 @@
+package com.quanxiaoha.weblog.admin.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-05-11 8:49
+ * @description: TODO
+ **/
+@ConfigurationProperties(prefix = "minio")
+@Component
+@Data
+public class MinioProperties {
+ private String endpoint;
+ private String accessKey;
+ private String secretKey;
+ private String bucketName;
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/WebSecurityConfig.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/WebSecurityConfig.java
new file mode 100644
index 0000000..f5fbac2
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/config/WebSecurityConfig.java
@@ -0,0 +1,65 @@
+package com.quanxiaoha.weblog.admin.config;
+
+import com.quanxiaoha.weblog.jwt.config.JwtAuthenticationSecurityConfig;
+import com.quanxiaoha.weblog.jwt.filter.TokenAuthenticationFilter;
+import com.quanxiaoha.weblog.jwt.handler.RestAccessDeniedHandler;
+import com.quanxiaoha.weblog.jwt.handler.RestAuthenticationEntryPoint;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-08-23 15:48
+ * @description: Spring Security 配置类
+ **/
+@Configuration
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Autowired
+ private JwtAuthenticationSecurityConfig jwtAuthenticationSecurityConfig;
+ @Autowired
+ private RestAuthenticationEntryPoint authEntryPoint;
+ @Autowired
+ private RestAccessDeniedHandler deniedHandler;
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.csrf().disable(). // 禁用 csrf
+ formLogin().disable() // 禁用表单登录
+ .apply(jwtAuthenticationSecurityConfig) // 设置用户登录认证相关配置
+ .and()
+ .authorizeHttpRequests()
+ .mvcMatchers("/admin/**").authenticated() // 认证所有以 /admin 为前缀的 URL 资源
+ .anyRequest().permitAll() // 其他都需要放行,无需认证
+ .and()
+ .httpBasic().authenticationEntryPoint(authEntryPoint) // 处理用户未登录访问受保护的资源的情况
+ .and()
+ .exceptionHandling().accessDeniedHandler(deniedHandler) // 处理登录成功后访问受保护的资源,但是权限不够的情况
+ .and()
+ .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 前后端分离,无需创建会话
+ .and()
+ .addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) // 将 Token 校验过滤器添加到用户认证过滤器之前
+ ;
+ }
+
+ /**
+ * Token 校验过滤器
+ * @return
+ */
+ @Bean
+ public TokenAuthenticationFilter tokenAuthenticationFilter() {
+ return new TokenAuthenticationFilter();
+ }
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminArticleController.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminArticleController.java
new file mode 100644
index 0000000..bd0ea4d
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminArticleController.java
@@ -0,0 +1,39 @@
+package com.quanxiaoha.weblog.admin.controller;
+
+import com.quanxiaoha.weblog.admin.model.vo.article.PublishArticleReqVO;
+import com.quanxiaoha.weblog.admin.service.AdminArticleService;
+import com.quanxiaoha.weblog.common.aspect.ApiOperationLog;
+import com.quanxiaoha.weblog.common.utils.Response;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:01
+ * @description: 文章模块
+ **/
+@RestController
+@RequestMapping("/admin/article")
+@Api(tags = "Admin 文章模块")
+public class AdminArticleController {
+
+ @Autowired
+ private AdminArticleService articleService;
+
+ @PostMapping("/publish")
+ @ApiOperation(value = "文章发布")
+ @ApiOperationLog(description = "文章发布")
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
+ public Response publishArticle(@RequestBody @Validated PublishArticleReqVO publishArticleReqVO) {
+ return articleService.publishArticle(publishArticleReqVO);
+ }
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminBlogSettingsController.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminBlogSettingsController.java
new file mode 100644
index 0000000..17fd3be
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminBlogSettingsController.java
@@ -0,0 +1,48 @@
+package com.quanxiaoha.weblog.admin.controller;
+
+import com.quanxiaoha.weblog.admin.model.vo.blogsettings.UpdateBlogSettingsReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.user.UpdateAdminUserPasswordReqVO;
+import com.quanxiaoha.weblog.admin.service.AdminBlogSettingsService;
+import com.quanxiaoha.weblog.admin.service.AdminUserService;
+import com.quanxiaoha.weblog.common.aspect.ApiOperationLog;
+import com.quanxiaoha.weblog.common.utils.Response;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:01
+ * @description: 博客设置
+ **/
+@RestController
+@RequestMapping("/admin/blog/settings")
+@Api(tags = "Admin 博客设置模块")
+public class AdminBlogSettingsController {
+
+ @Autowired
+ private AdminBlogSettingsService blogSettingsService;
+
+ @PostMapping("/update")
+ @ApiOperation(value = "博客基础信息修改")
+ @ApiOperationLog(description = "博客基础信息修改")
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
+ public Response updateBlogSettings(@RequestBody @Validated UpdateBlogSettingsReqVO updateBlogSettingsReqVO) {
+ return blogSettingsService.updateBlogSettings(updateBlogSettingsReqVO);
+ }
+
+ @PostMapping("/detail")
+ @ApiOperation(value = "获取博客设置详情")
+ @ApiOperationLog(description = "获取博客设置详情")
+ public Response findDetail() {
+ return blogSettingsService.findDetail();
+ }
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminCategoryController.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminCategoryController.java
new file mode 100644
index 0000000..74225d8
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminCategoryController.java
@@ -0,0 +1,67 @@
+package com.quanxiaoha.weblog.admin.controller;
+
+import com.quanxiaoha.weblog.admin.model.vo.category.AddCategoryReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.category.DeleteCategoryReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.category.FindCategoryPageListReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.user.UpdateAdminUserPasswordReqVO;
+import com.quanxiaoha.weblog.admin.service.AdminCategoryService;
+import com.quanxiaoha.weblog.admin.service.AdminUserService;
+import com.quanxiaoha.weblog.common.aspect.ApiOperationLog;
+import com.quanxiaoha.weblog.common.utils.PageResponse;
+import com.quanxiaoha.weblog.common.utils.Response;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:01
+ * @description: 分类
+ **/
+@RestController
+@RequestMapping("/admin/category")
+@Api(tags = "Admin 分类模块")
+public class AdminCategoryController {
+
+ @Autowired
+ private AdminCategoryService categoryService;
+
+ @PostMapping("/add")
+ @ApiOperation(value = "添加分类")
+ @ApiOperationLog(description = "添加分类")
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
+ public Response addCategory(@RequestBody @Validated AddCategoryReqVO addCategoryReqVO) {
+ return categoryService.addCategory(addCategoryReqVO);
+ }
+
+ @PostMapping("/list")
+ @ApiOperation(value = "分类分页数据获取")
+ @ApiOperationLog(description = "分类分页数据获取")
+ public PageResponse findCategoryPageList(@RequestBody @Validated FindCategoryPageListReqVO findCategoryPageListReqVO) {
+ return categoryService.findCategoryPageList(findCategoryPageListReqVO);
+ }
+
+ @PostMapping("/delete")
+ @ApiOperation(value = "删除分类")
+ @ApiOperationLog(description = "删除分类")
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
+ public Response deleteCategory(@RequestBody @Validated DeleteCategoryReqVO deleteCategoryReqVO) {
+ return categoryService.deleteCategory(deleteCategoryReqVO);
+ }
+
+ @PostMapping("/select/list")
+ @ApiOperation(value = "分类 Select 下拉列表数据获取")
+ @ApiOperationLog(description = "分类 Select 下拉列表数据获取")
+ public Response findCategorySelectList() {
+ return categoryService.findCategorySelectList();
+ }
+
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminFileController.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminFileController.java
new file mode 100644
index 0000000..9caccb5
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminFileController.java
@@ -0,0 +1,38 @@
+package com.quanxiaoha.weblog.admin.controller;
+
+import com.quanxiaoha.weblog.admin.service.AdminFileService;
+import com.quanxiaoha.weblog.common.aspect.ApiOperationLog;
+import com.quanxiaoha.weblog.common.utils.Response;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:01
+ * @description: 文件模块
+ **/
+@RestController
+@RequestMapping("/admin")
+@Api(tags = "Admin 文件模块")
+public class AdminFileController {
+
+ @Autowired
+ private AdminFileService fileService;
+
+ @PostMapping("/file/upload")
+ @ApiOperation(value = "文件上传")
+ @ApiOperationLog(description = "文件上传")
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
+ public Response uploadFile(@RequestParam MultipartFile file) {
+ return fileService.uploadFile(file);
+ }
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminTagController.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminTagController.java
new file mode 100644
index 0000000..08dea58
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminTagController.java
@@ -0,0 +1,65 @@
+package com.quanxiaoha.weblog.admin.controller;
+
+import com.quanxiaoha.weblog.admin.model.vo.tag.AddTagReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.tag.DeleteTagReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.tag.FindTagPageListReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.tag.SearchTagsReqVO;
+import com.quanxiaoha.weblog.admin.service.AdminTagService;
+import com.quanxiaoha.weblog.common.aspect.ApiOperationLog;
+import com.quanxiaoha.weblog.common.utils.PageResponse;
+import com.quanxiaoha.weblog.common.utils.Response;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:01
+ * @description: 标签模块
+ **/
+@RestController
+@RequestMapping("/admin/tag")
+@Api(tags = "Admin 标签模块")
+public class AdminTagController {
+
+ @Autowired
+ private AdminTagService tagService;
+
+ @PostMapping("/add")
+ @ApiOperation(value = "添加标签")
+ @ApiOperationLog(description = "添加标签")
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
+ public Response addTags(@RequestBody @Validated AddTagReqVO addTagReqVO) {
+ return tagService.addTags(addTagReqVO);
+ }
+
+ @PostMapping("/list")
+ @ApiOperation(value = "标签分页数据获取")
+ @ApiOperationLog(description = "标签分页数据获取")
+ public PageResponse findTagPageList(@RequestBody @Validated FindTagPageListReqVO findTagPageListReqVO) {
+ return tagService.findTagPageList(findTagPageListReqVO);
+ }
+
+ @PostMapping("/delete")
+ @ApiOperation(value = "删除标签")
+ @ApiOperationLog(description = "删除标签")
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
+ public Response deleteTag(@RequestBody @Validated DeleteTagReqVO deleteTagReqVO) {
+ return tagService.deleteTag(deleteTagReqVO);
+ }
+
+ @PostMapping("/search")
+ @ApiOperation(value = "标签模糊查询")
+ @ApiOperationLog(description = "标签模糊查询")
+ public Response searchTags(@RequestBody @Validated SearchTagsReqVO searchTagsReqVO) {
+ return tagService.searchTags(searchTagsReqVO);
+ }
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminUserController.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminUserController.java
new file mode 100644
index 0000000..65d49ac
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/controller/AdminUserController.java
@@ -0,0 +1,46 @@
+package com.quanxiaoha.weblog.admin.controller;
+
+import com.quanxiaoha.weblog.admin.model.vo.user.UpdateAdminUserPasswordReqVO;
+import com.quanxiaoha.weblog.admin.service.AdminUserService;
+import com.quanxiaoha.weblog.common.aspect.ApiOperationLog;
+import com.quanxiaoha.weblog.common.utils.Response;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:01
+ * @description: 用户
+ **/
+@RestController
+@RequestMapping("/admin")
+@Api(tags = "Admin 用户模块")
+public class AdminUserController {
+
+ @Autowired
+ private AdminUserService userService;
+
+ @PostMapping("/password/update")
+ @ApiOperation(value = "修改用户密码")
+ @ApiOperationLog(description = "修改用户密码")
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
+ public Response updatePassword(@RequestBody @Validated UpdateAdminUserPasswordReqVO updateAdminUserPasswordReqVO) {
+ return userService.updatePassword(updateAdminUserPasswordReqVO);
+ }
+
+ @PostMapping("/user/info")
+ @ApiOperation(value = "获取用户信息")
+ @ApiOperationLog(description = "获取用户信息")
+ public Response findUserInfo() {
+ return userService.findUserInfo();
+ }
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/convert/BlogSettingsConvert.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/convert/BlogSettingsConvert.java
new file mode 100644
index 0000000..2dcec5f
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/convert/BlogSettingsConvert.java
@@ -0,0 +1,36 @@
+package com.quanxiaoha.weblog.admin.convert;
+
+import com.quanxiaoha.weblog.admin.model.vo.blogsettings.FindBlogSettingsRspVO;
+import com.quanxiaoha.weblog.admin.model.vo.blogsettings.UpdateBlogSettingsReqVO;
+import com.quanxiaoha.weblog.common.domain.dos.BlogSettingsDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023/10/8 14:57
+ * @description: 博客设置转换
+ **/
+@Mapper
+public interface BlogSettingsConvert {
+ /**
+ * 初始化 convert 实例
+ */
+ BlogSettingsConvert INSTANCE = Mappers.getMapper(BlogSettingsConvert.class);
+
+ /**
+ * 将 VO 转化为 DO
+ * @param bean
+ * @return
+ */
+ BlogSettingsDO convertVO2DO(UpdateBlogSettingsReqVO bean);
+
+ /**
+ * 将 DO 转化为 VO
+ * @param bean
+ * @return
+ */
+ FindBlogSettingsRspVO convertDO2VO(BlogSettingsDO bean);
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/package-info.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/package-info.java
new file mode 100644
index 0000000..e84aac5
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: TODO
+ **/
+package com.quanxiaoha.weblog.admin.model;
\ No newline at end of file
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/article/PublishArticleReqVO.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/article/PublishArticleReqVO.java
new file mode 100644
index 0000000..866a2d8
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/article/PublishArticleReqVO.java
@@ -0,0 +1,44 @@
+package com.quanxiaoha.weblog.admin.model.vo.article;
+
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: 文章发布
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ApiModel(value = "发布文章 VO")
+public class PublishArticleReqVO {
+
+ @NotBlank(message = "文章标题不能为空")
+ @Length(min = 1, max = 40, message = "文章标题字数需大于 1 小于 40")
+ private String title;
+
+ @NotBlank(message = "文章内容不能为空")
+ private String content;
+
+ @NotBlank(message = "文章封面不能为空")
+ private String cover;
+
+ private String summary;
+
+ @NotNull(message = "文章分类不能为空")
+ private Long categoryId;
+
+ // @NotEmpty(message = "文章标签不能为空")
+ private List tags;
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/blogsettings/FindBlogSettingsRspVO.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/blogsettings/FindBlogSettingsRspVO.java
new file mode 100644
index 0000000..0d15bd2
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/blogsettings/FindBlogSettingsRspVO.java
@@ -0,0 +1,40 @@
+package com.quanxiaoha.weblog.admin.model.vo.blogsettings;
+
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: 博客基础信息
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class FindBlogSettingsRspVO {
+
+ private String logo;
+
+ private String name;
+
+ private String author;
+
+ private String introduction;
+
+ private String avatar;
+
+ private String githubHomepage;
+
+ private String csdnHomepage;
+
+ private String giteeHomepage;
+
+ private String zhihuHomepage;
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/blogsettings/UpdateBlogSettingsReqVO.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/blogsettings/UpdateBlogSettingsReqVO.java
new file mode 100644
index 0000000..eb0c9de
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/blogsettings/UpdateBlogSettingsReqVO.java
@@ -0,0 +1,47 @@
+package com.quanxiaoha.weblog.admin.model.vo.blogsettings;
+
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: 博客基础信息修改
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ApiModel(value = " 博客基础信息修改 VO")
+public class UpdateBlogSettingsReqVO {
+
+ @NotBlank(message = "博客 LOGO 不能为空")
+ private String logo;
+
+ @NotBlank(message = "博客名称不能为空")
+ private String name;
+
+ @NotBlank(message = "博客作者不能为空")
+ private String author;
+
+ @NotBlank(message = "博客介绍语不能为空")
+ private String introduction;
+
+ @NotBlank(message = "博客头像不能为空")
+ private String avatar;
+
+ private String githubHomepage;
+
+ private String csdnHomepage;
+
+ private String giteeHomepage;
+
+ private String zhihuHomepage;
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/AddCategoryReqVO.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/AddCategoryReqVO.java
new file mode 100644
index 0000000..ff250e1
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/AddCategoryReqVO.java
@@ -0,0 +1,30 @@
+package com.quanxiaoha.weblog.admin.model.vo.category;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: 分类新增
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ApiModel(value = "添加分类 VO")
+public class AddCategoryReqVO {
+
+ @NotBlank(message = "分类名称不能为空")
+ @Length(min = 1, max = 20, message = "分类名称字数限制 1 ~ 20 之间")
+ private String name;
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/DeleteCategoryReqVO.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/DeleteCategoryReqVO.java
new file mode 100644
index 0000000..26e55a1
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/DeleteCategoryReqVO.java
@@ -0,0 +1,29 @@
+package com.quanxiaoha.weblog.admin.model.vo.category;
+
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: 删除分类
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ApiModel(value = "删除分类 VO")
+public class DeleteCategoryReqVO {
+
+ @NotNull(message = "分类 ID 不能为空")
+ private Long id;
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/FindCategoryPageListReqVO.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/FindCategoryPageListReqVO.java
new file mode 100644
index 0000000..3a26532
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/FindCategoryPageListReqVO.java
@@ -0,0 +1,43 @@
+package com.quanxiaoha.weblog.admin.model.vo.category;
+
+import com.quanxiaoha.weblog.common.model.BasePageQuery;
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: 分类分页
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ApiModel(value = "查询分类分页数据入参 VO")
+public class FindCategoryPageListReqVO extends BasePageQuery {
+
+ /**
+ * 分类名称
+ */
+ private String name;
+
+ /**
+ * 创建的起始日期
+ */
+ private LocalDate startDate;
+
+ /**
+ * 创建的结束日期
+ */
+ private LocalDate endDate;
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/FindCategoryPageListRspVO.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/FindCategoryPageListRspVO.java
new file mode 100644
index 0000000..b49b5a0
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/category/FindCategoryPageListRspVO.java
@@ -0,0 +1,40 @@
+package com.quanxiaoha.weblog.admin.model.vo.category;
+
+import com.quanxiaoha.weblog.common.model.BasePageQuery;
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: 分类分页
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class FindCategoryPageListRspVO {
+
+ /**
+ * 分类 ID
+ */
+ private Long id;
+
+ /**
+ * 分类名称
+ */
+ private String name;
+
+ /**
+ * 创建时间
+ */
+ private LocalDateTime createTime;
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/file/UploadFileRspVO.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/file/UploadFileRspVO.java
new file mode 100644
index 0000000..683baaf
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/file/UploadFileRspVO.java
@@ -0,0 +1,27 @@
+package com.quanxiaoha.weblog.admin.model.vo.file;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: 上传文件
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class UploadFileRspVO {
+
+ /**
+ * 文件的访问链接
+ */
+ private String url;
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/AddTagReqVO.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/AddTagReqVO.java
new file mode 100644
index 0000000..36d0a48
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/AddTagReqVO.java
@@ -0,0 +1,30 @@
+package com.quanxiaoha.weblog.admin.model.vo.tag;
+
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import java.util.List;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: 标签新增
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ApiModel(value = "添加标签 VO")
+public class AddTagReqVO {
+
+ @NotEmpty(message = "标签集合不能为空")
+ private List tags;
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/DeleteTagReqVO.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/DeleteTagReqVO.java
new file mode 100644
index 0000000..acd775d
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/DeleteTagReqVO.java
@@ -0,0 +1,27 @@
+package com.quanxiaoha.weblog.admin.model.vo.tag;
+
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: 删除标签
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ApiModel(value = "删除标签 VO")
+public class DeleteTagReqVO {
+
+ @NotNull(message = "标签 ID 不能为空")
+ private Long id;
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/FindTagPageListReqVO.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/FindTagPageListReqVO.java
new file mode 100644
index 0000000..12951fc
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/FindTagPageListReqVO.java
@@ -0,0 +1,40 @@
+package com.quanxiaoha.weblog.admin.model.vo.tag;
+
+import com.quanxiaoha.weblog.common.model.BasePageQuery;
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: 标签分页
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ApiModel(value = "查询标签分页数据入参 VO")
+public class FindTagPageListReqVO extends BasePageQuery {
+
+ /**
+ * 标签名称
+ */
+ private String name;
+
+ /**
+ * 创建的起始日期
+ */
+ private LocalDate startDate;
+
+ /**
+ * 创建的结束日期
+ */
+ private LocalDate endDate;
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/FindTagPageListRspVO.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/FindTagPageListRspVO.java
new file mode 100644
index 0000000..6835637
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/FindTagPageListRspVO.java
@@ -0,0 +1,37 @@
+package com.quanxiaoha.weblog.admin.model.vo.tag;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: 标签分页
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class FindTagPageListRspVO {
+
+ /**
+ * 标签 ID
+ */
+ private Long id;
+
+ /**
+ * 标签名称
+ */
+ private String name;
+
+ /**
+ * 创建时间
+ */
+ private LocalDateTime createTime;
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/SearchTagsReqVO.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/SearchTagsReqVO.java
new file mode 100644
index 0000000..0045454
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/tag/SearchTagsReqVO.java
@@ -0,0 +1,27 @@
+package com.quanxiaoha.weblog.admin.model.vo.tag;
+
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: 标签模糊查询
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ApiModel(value = "标签模糊查询 VO")
+public class SearchTagsReqVO {
+
+ @NotBlank(message = "标签查询关键词不能为空")
+ private String key;
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/user/FindUserInfoRspVO.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/user/FindUserInfoRspVO.java
new file mode 100644
index 0000000..13fcb86
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/user/FindUserInfoRspVO.java
@@ -0,0 +1,28 @@
+package com.quanxiaoha.weblog.admin.model.vo.user;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: 查询用户信息
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class FindUserInfoRspVO {
+ /**
+ * 用户名
+ */
+ private String username;
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/user/UpdateAdminUserPasswordReqVO.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/user/UpdateAdminUserPasswordReqVO.java
new file mode 100644
index 0000000..1107969
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/model/vo/user/UpdateAdminUserPasswordReqVO.java
@@ -0,0 +1,31 @@
+package com.quanxiaoha.weblog.admin.model.vo.user;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import javax.validation.constraints.*;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:07
+ * @description: TODO
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ApiModel(value = "修改用户密码 VO")
+public class UpdateAdminUserPasswordReqVO {
+
+ @NotBlank(message = "用户名不能为空")
+ @ApiModelProperty(value = "用户名")
+ private String username;
+
+ @NotBlank(message = "密码不能为空")
+ @ApiModelProperty(value = "密码")
+ private String password;
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/package-info.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/package-info.java
new file mode 100644
index 0000000..8a825e4
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-08-16 9:28
+ * @description: TODO
+ **/
+package com.quanxiaoha.weblog.admin;
\ No newline at end of file
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminArticleService.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminArticleService.java
new file mode 100644
index 0000000..664d10e
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminArticleService.java
@@ -0,0 +1,20 @@
+package com.quanxiaoha.weblog.admin.service;
+
+import com.quanxiaoha.weblog.admin.model.vo.article.PublishArticleReqVO;
+import com.quanxiaoha.weblog.common.utils.Response;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:03
+ * @description: 文章
+ **/
+public interface AdminArticleService {
+ /**
+ * 发布文章
+ * @param publishArticleReqVO
+ * @return
+ */
+ Response publishArticle(PublishArticleReqVO publishArticleReqVO);
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminBlogSettingsService.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminBlogSettingsService.java
new file mode 100644
index 0000000..80350a9
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminBlogSettingsService.java
@@ -0,0 +1,26 @@
+package com.quanxiaoha.weblog.admin.service;
+
+import com.quanxiaoha.weblog.admin.model.vo.blogsettings.UpdateBlogSettingsReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.user.UpdateAdminUserPasswordReqVO;
+import com.quanxiaoha.weblog.common.utils.Response;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:03
+ * @description: TODO
+ **/
+public interface AdminBlogSettingsService {
+ /**
+ * 更新博客设置信息
+ * @param updateBlogSettingsReqVO
+ * @return
+ */
+ Response updateBlogSettings(UpdateBlogSettingsReqVO updateBlogSettingsReqVO);
+
+ /**
+ * 获取博客设置详情
+ * @return
+ */
+ Response findDetail();
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminCategoryService.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminCategoryService.java
new file mode 100644
index 0000000..a16de2b
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminCategoryService.java
@@ -0,0 +1,45 @@
+package com.quanxiaoha.weblog.admin.service;
+
+import com.quanxiaoha.weblog.admin.model.vo.category.AddCategoryReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.category.DeleteCategoryReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.category.FindCategoryPageListReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.tag.AddTagReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.user.UpdateAdminUserPasswordReqVO;
+import com.quanxiaoha.weblog.common.utils.PageResponse;
+import com.quanxiaoha.weblog.common.utils.Response;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:03
+ * @description: TODO
+ **/
+public interface AdminCategoryService {
+ /**
+ * 添加分类
+ * @param addCategoryReqVO
+ * @return
+ */
+ Response addCategory(AddCategoryReqVO addCategoryReqVO);
+
+ /**
+ * 分类分页数据查询
+ * @param findCategoryPageListReqVO
+ * @return
+ */
+ PageResponse findCategoryPageList(FindCategoryPageListReqVO findCategoryPageListReqVO);
+
+ /**
+ * 删除分类
+ * @param deleteCategoryReqVO
+ * @return
+ */
+ Response deleteCategory(DeleteCategoryReqVO deleteCategoryReqVO);
+
+ /**
+ * 获取文章分类的 Select 列表数据
+ * @return
+ */
+ Response findCategorySelectList();
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminFileService.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminFileService.java
new file mode 100644
index 0000000..3219e63
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminFileService.java
@@ -0,0 +1,20 @@
+package com.quanxiaoha.weblog.admin.service;
+
+import com.quanxiaoha.weblog.admin.model.vo.user.UpdateAdminUserPasswordReqVO;
+import com.quanxiaoha.weblog.common.utils.Response;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:03
+ * @description: TODO
+ **/
+public interface AdminFileService {
+ /**
+ * 上传文件
+ * @param file
+ * @return
+ */
+ Response uploadFile(MultipartFile file);
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminTagService.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminTagService.java
new file mode 100644
index 0000000..5fe2f49
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminTagService.java
@@ -0,0 +1,45 @@
+package com.quanxiaoha.weblog.admin.service;
+
+import com.quanxiaoha.weblog.admin.model.vo.tag.AddTagReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.tag.DeleteTagReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.tag.FindTagPageListReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.tag.SearchTagsReqVO;
+import com.quanxiaoha.weblog.common.utils.PageResponse;
+import com.quanxiaoha.weblog.common.utils.Response;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:03
+ * @description: TODO
+ **/
+public interface AdminTagService {
+
+ /**
+ * 添加标签集合
+ * @param addTagReqVO
+ * @return
+ */
+ Response addTags(AddTagReqVO addTagReqVO);
+
+ /**
+ * 查询标签分页
+ * @param findTagPageListReqVO
+ * @return
+ */
+ PageResponse findTagPageList(FindTagPageListReqVO findTagPageListReqVO);
+
+ /**
+ * 删除标签
+ * @param deleteTagReqVO
+ * @return
+ */
+ Response deleteTag(DeleteTagReqVO deleteTagReqVO);
+
+ /**
+ * 根据标签关键词模糊查询
+ * @param searchTagsReqVO
+ * @return
+ */
+ Response searchTags(SearchTagsReqVO searchTagsReqVO);
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminUserService.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminUserService.java
new file mode 100644
index 0000000..53a26fe
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/AdminUserService.java
@@ -0,0 +1,25 @@
+package com.quanxiaoha.weblog.admin.service;
+
+import com.quanxiaoha.weblog.admin.model.vo.user.UpdateAdminUserPasswordReqVO;
+import com.quanxiaoha.weblog.common.utils.Response;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:03
+ * @description: TODO
+ **/
+public interface AdminUserService {
+ /**
+ * 修改密码
+ * @param updateAdminUserPasswordReqVO
+ * @return
+ */
+ Response updatePassword(UpdateAdminUserPasswordReqVO updateAdminUserPasswordReqVO);
+
+ /**
+ * 获取当前登录用户信息
+ * @return
+ */
+ Response findUserInfo();
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminArticleServiceImpl.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminArticleServiceImpl.java
new file mode 100644
index 0000000..5c24c3f
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminArticleServiceImpl.java
@@ -0,0 +1,100 @@
+package com.quanxiaoha.weblog.admin.service.impl;
+
+import com.quanxiaoha.weblog.admin.model.vo.article.PublishArticleReqVO;
+import com.quanxiaoha.weblog.admin.service.AdminArticleService;
+import com.quanxiaoha.weblog.common.domain.dos.ArticleCategoryRelDO;
+import com.quanxiaoha.weblog.common.domain.dos.ArticleContentDO;
+import com.quanxiaoha.weblog.common.domain.dos.ArticleDO;
+import com.quanxiaoha.weblog.common.domain.dos.CategoryDO;
+import com.quanxiaoha.weblog.common.domain.mapper.*;
+import com.quanxiaoha.weblog.common.enums.ResponseCodeEnum;
+import com.quanxiaoha.weblog.common.exception.BizException;
+import com.quanxiaoha.weblog.common.utils.Response;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:03
+ * @description: 文章
+ **/
+@Service
+@Slf4j
+public class AdminArticleServiceImpl implements AdminArticleService {
+
+ @Autowired
+ private ArticleMapper articleMapper;
+ @Autowired
+ private ArticleContentMapper articleContentMapper;
+ @Autowired
+ private ArticleCategoryRelMapper articleCategoryRelMapper;
+ @Autowired
+ private CategoryMapper categoryMapper;
+
+ /**
+ * 发布文章
+ *
+ * @param publishArticleReqVO
+ * @return
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Response publishArticle(PublishArticleReqVO publishArticleReqVO) {
+ // 1. VO 转 ArticleDO, 并保存
+ ArticleDO articleDO = ArticleDO.builder()
+ .title(publishArticleReqVO.getTitle())
+ .cover(publishArticleReqVO.getCover())
+ .summary(publishArticleReqVO.getSummary())
+ .createTime(LocalDateTime.now())
+ .updateTime(LocalDateTime.now())
+ .build();
+ articleMapper.insert(articleDO);
+
+ // 拿到插入记录的主键 ID
+ Long articleId = articleDO.getId();
+
+ // 2. VO 转 ArticleContentDO,并保存
+ ArticleContentDO articleContentDO = ArticleContentDO.builder()
+ .articleId(articleId)
+ .content(publishArticleReqVO.getContent())
+ .build();
+ articleContentMapper.insert(articleContentDO);
+
+ // 3. 处理文章关联的分类
+ Long categoryId = publishArticleReqVO.getCategoryId();
+
+ // 3.1 校验提交的分类是否真实存在
+ CategoryDO categoryDO = categoryMapper.selectById(categoryId);
+ if (Objects.isNull(categoryDO)) {
+ log.warn("==> 分类不存在, categoryId: {}", categoryId);
+ throw new BizException(ResponseCodeEnum.CATEGORY_NOT_EXISTED);
+ }
+
+ ArticleCategoryRelDO articleCategoryRelDO = ArticleCategoryRelDO.builder()
+ .articleId(articleId)
+ .categoryId(categoryId)
+ .build();
+ articleCategoryRelMapper.insert(articleCategoryRelDO);
+
+ // 4. 保存文章关联的标签集合
+ List publishTags = publishArticleReqVO.getTags();
+ insertTags(publishTags);
+
+ return Response.success();
+ }
+
+ /**
+ * 保存标签
+ * @param publishTags
+ */
+ private void insertTags(List publishTags) {
+ // TODO
+ }
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminBlogSettingsServiceImpl.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminBlogSettingsServiceImpl.java
new file mode 100644
index 0000000..d244b99
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminBlogSettingsServiceImpl.java
@@ -0,0 +1,61 @@
+package com.quanxiaoha.weblog.admin.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.quanxiaoha.weblog.admin.convert.BlogSettingsConvert;
+import com.quanxiaoha.weblog.admin.model.vo.blogsettings.FindBlogSettingsRspVO;
+import com.quanxiaoha.weblog.admin.model.vo.blogsettings.UpdateBlogSettingsReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.user.FindUserInfoRspVO;
+import com.quanxiaoha.weblog.admin.model.vo.user.UpdateAdminUserPasswordReqVO;
+import com.quanxiaoha.weblog.admin.service.AdminBlogSettingsService;
+import com.quanxiaoha.weblog.admin.service.AdminUserService;
+import com.quanxiaoha.weblog.common.domain.dos.BlogSettingsDO;
+import com.quanxiaoha.weblog.common.domain.mapper.BlogSettingsMapper;
+import com.quanxiaoha.weblog.common.domain.mapper.UserMapper;
+import com.quanxiaoha.weblog.common.enums.ResponseCodeEnum;
+import com.quanxiaoha.weblog.common.utils.Response;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:03
+ * @description: TODO
+ **/
+@Service
+public class AdminBlogSettingsServiceImpl extends ServiceImpl implements AdminBlogSettingsService {
+
+ @Autowired
+ private BlogSettingsMapper blogSettingsMapper;
+
+ @Override
+ public Response updateBlogSettings(UpdateBlogSettingsReqVO updateBlogSettingsReqVO) {
+ // VO 转 DO
+ BlogSettingsDO blogSettingsDO = BlogSettingsConvert.INSTANCE.convertVO2DO(updateBlogSettingsReqVO);
+ blogSettingsDO.setId(1L);
+
+ // 保存或更新(当数据库中存在 ID 为 1 的记录时,则执行更新操作,否则执行插入操作)
+ saveOrUpdate(blogSettingsDO);
+ return Response.success();
+ }
+
+ /**
+ * 获取博客设置详情
+ *
+ * @return
+ */
+ @Override
+ public Response findDetail() {
+ // 查询 ID 为 1 的记录
+ BlogSettingsDO blogSettingsDO = blogSettingsMapper.selectById(1L);
+
+ // DO 转 VO
+ FindBlogSettingsRspVO vo = BlogSettingsConvert.INSTANCE.convertDO2VO(blogSettingsDO);
+
+ return Response.success(vo);
+ }
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminCategoryServiceImpl.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminCategoryServiceImpl.java
new file mode 100644
index 0000000..849f95b
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminCategoryServiceImpl.java
@@ -0,0 +1,157 @@
+package com.quanxiaoha.weblog.admin.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.injector.methods.SelectPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.quanxiaoha.weblog.admin.model.vo.category.AddCategoryReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.category.DeleteCategoryReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.category.FindCategoryPageListReqVO;
+import com.quanxiaoha.weblog.admin.model.vo.category.FindCategoryPageListRspVO;
+import com.quanxiaoha.weblog.admin.model.vo.user.FindUserInfoRspVO;
+import com.quanxiaoha.weblog.admin.model.vo.user.UpdateAdminUserPasswordReqVO;
+import com.quanxiaoha.weblog.admin.service.AdminCategoryService;
+import com.quanxiaoha.weblog.admin.service.AdminUserService;
+import com.quanxiaoha.weblog.common.domain.dos.CategoryDO;
+import com.quanxiaoha.weblog.common.domain.mapper.CategoryMapper;
+import com.quanxiaoha.weblog.common.domain.mapper.UserMapper;
+import com.quanxiaoha.weblog.common.enums.ResponseCodeEnum;
+import com.quanxiaoha.weblog.common.exception.BizException;
+import com.quanxiaoha.weblog.common.model.vo.SelectRspVO;
+import com.quanxiaoha.weblog.common.utils.PageResponse;
+import com.quanxiaoha.weblog.common.utils.Response;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:03
+ * @description: TODO
+ **/
+@Service
+@Slf4j
+public class AdminCategoryServiceImpl implements AdminCategoryService {
+
+ @Autowired
+ private CategoryMapper categoryMapper;
+
+ /**
+ * 添加分类
+ *
+ * @param addCategoryReqVO
+ * @return
+ */
+ @Override
+ public Response addCategory(AddCategoryReqVO addCategoryReqVO) {
+ String categoryName = addCategoryReqVO.getName();
+
+ // 先判断该分类是否已经存在
+ CategoryDO categoryDO = categoryMapper.selectByName(categoryName);
+
+ if (Objects.nonNull(categoryDO)) {
+ log.warn("分类名称: {}, 此已存在", categoryName);
+ throw new BizException(ResponseCodeEnum.CATEGORY_NAME_IS_EXISTED);
+ }
+
+ // 构建 DO 类
+ CategoryDO insertCategoryDO = CategoryDO.builder()
+ .name(addCategoryReqVO.getName().trim())
+ .build();
+
+ // 执行 insert
+ categoryMapper.insert(insertCategoryDO);
+
+ return Response.success();
+ }
+
+ /**
+ * 分类分页数据查询
+ *
+ * @param findCategoryPageListReqVO
+ * @return
+ */
+ @Override
+ public PageResponse findCategoryPageList(FindCategoryPageListReqVO findCategoryPageListReqVO) {
+ // 获取当前页、以及每页需要展示的数据数量
+ Long current = findCategoryPageListReqVO.getCurrent();
+ Long size = findCategoryPageListReqVO.getSize();
+ String name = findCategoryPageListReqVO.getName();
+ LocalDate startDate = findCategoryPageListReqVO.getStartDate();
+ LocalDate endDate = findCategoryPageListReqVO.getEndDate();
+
+ // 执行分页查询
+ Page categoryDOPage = categoryMapper.selectPageList(current, size, name, startDate, endDate);
+
+ List categoryDOS = categoryDOPage.getRecords();
+
+ // DO 转 VO
+ List vos = null;
+ if (!CollectionUtils.isEmpty(categoryDOS)) {
+ vos = categoryDOS.stream()
+ .map(categoryDO -> FindCategoryPageListRspVO.builder()
+ .id(categoryDO.getId())
+ .name(categoryDO.getName())
+ .createTime(categoryDO.getCreateTime())
+ .build())
+ .collect(Collectors.toList());
+ }
+
+ return PageResponse.success(categoryDOPage, vos);
+ }
+
+ /**
+ * 删除分类
+ *
+ * @param deleteCategoryReqVO
+ * @return
+ */
+ @Override
+ public Response deleteCategory(DeleteCategoryReqVO deleteCategoryReqVO) {
+ // 分类 ID
+ Long categoryId = deleteCategoryReqVO.getId();
+
+ // 删除分类
+ categoryMapper.deleteById(categoryId);
+
+ return Response.success();
+ }
+
+ /**
+ * 获取文章分类的 Select 列表数据
+ *
+ * @return
+ */
+ @Override
+ public Response findCategorySelectList() {
+ // 查询所有分类
+ List categoryDOS = categoryMapper.selectList(null);
+
+ // DO 转 VO
+ List selectRspVOS = null;
+ // 如果分类数据不为空
+ if (!CollectionUtils.isEmpty(categoryDOS)) {
+ // 将分类 ID 作为 Value 值,将分类名称作为 label 展示
+ selectRspVOS = categoryDOS.stream()
+ .map(categoryDO -> SelectRspVO.builder()
+ .label(categoryDO.getName())
+ .value(categoryDO.getId())
+ .build())
+ .collect(Collectors.toList());
+ }
+
+ return Response.success(selectRspVOS);
+ }
+
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminFileServiceImpl.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminFileServiceImpl.java
new file mode 100644
index 0000000..85b224b
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminFileServiceImpl.java
@@ -0,0 +1,55 @@
+package com.quanxiaoha.weblog.admin.service.impl;
+
+import com.quanxiaoha.weblog.admin.model.vo.file.UploadFileRspVO;
+import com.quanxiaoha.weblog.admin.model.vo.user.FindUserInfoRspVO;
+import com.quanxiaoha.weblog.admin.model.vo.user.UpdateAdminUserPasswordReqVO;
+import com.quanxiaoha.weblog.admin.service.AdminFileService;
+import com.quanxiaoha.weblog.admin.service.AdminUserService;
+import com.quanxiaoha.weblog.admin.utils.MinioUtil;
+import com.quanxiaoha.weblog.common.domain.mapper.UserMapper;
+import com.quanxiaoha.weblog.common.enums.ResponseCodeEnum;
+import com.quanxiaoha.weblog.common.exception.BizException;
+import com.quanxiaoha.weblog.common.utils.Response;
+import io.minio.MinioClient;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:03
+ * @description: 文件上传
+ **/
+@Service
+@Slf4j
+public class AdminFileServiceImpl implements AdminFileService {
+
+ @Autowired
+ private MinioUtil minioUtil;
+
+ /**
+ * 上传文件
+ *
+ * @param file
+ * @return
+ */
+ @Override
+ public Response uploadFile(MultipartFile file) {
+ try {
+ // 上传文件
+ String url = minioUtil.uploadFile(file);
+
+ // 构建成功返参,将图片的访问链接返回
+ return Response.success(UploadFileRspVO.builder().url(url).build());
+ } catch (Exception e) {
+ log.error("==> 上传文件至 Minio 错误: ", e);
+ // 手动抛出业务异常,提示 “文件上传失败”
+ throw new BizException(ResponseCodeEnum.FILE_UPLOAD_FAILED);
+ }
+ }
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminTagServiceImpl.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminTagServiceImpl.java
new file mode 100644
index 0000000..12d9322
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminTagServiceImpl.java
@@ -0,0 +1,139 @@
+package com.quanxiaoha.weblog.admin.service.impl;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.quanxiaoha.weblog.admin.model.vo.tag.*;
+import com.quanxiaoha.weblog.admin.service.AdminTagService;
+import com.quanxiaoha.weblog.common.domain.dos.TagDO;
+import com.quanxiaoha.weblog.common.domain.mapper.TagMapper;
+import com.quanxiaoha.weblog.common.enums.ResponseCodeEnum;
+import com.quanxiaoha.weblog.common.model.vo.SelectRspVO;
+import com.quanxiaoha.weblog.common.utils.PageResponse;
+import com.quanxiaoha.weblog.common.utils.Response;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:03
+ * @description: TODO
+ **/
+@Service
+@Slf4j
+public class AdminTagServiceImpl extends ServiceImpl implements AdminTagService {
+
+ @Autowired
+ private TagMapper tagMapper;
+
+ /**
+ * 添加标签集合
+ *
+ * @param addTagReqVO
+ * @return
+ */
+ @Override
+ public Response addTags(AddTagReqVO addTagReqVO) {
+ // vo 转 do
+ List tagDOS = addTagReqVO.getTags().stream()
+ .map(tagName -> TagDO.builder()
+ .name(tagName.trim()) // 去掉前后空格
+ .createTime(LocalDateTime.now())
+ .updateTime(LocalDateTime.now())
+ .build())
+ .collect(Collectors.toList());
+
+ // 批量插入
+ try {
+ saveBatch(tagDOS);
+ } catch (Exception e) {
+ log.warn("该标签已存在", e);
+ }
+
+ return Response.success();
+ }
+
+ /**
+ * 查询标签分页
+ *
+ * @param findTagPageListReqVO
+ * @return
+ */
+ @Override
+ public PageResponse findTagPageList(FindTagPageListReqVO findTagPageListReqVO) {
+ // 分页参数、条件参数
+ Long current = findTagPageListReqVO.getCurrent();
+ Long size = findTagPageListReqVO.getSize();
+ String name = findTagPageListReqVO.getName();
+ LocalDate startDate = findTagPageListReqVO.getStartDate();
+ LocalDate endDate = findTagPageListReqVO.getEndDate();
+
+ // 分页查询
+ Page page = tagMapper.selectPageList(current, size, name, startDate, endDate);
+
+ List records = page.getRecords();
+
+ // do 转 vo
+ List vos = null;
+ if (!CollectionUtils.isEmpty(records)) {
+ vos = records.stream().map(tagDO -> FindTagPageListRspVO.builder()
+ .id(tagDO.getId())
+ .name(tagDO.getName())
+ .createTime(tagDO.getCreateTime())
+ .build()).collect(Collectors.toList());
+ }
+
+ return PageResponse.success(page, vos);
+ }
+
+ /**
+ * 删除标签
+ *
+ * @param deleteTagReqVO
+ * @return
+ */
+ @Override
+ public Response deleteTag(DeleteTagReqVO deleteTagReqVO) {
+ // 标签 ID
+ Long tagId = deleteTagReqVO.getId();
+
+ // 根据标签 ID 删除
+ int count = tagMapper.deleteById(tagId);
+
+ return count == 1 ? Response.success() : Response.fail(ResponseCodeEnum.TAG_NOT_EXISTED);
+ }
+
+ /**
+ * 根据标签关键词模糊查询
+ *
+ * @param searchTagsReqVO
+ * @return
+ */
+ @Override
+ public Response searchTags(SearchTagsReqVO searchTagsReqVO) {
+ String key = searchTagsReqVO.getKey();
+
+ // 执行模糊查询
+ List tagDOS = tagMapper.selectByKey(key);
+
+ // do 转 vo
+ List vos = null;
+ if (!CollectionUtils.isEmpty(tagDOS)) {
+ vos = tagDOS.stream()
+ .map(tagDO -> SelectRspVO.builder()
+ .label(tagDO.getName())
+ .value(tagDO.getId())
+ .build())
+ .collect(Collectors.toList());
+ }
+
+ return Response.success(vos);
+ }
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminUserServiceImpl.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminUserServiceImpl.java
new file mode 100644
index 0000000..5bf44ff
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/impl/AdminUserServiceImpl.java
@@ -0,0 +1,62 @@
+package com.quanxiaoha.weblog.admin.service.impl;
+
+import com.quanxiaoha.weblog.admin.model.vo.user.FindUserInfoRspVO;
+import com.quanxiaoha.weblog.admin.model.vo.user.UpdateAdminUserPasswordReqVO;
+import com.quanxiaoha.weblog.admin.service.AdminUserService;
+import com.quanxiaoha.weblog.common.domain.mapper.UserMapper;
+import com.quanxiaoha.weblog.common.enums.ResponseCodeEnum;
+import com.quanxiaoha.weblog.common.utils.Response;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:03
+ * @description: TODO
+ **/
+@Service
+public class AdminUserServiceImpl implements AdminUserService {
+
+ @Autowired
+ private UserMapper userMapper;
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ /**
+ * 修改密码
+ * @param updateAdminUserPasswordReqVO
+ * @return
+ */
+ @Override
+ public Response updatePassword(UpdateAdminUserPasswordReqVO updateAdminUserPasswordReqVO) {
+ // 拿到用户名、密码
+ String username = updateAdminUserPasswordReqVO.getUsername();
+ String password = updateAdminUserPasswordReqVO.getPassword();
+
+ // 加密密码
+ String encodePassword = passwordEncoder.encode(password);
+
+ // 更新到数据库
+ int count = userMapper.updatePasswordByUsername(username, encodePassword);
+
+ return count == 1 ? Response.success() : Response.fail(ResponseCodeEnum.USERNAME_NOT_FOUND);
+ }
+
+ /**
+ * 获取当前登录用户信息
+ * @return
+ */
+ @Override
+ public Response findUserInfo() {
+ // 获取存储在 ThreadLocal 中的用户信息
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ // 拿到用户名
+ String username = authentication.getName();
+
+ return Response.success(FindUserInfoRspVO.builder().username(username).build());
+ }
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/package-info.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/package-info.java
new file mode 100644
index 0000000..25284f5
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/service/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-09-15 14:02
+ * @description: TODO
+ **/
+package com.quanxiaoha.weblog.admin.service;
\ No newline at end of file
diff --git a/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/utils/MinioUtil.java b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/utils/MinioUtil.java
new file mode 100644
index 0000000..4bec268
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/main/java/com/quanxiaoha/weblog/admin/utils/MinioUtil.java
@@ -0,0 +1,75 @@
+package com.quanxiaoha.weblog.admin.utils;
+
+import com.quanxiaoha.weblog.admin.config.MinioProperties;
+import com.quanxiaoha.weblog.common.exception.BizException;
+import io.minio.MinioClient;
+import io.minio.PutObjectArgs;
+import io.minio.errors.*;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.UUID;
+
+/**
+ * @author: 犬小哈
+ * @url: www.quanxiaoha.com
+ * @date: 2023-05-11 9:02
+ * @description: TODO
+ **/
+@Component
+@Slf4j
+public class MinioUtil {
+
+ @Autowired
+ private MinioProperties minioProperties;
+
+ @Autowired
+ private MinioClient minioClient;
+
+ /**
+ * 上传文件
+ * @param file
+ * @return
+ * @throws Exception
+ */
+ public String uploadFile(MultipartFile file) throws Exception {
+ // 判断文件是否为空
+ if (file == null || file.getSize() == 0) {
+ log.error("==> 上传文件异常:文件大小为空 ...");
+ throw new RuntimeException("文件大小不能为空");
+ }
+
+ // 文件的原始名称
+ String originalFileName = file.getOriginalFilename();
+ // 文件的 Content-Type
+ String contentType = file.getContentType();
+
+ // 生成存储对象的名称(将 UUID 字符串中的 - 替换成空字符串)
+ String key = UUID.randomUUID().toString().replace("-", "");
+ // 获取文件的后缀,如 .jpg
+ String suffix = originalFileName.substring(originalFileName.lastIndexOf("."));
+
+ // 拼接上文件后缀,即为要存储的文件名
+ String objectName = String.format("%s%s", key, suffix);
+
+ log.info("==> 开始上传文件至 Minio, ObjectName: {}", objectName);
+
+ // 上传文件至 Minio
+ minioClient.putObject(PutObjectArgs.builder()
+ .bucket(minioProperties.getBucketName())
+ .object(objectName)
+ .stream(file.getInputStream(), file.getSize(), -1)
+ .contentType(contentType)
+ .build());
+
+ // 返回文件的访问链接
+ String url = String.format("%s/%s/%s", minioProperties.getEndpoint(), minioProperties.getBucketName(), objectName);
+ log.info("==> 上传文件至 Minio 成功,访问路径: {}", url);
+ return url;
+ }
+}
diff --git a/weblog-springboot-102/weblog-module-admin/src/test/java/com/quanxiaoha/weblog/admin/WeblogModuleAdminApplicationTests.java b/weblog-springboot-102/weblog-module-admin/src/test/java/com/quanxiaoha/weblog/admin/WeblogModuleAdminApplicationTests.java
new file mode 100644
index 0000000..1b6daf7
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-admin/src/test/java/com/quanxiaoha/weblog/admin/WeblogModuleAdminApplicationTests.java
@@ -0,0 +1,25 @@
+package com.quanxiaoha.weblog.admin;
+
+import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
+import com.quanxiaoha.weblog.common.domain.dos.UserDO;
+import com.quanxiaoha.weblog.common.domain.mapper.UserMapper;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Import;
+
+import java.time.LocalDateTime;
+
+@SpringBootTest(classes = WeblogModuleAdminApplicationTests.Application.class)
+class WeblogModuleAdminApplicationTests {
+ // @Import({
+ // DataSourceAutoConfiguration.class, // Spring DB 自动配置类
+ // DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类
+ // MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
+ // })
+ public static class Application {
+ }
+
+}
diff --git a/weblog-springboot-102/weblog-module-common/.gitignore b/weblog-springboot-102/weblog-module-common/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-common/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/weblog-springboot-102/weblog-module-common/pom.xml b/weblog-springboot-102/weblog-module-common/pom.xml
new file mode 100644
index 0000000..9ef9da3
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-common/pom.xml
@@ -0,0 +1,69 @@
+
+
+ 4.0.0
+
+ com.quanxiaoha
+ weblog-springboot
+ ${revision}
+
+
+ com.quanxiaoha
+ weblog-module-common
+ weblog-module-common
+ weblog-module-common (此模块用于存放一些通用的功能)
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+
+
+
+
+ mysql
+ mysql-connector-java
+
+
+
+ p6spy
+ p6spy
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
diff --git a/weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLog.java b/weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLog.java
new file mode 100644
index 0000000..38eeb0f
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLog.java
@@ -0,0 +1,17 @@
+package com.quanxiaoha.weblog.common.aspect;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+@Documented
+public @interface ApiOperationLog {
+ /**
+ * API 功能描述
+ *
+ * @return
+ */
+ String description() default "";
+
+}
+
diff --git a/weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLogAspect.java b/weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLogAspect.java
new file mode 100644
index 0000000..ef199b4
--- /dev/null
+++ b/weblog-springboot-102/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLogAspect.java
@@ -0,0 +1,102 @@
+
+package com.quanxiaoha.weblog.common.aspect;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.quanxiaoha.weblog.common.utils.JsonUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.*;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.MDC;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.UUID;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@Aspect
+@Component
+@Slf4j
+public class ApiOperationLogAspect {
+
+ /** 以自定义 @ApiOperationLog 注解为切点,凡是添加 @ApiOperationLog 的方法,都会执行环绕中的代码 */
+ @Pointcut("@annotation(com.quanxiaoha.weblog.common.aspect.ApiOperationLog)")
+ public void apiOperationLog() {}
+
+ /**
+ * 环绕
+ * @param joinPoint
+ * @return
+ * @throws Throwable
+ */
+ @Around("apiOperationLog()")
+ public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
+ try {
+ // 请求开始时间
+ long startTime = System.currentTimeMillis();
+
+ // MDC
+ MDC.put("traceId", UUID.randomUUID().toString());
+
+ // 获取被请求的类和方法
+ String className = joinPoint.getTarget().getClass().getSimpleName();
+ String methodName = joinPoint.getSignature().getName();
+
+ // 请求入参
+ Object[] args = joinPoint.getArgs();
+ // 入参转 JSON 字符串
+ String argsJsonStr = Arrays.stream(args).map(toJsonStr()).collect(Collectors.joining(", "));
+
+ // 功能描述信息
+ String description = getApiOperationLogDescription(joinPoint);
+
+ // 打印请求相关参数
+ log.info("====== 请求开始: [{}], 入参: {}, 请求类: {}, 请求方法: {} =================================== ",
+ description, argsJsonStr, className, methodName);
+
+ // 执行切点方法
+ Object result = joinPoint.proceed();
+
+ // 执行耗时
+ long executionTime = System.currentTimeMillis() - startTime;
+
+ // 打印出参等相关信息
+ log.info("====== 请求结束: [{}], 耗时: {}ms, 出参: {} =================================== ",
+ description, executionTime, JsonUtil.toJsonString(result));
+
+ return result;
+ } finally {
+ MDC.clear();
+ }
+ }
+
+ /**
+ * 获取注解的描述信息
+ * @param joinPoint
+ * @return
+ */
+ private String getApiOperationLogDescription(ProceedingJoinPoint joinPoint) {
+ // 1. 从 ProceedingJoinPoint 获取 MethodSignature
+ MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+
+ // 2. 使用 MethodSignature 获取当前被注解的 Method
+ Method method = signature.getMethod();
+
+ // 3. 从 Method 中提取 LogExecution 注解
+ ApiOperationLog apiOperationLog = method.getAnnotation(ApiOperationLog.class);
+
+ // 4. 从 LogExecution 注解中获取 description 属性
+ return apiOperationLog.description();
+ }
+
+ /**
+ * 转 JSON 字符串
+ * @return
+ */
+ private Function