Mapper XML 文件纳入 classpath 的解决方案
文章目录
- 一、背景与问题描述
- 二、原理与思路
- 三、具体配置示例
- 四、验证与注意事项
- 五、总结
一、背景与问题描述
在使用 MyBatis 进行开发时,一般会将 Mapper 接口(.java) 存放于 src/main/java
,而将对应的 Mapper XML(.xml) 存放于 src/main/resources
下,以便在 Maven 打包时,.xml
文件能够自动复制到 target/classes
目录,最终纳入 classpath 中。
如果因项目结构或其他原因,需要将 Mapper XML 与 Mapper 接口 放置在同一目录(即 src/main/java/com/xxx/dao
),就会遇到下列问题:
默认情况下,Maven 只编译
src/main/java
中的.java
文件,并不会把.xml
文件复制到target/classes
。结果是 MyBatis 在运行时无法在 classpath 中找到对应的 XML 映射文件,导致出现 “Invalid bound statement (not found)
” 或 “Could not find mapper file…” 等错误。
为解决此问题,需要修改 Maven 的资源复制配置,让 src/main/java
中的 .xml
文件也被视作资源文件,编译打包时一并放入 target/classes
。
二、原理与思路
- Maven 资源(resources)机制
- 默认情况下,Maven 会将
src/main/resources
目录下的所有文件拷贝到target/classes
,因此在运行或打包(jar/war)时,这些文件会处于 classpath 内。 - 而
src/main/java
目录下通常只放置.java
文件进行编译,.xml
、.properties
等非.java
文件不会自动复制到target/classes
。
- 默认情况下,Maven 会将
- 将特定目录或文件纳入资源
- Maven 提供
<resources>
配置,让我们可以对任意目录执行资源复制,也可以通过<includes>
/<excludes>
来筛选文件类型。 - 只要在
<resources>
中添加一个<resource>
块,指定directory=src/main/java
并include=**/*.xml
,就能让.xml
文件也被复制到target/classes
。
- Maven 提供
- MyBatis 加载 Mapper XML
- MyBatis 需要在 classpath 中找到 Mapper XML 文件,无论是通过
mapperLocations=classpath*:**/*.xml
方式,还是在mybatis-config.xml
里<mapper resource="...">
方式,都依赖文件实际存在于 classpath。 - 因此,只有当 Maven 把
.xml
复制进target/classes
后,MyBatis 才能在classpath
中正确读取这些文件。
- MyBatis 需要在 classpath 中找到 Mapper XML 文件,无论是通过
三、具体配置示例
在你的项目的 pom.xml
中,找到 <build>
节点,添加(或修改)如下 <resources>
配置:
<build>
<!-- 项目打包名称,可不关注 -->
<finalName>intelligenceCommand</finalName>
<resources>
<!-- 默认资源目录,保留不动。如果你没有此段,可自行添加 -->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
<!-- 额外添加,将 src/main/java 下的所有 .xml 文件也视为资源 -->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
配置解析
<directory>src/main/java</directory>
指定要扫描的目录为src/main/java
。<includes><include>**/*.xml</include></includes>
仅复制此目录下所有.xml
文件(递归子目录),其余.java
文件不会被当作资源。src/main/resources
配置还保留,方便项目其他配置文件(如application.properties
、mybatis-config.xml
等)也能被复制到target/classes
。
当你执行 mvn clean package
(或其他构建命令)后,Maven 就会:
- 编译
src/main/java
下的.java
文件生成.class
放到target/classes
- 同时 把
src/main/java
下的.xml
文件复制到target/classes
这样在运行阶段,所有 .xml
文件便存在于 classpath 下,MyBatis 即可加载它们。
四、验证与注意事项
-
查看编译输出
- 在执行
mvn clean package
后,进入target/classes/com/xxx/dao/
目录,确认能看到相应的.xml
文件。如果没有,说明资源配置未生效或写法有误。
- 在执行
-
MyBatis 中的 Mapper 配置
-
需要在 mybatis-config.xml或者 SqlSessionFactoryBean 的 mapperLocations中指定正确的扫描路径:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="personDataSource" /> <property name="mapperLocations" value="classpath*:com/zxz/intelligenceCommand/dao/*.xml" /> ... </bean>
或者在 mybatis-config.xml 中写:
<configuration> <mappers> <mapper resource="com/zxz/intelligenceCommand/dao/RoleDao.xml"/> <mapper resource="com/zxz/intelligenceCommand/dao/UserDao.xml"/> ... </mappers> </configuration>
-
只要你保证编译后路径下有
RoleDao.xml
等文件,MyBatis 就能找到。
-
-
避免与默认资源重复或冲突
- 如果你在
src/main/resources
下也有同名.xml
,可能会产生冲突或覆盖(除非你刻意这么做)。一般不建议同名重叠。
- 如果你在
-
项目结构最佳实践
- 虽然通过这种方式可以将
.xml
文件和.java
文件放在同一目录,但更常见或更推荐的做法是把 Mapper XML 放进src/main/resources/mapper
之类的专门目录,使结构更清晰。
- 虽然通过这种方式可以将
五、总结
目标:在 src/main/java
与 .java
同一目录下的 .xml
文件也能编译进 classpath
方法:在 pom.xml
的 <build><resources>
中,额外增加一个 <resource>
配置项,指向 src/main/java
并用 <include>**/*.xml</include>
,即可将对应的 XML 文件复制到 target/classes
。
通过以上操作,可确保 MyBatis 在运行时正常加载这些 Mapper XML 文件,避免由于找不到映射而引发的 “Invalid bound statement (not found)
” 等错误。