Spark无法从webjars加载静态文件

时间:2015-06-21 20:37:04

标签: java classloader spark-java

我在我的应用程序中使用Spark Framework,并使用

staticFileLocation("/META-INF/resources/");

这样我就可以使用webjars,其中包含css和js文件。我也有自己的资源放在我的项目src/main/resources/META-INF/resources文件夹中,因为我的gradle构建从那里获取它们。

我的构建使用了一种胖jar方法,其中所有内容都以一个jar形式结束,所有文件都由Spark完美提供。

我的问题是,当我从Eclipse独立运行一些单元测试时,即使我确保webjars在classpath上,它们也不是Spark服务的,只有我自己的项目静态资源。

@Test
public void testStartup() throws InterruptedException {
    InputStream schemaIS = this.getClass().getClassLoader().getResourceAsStream("META-INF/resources/webjars/bootstrap/3.2.0/js/bootstrap.min.js");
    System.out.println(schemaIS == null);
    staticFileLocation("/META-INF/resources/");
    // depending on the trailing / the bootstrap js is found, but Spark never serves it
}

我认为这与类加载器有关,但我找不到使其工作的方法。看看Spark代码,它说The thread context class loader will be used for loading the resource.我也看到代码本身删除了尾部斜杠,这在普通getResourceAsStream中有很大的不同。

它是Spark中的错误,还是有任何方法可以使其正常工作?

1 个答案:

答案 0 :(得分:1)

注意 删除前导斜杠是Jetty所必需的,而不是Spark。

不幸的是,Spark不能将静态文件(在物理目录/文件夹中)与作为jar资源的文件混合使用。许多罐子在Spark中都不起作用。

我几周前看过这个并得出结论,这是Spark中的一个小弱点(或者你可能会说错误)。

我发现的唯一方法是反转Spark并弄清楚码头是如何工作的。我使用以下Nashorn javascript片段进行管理,以使webjars和静态文件协同工作。

除非Spark作者更改其代码以允许包含定制的上下文处理程序,否则这对您无济于事。但是如果你想在码头上寻找,那么这个改编的代码可以帮助你。

此代码适用于Nashorn jjs(来自JDK8),但可以轻松移植到Java。使用此代码,我能够使用3个单独的webjars jquery / bootstrap / angular,其余的客户端代码位于物理目录/文件夹public中。

<强> app.js:

with(new JavaImporter(
  org.eclipse.jetty.server
, org.eclipse.jetty.server.handler
)) {

  var server = new Server(4567);

  var ctxs = new ContextHandlerCollection();
  ctxs.setHandlers(Java.to([
    load('src/static.js')
  , load('src/webjars.js')
  ], Handler.class.getName().concat('[]')));
  server.setHandler(ctxs);

  server.start();
  server.join();

}

<强>的src / static.js:

(function () {
  var context;
  with(new JavaImporter(
    org.eclipse.jetty.server.handler
  , org.eclipse.jetty.util.resource
  )) {
    context = new ContextHandler();
    context.setContextPath("/");
    var handler = new ResourceHandler();
    handler.setBaseResource(Resource.newResource("public"));
    context.setHandler(handler);
  }
  return context;
})();

<强>的src / webjars.js:

(function () {
  var context;
  with(new JavaImporter(
    org.eclipse.jetty.server.handler
  , org.eclipse.jetty.util.resource
  )) {
    context = new ContextHandler();
    context.setContextPath("/");
    var handler = new (Java.extend(ResourceHandler, {
      getResource: function(req) {
        var path = req.getUri();
        var resource = Resource.newClassPathResource(path);
        if (resource == null || !resource.exists()) {
          resource = Resource.newClassPathResource("META-INF/resources/webjars" + path);
        }
        return resource;
      }
    }))();
    handler.setDirectoriesListed(true); // true when debugging, false in production
    context.setHandler(handler);
  }
  return context;
})();