问题起因

在之前的一篇文章mybatis看这一篇就够了当中,提到过,在使用mybatis时,有时候需要把编写了SQL语句的XML文件,和Java文件放在同一个目录下,如

如果不加配置,用maven进行打包时,默认不会将src/main/java目录下的XML文件打包进去。因为src/main/java被设定为了源码目录,默认只会将其中的Java文件进行编译打包。

即,默认打包得到的结果如下

可以看到com.example.mp.mappers包下没有XML文件

我们可以配置pom.xml中的resources标签,指定打包时,加入src/main/java下面的XML文件,pom.xml如下

<build>
    <resources>
         <resource>
             <directory>src/main/java</directory>
             <includes>
                 <include>**/*.xml</include>
             </includes>
         </resource>
    </resources>
</build>

这样配置后,再次打包,src/main/java目录下的XML文件就会被打包进来了

问题出现

然而,今天在一个SpringBoot项目中测试mybatis-plus的demo时,发现,若pom.xml中增加了这一个自定义的resources标签配置,会覆盖掉默认的resources打包配置,使得src/main/resources目录下的文件无法打包进来,从而运行时因为缺少application.yml等资源文件而报错。

假设我们有一个SpringBoot的项目,目录结构如下

我们的pom.xml按照上面所说,配置了扫描src/main/java下面的XML文件。我们执行mvn clean package -DskipTests=true进行打包。

根据maven的执行日志,看到maven的resources插件只打包了一个资源文件

我们查看打包后的target目录

可以看到,src/main/java下的XML文件被成功打包了进来。

src/main/resources下的资源文件全都没有被打包进来

此时运行该SpringBoot项目,因为缺失application.yml,找不到配置的数据源,而报错

而如果我们在pom.xml中去掉resources标签的配置,即删掉

<build>
    <resources>
         <resource>
             <directory>src/main/java</directory>
             <includes>
                 <include>**/*.xml</include>
             </includes>
         </resource>
    </resources>
</build>

其他部分不变,再次打包

maven执行的日志显示,maven资源插件打包了3个资源文件

查看打包后的target目录

src/main/resources目录下的资源文件被成功打包进来了。而由于没有配置,src/main/java下的XML文件就没有被打包。

由此可知,默认情况下,maven打包会将资源目录(一般是src/main/resources)中的资源文件打包进去。

如何查看项目的资源目录呢?

IDEA左上角 File — Project Structure — Modules — 选中你的项目

可以看到,蓝色的文件夹就是源代码目录,右下角带着像金币一样图标的文件夹,就是资源目录,而绿色的是测试代码目录。

若要将某个目录设为资源目录,鼠标选中那个目录,在上方的Mark as那一行,点击Resources 即可。

初步结论

上面说到,maven默认会将资源目录下的资源文件进行打包,而如果在pom.xml中配置了resources标签,则默认的资源打包策略就被覆盖掉了,只会打包resources标签中配置的资源文件,所以,如果pom.xml中配置了

<build>
    <resources>
         <resource>
             <directory>src/main/java</directory>
             <includes>
                 <include>**/*.xml</include>
             </includes>
         </resource>
    </resources>
</build>

则只会打包该配置指定的目录,不会打包src/main/resources目录,即使它是项目的资源目录。

这一点需要特别注意!!!需要特别注意!!!特别注意!!!

解决方案呢?当然有,手动将src/main/resources也添加到配置就可以了。按如下的pom.xml配置,maven打包时,既能包含src/main/java下的XML文件,也能包含资源目录src/main/resources)下面的资源文件

<build>
    <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>

            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*</include>
                </includes>
            </resource>
        </resources>
</build>

或者,把全部的资源文件,统一放在src/main/resources目录下,这样无需额外配置pom.xml

问题回溯

然而,在一年前的这篇文章 -> mybatis看这一篇就够了 当中,提到过当把XML文件和java类放在一起时,可以通过增加pom.xml的配置解决XML文件没有被打包的问题,当时增加了pom.xml中的resources配置,仅配置了扫描src/main/java目录,但是src/main/resources下的文件也被打包了进来。好像并没有出现这次遇到的这种问题。
我起初怀疑跟SpringBoot有关,但是,经过反复的测试,发现maven项目都会出现这种问题,并且我把mybatis看这一篇就够了这篇文章中当时使用的demo代码找到了,重新用maven进行打包测试,发现问题仍然出现。这时我就很困惑了,当时为什么没有问题?当时为什么就把src/main/resources下的文件打包进来了?会不会和maven的版本,maven的插件版本等有关?



…(A FEW YEARS LATER)…



经过反反复复,反反复复的测试,我!终于复现了当时的情景!! 首先,运行mvn clean将maven构建的文件全部删除,然后在pom.xml中配置resources标签仅扫描src/main/java
在这里插入图片描述

随后,我们不运行maven命令进行打包,而直接选中一个测试类,直接点击运行一个测试用例

在这里插入图片描述

由于项目还未编译打包,此时会触发IDEA的自动构建

在这里插入图片描述

构建完毕后,我们查看target目录

在这里插入图片描述
发现src/main/java中的XML文件没有被打包进来,而src/main/resources下的资源文件倒是被打包了进来。根据我合理的猜测,IDEA的自动构建没有使用pom.xmlbuild标签下的配置,默认只是编译了源码目录下的java文件,并打包了资源目录下的资源文件。而此时我如果仅仅运行mvn package命令,而不是mvn clean package。由于没有运行mvn clean,所以先前已经构建好的文件不会被删掉。于是mvn package执行完毕后,src/main/java下的XML文件也被添加了进来。

谜团解开

至此,谜团解开。使用maven进行打包,若pom.xml中没有配置resources标签,则会采用默认策略,打包资源目录src/main/resources)下的资源文件。若pom.xml中配置了resources标签,则完全以配置的为准。即,如果pom.xml中的resources标签只配置了扫描src/main/java,则只会扫描src/main/java,不会扫描src/main/resources,即使后者已经被标记为项目的资源目录。

先前的,仅仅配置pom.xml扫描src/main/java下的XML文件,而src/main/resources下的文件也打包了进来,这种情况,是因为一开始就进行过构建,src/main/resources目录下的文件已经被打包了进来,而后续的打包并没有执行mvn clean清除已有的文件。

所以,在使用mybatis的时候,mapper.xml文件,最好就统一放在src/main/resources资源目录下,这样就无需额外配置pom.xml。(其他资源文件也一样)。若实在需要把XML文件放在src/main/java源码目录下,那么配置pom.xml中的resources标签时,一定要记得加上src/main/resources,如下

<build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>

            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*</include>
                </includes>
            </resource>
        </resources>
</build>

(完)

都看到这了,一定是个小可爱,这么可爱的你,会给我一个赞的对吧?☺️

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐