Spring Boot: Заміщення значка


83

Як я можу замінити значок Spring Boot?

ПРИМІТКА : Ось моє ще одне запитання, яке пропонує інше рішення, яке не передбачає кодування: Spring Boot: чи можна використовувати зовнішні файли application.properties у довільних каталогах із жировою банкою? Це для application.properties, але його також можна застосувати до значка. Насправді я зараз використовую цей метод для заміни значків.

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

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

Як я можу перевизначити це, не реалізувавши клас, який має @EnableWebMvc сам, тим самим відключаючи всю функціональність конфігурації за замовчуванням класу WebMvcAutoConfiguration класу Spring Boot?

Крім того, оскільки я хочу, щоб файл піктограм якнайшвидше оновлювався на стороні клієнта (веб-браузера), я хочу встановити для періоду кешування файлу значка значення 0. (наприклад, такий код, який я використовую `` статичний '' вміст веб-додатків та файли сценаріїв, які повинні бути оновлені на стороні клієнта якомога швидше після того, як я зміню файл.)

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

Отже, просто для того, щоб знайти місце для збереження файлу favicon.ico, почесних почесних виступів faviconRequestHandler Spring Boot може бути недостатньо.

ОНОВЛЕННЯ

Тепер я знаю, що можу замінити файл за замовчуванням, розмістивши файл значка у каталозі 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боб, але я не знаю, як це зробити.

Тепер я можу вибрати один із таких варіантів:

  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, вони відрізнялися.

Будемо вдячні за будь-які пропозиції щодо покращення мого середовища.
Оскільки я початківець весни, можливо, мені чогось не вистачає.

ОНОВЛЕННЯ

Нарешті, у мене є робочий код. Це наступне:

@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;
    }
}

Зверніть увагу на назви квасолі. Я додав "мій", щоб уникнути зіткнення імен.
Сам контекст програми автоматичного підключення здається незручним, але він був необхідний для імітації коду в org.springframework.web.servlet.config.annotation.ResourceHandlerRegistration.addResourceLocations().

Тепер у мене є обробник значків без проблем кешування, і я можу розмістити файл значка у будь-якому місці, куди захочу.
Дякую.


1
Ваш метод виглядає нормально. Хіба це не замінює обробник ресурсів Spring MVC за замовчуванням (тому, наприклад, статичні ресурси більше не будуть обслуговуватися classpath:/static). (Ось чому підтримка значків у Boot є у власному HandlerMapping, я думаю.)
Dave Syer

@DaveSyer Тепер я зрозумів, що це не нормально. Я писав третє оновлення вище. Можливо HandlerMapping, потрібне окреме .
zeodtr

@DaveSyer Будь ласка, дивіться моє четверте оновлення вище. Чи є інший спосіб? Наприклад, чи можу я зареєструвати свій власний HandlerMapping?
zeodtr

Так, ви можете додати файл HandlerMapping(просто скопіюйте той із Boot і надайте йому вищий пріоритет). Я не зовсім впевнений, чому ви піклуєтесь про місце розташування, favicon.ico fileале ми можемо зробити його налаштовувальним, якщо хочете. Усі браузери також кешують його, тому я сумніваюся, що налаштування кешу важливі, але раді, що довели, що вони помиляються.
Dave Syer

@DaveSyer Будь ласка, перегляньте оновлене запитання про те, чому я хочу розмістити статичні файли в іншому місці. Також проблема з кешем.
zeodtr

Відповіді:


53

Ви можете просто розмістити свій власний 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

Я пробую вашу пропозицію. Зауважимо одне: моє ім'я компонента не повинно бути 'faviconHandlerMapping', оскільки це спричиняє зіткнення імені компонента з bevic-файлом faviconHandlerMapping Spring Boot. Лише один із 2 компонентів буде вибраний методом, який викликається org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestor‌ s (), який знову викликається org.springframework.web.servlet.initHandlerMappings (). Здається, мій боб завантажується раніше, ніж замінює конфлікт імен.
zeodtr

Імена HandlerMapping квасолі зареєстрованої наступним чином : { faviconHandlerMapping, requestMappingHandlerMapping, viewControllerHandlerMapping, beanNameHandlerMapping, resourceHandlerMapping, defaultServletHandlerMapping, endpointHandlerMapping} Таким чином , я повинен уникати цих імен.
zeodtr

2
Вам слід прочитати оновлену відповідь, а також посібник користувача. Якщо все, що ви хочете зробити, це змінити піктограму, це ніколи не було дуже складною зміною. Я не знаю, чому ОП зіткнувся з такою великою проблемою.
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

@zeodtr просто цікаво чому. Мені це здається найбільш природним. Однак я би очікував, що це будеsrc/main/resources/static/images
btiernay

1
@btiernay Це тому, що веб-сервер є окремою сутністю від веб-клієнта. І значок (и) належить клієнту. Файл війни веб-сервера не має підстави включати файли, що належать клієнту, і які можна змінювати набагато частіше за потребою користувачів.
zeodtr

Просто FYI, тепер це можна вирішити favicon.icoз static: github.com/spring-projects/spring-boot/commit/…
btiernay

1
src / main / resources / static path працює добре. Це найпростіший і регулярний спосіб зробити.
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 в нових версіях для таких тривіальних функціональних можливостей.


4
Вам більше не доведеться базікати з відображеннями обробників (просто додайте favicon.ico у ваші статичні ресурси).
Dave Syer

Це так просто! Дякую. Я додаю це у свій фрагмент.
Lay Leangsros

що, якщо ви використовуєте springboot лише як
сервісну підтримку

@ParamvirSinghKarwal Якщо у вас є лише послуга, чому ви хочете отримати значок?
jeremyjjbrown

Якщо ви натиснете api безпосередньо з адреси браузера, він відображає значок за замовчуванням про весняний додаток, який схожий на зелений лист. Я хочу, щоб це був фірмовий значок. Я зміг це зробити.
Парамвір Сінгх Карвал

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 він нічим не замінений, оскільки більше немає стандартного значка - взагалі. Якщо ви хочете, вам потрібно налаштувати відображення для власного значка.
Тринкєвич Маріуш

1
так в кінці я дізнався, що мені потрібно зробити це замість цього: @Override public void addResourceHandlers (реєстр ResourceHandlerRegistry) {registry.addResourceHandler ("/ favicon.ico"). addResourceLocations ("classpath: / static /"); }
Шилан

2

Новіші версії Boot (напевно 1.2, але, можливо, і 1.1.8) дозволяють просто розмістити favicon.ico у своїх статичних ресурсах.


2

Я спробував багато варіантів / варіантів, але тільки це спрацювало. (Spring Boot 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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.