Статьи

Двухэтапное управление ресурсами с помощью Spring MVC

При обслуживании статических ресурсов обычной практикой является добавление некоторой информации о версии к URL-адресу ресурса. Это позволяет браузеру кешировать ресурсы неограниченное время. Всякий раз, когда изменяется содержимое ресурса, информация о версии в URL также изменяется. Обновленный URL-адрес заставляет браузер клиента отказаться от кэшированного ресурса и перезагрузить последнюю версию ресурса с сервера.

В Spring для настройки версионных URL-адресов ресурсов требуется всего два простых шага. В этом посте мы увидим, как это работает.

Обслуживание версионных URL

Сначала мы должны сказать Spring, что ресурсы должны быть доступны через версионный URL. Это делается в конфигурации MVC обработчика ресурсов:

@Configuration
public class MvcApplication extends WebMvcConfigurerAdapter {

  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    VersionResourceResolver versionResourceResolver = new VersionResourceResolver()
        .addVersionStrategy(new ContentVersionStrategy(), "/**");

    registry.addResourceHandler("/javascript/*.js")
        .addResourceLocations("classpath:/static/")
        .setCachePeriod(60 * 60 * 24 * 365) /* one year */
        .resourceChain(true)
        .addResolver(versionResourceResolver);
  }

  ...
}

Здесь мы создаем обработчик ресурсов для файлов JavaScript, расположенных в папке с именем static внутри classpath. Период кэширования для этих файлов JavaScript установлен на один год. Важной частью является VersionResourceResolver, который поддерживает URL ресурсов с информацией о версии. VersionStrategy используется для получения фактической версии для ресурса.

В этом примере мы используем ContentVersionStrategy . Эта реализация VersionStrategy вычисляет хеш MD5 из содержимого ресурса и добавляет его к имени файла.

Например: предположим, у нас есть файл JavaScript test.js в каталоге classpath: / static /. Хеш MD5 для test.js равен 69ea0cf3b5941340f06ea65583193168.

Теперь мы можем отправить запрос

/javascript/test-69ea0cf3b5941340f06ea65583193168.js

который будет преобразован в classpath: /static/test.js.

Обратите внимание, что все еще можно запросить ресурс без хеша MD5. Так что этот запрос тоже работает:

/javascript/test.js

Альтернативной реализацией VersionStrategy является FixedVersionStrategy . FixedVersionStrategy использует фиксированную строку версии, которая добавляется в качестве префикса к пути ресурса.

Например:

/v1.2.3/javascript/test.js

Генерация версионных URL

Теперь нам нужно убедиться, что приложение генерирует URL ресурсов, которые содержат хеш MD5.

Одним из подходов для этого является использование ResourceUrlProvider . С помощью ResourceUrlProvider URL ресурса (например, /javascript/test.js) можно преобразовать в версионный URL (например, /javascript/test-69ea0cf3b5941340f06ea65583193168.js). Bean-компонент ResourceUrlProvider с идентификатором mvcResourceUrlProvider автоматически объявляется в конфигурации MVC.

Если вы используете Thymeleaf в качестве механизма шаблонов, вы можете получить доступ к компоненту ResourceUrlProvider напрямую из шаблонов, используя синтаксис @bean.

Например:

<script type="application/javascript"
        th:src="${@mvcResourceUrlProvider.getForLookupPath('/javascript/test.js')}">
</script>

Если вы используете шаблонизатор, который не дает вам прямого доступа к бинам Spring, вы можете добавить компонент ResourceUrlProvider в атрибуты модели. Используя ControllerAdvice , это может выглядеть так:

@ControllerAdvice
public class ResourceUrlAdvice {

  @Inject
  ResourceUrlProvider resourceUrlProvider;

  @ModelAttribute("urls")
  public ResourceUrlProvider urls() {
    return this.resourceUrlProvider;
  }
}

Внутри представления мы можем получить доступ к ResourceUrlProvider, используя атрибут модели urls:

<script type="application/javascript" 
        th:src="${urls.getForLookupPath('/javascript/test.js')}">
</script>

Этот подход должен работать со всеми шаблонизаторами, которые поддерживают вызовы методов.

Альтернативный подход для создания версионных URL-адресов — это использование ResourceUrlEncodingFilter . Это фильтр сервлетов, который переопределяет метод HttpServletResponse.encodeURL () для генерации версионных URL ресурсов.

Чтобы использовать ResourceUrlEncodingFilter, нам просто нужно добавить дополнительный компонент в наш класс конфигурации:

@SpringBootApplication
public class MvcApplication extends WebMvcConfigurerAdapter {

  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    // same as before ..
  }

  @Bean
  public ResourceUrlEncodingFilter resourceUrlEncodingFilter() {
    return new ResourceUrlEncodingFilter();
  }

  ...
}

Если используемый вами шаблонизатор вызывает метод encodeURL () ответа, информация о версии будет автоматически добавлена ​​в URL. Это будет работать в JSP, Thymeleaf, FreeMarker и Velocity.

Например: с Thymeleaf мы можем использовать стандартный синтаксис @ {..} для создания URL:

<script type="application/javascript" th:src="@{/javascript/test.js}"></script>

Это приведет к:

<script type="application/javascript" 
        src="/javascript/test-69ea0cf3b5941340f06ea65583193168.js">
</script>

Резюме

Добавление информации о версии к URL-адресам ресурсов является обычной практикой для максимального кэширования браузера. В Spring нам просто нужно определить VersionResourceResolver и VersionStrategy для обслуживания версионных URL-адресов. Самый простой способ создания версионных URL-адресов внутри шаблонизаторов — это использование ResourceUrlEncodingFilter.

Если стандартные реализации VersionStrategy не соответствуют вашим требованиям, вы можете создать нашу собственную реализацию VersionStrategy.

Вы можете найти полный пример исходного кода на GitHub .