Spring Boot: переопределение значка

84

Как я могу переопределить значок Spring Boot?

ПРИМЕЧАНИЕ . Вот еще один мой вопрос, который предлагает другое решение, не связанное с кодированием: Spring Boot: можно ли использовать внешние файлы application.properties в произвольных каталогах с толстой банкой? Это для application.properties, но его также можно применить к значку. Фактически, я сейчас использую этот метод для переопределения значков.

Если я реализую класс с @EnableWebMvc, класс WebMvcAutoConfiguration Spring Boot не загружается, и я могу обслуживать свой собственный значок, помещая его в корневой каталог статического содержимого.

В противном случае WebMvcAutoConfiguration регистрирует bean-компонент faviconRequestHandler (см. Источник https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconframework/boot/autoconfigure/ web / WebMvcAutoConfiguration.java ), и он обслуживает значок «зеленый лист», который помещается в основной каталог ресурсов Spring Boot.

Как я могу переопределить его, не реализуя класс, который сам имеет @EnableWebMvc, тем самым отключив всю функциональность конфигурации по умолчанию для класса WebMvcAutoConfiguration класса Spring Boot?

Кроме того, поскольку я хочу, чтобы файл значка был обновлен как можно скорее на стороне клиента (веб-браузера), я хочу установить период кеширования файла значка на 0. (например, следующий код, который я использую для своего «статический» контент веб-приложения и файлы сценариев, которые должны быть обновлены на стороне клиента как можно скорее после того, как я изменю файл.)

public void addResourceHandlers(ResourceHandlerRegistry registry)
{
    registry.addResourceHandler("/**")
        .addResourceLocations("/")
        .setCachePeriod(0);
}

Итак, просто найти место для сохранения файла favicon.ico, который уважает Spring Boot faviconRequestHandler, может быть недостаточно.

ОБНОВИТЬ

Теперь я знаю, что могу изменить значение по умолчанию, поместив файл значка в каталог src / main / resources. Но проблема периода кеширования все еще остается.
Кроме того, предпочтительно помещать файл значка в каталог, в который помещаются статические веб-файлы, а не в каталог ресурсов.

ОБНОВИТЬ

Хорошо, мне удалось изменить значение по умолчанию. Я сделал следующее:

@Configuration
public class WebMvcConfiguration
{
    @Bean
    public WebMvcConfigurerAdapter faviconWebMvcConfiguration()
    {
        return new FaviconWebMvcConfiguration();
    }

    public class FaviconWebMvcConfiguration extends WebMvcConfigurerAdapter
    {
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry)
        {
            registry.setOrder(Integer.MIN_VALUE);
            registry.addResourceHandler("/favicon.ico")
                .addResourceLocations("/")
                .setCachePeriod(0);
        }
    }
}

По сути, я отменял стандартное, добавляя обработчик ресурсов с наивысшим порядком, вызывая registry.setOrder (Integer.MIN_VALUE).

Поскольку значение по умолчанию в Spring Boot имеет значение порядка (Integer.MIN_VALUE + 1) (см. Класс FaviconConfiguration в https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/ src / main / java / org / springframework / boot / autoconfigure / web / WebMvcAutoConfiguration.java ) мой обработчик побеждает.

Это нормально? Есть ли другой способ (что-то более мягкое, чем то, что я сделал)?

ОБНОВИТЬ

Это не хорошо. Когда я звоню registry.setOrder(Integer.MIN_VALUE), я фактически повышаю приоритет всех обработчиков ресурсов. Итак, когда я добавляю следующий код к другому WebMvcConfigurerAdapter, фактически весь HTTP-запрос направляется этому обработчику ресурсов, предотвращая любую динамическую обработку кодом Java.

public void addResourceHandlers(ResourceHandlerRegistry registry)
{
    registry.addResourceHandler("/**")
        .addResourceLocations("/")
        .setCachePeriod(0);
}

Требуется другое решение.

ОБНОВИТЬ

На данный момент я не смог найти способ переопределить функциональность значка, предоставляемую Spring Boot.
Может есть способ добавить свойHandlerMapping bean-компонент, но я не знаю, как это сделать.

Теперь я могу выбрать один из следующих вариантов:

  1. Имейте класс, который @EnableWebMvcотключил WebMvcAutoConfigurationкласс Spring Boot . (Я могу скопировать код WebMvcAutoConfigurationкласса и удалить функцию фавикона)
  2. Откажитесь от свободы размещения файла значка в произвольном месте и поместите его в каталог ресурсов, как того требует функциональность значков Spring Boot. И игнорируйте проблему кеширования.

Но ни один из вариантов не является удовлетворительным.
Я просто хочу разместить файл значка со своими статическими веб-файлами (это может быть любой каталог, поскольку я могу изменить корень документа) и решить проблему кеширования.
Я что-то упускаю?
Любое предложение будет принято с благодарностью.

ОБНОВИТЬ

Кстати, причина, по которой я хочу изменить расположение значка и других статических файлов, заключается в следующем. Пока это в основном проблема среды разработки.

Я создаю одностраничное веб-приложение (SPA).

Библиотеки / Фреймворки:

  • На стороне сервера я использую Spring. (конечно)
  • На стороне клиента (веб-браузера) я использую AngularJS.

Инструменты:

  • На стороне сервера я использую Spring Tool Suite.
  • На стороне клиента я использую WebStorm.

Структура основного каталога:

ProjectRoot\
    src\
    bin\
    build\
    webapp\
    build.gradle
  • src: Где находятся мои исходные файлы Java Spring.
  • bin: Где Spring Tool Suite размещает свои выходные данные сборки.
  • build: где gradle build размещает вывод сборки.
  • webapp: Где находятся мои исходные файлы клиента (.js, .css, .htm и favicon). Таким образом, это каталог проекта WebStorm. (При необходимости я могу изменить имя каталога)

Я хочу:

  • Чтобы иметь возможность изменять и тестировать мой клиентский код без перестройки / перезапуска моего серверного приложения Spring. Таким образом, код клиента нельзя помещать в файл jar. В любом случае Spring Tool Suite вообще не создает файл jar (по крайней мере, для текущей конфигурации)
  • Чтобы иметь возможность тестировать мое серверное приложение Spring с клиентским кодом, легко переключаясь между выходом Spring Tool Suite и выходом gradle. Таким образом, клиентский код должен быть доступен как из серверного приложения в buildподкаталоге (фактически build\libs), так и из серверного приложения в binкаталоге.
  • Когда я изменяю код клиента, он должен быть немедленно доступен для веб-браузера. Таким образом, браузер не должен кэшировать его на неопределенный срок и всегда должен запрашивать обновление у сервера.
  • При развертывании клиентский код должен быть изменяемым без перекомпоновки / перезапуска серверного приложения. Поэтому код клиента нельзя помещать в файл jar.

Что касается проблемы с кешем:

Без setCachePeriod (0) в addResourceHandlers () Google Chrome кэширует файл на неопределенный срок, не запрашивая обновления у сервера. Он даже не подключается к серверу. (Инженеры Google говорят, что поведение правильное.) Итак, все, что я могу сделать, это вручную очистить кеш браузера. Это расстраивает среду разработки и неприемлемо для производственной среды.

Кстати, модуль express.js на Node.js предоставляет разумный HTTP-заголовок по умолчанию, чтобы Google Chrome запрашивал у сервера обновления. Когда я просмотрел заголовки HTTP, которые Spring и express.js создают с помощью Fiddler, они были разными.

Любые предложения по улучшению моей среды будут оценены.
Поскольку я новичок в Spring, возможно, мне что-то не хватает.

ОБНОВИТЬ

Наконец-то у меня есть рабочий код. Это выглядит следующим образом:

@Configuration
public static class FaviconConfiguration
{
    @Bean
    public SimpleUrlHandlerMapping myFaviconHandlerMapping()
    {
        SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
        mapping.setOrder(Integer.MIN_VALUE);
        mapping.setUrlMap(Collections.singletonMap("/favicon.ico",
            myFaviconRequestHandler()));
        return mapping;
    }

    @Autowired
    ApplicationContext applicationContext;

    @Bean
    protected ResourceHttpRequestHandler myFaviconRequestHandler()
    {
        ResourceHttpRequestHandler requestHandler =
            new ResourceHttpRequestHandler();
        requestHandler.setLocations(Arrays
            .<Resource> asList(applicationContext.getResource("/")));
        requestHandler.setCacheSeconds(0);
        return requestHandler;
    }
}

Обратите внимание на имена бобов. Я добавил «мой», чтобы избежать конфликта имен.
Сам по себе контекст приложения Autowiring кажется неудобным, но он был необходим для имитации кода org.springframework.web.servlet.config.annotation.ResourceHandlerRegistration.addResourceLocations().

Теперь у меня есть обработчик значков без проблем с кешированием, и я могу разместить файл значков в любом месте.
Благодарю.

zeodtr
источник
1
Ваш метод выглядит нормально. Разве он не заменяет обработчик ресурсов Spring MVC по умолчанию (например, статические ресурсы больше не будут обслуживаться classpath:/static). (Вот почему поддержка значков в Boot, я думаю, находится в собственном HandlerMapping.)
Дэйв Сайер,
@DaveSyer Теперь я понял, что это не нормально. Я написал выше третье обновление. Может HandlerMappingнужно отдельное .
zeodtr
@DaveSyer Пожалуйста, посмотрите мое четвертое обновление выше. Есть ли другой путь? Например, могу ли я зарегистрировать свою HandlerMapping?
zeodtr
Да, вы можете добавить HandlerMapping(просто скопируйте его из Boot и установите более высокий приоритет). Я не совсем уверен, почему вам нужно заботиться о местоположении, favicon.ico fileно мы можем сделать его настраиваемым, если хотите. Все браузеры также будут кэшировать его, поэтому я сомневаюсь, что настройки кеша имеют значение, но я рад, что ошибся.
Дэйв Сайер
@DaveSyer См. Обновленный вопрос, чтобы узнать, почему я хочу разместить статические файлы в другом месте. Также проблема с кешем.
zeodtr

Ответы:

54

Вы можете просто поместить свой собственный favicon.ico в корень пути к классам или в любое из мест статических ресурсов (например, classpath:/static ). Вы также можете полностью отключить разрешение значков с помощью одного флага spring.mvc.favicon.enabled=false.

Или, чтобы получить полный контроль, вы можете добавить HandlerMapping (просто скопируйте его из Boot и назначьте ему более высокий приоритет), например

@Configuration
public static class FaviconConfiguration {

@Bean
public SimpleUrlHandlerMapping faviconHandlerMapping() {
    SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
    mapping.setOrder(Integer.MIN_VALUE);
    mapping.setUrlMap(Collections.singletonMap("mylocation/favicon.ico",
            faviconRequestHandler()));
    return mapping;
}

@Bean
protected ResourceHttpRequestHandler faviconRequestHandler() {
    ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
    requestHandler.setLocations(Arrays
            .<Resource> asList(new ClassPathResource("/")));
    return requestHandler;
}
}
оборота Дэйв Сайер
источник
Спасибо. Думал уже пробовал, но вот думаю, пропустил @Configurationаннотацию. Кстати, я написал причину, по которой я хочу разместить статические файлы в другом месте в вопросе.
zeodtr
Кстати, поскольку я должен использовать ResourceLoader.gerResource ("/"), чтобы получить файл в корне документа (верно?), Я должен использовать @Autowire ApplicationContext. Можно ли DI контекст приложения? Некоторые говорят, что это плохо.
zeodtr
Пробую ваше предложение. Одно замечание: имя моего bean-компонента не должно быть faviconHandlerMapping, поскольку оно вызывает конфликт имени bean-компонента с bean-компонентом faviconHandlerMapping Spring Boot. Только один из двух bean-компонентов будет выбран методом, который вызывается org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestor‌ s (), который снова вызывается org.springframework.web.servlet.initHandlerMappings (). Похоже, что мой bean-компонент загружается раньше, чем перекрывается конфликтом имен.
zeodtr
Имена HandlerMapping фасоли зарегистрированной следующим образом : { faviconHandlerMapping, requestMappingHandlerMapping, viewControllerHandlerMapping, beanNameHandlerMapping, resourceHandlerMapping, defaultServletHandlerMapping, endpointHandlerMapping} Таким образом , я должен избегать этих имен.
zeodtr
2
Вам следует прочитать обновленный ответ, а также руководство пользователя. Если все, что вам нужно, это изменить значок, это никогда не было очень сложной задачей. Я не знаю, почему OP пошла на такие неприятности.
Dave Syer
75

Мне все это было не нужно.

Зачем переопределять значение по умолчанию, если вы можете связать ресурс с сгенерированным JAR, который будет иметь более высокий приоритет, чем приоритет по умолчанию.

Чтобы создать собственный favicon.icoфайл, я создал src/main/resourcesкаталог для своего приложения, а затем скопировал в него favicon.icoфайл. Файлы в этом каталоге ресурсов перемещаются в корень скомпилированного JAR, и поэтому ваш заказ favicon.icoнаходится до того, как его предоставил Spring.

Выполнение вышеуказанного привело к тому же эффекту, что и ваше обновленное решение, указанное выше.

Обратите внимание, что начиная с версии 1.2.0 вы также можете поместить файл в формат src/main/resources/static.

Росс
источник
6
Причина проста. Я не хочу помещать файл значка в JAR.
zeodtr 07
@zeodtr просто любопытно, почему. Мне это кажется наиболее естественным. Тем не менее, я ожидал, что это будетsrc/main/resources/static/images
btiernay
1
@btiernay Это потому, что веб-сервер является отдельным от веб-клиента объектом. И значок (значки) принадлежит клиенту. Военный файл веб-сервера не имеет причин для включения файлов, принадлежащих клиенту, которые можно изменять гораздо чаще по мере необходимости.
zeodtr
Просто к сведению, теперь это можно решить favicon.icoс помощью static: github.com/spring-projects/spring-boot/commit/…
btiernay
1
src / main / resources / static путь работает хорошо. Это самый простой и регулярный способ сделать.
pdem
29

Мне очень нравится Springboot, потому что в целом он полон умных решений, но я отказываюсь регистрировать компонент приложения для предоставления значка, потому что это просто глупо.

Я просто добавил свою собственную ссылку на значок в заголовке своей html-страницы вот так.

<link rel="icon" type="image/png" href="images/fav.png">

Затем я переименовал свой значок и поместил его в

<ProjFolder>/src/main/resources/static/images/fav.png

Теперь у меня есть значок на вкладках браузера Chrome и Firefox и в адресной строке Safari без использования Spring и Java, и мне не придется гнаться за изменениями Springboot в новых версиях для такой тривиальной функциональности.

Jeremyjjbrown
источник
4
Вам больше не нужно возиться с сопоставлениями обработчиков (просто поместите favicon.ico в свои статические ресурсы).
Дэйв Сайер 05
Это так просто! Благодарю. Добавляю в свой фрагмент.
Lay Leangsros
что, если вы используете springboot только в качестве серверной части службы API, у вас нет там HTML-страниц: /
Парамвир Сингх Карвал
@ParamvirSinghKarwal Если у вас есть только услуга, зачем вам фавикон?
jeremyjjbrown
Если вы нажмете api прямо с адреса браузера, он покажет значок по умолчанию приложения Spring, который похож на зеленый лист. Я хочу, чтобы это был фирменный значок. Я смог это сделать.
Парамвир Сингх Карвал
13

Начиная с Spring Boot 1.2.2 и 1.1.11 вы можете легко отключить значок по умолчанию, используя spring.mvc.favicon.enabled = falseсвойство.

Для получения дополнительной информации посетите:

ОБНОВЛЕНИЕ: spring.mvc.favicon.enabledсвойство больше не существует с Spring Boot 2.2.x

Трынкевич Мариуш
источник
spring.mvc.favicon.enabled удален из пружинного чехла 2.2. Вы знаете, чем его заменяют?
Шилан
1
@Shilan он заменен ничем, так как больше нет значка по умолчанию - вообще. Если вы хотите его, вам нужно настроить отображение для своего собственного значка.
Trynkiewicz Mariusz
1
да, в конце концов, я обнаружил, что мне нужно сделать это вместо этого: @Override public void addResourceHandlers (реестр ResourceHandlerRegistry) {registry.addResourceHandler ("/ favicon.ico"). addResourceLocations ("classpath: / static /"); }
Shilan
2

Более новые версии Boot (наверняка 1.2, но, возможно, также и 1.1.8) позволяют вам просто поместить favicon.ico в ваши статические ресурсы.

Дэйв Сайер
источник
2

Я перепробовал много вариантов / вариантов, но только это сработало. (Весенняя загрузка 2.2.7)

Файлы Favicon.ico и robots.txt помещаются в / resources / static

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
  protected void configure(HttpSecurity http) throws Exception { 
    http
      .authorizeRequests()
        .antMatchers("/favicon.ico").permitAll()
        .antMatchers("/robots.txt").permitAll()
        .antMatchers("/").permitAll()
        .anyRequest().authenticated();
    }
}

и

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
@Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler(
      "/favicon.ico",
      "/robots.txt")
      .addResourceLocations(
        "classpath:/static/");
  }
}

Если поможет, пожалуйста, полюбите;)

Юрий Слизников
источник
1

registry.addResourceHandler ("/ robots.txt"). addResourceLocations ("/");

registry.addResourceHandler ("/ favicon.ico"). addResourceLocations ("/");

robots.txt, расположение файла favicon.ico: / src / main / resources

я использовал пружинный ботинок 1.2.1

вебмап
источник