docker部署jar包找不到资源文件-jar包报错找不到资源文件

前言:

之前开发过程中碰到本地运行无问题,测试环境运行找不到资源文件的问题。已解决,记录一下
线上环境使用jar包部署至docker。
docker部署jar包找不到资源文件-jar包报错找不到资源文件_第1张图片
这里使用的是相对路径获取,获取不到。

原理解析:(重点)

打成jar包后项目本身就是一个文件,不能再用(File)获取文件的方式来读取,只能用流的方式来读取文件内容,本地之所以能运行,是因为IDE中的资源文件在target/classes目录下,是正常的文件系统结构。所以本质都是需要使用流来获取文件。

解决方案

方法一:(本人使用方法)

原理:首先通过读取文件inputStream流,通过input流将文件写入docker容器中,通过绝对路径获取文件。
优点:可以获取file文件,在一些工具类需要传入filePath可以使用
缺点:需要将文件从jar包中读取出来,写入到docker容器中

package org.jeecg.modules.lst.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

@Slf4j
@Component
public class DocUtil {

    //此路径是其余方法进行调用,且只需要加载一次
    private static String sourceTemplatePath;
    // 读取文件名称
    private static String[] ftlArray = {"shopPDF.ftl","yahei.ttf"};
    // resources下模板文件夹名称
    private static String temPath = "templates/shopsummary/";
    //模块名,针对多模块项目。单模块项目需删除
    private static String modelPath = String.format("jeecg-module-system%sjeecg-system-biz", File.separator);

    static {
        //静态方法调用一次 
        sourceTemplatePath = createFtlFileByFtlArray();
    }
    // 获取临时文件路径
    public static String getSourceTemplatePath(){
        return sourceTemplatePath;
    }

    //获取临时文件模板路径
    public static String getRentalAgreementPath(){
        return sourceTemplatePath+ ftlArray[0];
    }

    private static String createFtlFileByFtlArray() {
        String path = "";
        for (int i = 0; i < ftlArray.length; i++) {
            path = createFtlFile(temPath, ftlArray[i]);
            if (null == path) {
                log.info("not copy success:" + ftlArray[i]);
            }
        }
        return path;
    }

    private static String createFtlFile(String ftlPath, String ftlName) {
        try {
            //获取当前项目所在的绝对路径
            String proFilePath = System.getProperty("user.dir");
            log.info("project run path:" + proFilePath);
            //获取模板下的路径 
            String newFilePath = proFilePath + File.separator + modelPath + File.separator + "src" + File.separator + "main" + File.separator + "resources" + File.separator + ftlPath;
            newFilePath = newFilePath.replace("/", File.separator);
            log.info("newFilePath:" + newFilePath);
            //检查项目运行时的src下的对应路径
            File newFile = new File(newFilePath + ftlName);
            if (newFile.isFile() && newFile.exists()) {
                return newFilePath;
            }
            //当项目打成jar包会运行下面的代码,而且复制一份到src路径下(具体结构看下面图片)
            InputStream certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(ftlPath + ftlName);
            byte[] certData = IOUtils.toByteArray(certStream);
            FileUtils.writeByteArrayToFile(newFile, certData);
            return newFilePath;
        } catch (IOException e) {
            log.error("复制文件失败--> 异常信息:" + e);
        }
        return "";
    }
}

写一个静态文件,在项目启动时,首先读取文件是否存在,如不存在,使用Thread.currentThread().getContextClassLoader().getResourceAsStream(ftlPath + ftlName);读取文件input流,写入到docker容器中。
因为我是多模块项目,所以代码中添加了modelPath,如果是单体项目,将modelPath去掉,本质上就是取相对路径,只要能通过相对路径取到文件即可。
docker部署jar包找不到资源文件-jar包报错找不到资源文件_第2张图片
代码解析:
为方便理解,我使用gpt解析了这段代码。大家可以参考下。

该类使用了以下注解:

  • @Slf4j:来自 lombok 库,自动为该类提供一个名为"log"的日志记录器对象,用于记录日志。

  • @Component:来自 Spring 框架,将这个类标记为 Spring 管理的组件,使得 Spring 框架可以初始化并使用这个实例。
    DocUtil类中定义了以下静态变量:
    sourceTemplatePath:作为其他方法调用的路径变量,只需加载一次。

  • ftlArray:包含两个文件名称的字符串数组。

  • temPath:定义在 resources 下的模板文件夹名称。

  • modelPath:针对多模块项目的模块名称。单模块项目需要删除该变量。
    类中包含以下静态方法:

  • static代码块:只执行一次(类加载时)。调用createFtlFileByFtlArray()方法来加载并获取模板文件路径。

  • getSourceTemplatePath():返回临时文件路径。 getRentalAgreementPath():返回rental

  • agreement模板文件路径。

  • createFtlFileByFtlArray():遍历ftlArray数组中的所有文件名,并为每个文件名调用createFtlFile()方法。返回文件路径。

  • createFtlFile(String ftlPath, String ftlName):使用输入的ftlPath和文件名ftlName创建文件,返回新文件的路径。 首先,获取项目当前运行路径并输出到日志中。再获取所需文件的目标路径。 检查文件是否存在。如果存在,则返回新文件路径。 对于以jar包形式运行的项目,使用类加载器从jar文件中读取文件内容,然后复制到具有相同文件结构的src路径下,并返回新文件路径。 如果复制过程发生错误,捕获并记录异常,并返回空字符串。这段代码主要处理了从项目resources文件夹中读取模板文件,复制到合适的位置,返回这些模板文件的文件路径。同时处理了项目以jar包形式运行的情况。

获取文件方式:

//获取资源文件夹目录
DocUtil.getSourceTemplatePath();
//获取资源文件
DocUtil.getSourceTemplatePath() + fileName;

docker部署jar包找不到资源文件-jar包报错找不到资源文件_第3张图片
docker容器内路径展示,更新在项目路径下
docker部署jar包找不到资源文件-jar包报错找不到资源文件_第4张图片

方法二:

如果只需要读取文件。可以直接使用inputStream流获取。

用第二种方式读取jar中的文件流

ClassPathResource resource = new ClassPathResource("static/xxx.docx");
File sourceFile = resource.getFile();
InputStream fis = resource.getInputStream();

还要在项目pom.xml中配置resources

<build>
		
		<resources>
			<resource>
				<directory>src/main/javadirectory>
				<includes>
					<include>**/*.propertiesinclude>
					<include>**/*.xmlinclude>
					<include>**/*.ymlinclude>
				includes>
				
				<filtering>falsefiltering>
			resource>
			<resource>
				<directory>src/main/resourcesdirectory>
				<includes>
					<include>**/*.*include>
				includes>
				
				<filtering>falsefiltering>
			resource>
		resources>
	build>

你可能感兴趣的:(java篇,docker,jar,容器,java,spring)