1. Обзор
В этом руководстве будет показано, как обслуживать статические ресурсы с помощью Spring , используя конфигурацию XML и Java.
2. Использование Spring Boot
Spring Boot поставляется с предварительно настроенной реализацией ResourceHttpRequestHandler
для облегчения обслуживания статических ресурсов.
По умолчанию этот обработчик обслуживает статическое содержимое из любых каталогов /static, /public, /resources
и /META-INF/resources
, которые находятся в пути к классам . Поскольку src/main/resources
обычно находится в пути к классам по умолчанию, мы можем поместить туда любой из этих каталогов.
Например, если мы поместим файл about.html в каталог
/static
в нашем пути к классам, мы сможем получить доступ к этому файлу через http://localhost:8080/about.html
. Точно так же мы можем добиться того же результата, добавив этот файл в другие упомянутые каталоги.
2.1. Пользовательские шаблоны пути
По умолчанию Spring Boot обслуживает весь статический контент в корневой части запроса /**
.
Несмотря на то, что это кажется хорошей конфигурацией по умолчанию, мы можем изменить ее с помощью свойства конфигурации spring.mvc.static-path-pattern
.
Например, если мы хотим получить доступ к тому же файлу через http://localhost:8080/content/about.html,
мы можем указать это в нашем application.properties:
spring.mvc.static-path-pattern=/content/**
В средах WebFlux мы должны использовать свойство spring.webflux.static-path-pattern
.
2.2. Пользовательские каталоги
Подобно шаблонам пути, также можно изменить расположение ресурсов по умолчанию с помощью свойства конфигурации spring.web.resources.static-locations
. Это свойство может принимать несколько расположений ресурсов, разделенных запятыми:
spring.web.resources.static-locations=classpath:/files/,classpath:/static-files
Здесь мы обслуживаем статическое содержимое из каталогов /files
и /static-files
внутри пути к классам. Более того, Spring Boot может обслуживать статические файлы вне пути к классам :
spring.web.resources.static-locations=file:/opt/files
Здесь мы используем сигнатуру файлового ресурса , file:/
, для обслуживания файлов с нашего локального диска.
3. XML-конфигурация
Если нам нужно пойти по старинке с конфигурацией на основе XML, мы можем эффективно использовать элемент mvc:resources
, чтобы указать расположение ресурсов с помощью определенного общедоступного шаблона URL.
Например, следующая строка будет обслуживать все запросы на ресурсы, поступающие с общедоступным шаблоном URL, например « /resources/**»,
путем поиска в каталоге «/ resources/
» в корневой папке нашего приложения:
<mvc:resources mapping="/resources/**" location="/resources/" />
Теперь мы можем получить доступ к файлу CSS, как на следующей HTML-странице:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<link href="<c:url value="/resources/myCss.css" />" rel="stylesheet">
<title>Home</title>
</head>
<body>
<h1>Hello world!</h1>
</body>
</html>
4. Обработчик ResourceHttpRequestHandler
Весна 3.1. представил ResourceHand
lerRegistry
для настройки ResourceHttpRequestHandler
для обслуживания статических ресурсов из пути к классам, WAR или файловой системы. Мы можем настроить ResourceHandlerRegistry
программно внутри нашего класса конфигурации веб-контекста.
4.1. Обслуживание ресурса, хранящегося в WAR
Чтобы проиллюстрировать это, мы будем использовать тот же URL-адрес, что и раньше, чтобы указать на myCss.css
, но теперь фактический файл будет находиться в папке WAR webapp/resources
, где мы должны размещать статические ресурсы при развертывании приложений Spring 3.1+. :
@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
}
Давайте немного проанализируем этот пример. Во-первых, мы настраиваем внешний путь URI, определяя обработчик ресурсов. Затем мы сопоставляем этот внешний путь URI с физическим путем, где фактически находятся ресурсы.
Мы можем, конечно, определить несколько обработчиков ресурсов, используя этот простой, но гибкий API.
Теперь следующая строка на html
- странице даст нам ресурс myCss.css
внутри каталога webapp/resources
:
<link href="<c:url value="/resources/myCss.css" />" rel="stylesheet">
4.2. Обслуживание ресурса, хранящегося в файловой системе
Допустим, мы хотим обслуживать ресурс, хранящийся в каталоге /opt/files/,
всякий раз, когда поступает запрос на общедоступный URL-адрес, соответствующий шаблону /files/** .
Мы просто настраиваем шаблон URL и сопоставляем его с этим конкретным местом на диске:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/files/**")
.addResourceLocations("file:/opt/files/");
}
Для пользователей Windows аргумент, переданный в addResourceLocations
для этого примера, будет « file:///C:/opt/files/
».
Как только мы настроим расположение ресурса, мы можем использовать сопоставленный шаблон URL-адреса в нашем home.html
для загрузки изображения, хранящегося в файловой системе:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<link href="<c:url value="/resources/myCss.css" />" rel="stylesheet">
<title>Home</title>
</head>
<body>
<h1>Hello world!</h1>
<img alt="image" src="<c:url value="files/myImage.png" />">
</body>
</html>
4.3. Настройка нескольких местоположений для ресурса
Что, если мы хотим искать ресурс более чем в одном месте?
Мы можем включить несколько местоположений с помощью метода addResourceLocations
. Список местоположений будет искаться по порядку, пока не будет найден ресурс:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/resources/**")
.addResourceLocations("/resources/","classpath:/other-resources/");
}
Следующий запрос curl отобразит страницу Hello.html
, хранящуюся либо в папке webappp/resources
приложения, либо в папке other-resources
в пути к классам:
curl -i http://localhost:8080/handling-spring-static-resources/resources/Hello.html
5. Новые ResourceResolvers
Весна 4.1. предоставляет с новыми ResourcesResolvers
различные типы преобразователей ресурсов, которые можно использовать для оптимизации производительности браузера при загрузке статических ресурсов. Эти преобразователи могут быть объединены в цепочку и кэшированы в браузере для оптимизации обработки запросов.
5.1. PathResourceResolver
_ ``
Это простейший распознаватель, и его цель — найти ресурс по общедоступному шаблону URL. На самом деле, если мы не добавим ResourceResolver
в ResourceChainRegistration
, это будет преобразователь по умолчанию.
Давайте посмотрим на пример:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/resources/**")
.addResourceLocations("/resources/","/other-resources/")
.setCachePeriod(3600)
.resourceChain(true)
.addResolver(new PathResourceResolver());
}
На что следует обратить внимание:
- Мы регистрируем
PathResourceResolver
в цепочке ресурсов как единственный в нейResourceResolver
. Мы можем обратиться к разделу 4.3. чтобы увидеть, как связать более одногоResourceResolver
. - Обслуживаемые ресурсы будут кэшироваться в браузере на 3600 секунд.
- Наконец, цепочка настроена с помощью метода
resourceChain(true)
.
Теперь HTML-код, который в сочетании с PathResourceResolver
находит скрипт foo.js
либо в папке webapp/resources
, либо в папке webapp/other-resources
:
<script type="text/javascript" src="<c:url value="/resources/foo.js" />">
5.2. EncodedResourceResolver
_ ``
Этот сопоставитель пытается найти закодированный ресурс на основе значения заголовка запроса Accept-Encoding .
Например, нам может потребоваться оптимизировать пропускную способность, предоставляя сжатую версию статического ресурса с использованием кодирования содержимого gzip .
Чтобы настроить EncodedResourceResolver,
нам нужно настроить его в ResourceChain
так же, как мы настроили PathResourceResolver
:
registry
.addResourceHandler("/other-files/**")
.addResourceLocations("file:/Users/Me/")
.setCachePeriod(3600)
.resourceChain(true)
.addResolver(new EncodedResourceResolver());
По умолчанию EncodedResourceResolver
настроен на поддержку кодировок br
и gzip .
Таким образом, следующий запрос curl
получит заархивированную версию файла Home.html
, расположенного в файловой системе в каталоге Users/Me/
:
curl -H "Accept-Encoding:gzip"
http://localhost:8080/handling-spring-static-resources/other-files/Hello.html
Обратите внимание, как мы устанавливаем для заголовка Accept-Encoding
значение gzip.
Это важно, потому что этот конкретный распознаватель сработает только в том случае, если содержимое gzip допустимо для ответа.
Наконец, обратите внимание, что, как и раньше, сжатая версия будет оставаться доступной в течение периода времени, в течение которого она кэшируется в браузере, что в данном случае составляет 3600 секунд.
5.3. Цепочка ResourceResolvers
Чтобы оптимизировать поиск ресурсов, ResourceResolvers
могут делегировать обработку ресурсов другим распознавателям. Единственный преобразователь, который не может делегировать цепочку, — это PathResourceResolver,
который мы должны добавить в конец цепочки.
На самом деле, если для resourceChain
не задано значение true
, то по умолчанию для обслуживания ресурсов будет использоваться только PathResourceResolver .
Здесь мы связываем PathResourceResolver
для разрешения ресурса, если GzipResourceResolver
не удался:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/js/**")
.addResourceLocations("/js/")
.setCachePeriod(3600)
.resourceChain(true)
.addResolver(new GzipResourceResolver())
.addResolver(new PathResourceResolver());
}
Теперь, когда мы добавили шаблон /js/** в
ResourceHandler
, давайте включим ресурс foo.js
, расположенный в каталоге webapp/js/
на нашей странице home.html
:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<link href="<c:url value="/resources/bootstrap.css" />" rel="stylesheet" />
<script type="text/javascript" src="<c:url value="/js/foo.js" />"></script>
<title>Home</title>
</head>
<body>
<h1>This is Home!</h1>
<img alt="bunny hop image" src="<c:url value="files/myImage.png" />" />
<input type = "button" value="Click to Test Js File" onclick = "testing();" />
</body>
</html>
Стоит отметить, что начиная с Spring Framework 5.1 GzipResourceResolver
устарел в пользу EncodedResourceResolver
. Поэтому нам следует избегать его использования в будущем.
6. Дополнительная конфигурация безопасности
При использовании Spring Security важно разрешить доступ к статическим ресурсам. Нам нужно добавить соответствующие разрешения для доступа к URL-адресу ресурса:
<intercept-url pattern="/files/**" access="permitAll" />
<intercept-url pattern="/other-files/**/" access="permitAll" />
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/js/**" access="permitAll" />
7. Заключение
В этой статье мы проиллюстрировали различные способы, которыми приложение Spring может обслуживать статические ресурсы.
Конфигурация ресурсов на основе XML — это устаревший вариант , который мы можем использовать, если пока не можем пойти по пути конфигурации Java.
Весна 3.1. вышел с базовой программной альтернативой через свой объект ResourceHandlerRegistry .
Наконец, новые готовые объекты ResourceResolvers
и ResourceChainRegistration ,
поставляемые с Spring 4.1 . предлагает функции оптимизации загрузки ресурсов, такие как кэширование и связывание обработчиков ресурсов, для повышения эффективности обслуживания статических ресурсов.
Как всегда, полный пример доступен на Github . Кроме того, в этом проекте также доступны исходные коды, относящиеся к Spring Boot .