Spring Boot: Favicon überschreiben

83

Wie kann ich das Favicon von Spring Boot überschreiben?

HINWEIS : Hier ist meine andere Frage, die eine andere Lösung bietet, die keine Codierung beinhaltet: Spring Boot: Ist es möglich, externe application.properties-Dateien in beliebigen Verzeichnissen mit einem fetten Glas zu verwenden? Es ist für application.properties, kann aber auch auf das Favicon angewendet werden. Tatsächlich verwende ich diese Methode jetzt zum Überschreiben von Favicon.

Wenn ich eine Klasse mit @EnableWebMvc implementiere, wird die WebMvcAutoConfiguration-Klasse von Spring Boot nicht geladen, und ich kann mein eigenes Favicon bereitstellen, indem ich es in das Stammverzeichnis des statischen Inhalts lege.

Andernfalls registriert WebMvcAutoConfiguration die Bean faviconRequestHandler (siehe Quelle https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/). web / WebMvcAutoConfiguration.java ) und es dient das Symbol 'grünes Blatt', das sich im Hauptressourcenverzeichnis des Spring Boot befindet.

Wie kann ich es überschreiben, ohne selbst eine Klasse mit @EnableWebMvc zu implementieren, wodurch die gesamte Standardkonfigurationsfunktionalität der WebMvcAutoConfiguration-Klasse von Spring Boot deaktiviert wird?

Da ich möchte, dass die Symboldatei auf der Client-Seite (Webbrowser) so schnell wie möglich aktualisiert wird, möchte ich den Cache-Zeitraum der Favicon-Datei auf 0 setzen (wie den folgenden Code, den ich für meine verwende 'statische' Webapp-Inhalte und Skriptdateien, die auf der Clientseite so schnell wie möglich aktualisiert werden müssen, nachdem ich die Datei geändert habe.)

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

Nur um den Speicherort für die Datei favicon.ico zu finden, reicht die faviconRequestHandler-Auszeichnung von Spring Boot möglicherweise nicht aus.

AKTUALISIEREN

Jetzt weiß ich, dass ich die Standarddatei überschreiben kann, indem ich eine Favicon-Datei im Verzeichnis src / main / resources ablege. Das Problem der Cache-Periode bleibt jedoch bestehen.
Außerdem ist es vorzuziehen, die Favicon-Datei in das Verzeichnis zu legen, in dem statische Webdateien abgelegt werden, und nicht in das Ressourcenverzeichnis.

AKTUALISIEREN

Ok, ich habe es geschafft, die Standardeinstellung zu überschreiben. Was ich getan habe ist wie folgt:

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

Grundsätzlich habe ich den Standard überschrieben, indem ich einen Ressourcenhandler mit der höchsten Ordnung hinzugefügt habe, indem ich registry.setOrder (Integer.MIN_VALUE) aufgerufen habe.

Da der Standardwert in Spring Boot den Bestellwert (Integer.MIN_VALUE + 1) hat (siehe FaviconConfiguration-Klasse unter https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/). src / main / java / org / springframework / boot / autoconfigure / web / WebMvcAutoConfiguration.java ) Mein Handler gewinnt.

Ist das ok? Gibt es einen anderen Weg (etwas Sanfteres als das, was ich getan habe)?

AKTUALISIEREN

Es ist nicht okay. Wenn ich anrufe registry.setOrder(Integer.MIN_VALUE), erhöhe ich tatsächlich die Priorität aller Ressourcenhandler. Wenn ich also folgenden Code zu einem anderen hinzufüge WebMvcConfigurerAdapter, werden effektiv alle http-Anforderungen an diesen Ressourcenhandler gerichtet, wodurch jegliche dynamische Behandlung durch Java-Code verhindert wird.

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

Eine andere Lösung ist erforderlich.

AKTUALISIEREN

Im Moment konnte ich die Favicon-Funktionalität von Spring Boot nicht überschreiben.
Vielleicht gibt es eine Möglichkeit, meine eigene HandlerMappingBohne hinzuzufügen , aber ich weiß nicht, wie ich das machen soll.

Jetzt kann ich eine der folgenden Optionen auswählen:

  1. Haben Sie eine Klasse, die @EnableWebMvcsomit die Spring Boot- WebMvcAutoConfigurationKlasse deaktiviert . (Ich kann den WebMvcAutoConfigurationKlassencode kopieren und die Favicon-Funktionalität löschen.)
  2. Geben Sie die Freiheit auf, Favicon-Dateien an einem beliebigen Speicherort abzulegen, und legen Sie sie im Ressourcenverzeichnis ab, wie es die Favicon-Funktionalität von Spring Boot erfordert. Und ignorieren Sie das Caching-Problem.

Aber keine Option ist zufriedenstellend.
Ich möchte nur die Favicon-Datei in meine statischen Webdateien einfügen (dies kann ein beliebiges Verzeichnis sein, da ich den Dokumentstamm ändern kann) und das Caching-Problem beheben.
Vermisse ich etwas
Jeder Vorschlag wäre sehr dankbar.

AKTUALISIEREN

Übrigens, der Grund, warum ich den Speicherort von Favicon und anderen statischen Dateien ändern möchte, ist folgender. Im Moment geht es hauptsächlich um die Entwicklungsumgebung.

Ich erstelle eine Single Page Web Application (SPA).

Bibliotheken / Frameworks:

  • Für die Serverseite verwende ich Spring. (natürlich)
  • Für die Client-Seite (Webbrowser) verwende ich AngularJS.

Werkzeuge:

  • Für die Serverseite verwende ich Spring Tool Suite.
  • Für die Client-Seite verwende ich WebStorm.

Hauptverzeichnisstruktur:

ProjectRoot\
    src\
    bin\
    build\
    webapp\
    build.gradle
  • src: Wo sich meine Spring Java-Quelldateien befinden.
  • bin: Wo Spring Tool Suite seine Build-Ausgabe platziert.
  • build: Wo 'gradle build' seine Build-Ausgabe platziert.
  • webapp: Wo sich meine Client-Quelldateien (.js, .css, .htm und favicon) befinden. Dies ist also das WebStorm-Projektverzeichnis. (Ich kann den Verzeichnisnamen bei Bedarf ändern)

Was ich will ist:

  • Um meinen Client-Code ändern und testen zu können, ohne meine Spring Server-Anwendung neu zu erstellen / neu zu starten. Der Client-Code darf also nicht in die JAR-Datei eingefügt werden. Wie auch immer, Spring Tool Suite erstellt überhaupt keine JAR-Datei (zumindest für die aktuelle Konfiguration)
  • Um meine Spring Server-Anwendung mit dem Client-Code testen zu können, können Sie problemlos zwischen der Spring Tool Suite-Ausgabe und der Gradle-Ausgabe wechseln. Daher muss auf den Clientcode sowohl von der Serveranwendung im buildUnterverzeichnis (tatsächlich build\libs) als auch von der Serveranwendung im binVerzeichnis aus zugegriffen werden können .
  • Wenn ich den Client-Code ändere, muss er dem Webbrowser sofort zur Verfügung stehen. Der Browser darf es also nicht auf unbestimmte Zeit zwischenspeichern und muss immer nach dem Server für die Aktualisierung fragen.
  • Bei der Bereitstellung muss der Clientcode geändert werden können, ohne dass die Serveranwendung neu erstellt / neu gestartet werden muss. Der Client-Code darf also nicht in die JAR-Datei eingefügt werden.

In Bezug auf das Cache-Problem:

Ohne setCachePeriod (0) in addResourceHandlers () speichert Google Chrome die Datei auf unbestimmte Zeit zwischen, ohne den Server nach Updates zu fragen. Es wird nicht einmal eine Verbindung zum Server hergestellt. (Google-Ingenieure sagen, dass das Verhalten korrekt ist.) Ich kann also nur den Browser-Cache manuell leeren. Dies ist in der Entwicklungsumgebung frustrierend und in der Produktionsumgebung nicht akzeptabel.

Übrigens gibt das express.js-Modul auf Node.js einen angemessenen Standard-HTTP-Header an, sodass Google Chrome den Server nach Updates fragt. Als ich die HTTP-Header überprüfte, die Spring und express.js mit Fiddler erstellen, waren sie unterschiedlich.

Jeder Vorschlag zur Verbesserung meiner Umgebung wäre willkommen.
Da ich ein Frühlingsanfänger bin, fehlt mir möglicherweise etwas.

AKTUALISIEREN

Endlich habe ich einen Arbeitscode. Es ist wie folgt:

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

Beachten Sie die Bean-Namen. Ich habe 'my' hinzugefügt, um Namenskonflikte zu vermeiden.
Der Autowiring-Anwendungskontext selbst scheint umständlich zu sein, war jedoch für die Nachahmung des Codes erforderlich org.springframework.web.servlet.config.annotation.ResourceHandlerRegistration.addResourceLocations().

Jetzt habe ich einen Favicon-Handler ohne Caching-Probleme und kann die Favicon-Datei an einer beliebigen Stelle platzieren.
Vielen Dank.

zeodtr
quelle
1
Ihre Methode sieht in Ordnung aus. Ist es nicht ersetzen die Standard - Spring MVC Ressource Handler aber (so statische Ressourcen nicht aus bedient werden classpath:/staticjede weitere zum Beispiel). (Deshalb ist die Favicon-Unterstützung in Boot in einem eigenen HandlerMapping, denke ich.)
Dave Syer
@ DaveSyer Jetzt wurde mir klar, dass es nicht in Ordnung ist. Ich habe oben das dritte Update geschrieben. Möglicherweise wird eine separate HandlerMappingbenötigt.
Zeodtr
@ DaveSyer Bitte siehe mein viertes Update oben. Gibt es einen anderen Weg? Kann ich zum Beispiel meine eigenen registrieren HandlerMapping?
Zeodtr
Ja, Sie können eine hinzufügen HandlerMapping(kopieren Sie einfach die von Boot und geben Sie ihr eine höhere Priorität). Ich bin mir nicht sicher, warum Sie sich für den Standort des interessieren würden, favicon.ico fileaber wir können ihn konfigurierbar machen, wenn Sie möchten . Alle Browser werden es ebenfalls zwischenspeichern, daher bezweifle ich, dass die Cache-Einstellungen wichtig sind, bin aber froh, dass ich mich als falsch erwiesen habe.
Dave Syer
@ DaveSyer In der aktualisierten Frage erfahren Sie, warum ich die statischen Dateien an einem anderen Ort ablegen möchte. Auch das Cache-Problem.
Zeodtr

Antworten:

53

Sie können einfach Ihre eigene favicon.ico in das Stammverzeichnis des Klassenpfads oder in einen der statischen Ressourcenpositionen (z classpath:/static. B. ) einfügen . Sie können die Favicon-Auflösung auch mit einem einzigen Flag vollständig deaktivieren spring.mvc.favicon.enabled=false.

Um die vollständige Kontrolle zu übernehmen, können Sie ein HandlerMapping hinzufügen (kopieren Sie einfach das von Boot und geben Sie ihm eine höhere Priorität), z

@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;
}
}
Dave Syer
quelle
Vielen Dank. Ich dachte, ich hätte es bereits versucht, aber jetzt denke ich daran, ich habe die @ConfigurationAnmerkung verpasst . Übrigens habe ich den Grund geschrieben, warum ich statische Dateien an einem anderen Ort auf der Frage platzieren möchte.
Zeodtr
Übrigens, da ich ResourceLoader.gerResource ("/") verwenden muss, um eine Datei im Dokumentstamm zu erhalten (richtig?), Muss ich @Autowire ApplicationContext. Ist es in Ordnung, den Anwendungskontext zu ändern? Einige sagen, es ist eine schlechte Sache.
Zeodtr
Ich versuche Ihren Vorschlag. Eines ist zu beachten: Mein Bean-Name darf nicht 'faviconHandlerMapping' sein, da dies zu einem Konflikt zwischen dem Bean-Namen und der faviconHandlerMapping-Bean des Spring Boot führt. Nur eine von zwei Beans wird von einer Methode ausgewählt, die von org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors () aufgerufen wird und erneut von org.springframework.web.servlet.initHandlerMappings () aufgerufen wird. Es scheint, dass meine Bean früher geladen und dann durch den Namenskonflikt überschrieben wird.
Zeodtr
Die Namen der HandlerMapping Bohnen registriert sind wie folgt: { faviconHandlerMapping, requestMappingHandlerMapping, viewControllerHandlerMapping, beanNameHandlerMapping, resourceHandlerMapping, defaultServletHandlerMapping, endpointHandlerMapping} Also ich diese Namen müssen vermeiden.
Zeodtr
2
Sie sollten die aktualisierte Antwort und auch das Benutzerhandbuch lesen. Wenn Sie nur das Symbol ändern möchten, war dies nie eine sehr schwierige Änderung. Ich weiß nicht, warum das OP so viel Ärger gemacht hat.
Dave Syer
75

Nichts davon war für mich notwendig.

Warum sollten Sie die Standardeinstellung überschreiben, wenn Sie eine Ressource mit der generierten JAR bündeln können, die eine höhere Priorität als die Standard-JAR hat?

Um eine benutzerdefinierte favicon.icoDatei zu erstellen, habe ich ein src/main/resourcesVerzeichnis für meine Anwendung erstellt und die favicon.icoDatei dort kopiert . Die Dateien in diesem Ressourcenverzeichnis werden in das Stammverzeichnis der kompilierten JAR verschoben. Daher wird Ihre benutzerdefinierte Datei favicon.icovor der von Spring bereitgestellten Datei gefunden.

Wenn Sie dies tun, erzielen Sie den gleichen Effekt wie bei Ihrer oben aktualisierten Lösung.

Beachten Sie, dass Sie seit Version 1.2.0 die Datei auch einfügen können src/main/resources/static.

Ross
quelle
6
Der Grund ist einfach. Ich möchte die Favicon-Datei nicht in die JAR einfügen.
Zeodtr
@zeodtr nur neugierig warum. Das scheint mir am natürlichsten. Allerdings würde ich es erwartet haben , in zu seinsrc/main/resources/static/images
btiernay
1
@btiernay Das liegt daran, dass der Webserver eine vom Webclient getrennte Entität ist. Und die Favicon (s) gehören dem Kunden. Die War-Datei des Webservers hat keinen Grund, die zum Client gehörenden Dateien aufzunehmen, die je nach Bedarf der Benutzer viel häufiger geändert werden können.
Zeodtr
Nur zu favicon.icostatic
Ihrer Information
1
src / main / resources / static path funktionieren gut. Dies ist der einfachste und regelmäßigste Weg.
pdem
29

Ich mag Springboot wirklich, weil es insgesamt voller intelligenter Lösungen ist, aber ich lehne es ab, eine Application Bean zu registrieren, um ein Favicon bereitzustellen, weil das einfach nur dumm ist.

Ich habe gerade meinen eigenen Favicon-Link in meinen HTML-Seitenkopf eingefügt.

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

Dann habe ich mein Favicon umbenannt und bei platziert

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

Jetzt habe ich ein Symbol in den Browser-Registerkarten von Chrome und Firefox und in der Safari-Adressleiste, ohne Spring und Java verwenden zu müssen, und ich sollte keine Änderungen an Springboot in neueren Versionen verfolgen müssen, um solch triviale Funktionen zu erhalten.

jeremyjjbrown
quelle
4
Sie müssen nicht mehr mit Handler-Zuordnungen herumspielen (fügen Sie einfach eine favicon.ico in Ihre statischen Ressourcen ein).
Dave Syer
Das ist so einfach! Vielen Dank. Ich füge es in mein Fragment ein.
Lay Leangsros
Was ist, wenn Sie Springboot nur als API Service Backend verwenden, haben Sie dort keine HTML-Seiten: /
Paramvir Singh Karwal
@ParamvirSinghKarwal Wenn Sie nur einen Service haben, warum möchten Sie dann ein Favicon?
Jeremyjjbrown
Wenn Sie die API direkt von der Adresse des Browsers aus aufrufen, wird ein Standardfavicon der Frühlingsanwendung angezeigt, das wie ein grünes Blatt aussieht. Ich möchte, dass es ein Markenfavicon ist. Ich konnte es schaffen.
Paramvir Singh Karwal
13

Seit Spring Boot 1.2.2 und 1.1.11 können Sie das Standard-Favicon mithilfe der spring.mvc.favicon.enabled = falseEigenschaft einfach deaktivieren .

Weitere Informationen finden Sie unter:

UPDATE: spring.mvc.favicon.enabledSeit Spring Boot 2.2.x gibt es keine Eigenschaft mehr

Trynkiewicz Mariusz
quelle
spring.mvc.favicon.enabled wird aus dem Federschuh 2.2 entfernt. Wissen Sie, durch was es ersetzt wird?
Shilan
1
@Shilan es wird durch nichts ersetzt, da es überhaupt kein Standard-Favicon mehr gibt. Wenn Sie eine möchten, müssen Sie die Zuordnung für Ihr eigenes Favicon konfigurieren.
Trynkiewicz Mariusz
1
Ja, am Ende habe ich herausgefunden, dass ich dies stattdessen tun muss: @Override public void addResourceHandlers (ResourceHandlerRegistry-Registrierung) {registry.addResourceHandler ("/ favicon.ico"). addResourceLocations ("classpath: / static /"); }
Shilan
2

Mit neueren Versionen von Boot (1.2 sicher, aber vielleicht auch 1.1.8) können Sie einfach eine favicon.ico in Ihre statischen Ressourcen einfügen.

Dave Syer
quelle
2

Ich habe viele Optionen / Varianten ausprobiert, aber nur das hat funktioniert. (Spring Boot 2.2.7)

Favicon.ico Dateien & robots.txt in / 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();
    }
}

und

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

Wenn es hilft, gefällt es bitte;)

Yury Sliznikov
quelle
1

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

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

robots.txt, Speicherort der Datei favicon.ico: / src / main / resources

Ich habe Spring Boot 1.2.1 verwendet

webmadeup
quelle