基于maven,如何将额外的文件打包到jar包中?

1. 絮絮叨叨

  • 自从梳理清楚了与Java文件有关的输入/输出流,现在读取或写入文件基本都不需要上网查资料了,简直磨刀不误砍柴工~ 🐯
  • 感兴趣的,可以查看本人之前的博客:基于文件的java输入/输出流

2. 本地执行Java代码以读取文件

  • 现在有个需求:读取countries文件,计算世界上有多少个国家

  • 创建maven项目,编写代码、本地运行,那是溜溜的,几下就完成了

    // 其他import省略,只展示sl4j的
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class CountriesTest {
        private static final Logger logger = LoggerFactory.getLogger(CountriesTest.class);
    
        public static void main(String[] args) {
            try {
                CountriesTest test = new CountriesTest();
                test.countCountries1();
            } catch (IOException e) {
                logger.error("读取文件失败", e);
            }
        }
    
        /**
         * 直接读取指定目录的文件
         **/
        public void countCountries1() throws IOException {
            // 获取文件目录
            String filePath = this.getClass().getResource("/").getPath().replace("/target/classes/", "");
            logger.info("开始从指定目录读取文件, {} ...", filePath);
            try (BufferedReader reader = new BufferedReader(new FileReader(filePath + "/countries"))) {
                int count = 0;
                String country = reader.readLine();
                while (country != null) {
                    count++;
                    // 获取下一个国家
                    country = reader.readLine();
                }
                logger.info("There are {} countries in the world", count);
            }
        }
    }
    
  • 其中,slf4j的maven依赖为

    <dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.30</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>
    
  • countries文件,放在maven模块的父目录下:

  • countries文件的内容,是从网页上粘贴的,部分内容如下:

    Afghanistan
    Albania
    Algeria
    Andorra
    

3. 以jar包的形式执行程序

3.1 打包后执行失败

  • 现在需求升级:将代码打包成jar包,放到服务器上执行

  • 这也很简单,一个打包命令mvn clean package就搞定

  • 结果到服务器上执行时,却报错了。
    在这里插入图片描述

  • 通过对比代码,发现如下代码存在空指针问题

    String filePath = this.getClass().getResource("/").getPath().replace("/target/classes/", "");
    
  • 自己解压缩对应jar包,也没有在jar包里面找到countries文件。所以,即使文件目录正确,文件不存在,也会读取失败 😓

3.2 将文件放到resources目录

  • 灵机一动,想到Java项目中还有个src/main/resources目录,

  • Java Web项目中很多配置文件都是放在这里面的,打包时,好像也没有做什么额外的配置,最后还能读取这些文件

  • 抱着试一试的心理,将countries文件移动到了resources目录

  • 然后参考博客:java项目中获得resources目录下的文件或图片,直接以文件流的形式读取resources目录下的countries文件

  • 最终完整的代码如下:

    public class CountriesTest {
        private static final Logger logger = LoggerFactory.getLogger(CountriesTest.class);
    
        public static void main(String[] args) {
            try {
                CountriesTest test = new CountriesTest(); 
                test.countCountries2();
            } catch (IOException e) {
                logger.error("读取文件失败", e);
            }
        }
    
        /**
         * 从resources目录读取文件
         **/
        public void countCountries2() throws IOException {
            logger.info("开始从resources目录读取文件 ...");
            // 获取resources下的文件资源
            InputStream in = getClass().getResourceAsStream("/countries");
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
                int count = 0;
                String country = reader.readLine();
                while (country != null) {
                    count++;
                    // 获取下一个国家
                    country = reader.readLine();
                }
                logger.info("There are {} countries in the world", count);
            } catch (IOException e) {
                throw e;
            }
        }
    }
    
  • 重新打包后,成功读取文件 👍
    在这里插入图片描述

  • 同时,jar包的根目录下出现了countries文件 —— 说明countries文件被成功打包

4. maven resources plugin

4.1 考虑将文件放到其他地方

  • 将文件放在resources目录可以自动打包,如果放到其他层级呢?

  • 下面是笔者的一些试验:

    目录是否ok是否打包
    src/main/java 目录failedNo
    src/main/resources/files目录ok,需要将文件路径更新为InputStream in = getClass().getResourceAsStream("/files/countries");Yes,在files/目录下
    src/files目录failedNo

4.2 指定resources目录

  • 通过网上查阅资料,发现maven resources plugin,可以指定resources目录

  • 按照官网描述,默认的resources目录为src/main/resources,可以通过如下方式在<build>标签中指定resources目录

    <resources>
      <resource>
        <directory>resource1</directory>
      </resource>
      <resource>
        <directory>resource2</directory>
      </resource>
      <resource>
        <directory>resource3</directory>
      </resource>
    </resources>
    
  • 以将countries文件放到src/main/java 目录为例,配置如下:

    <resources>
        <resource>
            <directory>src/main/java</directory>
        </resource>
        <!-- 原本的默认值将被覆盖,需要显式指定-->
        <resource>
            <directory>src/main/resources</directory>
        </resource>
    </resources>
    

4.3 其他一些高级配置

4.3.1 指定或排除文件

  • 在resources目录下,有各种类型的文件,只有某些文件在文件运行时是需要的

  • 这时,可以通过<include><exclude>指定或排除文件,详情参考官网:Including and excluding files and directories

    <resources>
        <resource>
            <directory>src/main/java</directory>
            <!-- 指定打包的文件类型,**/表示当前目录或任意子目录-->
            <includes>
                <include>**/*.txt</include>
                ...
            </includes>
        </resource>
        <!-- 原本的默认值将被覆盖,需要显式指定 -->
        <resource>
            <directory>src/main/resources</directory>
            <!-- 排除各种格式的图片文件 -->
            <excludes>
                <exclude>**/*.bmp</exclude>
                ...
            </excludes>
        </resource>
    </resources>
    

4.3.2 更新文件中的值

  • 文件中,某些变量需要在编译时更新。如hello.txt中,包含${name}

    Hello ${name}
    
  • 可以通过开启filtering属性,将${name}更新为实际值

    <resource>
        <directory>src/main/resources</directory>
        <!-- 开启filter -->
        <filtering>true</filtering>
    </resource>
    
  • ${name}的来源主要有三种,具体参考官网:Filtering

    • maven自带的属性,如${basedir}${name},可以参考作者之前的博客:10. maven属性,或者网上查阅资料
    • 执行maven命令是,通过-Dxxx传入的值,类似mvn resources:resources -Dname="world"
    • 自定义的property,可以放在pom文件中,也可以使用单独的.properties文件存储
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值