Spring <mvc:resources>:如果查询目录,如何使服务器成为索引文件/ welcome-file?

时间:2016-09-02 14:09:40

标签: spring-mvc

如果只查询目录,大多数Web服务器都可以配置为传递特殊文件。通常,在这种情况下会传递“index.html”或类似文件。

我正在使用<mvc:resources>在spring应用程序中提供静态资源,我想这样做:如果查询目录,则应将该目录中的预先指定的文件传递给客户端。到目前为止,我的配置如下所示:

public class CoreWebMvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {
        registry
            .addResourceHandler("/static/**/*")
            .addResourceLocations("/www/");
    }
}

1 个答案:

答案 0 :(得分:0)

令我惊讶的是,我没有找到任何与弹簧捆绑在一起解决这个问题的东西。毕竟这似乎很正常。

可能的解决方案

我找到的一种方法是编写一个这样的自定义路径解析器:

public class CoreWebMvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {
        registry
            .addResourceHandler("/static/**/*")
            .addResourceLocations("/www/")
            .resourceChain(true).addResolver(new WelcomeFilePathResolver());
    }

    /**
     * An extension to Spring's {@link PathResourceResolver} which checks if the requested resource is a directory.
     * If it is, it attempts to deliver a file "index.html" within this directory rather than failing.
     */
    private static class WelcomeFilePathResolver extends PathResourceResolver {
        @Override
        protected Resource getResource(final String resourcePath, final Resource location) throws IOException {
            Resource resource = location.createRelative(resourcePath);
            if (resource.getFile().isDirectory()) {
                return super.getResource(resourcePath + "/index.html", location);
            }
            return super.getResource(resourcePath, location);
        }
    }
}

但请注意,这不适用于根目录,但仅适用于子目录。对于根目录,将以下内容添加到您的WebMvcConfigurerAdapter扩展名:

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/").setViewName("forward:/index.html");
}

背景说明

通常,如果您未注册resourceChain,则spring将使用PathResourceResolver解析资源。原始方法PathResourceResolver.getResource的开头如下:

protected Resource getResource(String resourcePath, Resource location) throws IOException {
    Resource resource = location.createRelative(resourcePath);
    if (resource.exists() && resource.isReadable()) {

找到目录,resource.exists()返回true,但resource.isReadable()返回false,因为目录本身不可读,因此最终会出现在404中。

自定义ResourceResolver拦截对此方法的调用,并检查所请求的资源是否是目录。如果不是它只是委托原始的getResource - 方法。但是,如果是,则更改路径并在该目录中查找index.html文件。

需要额外配置root的原因是因为the ResourceHttpRequestHandler checks for non empty paths(不确定为什么它会指示这一点而不是将其留给ResourceResolve ...)。

限制

因为我打电话给resource.getFile()我认为有很多情况下这不起作用。我测试它是从Tomcat中的war文件传递的文件。但是,如果直接从jar文件中读取资源,则可能无法正常工作。检查不是.getFile().isDirectory()而是resource.isReadable()的匹配可以用作替代方案。