Spark 无法从 webjars 加载静态文件
Spark can't load static files from webjars
我在我的应用程序中使用 Spark 框架,并使用
staticFileLocation("/META-INF/resources/");
这样我就可以使用 webjars,其中包含 css 和 js 文件。我也有自己的资源放在我的项目 src/main/resources/META-INF/resources
文件夹中,因为我的 gradle 构建从那里获取它们。
我的构建使用 fat-jar 方法,其中所有内容最终都在一个 jar 中,所有文件都由 Spark 完美提供。
我的问题是,当我 运行 独立于 Eclipse 进行一些单元测试时,即使我确保 webjars 在类路径中,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的bug,或者有什么方法可以让它正常工作吗?
注意 Jetty 需要删除前导斜杠,Spark 不需要。
不幸的是,对于 Spark,您不能将静态文件(在物理 directory/folder 中)与作为资源的文件混合在 jar 中。许多罐子在 Spark 中也无法工作。
几周前我看过这个并得出结论这是 Spark 中的一个小弱点(或者如果你可以说是一个错误)。
我发现的唯一方法是逆向 Spark 并弄清楚 jetty 是如何工作的。我设法使用以下 Nashorn javascript 片段使 webjars 和静态文件一起工作。
除非 Spark 作者更改他的代码以允许包含定制的上下文处理程序,否则这对您没有帮助。但是如果你想在 jetty 中追求,这个带有适配的代码可以帮助你。
此代码适用于 Nashorn jjs(来自 JDK8),但可以轻松移植到 Java。使用此代码,我能够使用 3 个单独的 webjars jquery/bootstrap/angular,而我的客户端代码的其余部分位于物理 directory/folder 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;
})();
我在我的应用程序中使用 Spark 框架,并使用
staticFileLocation("/META-INF/resources/");
这样我就可以使用 webjars,其中包含 css 和 js 文件。我也有自己的资源放在我的项目 src/main/resources/META-INF/resources
文件夹中,因为我的 gradle 构建从那里获取它们。
我的构建使用 fat-jar 方法,其中所有内容最终都在一个 jar 中,所有文件都由 Spark 完美提供。
我的问题是,当我 运行 独立于 Eclipse 进行一些单元测试时,即使我确保 webjars 在类路径中,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的bug,或者有什么方法可以让它正常工作吗?
注意 Jetty 需要删除前导斜杠,Spark 不需要。
不幸的是,对于 Spark,您不能将静态文件(在物理 directory/folder 中)与作为资源的文件混合在 jar 中。许多罐子在 Spark 中也无法工作。
几周前我看过这个并得出结论这是 Spark 中的一个小弱点(或者如果你可以说是一个错误)。
我发现的唯一方法是逆向 Spark 并弄清楚 jetty 是如何工作的。我设法使用以下 Nashorn javascript 片段使 webjars 和静态文件一起工作。
除非 Spark 作者更改他的代码以允许包含定制的上下文处理程序,否则这对您没有帮助。但是如果你想在 jetty 中追求,这个带有适配的代码可以帮助你。
此代码适用于 Nashorn jjs(来自 JDK8),但可以轻松移植到 Java。使用此代码,我能够使用 3 个单独的 webjars jquery/bootstrap/angular,而我的客户端代码的其余部分位于物理 directory/folder 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;
})();