【问题标题】:Diference in getResource between Jetty and Tomcat produces file not found exceptionJetty 和 Tomcat 之间的 getResource 差异产生文件未找到异常
【发布时间】:2013-09-27 22:03:09
【问题描述】:

我正在使用以下代码查找 Freemarker 从 HTML 创建 PDF 所需的资源。

public static URL lookupResource(String resource) {
    System.out.println("Looking up resource: " + resource);
    ClassLoader classLoader =  Thread.currentThread().getContextClassLoader();      
    URL templateFileUrl = classLoader.getResource(resource);        
    System.out.println("path: " + templateFileUrl.getPath());   
    return templateFileUrl;
}

在 Eclipse Maven 项目中的 Jetty 上运行我得到以下信息:

Looking up resource: abc.html
path: /C:/Projects/WebDocs/EclipseProjects/webdocs2/webdocs/target/classes/abc.xhtml

这是资源所在并且工作正常的地方。

当我将战争文件导出到 Tomcat 时,资源被放入 /C:/Program%20Files/Apache%20Software%20Foundation/Tomcat%207.0/webapps/webdocs

在 Tomcat 上运行我得到以下信息:

Looking up resource: abc.html
path: /C:/Program%20Files/Apache%20Software%20Foundation/Tomcat%207.0/webapps/webdocs/WEB-INF/classes/abc.xhtml

这不是资源所在的位置,会导致文件未找到异常。

我做错了什么?

【问题讨论】:

    标签: java tomcat resources jetty filenotfoundexception


    【解决方案1】:

    理想情况下你应该是:

    因为 webapp 容器可以移动内容以满足自己的需要。

    (有关详细信息,请参阅javax.servlet.ServletContext.getResource(String path) 上的 javadoc)

    此外,实用程序类不应依赖于Thread.currentThread().getContextClassLoader()。而是使用从请求资源的类中获得的类加载器。

    public class MyClass {
      public void doIt() {
        URL url = Utils.getResource(this,"abc.html");
      }
    }
    
    public final class Utils {
      public static URL getResource(Object obj, String resource) {
        return obj.getClass().getClassLoader().getResource(resource);
      }
    }
    

    【讨论】:

    • 感谢您的回复。这可能在 Web 容器中工作,但代码不一定总是在 servlet 容器中运行,并且提供资源的实用程序类无权访问 ServletContext。我可以通过一系列方法将 ServletContext 传递给实用程序类,或者使用线程局部变量,但还有另一个问题。代码需要在独立程序和不在 Web 容器中运行的单元测试中运行。它只需要一个 html 模板和一个 Map 来生成 PDF 输出。
    • 那么不要把资源放到/WEB-INF/classes/,把资源放到/WEB-INF/lib/找到的jar文件里。这样您将获得最大的兼容性。
    • @JoakimErdfelt 请提供完整的解决方案
    • @JoakimErdfelt 我正在这样做: public static int EMP_LEDGER = 6;私有静态字符串 EMP_LEDGER_PATH ="\\employee_ledger\\EmployeeLedger.jasper";案例6:return getParentDir() + EMP_LEDGER_PATH;
    【解决方案2】:

    如果您想将模板(或任何其他资源)存储为 jar 的一部分,我会查看代码以改用 InputStreams。要获取模板,请使用this.getClass().getClassLoader().getResourceAsStream()(或者更好的是this.getClass().getResourceAsStream(),并以包结构组织资源)。之后,使用构造函数Template(InputStream stream) 构造模板。这样,即使您的 jar/war 没有“分解”成物理文件,您的代码也能正常工作。

    要使用this.getClass().getResourceAsStream(),当你的资源作为类文件编译成jar 时,你的资源必须在同一个目录中。如果您使用 maven,请将资源放在 "resources/path/to/yourpackage/resource.file" 中。注意:更安全的方法是为此解决方案使用类名本身,例如 MyClass.getResourceAsStream(),因为 this.getClass() 通常在子类化或自动代理场景中不起作用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-02
      • 1970-01-01
      相关资源
      最近更新 更多