当前位置: 首页 > news >正文

【MyBatis新手避坑】详解 `Could not find resource ...Mapper.xml` 错误

文章目录

      • 一、 问题发现:当满屏红色指向一个“文件找不到”的错误
      • 二、 为啥?深入理解 Maven/Gradle 的构建约定
      • 三、 咋办?两种解决方案(强烈推荐第一种)
        • 方案一:【最佳实践】将 Mapper.xml 文件移至 `resources` 目录
        • 方案二:【备用方案】修改 `pom.xml` 配置文件
      • 四、 总结

如果你是一位正在学习 MyBatis 的 Java 开发者,那么你很可能在某个深夜,满怀期待地运行第一个测试时,被一盆红色的 ExceptionInInitializerError 冷水浇得透心凉。别灰心,这几乎是每个 MyBatis 新手的“成年礼”。今天,我们就来彻底解剖这个经典的错误,让你不仅知道“咋办”,更明白“为啥”。

一、 问题发现:当满屏红色指向一个“文件找不到”的错误

让我们先回顾一下案发现场。你可能像我一样,精心编写了 StudentDao 接口、StudentMapper.xml 映射文件,以及一个用于获取 SqlSessionMyBatisUtils 工具类。然后,当你运行 StudentDaoTest 时,控制台却无情地打印出如下错误:

Exception in thread "main" java.lang.ExceptionInInitializerErrorat com.github.xxx.dao.StudentDaoTest.main(StudentDaoTest.java:16)
Caused by: org.apache.ibatis.exceptions.PersistenceException: 
### Error building SqlSession.
### The error may exist in com/github/xxx/dao/StudentMapper.xml
### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource com/github/xxx/dao/StudentMapper.xml...
Caused by: java.io.IOException: Could not find resource com/github/xxx/dao/StudentMapper.xml...

作为“侦探”,我们应该学会从错误堆栈(Stack Trace)中寻找线索。拨开层层上报的异常迷雾,我们最终会定位到最根本的原因(Root Cause):

java.io.IOException: Could not find resource com/github/xxx/dao/StudentMapper.xml

这句话的潜台词非常直白:“嘿,我(MyBatis)找不到你让我加载的 StudentMapper.xml 这个文件!

二、 为啥?深入理解 Maven/Gradle 的构建约定

要理解为什么会找不到,我们必须先了解 Java 项目构建工具(如 Maven 或 Gradle)的基本工作原理,这被称为“约定优于配置”(Convention over Configuration)。

在一个标准的 Maven 项目中,目录结构有着明确的约定:

  • src/main/java存放 Java 源代码(.java 文件)。构建时,这个目录下的 .java 文件会被编译成 .class 文件,并输出到 target/classes 目录。
  • src/main/resources存放所有资源文件(非 .java 文件)。例如 .xml, .properties 等。构建时,这个目录下的所有文件和目录结构会被原封不动地复制target/classes 目录。

那么,问题的根源就浮出水面了:

我们通常习惯于将 StudentMapper.xml 和它的接口 StudentDao.java 放在同一个包下,也就是 src/main/java/com/github/xxx/dao/。然而,根据 Maven 的默认约定,它只会编译 java 目录下的 .java 文件,而会忽略掉所有的 .xml 文件

最终导致的结果是,项目编译打包后,你的 target/classes 目录中只包含了 StudentDao.class,而 StudentMapper.xml 却“人间蒸发”了。当程序运行时,MyBatis 在 Classpath(也就是 target/classes)里自然找不到这个至关重要的 XML 文件,于是毫不犹豫地抛出了 IOException

三、 咋办?两种解决方案(强烈推荐第一种)

既然找到了病因,对症下药就变得非常简单了。

方案一:【最佳实践】将 Mapper.xml 文件移至 resources 目录

这是最符合 Maven 规范,也是业界通用的标准做法。它能确保你的项目结构清晰,职责分明。

  1. 定位 resources 目录:在你的项目结构中,找到 src/main/resources

  2. 创建镜像目录:在 resources 目录下,手动创建与你的 Dao 接口包名完全相同的目录结构。

    • 例如,如果你的 Dao 接口在 com.github.xxx.dao,那么就在 resources 下创建 com/github/xxx/dao
  3. 移动文件:将 StudentMapper.xml 文件从 src/main/java/... 目录剪切并粘贴到新创建的 src/main/resources/com/github/xxx/dao/ 目录下。

最终,你的项目结构会是这样,清爽又规范:

src
├── main
│   ├── java
│   │   └── com/github/xxx/dao
│   │       └── StudentDao.java          # 接口留在这里
│   │
│   └── resources
│       ├── com/github/xxx/dao
│       │   └── StudentMapper.xml      # XML文件移到这里
│       │
│       └── mybatis-config.xml         # 其他资源文件
│
└── test
  1. 重新运行:现在,重新运行你的测试代码。Maven 会将 resources 下的所有内容 faithfully 复制到 target/classes,MyBatis 将顺利找到它的映射文件,错误也就随之消失。
方案二:【备用方案】修改 pom.xml 配置文件

如果你有强烈的个人偏好,坚持要将 .java.xml 文件放在一起,也不是不可以。你需要通过修改 pom.xml 文件来覆盖 Maven 的默认行为

  1. 打开项目根目录下的 pom.xml 文件。
  2. <build> 标签内,添加如下 <resources> 配置。这相当于告诉 Maven:“除了 resources 目录,也请把 java 目录下的 .xml 文件当作资源文件处理。”
<build><resources><!-- 处理 src/main/java 目录下的 XML 文件 --><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes><filtering>false</filtering></resource><!-- 确保 src/main/resources 的默认行为不受影响 --><resource><directory>src/main/resources</directory><includes><include>**/*.xml</include><include>**/*.properties</include></includes><filtering>true</filtering></resource></resources>
</build>
  1. 保存 pom.xml 文件,等待 IDE 刷新 Maven 配置后,再次运行即可。

虽然这种方法也能解决问题,但我个人不太推荐。因为它破坏了“约定优于配置”的原则,可能会让其他接手你项目的开发者感到困惑。

四、 总结

编程中的许多错误,看似是代码逻辑问题,实则是对工具链和底层原理理解不够深入。Could not find resource 这个错误就是最好的例子。

  • 病因:Maven/Gradle 默认不打包 src/main/java 目录下的资源文件。
  • 药方:遵循“约定优于配置”的原则,将资源文件(如 .xml)放置在 src/main/resources 目录下,并保持与 Java 包结构一致的目录结构。

希望这篇博客能帮助你彻底告别这个“新手村”的拦路虎。如果你觉得有帮助,欢迎点赞、收藏和分享!下次遇到问题,记得先从“为什么”开始思考,你会发现编程的世界会因此变得更加清晰。Happy Coding!

http://www.dtcms.com/a/318633.html

相关文章:

  • Class30数据增广
  • Leetcode刷题营:字符串相关--第35,36题
  • 深度探索:非静态内部类不能定义 static 成员属性和方法 及 静态内部类的必要性
  • 若依前后端分离版学习笔记(六)——JWT
  • K8S、Docker安全漏洞靶场
  • Go语言“fmt”包详解
  • KNN算法:从原理到实战应用
  • SDIO三种触发枚举的方式
  • Python高级排序技术:非原生可比对象的自定义排序策略详解
  • 第14届蓝桥杯Scratch选拔赛初级及中级(STEMA)真题2022年11月27日
  • Java面试宝典:类加载器分层设计与核心机制解析
  • 栈与队列的基本逻辑
  • ToonMe:将照片转换为卡通风格的艺术作品
  • docker run 入门到进阶:容器启动背后的门道
  • 嵌入式开发入门—电感器
  • CASA模型原理详细解析
  • 【unity 中的RectTransform组件中的`RectTransform.sizeDelta理解】
  • Unity3D水下场景与游泳系统开发指南
  • ubuntu18.04在fstab文件中挂载硬盘失败,系统进入紧急模式的解决方法
  • js 从 json 中取 key 的值
  • 云平台托管集群:EKS、GKE、AKS 深度解析与选型指南-第一章
  • 磁悬浮转子变转速工况下的振动抑制全解析
  • 什么是「回调函数」 Callback Function ?
  • Linux(17)——Linux进程信号(上)
  • 28.(vue3.x+vite)el-pagination中文设置(兼容其他elementPlus组件)
  • PaddleOCR 多线程并发问题
  • K8S命令记录
  • 利用多线程设计群ping工具
  • 5G随身WiFi怎么选?实测延迟/网速/续航,中兴V50适合商务,格行MT700适合短租、户外党~避坑指南+适用场景全解析
  • 无监督学习之K-means算法