You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ktor shadow插件打包fat jar未包含resources文件夹问题

问题根因

执行gradle shadowJar --no-daemon构建出的Ktor fat jar缺失resources资源,通常由两个原因导致:

  1. Shadow插件未显式配置资源拷贝规则,构建时未将main源码集的资源输出纳入打包范围
  2. 本地开发时使用了依赖项目工作目录的资源读取写法,IDEA运行时工作目录为项目根目录可正常读取,但jar包内不存在src目录结构,导致路径失效
解决步骤
  • 配置Shadow插件打包规则
    在你的build.gradle.kts中添加如下任务配置,强制将主源码集的编译输出(含class文件与处理后的资源文件)打入jar包,同时处理重复文件冲突:
    tasks {
        shadowJar {
            from(project.sourceSets.main.get().output)
            duplicatesStrategy = DuplicatesStrategy.EXCLUDE
            manifest {
                attributes["Main-Class"] = "com.cstcompany.ApplicationKt"
            }
        }
    }
    
  • 修正资源读取逻辑
    禁止使用File("src/main/resources/xxx")这类相对路径读取资源,必须通过类加载器从classpath加载资源,兼容jar包运行环境:

    错误写法(仅本地IDEA可运行)

    val templateFile = File("src/main/resources/templates/index.ftl")
    

    正确写法(兼容jar部署)

    // 读取资源为URL
    val templateUrl = ApplicationKt::class.java.classLoader.getResource("templates/index.ftl")
    // 读取资源为输入流
    val templateStream = ApplicationKt::class.java.classLoader.getResourceAsStream("templates/index.ftl")
    
    你项目中使用了FreeMarker,安装插件时直接指定classpath下的模板路径即可,无需手动读取文件:
    install(FreeMarker) {
        templateLoader = ClassTemplateLoader(this::class.java.classLoader, "templates")
    }
    
  • 清理缓存重新构建
    执行以下命令清理旧构建缓存后重新打包,避免历史产物干扰:
    gradle clean shadowJar --no-daemon
    
  • (可选)显式声明资源目录
    如果上述配置后资源仍未打入,可在配置中显式指定Gradle识别的资源目录:
    sourceSets {
        main {
            resources {
                srcDirs("src/main/resources")
            }
        }
    }
    
打包结果验证

构建完成后,执行以下命令查看jar包内的文件列表,确认资源文件已被打入:

jar tf build/libs/[你的jar包文件名].jar

如果输出列表中能看到resources下存放的配置文件、模板文件(如logback.xml、templates/index.ftl),说明打包正常,直接运行jar即可。

内容的提问来源于stack exchange,提问作者Patrik Csikós

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 16:06:22