J2EE

weblog-module-common 是项目核心公共组件库,作用如下:

基础架构:提供全局常量、统一 API 响应封装,配置 MyBatis-Plus 分页 / 批量插入能力。
领域模型:集中管理数据对象(DO,如 ArticleDO )及数据访问接口(Mapper,如 ArticleMapper )。
公共能力:覆盖事件总线、接口日志 / 性能统计切面、全局异常处理、IP / 日期工具类。
跨模块支撑:向业务模块(如 weblog-module-admin )输出数据接口、公共配置、枚举(如 ResponseCodeEnum )、通用注解(如 @ApiOperationLog )。

模块按功能拆分为 constant、config 等子包,通过聚合公共代码减少冗余,提升复用性,统一基础能力支撑。

weblog-module-admin模块作用总结

该模块是项目的 管理后台核心模块 ,负责提供博客系统的后台管理功能,主要作用包括:

  1. 核心业务功能实现
  • 文章管理 :发布、编辑、删除文章及分页查询( 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);

技术特点总结

  1. 动态条件控制 :通过 Objects.nonNull() 判断是否添加搜索条件,避免无效查询
  2. 多种匹配模式 :支持基础模糊搜索和大小写不敏感搜索两种模式
  3. 安全防注入 :使用MyBatis-Plus参数绑定机制,避免直接字符串拼接导致的SQL注入风险
  4. 性能优化 :结合分页查询,避免全表扫描,提升搜索效率

创新点一:基于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层)返回前端
这种分层设计实现了 接口契约 与 数据持久化 的解耦,符合分层架构设计原则,同时通过模块划分确保了代码的复用性和维护性。
posted @ 2025-06-18 11:00  joiny-  阅读(19)  评论(0)    收藏  举报