J2EE
weblog-module-common 是项目核心公共组件库,作用如下:
基础架构:提供全局常量、统一 API 响应封装,配置 MyBatis-Plus 分页 / 批量插入能力。
领域模型:集中管理数据对象(DO,如 ArticleDO )及数据访问接口(Mapper,如 ArticleMapper )。
公共能力:覆盖事件总线、接口日志 / 性能统计切面、全局异常处理、IP / 日期工具类。
跨模块支撑:向业务模块(如 weblog-module-admin )输出数据接口、公共配置、枚举(如 ResponseCodeEnum )、通用注解(如 @ApiOperationLog )。
模块按功能拆分为 constant、config 等子包,通过聚合公共代码减少冗余,提升复用性,统一基础能力支撑。
weblog-module-admin模块作用总结
该模块是项目的 管理后台核心模块 ,负责提供博客系统的后台管理功能,主要作用包括:
- 核心业务功能实现
- 文章管理 :发布、编辑、删除文章及分页查询( AdminArticleController 、 AdminArticleServiceImpl )
AdminArticleServiceImpl.java
- 标签管理 :标签的增删改查和批量操作( AdminTagServiceImpl )
AdminTagServiceImpl.java
- 分类管理 :文章分类的创建与维护( AdminCategoryServiceImpl )
- 系统配置 :博客基本信息设置( AdminBlogSettingServiceImpl )
- 用户管理 :管理员密码修改等权限控制 2. 数据访问层实现
- 提供各业务实体的数据库操作实现,如 AdminArticleDaoImpl 、 AdminArticleContentDaoImpl 等
AdminArticleDaoImpl.java
- 使用MyBatis-Plus的QueryWrapper实现动态条件查询
- 支持分页查询、日期范围筛选和关键词搜索 3. 异步任务处理
- PV统计 :通过 PVIncreaseAsyncTask 异步更新文章阅读量
PVIncreaseAsyncTask.java
- 基于Spring的 @Async 注解实现非阻塞处理 4. 安全认证与授权
- 集成Spring Security实现基于角色的权限控制
- 通过JWT实现无状态认证( WebSecurityConfig )
WebSecurityConfig.java
- 配置URL访问权限和资源保护策略 5. 文件存储管理
- 集成MinIO对象存储服务( MinioConfig 、 MinioUtil )
MinioUtil.java
- 实现图片上传、URL转换和存储桶管理 模块结构特点
采用标准的分层架构设计:
com.quanxiaoha.weblog.admin
├── async/ # 异步任务
├── config/ # 配置类
├── controller/ # 控制器
├── service/ # 业务逻辑
│ └── impl/ # 服务实现
├── dao/ # 数据访问
│ └── impl/ # DAO实现
├── model/ # 数据模型
└── utils/ # 工具类
该模块通过提供完整的后台管理功能,实现了对博客系统的全面管控,同时采用异步处理和权限控制等机制,确保系统的高性能和安全性。
项目中的 model
目录主要承担 数据模型定义 的核心功能,具体作用如下:
1. 统一管理数据传输对象(DTO/VO)
该目录下的 vo
子目录按业务模块(如article、category、tag等)组织,包含两类核心对象:
- 请求参数VO :如
QueryArticlePageListReqVO
定义文章分页查询条件 - 响应数据VO :如
QueryArticleDetailRspVO
封装文章详情返回结果
2. 实现请求参数校验
通过JSR-303注解(如 @NotBlank 、 @NotNull 、 @Length )在VO类中定义校验规则,例如:
@NotBlank(message = "博客名称不能为空")
private String blogName;
确保接口输入数据的合法性,减少业务层校验逻辑冗余。
3. 业务逻辑与数据存储解耦
通过VO对象隔离Controller层与Service/DAO层的数据交互,避免直接暴露数据库实体类(Entity),例如:
- 前端请求通过 ReqVO 接收后转换为业务对象处理
- 后端响应通过 RspVO 组装后返回,隐藏内部实现细节
4. 模块化代码组织
按功能模块划分的子目录结构(如article/、category/、tag/)使代码职责清晰,例如:
article
集中管理文章相关的所有数据模型dashboard
存放仪表盘统计数据模型
综上,该目录是Admin模块的 数据契约中心 ,通过标准化的数据模型定义,保障了接口交互的规范性、数据校验的统一性和代码结构的清晰性。
项目中的关键词模糊搜索功能主要基于MyBatis-Plus的查询构造器实现,支持多种场景下的灵活搜索需求,以下是具体实现方式:
1. 基础模糊搜索实现(文章标题搜索)
在文章管理模块中,通过MyBatis-Plus的 like 方法实现标题关键词模糊匹配,核心代码位于:
AdminArticleDaoImpl.java
实现原理 :
- 使用 like 方法自动拼接 %keyword% 模糊匹配格式
- 通过 Objects.nonNull(searchTitle) 实现条件动态判断,避免空搜索条件影响查询效率
- 生成的SQL片段: WHERE title LIKE '%搜索关键词%'
2. 高级模糊搜索实现(标签搜索,忽略大小写)
在标签管理模块中,实现了忽略大小写的关键词模糊搜索,核心代码位于:
AdminTagDaoImpl.java
实现原理 :
- 使用 apply 方法自定义SQL片段,通过 UPPER() 和 LOWER() 函数实现大小写不敏感搜索
- 使用 CONCAT('%', {0}, '%') 拼接模糊匹配格式,避免SQL注入风险
- 生成的SQL片段: WHERE NAME like UPPER('%关键词%') OR NAME LIKE LOWER('%关键词%')
3. 分类名称模糊搜索
在分类管理模块中同样实现了基础模糊搜索功能:
AdminCategoryServiceImpl.java
wrapper.lambda()
.like(Objects.nonNull
(categoryName),
CategoryDO::getName,
categoryName)
.ge(Objects.nonNull(startDate),
CategoryDO::getCreateTime,
startDate)
.le(Objects.nonNull(endDate),
CategoryDO::getCreateTime,
endDate)
.orderByDesc
(CategoryDO::getCreateTime);
技术特点总结
- 动态条件控制 :通过 Objects.nonNull() 判断是否添加搜索条件,避免无效查询
- 多种匹配模式 :支持基础模糊搜索和大小写不敏感搜索两种模式
- 安全防注入 :使用MyBatis-Plus参数绑定机制,避免直接字符串拼接导致的SQL注入风险
- 性能优化 :结合分页查询,避免全表扫描,提升搜索效率
创新点一:基于MyBatis-Plus的动态条件查询与智能分页实现
优化叙述 :
采用MyBatis-Plus框架实现了高度灵活的动态查询机制,通过Lambda表达式构建器实现无SQL侵入式的条件拼接,结合内置分页插件实现高性能数据分页。该方案支持多条件组合查询、动态日期范围筛选和关键词模糊搜索,同时保持代码的可维护性和扩展性。
核心实现模块 :
-
AdminArticleDaoImpl.java
-
queryArticlePageList
:实现文章多条件分页查询 -
AdminTagDaoImpl.java
-
queryTagPageList
:标签分页查询实现 -
AdminCategoryServiceImpl.java
-
queryCategoryPageList
:分类动态条件查询
创新点二:基于MinIO的高性能图片存储与URL访问控制
优化叙述 :
集成MinIO对象存储服务实现分布式图片存储,通过自定义URL转换器实现API端点与公共访问端点的智能转换,确保图片资源安全高效访问。系统自动处理图片URL的生成与转换,支持海量图片存储与高并发访问场景,同时提供灵活的访问权限控制。
核心实现模块 :
-
AdminArticleServiceImpl.java
-
convertUrl
:MinIO URL转换核心方法
private String convertUrl(String url)
{
if (url == null || url.isEmpty())
{
return url;
}
// 如果URL包含API端点,则替换为公共访问
端点
if (url.contains(apiEndpoint)) {
String convertedUrl = url.
replace(apiEndpoint,
publicEndpoint);
log.debug("转换Minio URL: {}
-> {}", url, convertedUrl);
return convertedUrl;
}
return url;
}
-
ArticleServiceImpl.java
-
使用MinioUrlConverter处理文章封面图URL转换
-
ArchiveServiceImpl.java
-
处理归档页面文章图片URL转换
图片上传到MinIO及前端调用业务流程 一、整体架构
项目采用前后端分离架构,图片上传流程涉及:
- 前端 :负责文件选择、上传请求发送和图片渲染
- 后端 :处理上传请求、与MinIO交互、URL管理
- MinIO :对象存储服务,存储图片文件 二、后端实现流程 1. 图片上传核心实现
后端通过 MinioClient 实现文件上传,主要逻辑包括:
// 伪代码示例:MinIO上传核心逻辑
public String uploadImage(MultipartFile file) {
// 1. 生成唯一文件名
String fileName = UUID.randomUUID().toString() + getFileExtension(file.
getOriginalFilename());
// 2. 上传到MinIO指定桶
minioClient.putObject(PutObjectArgs.builder()
.bucket("weblog")
.object("image/" + fileName)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build());
// 3. 生成访问URL
return minioConfig.getPublicEndpoint() + "/weblog/image/" + fileName;
}
``` 2. URL管理策略
- 双端点配置 :
- API端点( minio.endpoint ):内部使用,如 http://127.0.0.1:9005
- 公开端点( minio.publicEndpoint ):前端访问,如 http://127.0.0.1:9000
- 配置位置: application.yml 中的MinIO配置项
- URL转换工具 :
通过 `MinioUrlConverter.java` 实现URL标准化,确保存储和返回的URL使用统一格式。 3. 数据持久化
上传成功后,图片URL会存储在:
- 文章标题图: `ArticleDO` 的 titleImage 字段
- 文章内容图:存储在文章内容HTML中,与文章内容一起保存在 `ArticleContentDO` 的 content 字段 4. 历史数据迁移
系统启动时, `MinioMigrationTool.java` 会自动执行:
- 检测并修复数据库中使用9005端口的URL
- 支持Markdown和HTML两种格式的图片链接转换
- 批量处理文章标题图和内容图 三、前端调用流程 1. 图片上传交互
前端通过表单或富文本编辑器上传图片,典型流程:
// 伪代码:前端上传实现
async function uploadImage(file) {
const formData = new FormData();
formData.append('file', file);
const response = await axios.post('/admin/upload/image', formData, {
headers: {'Content-Type': 'multipart/form-data'}
});
return response.data.data.url; // 返回MinIO图片URL
}
在 `article-detail.vue` 中:
- 使用 v-html 指令渲染包含图片的文章内容
- 通过 `MinioImageDirective` 自动修正URL
- 实现双重保障:
1. 主动修正: processArticleContent 方法替换内容中的URL端口
2. 错误恢复: handleImageError 在加载失败时尝试备用端口 3. URL修正逻辑
`minioImageFixer.js` 提供三大核心功能:
- fixMinioImageUrl :自动替换URL中的端口
- handleImageError :图片加载失败时的重试机制
- MinioImageDirective :全局Vue指令,统一处理图片URL 四、完整业务流程图
┌───────────┐ ┌───────────┐ ┌───────────┐
│ 前端 │ │ 后端 │ │ MinIO │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
│ 1. 上传图片请求 │ │
├────────────────>│ │
│ │ │
│ │ 2. 存储图片 │
│ ├────────────────>│
│ │ │
│ │ 3. 返回URL │
│ │<────────────────┤
│ │ │
│ 4. 返回URL给前端 │ │
│<────────────────┤ │
│ │ │
│ 5. 渲染图片(带URL修正) │ │
├────────────────────────────────────>│
│ │ │
1. 端口适配 :解决MinIO内部API端口(9005)与公开访问端口(9000)不一致问题
2. 双重保障 :同时在后端(存储时)和前端(渲染时)处理URL,确保兼容性
3. 自动化迁移 :系统启动时自动修复历史数据中的URL问题
4. 错误恢复 :图片加载失败时自动尝试备用URL
通过这套流程,系统实现了图片的可靠上传、存储和访问,同时处理了不同环境下的URL兼容性问题。
f:\Code\blog\WeBlog-master1\WeBlog-master\weblog-springboot\weblog-module-common\src\main\java\com\quanxiaoha\weblog
weblog-module-admin/
├── .gitignore # Git版本控制忽略文件配置
├── pom.xml # Maven项目依赖管理文件
├── src/ # 源代码根目录
│ └── main/ # 主程序代码目录
│ └── java/ # Java源代码目录
│ └── com/ # 公司域名反向包路径
│ └── quanxiaoha/ # 项目作者包路径
│ └── weblog/ # 项目核心包路径
│ └── admin/ # 管理后台核心功能包
│ ├── async/ # 异步任务处理类目录
│ │ └── PVIncreaseAsyncTask.java # 文章PV阅读量异步增加任务
│ ├── config/ # 配置类目录
│ │ ├── MinioConfig.java # Minio对象存储客户端配置类
│ │ ├── MinioProperties.java # Minio配置参数读取类
│ │ ├── ThreadPoolConfig.java # 线程池配置类
│ │ └── WebSecurityConfig.java # 管理后台安全配置类
│ ├── controller/ # 控制器(接口)类目录
│ │ ├── AdminUserController.java # 管理员用户接口控制器
│ │ └── AdminBlogSettingController.java # 博客设置接口控制器
│ ├── service/ # 业务逻辑服务类目录
│ │ ├── impl/ # 服务实现类子目录
│ │ │ ├── AdminArticleServiceImpl.java # 文章管理业务实现
│ │ │ └── AdminFileServiceImpl.java # 文件上传业务实现
│ ├── utils/ # 工具类目录
│ │ └── MinioUtil.java # Minio文件操作工具类
│ └── model/ # 模型(VO/DTO)类目录
│ └── vo/ # 视图对象(请求/响应)子目录
└── target/ # Maven构建输出目录
### 后台文章管理功能实现详解
### 一、整体架构
项目采用经典的MVC分层架构实现文章管理功能:
- Controller层 :接收前端请求,返回响应结果
- Service层 :处理核心业务逻辑
- DAO层 :与数据库交互
- Model层 :定义数据对象和视图对象
### 二、文章发布流程
1. 请求入口 :
@PostMapping("/publish")
@ApiOperationLog(description = "发布文章")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public Response publishArticle(@RequestBody @Validated PublishArticleReqVO
publishArticleReqVO) {
return articleService.publishArticle(publishArticleReqVO);
}
2. 业务逻辑处理 : `AdminArticleServiceImpl.java` 中的 publishArticle 方法
- 使用 TransactionTemplate 管理事务
- 转换MinIO图片URL( convertUrl 方法)
- 保存文章基本信息到 article 表
- 保存文章内容到 article_content 表
- 处理分类关联
- 处理标签关联( handleTagBiz 方法)
3. 数据持久化 :
- `AdminArticleDao.java` :文章基本信息CRUD
- `AdminArticleContentDao.java` :文章内容CRUD
- `AdminArticleCategoryRelDao.java` :文章分类关联
### 三、文章查询流程
1. 分页查询 :
@PostMapping("/list")
@ApiOperationLog(description = "获取文章分页数据")
public Response queryArticlePageList(@RequestBody QueryArticlePageListReqVO
queryArticlePageListReqVO) {
return articleService.queryArticlePageList(queryArticlePageListReqVO);
}
2. 详情查询 :
@PostMapping("/detail")
@ApiOperationLog(description = "获取文章详情")
public Response queryArticleDetail(@RequestBody QueryArticleDetailReqVO
queryArticleDetailReqVO) {
return articleService.queryArticleDetail(queryArticleDetailReqVO);
}
- 联表查询文章基本信息、内容和关联标签
- 转换图片URL为公共访问地址
### 四、文章编辑流程
1. 请求入口 :
@PostMapping("/update")
@ApiOperationLog(description = "修改文章")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public Response updateArticle(@RequestBody @Validated UpdateArticleReqVO
updateArticleReqVO) {
return articleService.updateArticle(updateArticleReqVO);
}
2. 业务逻辑 :
- 更新文章基本信息
- 更新文章内容
- 处理标签变更(新增/删除标签关联)
- 处理分类变更
### 五、文章删除流程
1. 请求入口 :
@PostMapping("/delete")
@ApiOperationLog(description = "删除文章")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public Response deleteArticle(@RequestBody @Validated DeleteArticleReqVO
deleteArticleReqVO) {
return articleService.deleteArticle(deleteArticleReqVO);
}
2. 业务逻辑 :
@Override
@Transactional(rollbackFor = Exception.class)
public Response deleteArticle(DeleteArticleReqVO deleteArticleReqVO) {
Long articleId = deleteArticleReqVO.getArticleId();
articleDao.deleteById(articleId);
articleContentDao.deleteByArticleId(articleId);
return Response.success();
}
- 级联删除文章基本信息和内容
- 事务管理确保数据一致性
### 六、核心文件总结
1. 控制器 :
- `AdminArticleController.java` :处理所有文章相关请求
2. 服务层 :
- `AdminArticleService.java` :服务接口定义
- `AdminArticleServiceImpl.java` :业务逻辑实现
3. 数据访问层 :
- AdminArticleDao :文章基本信息操作
- AdminArticleContentDao :文章内容操作
- AdminArticleCategoryRelDao :文章分类关联操作
- AdminArticleTagRelDao :文章标签关联操作
4. 数据模型 :
- 请求对象: PublishArticleReqVO 、 UpdateArticleReqVO 等
- 响应对象: QueryArticleDetailRspVO 、 QueryArticlePageListRspVO 等
- 数据对象: ArticleDO 、 ArticleContentDO 等
# weblog-module-common模块文件及功能注释
## 根目录
- `.gitignore` - Git忽略规则配置文件
- `pom.xml` - Maven项目配置文件
- `readme.txt` - 模块说明文件
## src/main/java/com/quanxiaoha/weblog/common
### 核心类
- `PageResponse.java` - 分页响应封装类
- `Response.java` - 统一API响应封装类
### aspect包(切面相关)
- `ApiOperationLog.java` - API操作日志注解
- `ApiOperationLogAspect.java` - API操作日志切面实现
### config包(配置类)
- `EventBusConfig.java` - 事件总线配置
- `InsertBatchSqlInjector.java` - 批量插入SQL注入器
- `MyBaseMapper.java` - 自定义MyBatis-Plus基础Mapper
- `MybatisPlusConfig.java` - MyBatis-Plus配置
### constant包(常量)
- `Constants.java` - 全局静态常量
### domain包(领域模型)
#### dos子包(数据对象)
- `ArticleCategoryRelDO.java` - 文章-分类关联实体
- `ArticleContentDO.java` - 文章内容实体
- `ArticleCountDO.java` - 文章统计实体
- `ArticleDO.java` - 文章实体
- `ArticleTagRelDO.java` - 文章-标签关联实体
- `BlogSettingDO.java` - 博客设置实体
- `CategoryDO.java` - 分类实体
- `StatisticsArticlePVDO.java` - 文章PV统计实体
- `TagDO.java` - 标签实体
- `UserDO.java` - 用户实体
- `UserRoleDO.java` - 用户角色实体
- `VisitorRecordDO.java` - 访客记录实体
#### mapper子包(数据访问)
- `ArticleCategoryRelMapper.java` - 文章-分类关联Mapper
- `ArticleContentMapper.java` - 文章内容Mapper
- `ArticleMapper.java` - 文章Mapper
- `ArticleTagRelMapper.java` - 文章-标签关联Mapper
- `BlogSettingMapper.java` - 博客设置Mapper
- `CategoryMapper.java` - 分类Mapper
- `StatisticsArticlePVMapper.java` - 文章PV统计Mapper
- `TagMapper.java` - 标签Mapper
- `UserMapper.java` - 用户Mapper
- `UserRoleMapper.java` - 用户角色Mapper
- `VisitorMapper.java` - 访客Mapper
### enums包(枚举)
- `EventEnum.java` - 事件类型枚举
- `ResponseCodeEnum.java` - 响应码枚举
### eventbus包(事件总线)
- `ArticleEvent.java` - 文章事件
- `EventListener.java` - 事件监听器
### exception包(异常处理)
- `BaseExceptionInterface.java` - 基础异常接口
- `BizException.java` - 业务异常
- `GlobalExceptionHandler.java` - 全局异常处理器
- `NotAuthorizedException.java` - 未授权异常
- `ResourceNotFoundException.java` - 资源未找到异常
### model/vo包(视图对象)
- `QuerySelectListRspVO.java` - 查询下拉列表响应VO
### utils包(工具类)
- `AgentRegionUtils.java` - 用户代理区域解析工具
#Workspace
以下是两个目录的核心区别分析,从功能定位、内容组成和技术实现三个维度展开:
### 一、功能定位与职责边界
维度 `model` `domain` 核心职责 定义 接口契约 ,处理前后端数据传输 定义 数据持久化模型 ,处理数据库交互 模块归属 属于 personalblog-module-admin 业务模块,仅限管理后台使用 属于 personalblog-module-common 公共模块,全项目共享 依赖方向 依赖 domain 层进行数据持久化操作 被上层业务模块依赖,不依赖其他业务模块
### 二、目录结构与内容组成 1. Admin Model 目录
model/
├── package-info.java
└── vo/ // 按业务模块划分
的视图对象
├── article/ // 文章相关VO
├── category/ // 分类相关VO
├── blogsetting/ // 博客设置相关VO
└── ... // 其他业务模块VO
- 核心内容 :请求/响应数据模型(VO),如:
- `PublishArticleReqVO` (文章发布请求)
- `AddCategoryReqVO` (分类创建请求) 2. Common Domain 目录
domain/
├── dos/ // 数据对象
(Database Object)
│ ├── ArticleDO.java
│ ├── CategoryDO.java
│ └── ...
└── mapper/ // 数据访问接口
├── ArticleMapper.java
├── CategoryMapper.java
└── ...
- 核心内容 :
- DO类 :如 `ArticleDO` (映射数据库表 t_article )
- Mapper接口 :如 `ArticleMapper` (提供数据库操作方法)
### 三、技术实现差异
特性 Admin Model 目录 Common Domain 目录 核心注解 以 参数校验注解 为主: @NotBlank(message = "文章头图不能为空") @Length(min = 1, max = 10) 以 数据库映射注解 为主: @TableName("t_category") @TableId(type = IdType.AUTO) 数据流向 前端 ←→ Controller 层数据传输载体 Service 层 ←→ 数据库数据持久化载体 依赖框架 Lombok( @Data / @Builder ) Validation API(参数校验) MyBatis-Plus( BaseMapper ) 数据库驱动(JDBC) 示例代码 java<br>@Data<br>public class AddCategoryReqVO {<br> @NotBlank(message = "分类名称不能为空")<br> @Length(min = 1, max = 10)<br> private String name;<br>}<br> java<br>@Data<br>@TableName("t_category")<br>public class CategoryDO {<br> @TableId(type = IdType.AUTO)<br> private Long id;<br> private String name;<br> private Date createTime;<br>}<br>
### 四、典型业务流程关系
1. 前端提交分类创建请求 → AddCategoryReqVO (Model层)接收并校验
2. Controller 层将 VO 转换为 DO → CategoryDO (Domain层)
3. Service 层调用 CategoryMapper (Domain层)执行数据库插入
4. 数据库操作结果通过 QueryCategoryPageListRspVO (Model层)返回前端
这种分层设计实现了 接口契约 与 数据持久化 的解耦,符合分层架构设计原则,同时通过模块划分确保了代码的复用性和维护性。