К моему удивлению, я не нашел ничего связанного с весной, которое решает эту проблему. В конце концов, это кажется довольно нормальным.
Возможное решение
Один из способов я нашел, чтобы написать собственный путь распознаватель так:
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
, то весна будет решать ресурсы, используя PathResourceResolver
. Оригинальный метод PathResourceResolver.getResource
начинается так:
protected Resource getResource(String resourcePath, Resource location) throws IOException {
Resource resource = location.createRelative(resourcePath);
if (resource.exists() && resource.isReadable()) {
Там каталог найден, resource.exists()
возвращает истину, но resource.isReadable()
возвращает ложь, потому что сам каталог не доступен для чтения и, таким образом, это будет в конечном итоге в 404.
Пользовательский ResourceResolver
перехватывает вызовы этого метода и проверяет, является ли запрошенный ресурс каталогом. Если это не просто делегирует оригинал getResource
-метод. Однако, если это так, он изменяет путь и ищет файл index.html в этом каталоге.
Причина, по которой необходима дополнительная настройка для корня, заключается в том, что the ResourceHttpRequestHandler checks for non empty paths (не уверен, почему он диктует это и не оставляет это до ResourceResolve ...).
Ограничения
Поскольку я называю resource.getFile()
я полагаю, что существует целый ряд случаев, когда это не будет работать. Я тестирую файлы, доставленные из военного файла в Tomcat. Однако, если ресурсы читаются непосредственно из файла jar, это, вероятно, не сработает. В качестве альтернативы может быть использована адаптация, где не .getFile().isDirectory()
, а скорее resource.isReadable()
.