wake-up-neo.com

Spring Boot bietet keinen statischen Inhalt

Ich pralle jetzt seit ein paar Stunden mit dem Kopf gegen die Wand. Mein Projekt ist fast fertig, aber ich kann keine statischen Inhalte bereitstellen.

Ich habe einen Ordner namens static unter src/main/resources abgelegt. Darin habe ich einen Ordner namens images. Wenn ich die App packe und ausführen, kann sie die Bilder, die ich in diesem Ordner abgelegt habe, nicht finden.

Ich habe versucht, die statischen Dateien in public, resources und META-INF/resources zu legen, aber nichts funktioniert.

Wenn ich -tvf app.jar jar sehe, kann ich sehen, dass sich die Dateien in dem jar im rechten Ordner befinden: /static/images/head.png zum Beispiel, aber beim Aufruf von: http://localhost:8080/images/head.png bekomme ich nur einen 404

Irgendwelche Ideen, warum Spring-Boot das nicht findet? (Ich verwende 1.1.4 BTW)

124

Nicht um die Toten nach mehr als einem Jahr zu erwecken, aber alle vorherigen Antworten lassen einige entscheidende Punkte vermissen:

  1. @EnableWebMvc in Ihrer Klasse deaktiviert org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration. Das ist in Ordnung, wenn Sie vollständige Kontrolle wünschen, aber ansonsten ist es ein Problem.
  2. Sie müssen keinen Code schreiben, um zusätzlich zu den bereits bereitgestellten Ressourcen einen weiteren Speicherort für statische Ressourcen hinzuzufügen. Beim Betrachten von org.springframework.boot.autoconfigure.web.ResourceProperties von v1.3.0.RELEASE sehe ich ein Feld staticLocations, das in application.properties konfiguriert werden kann. Hier ist ein Ausschnitt aus der Quelle:

    /**
     * Locations of static resources. Defaults to classpath:[/META-INF/resources/,
     * /resources/, /static/, /public/] plus context:/ (the root of the servlet context).
     */
    private String[] staticLocations = RESOURCE_LOCATIONS;
    
  3. Wie bereits erwähnt, wird die Anforderungs-URL relativ an diesen Speicherorten aufgelöst. Daher wird src/main/resources/static/index.html geliefert, wenn die Anforderungs-URL /index.html lautet. Die Klasse, die für das Auflösen des Pfads ab Spring 4.1 verantwortlich ist, ist org.springframework.web.servlet.resource.PathResourceResolver.

  4. Der Suffix-Musterabgleich ist standardmäßig aktiviert. Dies bedeutet für eine Anforderungs-URL /index.html. Spring sucht nach Handlern, die /index.html entsprechen. Dies ist ein Problem, wenn statische Inhalte bereitgestellt werden sollen. Um dies zu deaktivieren, erweitern Sie WebMvcConfigurerAdapter (verwenden Sie jedoch nicht @EnableWebMvc) und überschreiben Sie configurePathMatch wie folgt:

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        super.configurePathMatch(configurer);
    
        configurer.setUseSuffixPatternMatch(false);
    }
    

IMHO besteht die einzige Möglichkeit, weniger Fehler in Ihrem Code zu haben, darin, Code nicht wann immer möglich zu schreiben. Verwenden Sie das, was bereits zur Verfügung gestellt wird, auch wenn dies einige Nachforschungen erfordert, die Rendite lohnt sich.

134
Abhijit Sarkar

Im Gegensatz zu dem, was der Spring-Boot besagt, muss mein Spring-Boot-Glas den Inhalt liefern: Ich musste meinen src/main/resources/static-Inhalt durch diese Konfigurationsklasse registrieren:

@Configuration
public class StaticResourceConfiguration extends WebMvcConfigurerAdapter {

    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
            "classpath:/META-INF/resources/", "classpath:/resources/",
            "classpath:/static/", "classpath:/public/" };

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
            .addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS);
    }
}
62
Francois

Ich hatte ein ähnliches Problem, und es stellte sich heraus, dass die einfache Lösung darin bestand, dass meine Konfigurationsklasse WebMvcAutoConfiguration erweitert wurde:

@Configuration
@EnableWebMvc
@ComponentScan
public class ServerConfiguration extends WebMvcAutoConfiguration{
}

Ich brauchte keinen anderen Code, um die Bereitstellung meines statischen Inhalts zu ermöglichen. Allerdings habe ich ein Verzeichnis namens public unter src/main/webapp eingegeben und maven so konfiguriert, dass es auf src/main/webapp als Ressourcenverzeichnis verweist. Dies bedeutet, dass public in target/classes kopiert wird und daher zur Laufzeit für Spring-Boot/Tomcat im Klassenpfad zu finden ist.

47

Suchen Sie nach Controllern, die auf "/" oder ohne Pfad zugeordnet sind.

Ich hatte ein Problem wie dieses, bekam 405 Fehler und schlug mir tagelang den Kopf. Das Problem erwies sich als @RestController-kommentierter Controller, den ich mit einer @RequestMapping-Anmerkung vergessen hatte. Ich vermute, dass dieser zugeordnete Pfad standardmäßig "/" war und die Zuordnung von statischen Inhalten blockierte.

21
Johannes

Die Konfiguration kann wie folgt vorgenommen werden:

@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcAutoConfigurationAdapter {

// specific project configuration

}

Wichtig hierbei ist, dass Ihre WebMvcConfigmayaddResourceHandlers-Methode überschreibt und Sie daher super.addResourceHandlers(registry) explizit aufrufen müssen (wenn Sie mit den Standardressourcen-Speicherorten zufrieden sind, müssen Sie keine Methode überschreiben). 

Eine weitere Sache, die hier kommentiert werden muss, ist, dass diese Standardressourcenpositionen (/static, /public, /resources und /META-INF/resources) nur registriert werden, wenn noch kein Ressourcen-Handler vorhanden ist, der /** zugeordnet ist.

Wenn Sie beispielsweise ein Image auf src/main/resources/static/images mit dem Namen image.jpg haben, können Sie über die folgende URL darauf zugreifen: http://localhost:8080/images/image.jpg (dabei handelt es sich um den Server, der an Port 8080 gestartet wurde und die Anwendung im Root-Kontext bereitgestellt wurde).

18

Haben Sie die Spring Boot-Referenzdokumente überprüft? 

Standardmäßig stellt Spring Boot statischen Inhalt aus einem Ordner namens /static (oder /public oder /resources oder /META-INF/resources) im Klassenpfad oder vom Stamm des ServletContext bereit. 

Sie können Ihr Projekt auch mit der Anleitung Serving Web Content mit Spring MVC vergleichen oder den Quellcode des Projekts spring-boot-sample-web-ui auschecken.

11
matsev

Ich hatte genau dieses Problem und merkte dann, dass ich in meinen application.properties definiert hatte: 

spring.resources.static-locations=file:/var/www/static

Das war alles andere, was ich versucht hatte. In meinem Fall wollte ich beides behalten, also behielt ich die Immobilie und fügte hinzu:

spring.resources.static-locations=file:/var/www/static,classpath:static

Welche Dateien von src/main/resources/static als localhost bereitgestellt haben: {port} /file.html.

Keines der oben genannten Dinge funktionierte für mich, weil niemand diese kleine Eigenschaft erwähnte, die leicht aus dem Internet kopiert werden könnte, um einen anderen Zweck zu erfüllen.

Ich hoffe es hilft! Ich dachte, es würde gut in diesen langen Beitrag mit Antworten für Menschen mit diesem Problem passen.

5
S. Jacob Powell

Ich denke, die vorherigen Antworten sprechen das Thema sehr gut an. In einem Fall, in dem Spring Security in Ihrer Anwendung aktiviert ist, müssen Sie Spring jedoch ausdrücklich anweisen, Anforderungen an andere statische Ressourcenverzeichnisse wie beispielsweise "/ static/fonts" zuzulassen.

In meinem Fall hatte ich standardmäßig "/ static/css", "/ static/js", "/ static/images", aber/static/fonts/** wurde von meiner Spring Security-Implementierung blockiert.

Unten ist ein Beispiel, wie ich das behoben habe.

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
.....
    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/", "/fonts/**").permitAll().
        //other security configuration rules
    }
.....
}
5
RemusS

Diese Lösung funktioniert für mich:

Legen Sie zunächst einen Ressourcenordner unter webapp/WEB-INF wie folgt ab

-- src
  -- main
    -- webapp
      -- WEB-INF
        -- resources
          -- css
          -- image
          -- js
          -- ...

Zweitens im Frühjahr Config-Datei

@Configuration
@EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter{

    @Bean
    public ViewResolver getViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".html");
        return resolver;
    }

    @Override
    public void configureDefaultServletHandling(
            DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resource/**").addResourceLocations("WEB-INF/resources/");
    }
}

Dann können Sie auf den Inhalt Ihrer Ressource zugreifen, z. B. http: // localhost: 8080/resource/image/yourimage.jpg

3
ldeng

Um einer alten Frage noch eine weitere Antwort hinzuzufügen ... Die Leute haben erwähnt, dass @EnableWebMvc das Laden von WebMvcAutoConfiguration verhindert. Dies ist der Code, der für das Erstellen der statischen Ressourcenhandler verantwortlich ist. Es gibt andere Bedingungen, die das Laden von WebMvcAutoConfiguration ebenfalls verhindern. Am deutlichsten erkennen Sie dies an der Quelle:

https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-autoconfigure/src/main/Java/org/springframework/boot/autoconfigure/web/ Servlet/WebMvcAutoConfiguration.Java # L139-L141

In meinem Fall hatte ich eine Bibliothek mit einer Klasse, die sich von WebMvcConfigurationSupport aus erstreckte. Dies ist eine Bedingung, die die automatische Konfiguration verhindert: 

@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)

Es ist wichtig, dass never sich von WebMvcConfigurationSupport erstreckt. Erweitern Sie stattdessen von WebMvcConfigurerAdapter.

2
Bal

Es gibt zwei Dinge, die zu beachten sind (Spring Boot v1.5.2.RELEASE) - 1) Alle Controller-Klassen auf @EnableWebMvc-Annotation prüfen, entfernen, falls vorhanden 2) Überprüfen Sie die Controller-Klassen, für die Annotation verwendet wird - @RestController oder @Controller. Mischen Sie das Rest-API- und MVC-Verhalten nicht in einer Klasse. Verwenden Sie für MVC @Controller und für die REST - API @RestController

Wenn ich über 2 Dinge tat, wurde mein Problem gelöst. Jetzt lädt mein Spring Boot statische Ressourcen ohne Probleme. _. @ Controller => load index.html => lädt statische Dateien.

@Controller
public class WelcomeController {

    // inject via application.properties
    @Value("${welcome.message:Hello}")
    private String message = "Hello World";

    @RequestMapping("/")
    public String home(Map<String, Object> model) {
        model.put("message", this.message);
        return "index";
    }

}

index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>index</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />


    <link rel="stylesheet/less" th:href="@{/webapp/assets/theme.siberia.less}"/>

    <!-- The app's logic -->
    <script type="text/javascript" data-main="/webapp/app" th:src="@{/webapp/libs/require.js}"></script>
    <script type="text/javascript">
        require.config({
            paths: { text:"/webapp/libs/text" }
        });
    </script>



   <!-- Development only -->
     <script type="text/javascript" th:src="@{/webapp/libs/less.min.js}"></script>


</head>
<body>

</body>
</html>
2
gjp

Ich hatte das gleiche Problem mit Spring Boot 2.1.3, das besagte, dass die Ressource 404 nicht gefunden wurde. Ich habe es unten aus applicatiion.properties entfernt.

#spring.resources.add-mappings=true
#spring.resources.static-locations=classpath:static
#spring.mvc.static-path-pattern=/**,

Entfernte @enableWebMVC und entfernte alle überschreibenden WebMvcConfigurer

// @ EnableWebMvc

Stellen Sie außerdem sicher, dass Sie @EnableAutoConfiguration in Ihrer Konfiguration haben.

Und stelle alle statischen Ressourcen in src/main/resources/static und es funktionierte endlich wie Magie.

1
Debadatta

Wenn das Problem beim Starten der Anwendung innerhalb einer IDE (dh ab Eclipse oder IntelliJ Idea) und bei Verwendung von Maven auftaucht, befindet sich der Schlüssel zur Lösung im Spring-Boot-Erste Schritte Dokumentation:

Wenn Sie Maven verwenden, führen Sie Folgendes aus:

mvn package && Java -jar target/gs-spring-boot-0.1.0.jar

Der wichtige Teil davon ist das Hinzufügen des package - Ziels, das ausgeführt werden soll, bevor die Anwendung tatsächlich gestartet wird. (Idee: Run-Menü, Edit Configrations..., Add, und dort Run Maven Goal auswählen und das package-Ziel im Feld angeben.)

1
ppeterka

Ich verwende 1.3.5 und hoste eine Reihe von REST-Diensten über die Jersey-Implementierung. Das hat gut funktioniert, bis ich beschlossen habe, ein paar HTMLs + js-Dateien hinzuzufügen. __ Keine der Antworten in diesem Forum hat mir geholfen. Wenn ich jedoch folgende Abhängigkeit in meiner pom.xml hinzufügte, wurde der gesamte Inhalt in src/main/resources/static schließlich über den Browser angezeigt:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<dependency>

Es scheint, dass Spring-Web/Spring-Webmvc die wichtige transitive Abhängigkeit ist, die die automatische Konfiguration von Spring Boot aktiviert.

0
LilleElefant

Ich bin in derselben Situation, in der meine Spring-Boot-Winkel-App (Integration) keinen statischen Ordnerinhalt bereitstellt, um die Benutzeroberfläche auf localhost anzuzeigen: 8080. Frontend wurde in angle4 entwickelt, also ng build, der Dateien im Ausgabepfad dir src/main/resources/static generiert, jedoch keinen Inhalt anzeigt. Ich habe einen Controller speziell für die Bereitstellung von index.html erstellt, scheint jedoch etwas für Spring-Boot auszuschließen, um das Winkelrouting-Material und den localhost zu verstehen: 8080 zeigt nur die zurückgegebene Zeichenfolge aus meiner Controller-Methode "index.html" auf der Webseite an. Unten ist index.html (Ich habe das Standardselector-Tag im Body so geändert, dass die Anmeldekomponente die von mir erstellte und meine Hauptwinkelkomponente für die Benutzeroberfläche ist, aber immer noch nicht funktioniert, ob App-Root oder diese).

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Hello Test App</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-login></app-login>
<script type="text/javascript" src="runtime.js"></script><script type="text/javascript" src="polyfills.js"></script><script type="text/javascript" src="styles.js"></script><script type="text/javascript" src="vendor.js"></script><script type="text/javascript" src="main.js"></script></body>
</html>

Controller-Code:

@RequestMapping("/")
public String userInterface() {
    return "index.html";
}

Nicht sicher, ob es wichtig ist, aber dies ist ein gradle-basiertes Projekt, das in IntellijIdea entwickelt wurde. Die Spring-Boot-Version ist -org.springframework.boot:spring-boot-starter-web:2.0.2.RELEASE.

@Vizcaino - Wie Sie schon sagten, gibt es einen einfachen Trick. Bietet Intellijidea eine ähnliche Option zum Erstellen von Quellverzeichnis/-ordner? Ich habe aus Rechtsklick-Menü -> Neu -> Verzeichnis erstellt. Aber nicht sicher, ob es dasselbe ist, und sich fragen, ob dies die Ursache meines Problems sein könnte?

0
user6087439

Manchmal lohnt es sich zu prüfen, ob Sie die globalen Zuordnungen von einem Rest-Controller überschrieben haben. Einfacher Beispielfehler (Kotlin):

@RestController("/foo")
class TrainingController {

    @PostMapping
    fun bazz(@RequestBody newBody: CommandDto): CommandDto = return commandDto

}

Im obigen Fall erhalten Sie, wenn Sie statische Ressourcen anfordern:

{
    title: "Method Not Allowed",
    status: 405,
    detail: "Request method 'GET' not supported",
    path: "/index.html"
}

Der Grund dafür könnte sein, dass Sie @PostMapping zu /foo zuordnen wollten, aber die @RequestMapping-Annotation auf der @RestController-Ebene vergessen. In diesem Fall werden alle Anforderungen auf POST abgebildet, und Sie erhalten in diesem Fall keinen statischen Inhalt.

0
Przemek Nowak

FYI: Ich habe auch gemerkt, dass ich eine perfekt funktionierende Spring-Boot-App durcheinander bringen und verhindern kann, dass Inhalte aus dem statischen Ordner bereitgestellt werden, wenn ich einen schlechten Rest-Controller so hinzufüge 

 @RestController
public class BadController {
    @RequestMapping(method= RequestMethod.POST)
    public String someMethod(@RequestParam(value="date", required=false)String dateString, Model model){
        return "foo";
    }
}

In diesem Beispiel lautet die Fehlerantwort "405 Method Not Allowed", wenn der Browser nach dem Hinzufügen des fehlerhaften Controllers zum Projekt nach einer Datei im statischen Ordner fragt. 

Hinweispfade werden im fehlerhaften Controller-Beispiel nicht zugeordnet. 

0
Ganesh

Hatte das gleiche Problem, Gradle und Eclipse und verbrachte Stunden damit, es herauszufinden.

Keine Codierung erforderlich, der Trick besteht darin, dass Sie die Menüoption Neu-> Quellordner (NICHT Neu -> Ordner) verwenden müssen, um den statischen Ordner unter src/main/resources zu erstellen. Ich weiß nicht, warum das funktioniert, aber habe einen neuen -> Quellordner erstellt, dann habe ich den Ordner statisch benannt (der Dialog "Quellordner" gibt einen Fehler aus, für den Sie Folgendes überprüfen müssen: Aktualisieren Sie Ausschlussfilter in anderen Quellordnern, um die Verschachtelung zu lösen). In meinem neuen statischen Ordner habe ich index.html hinzugefügt und jetzt funktioniert es.

0
Vizcaino