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

Embedded Tomcat 10从Fat Jar加载静态资源失败求助

问题原因与解决方案

问题本质

在IDE中运行时,src/main/resources/static是文件系统上的真实目录,因此getResource("static").getFile()能返回有效的文件路径。但打包成Fat Jar后,静态资源位于Jar内部,getFile()返回的是类似file:/tmp/abc/awfemb.jar!/static的URL路径,而Tomcat默认的上下文配置期望一个物理文件目录,导致路径拼接错误,出现资源集无效的问题。

解决方案:使用WebResourceRoot处理Jar内资源

必须通过WebResourceRoot系列类来配置Tomcat的资源加载逻辑,使其能够识别Jar内部的资源。以下是修正后的代码:

import org.apache.catalina.Context;
import org.apache.catalina.servlets.DefaultServlet;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.webresources.DirResourceSet;
import org.apache.catalina.webresources.JarResourceSet;
import org.apache.catalina.webresources.StandardRoot;

import java.net.URI;
import java.net.URL;

public class MainTomcat {

    public static void main(String[] args) throws Exception {
        Tomcat tomcat = new Tomcat();
        tomcat.getConnector();
        tomcat.setPort(8080);

        // 获取static资源的URL(支持文件系统和Jar内两种场景)
        URL staticUrl = MainTomcat.class.getClassLoader().getResource("static/");
        URI staticUri = staticUrl.toURI();

        // 创建上下文,不指定docBase(避免Tomcat默认的目录解析逻辑)
        Context context = tomcat.addContext("/", null);

        // 配置资源加载根目录
        StandardRoot resources = new StandardRoot(context);
        if (staticUri.getScheme().equals("jar")) {
            // Jar内资源:使用JarResourceSet加载
            resources.addPreResources(new JarResourceSet(
                    resources,
                    "/",          // 上下文挂载路径
                    staticUri,    // Jar文件的URI
                    "/"           // Jar内的资源路径(static目录下的内容)
            ));
        } else {
            // 文件系统资源(IDE场景):使用DirResourceSet加载
            resources.addPreResources(new DirResourceSet(
                    resources,
                    "/",          // 上下文挂载路径
                    staticUri.getPath(), // 文件系统目录路径
                    "/"           // 目录内的资源路径
            ));
        }
        context.setResources(resources);

        // 注册并映射DefaultServlet
        tomcat.addServlet("/", "default", new DefaultServlet());
        context.addServletMappingDecoded("/", "default");

        tomcat.start();
        tomcat.getServer().await();
    }
}

关键修改说明

  1. 移除docBase依赖:创建Context时不再传入文件路径,避免Tomcat尝试将Jar URL解析为物理目录。
  2. 使用WebResourceRoot:通过StandardRoot统一管理资源加载,根据资源所在位置(文件系统或Jar)选择对应的DirResourceSet或JarResourceSet。
  3. 兼容两种运行场景:代码自动识别资源的URL协议,同时支持IDE开发和Fat Jar部署。

Maven配置无需修改

你的现有Maven打包配置已经正确,执行mvn clean package后生成的Fat Jar即可正常运行。

内容的提问来源于stack exchange,提问作者DBE

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 04:17:35