216

I can't get my Spring-boot project to serve static content.

I've placed a folder named static under src/main/resources. Inside it I have a folder named images. When I package the app and run it, it can't find the images I have put on that folder.

I've tried to put the static files in public, resources and META-INF/resources but nothing works.

If I jar -tvf app.jar I can see that the files are inside the jar on the right folder: /static/images/head.png for example, but calling: http://localhost:8080/images/head.png, all I get is a 404

Any ideas why spring-boot is not finding this? (I'm using 1.1.4 BTW)

Raedwald
  • 46,613
  • 43
  • 151
  • 237
Vinicius Carvalho
  • 3,994
  • 4
  • 23
  • 29
  • 1
    Have enabled spring boot auto-configuration? – geoand Jul 09 '14 at 18:52
  • 9
    The default resource handling maps to /**. I'd double-check that it's enabled. If it is, you'll see a line that ends with "Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]" in the output when you start your app. Another possibility is a controller of your own that's also mapped to /** and is taking precedence over the resource handler. Posting the output of your app's startup would make it easier for us to see what's going on. – Andy Wilkinson Jul 09 '14 at 20:24
  • 18
    I'm guessing you have `@EnableWebMvc` (or equivalent) in your app. That would switch off the default Boot MVC config. – Dave Syer Jul 11 '14 at 19:10
  • 4
    Nope, I don't have @EnableWebMvc anywhere. I don't get this. Now its happening with templates as well. Any of my templates (freemarker) are being found by the classloader of spring boot. – Vinicius Carvalho Jul 15 '14 at 20:58
  • 2
    @DaveSyer great tip man! It saved me a headache! Turned out that exactly this annotation (leftover from migration to Boot) screwed up things for me. Thanks! – ŁukaszBachman Feb 12 '15 at 22:54
  • 3
    I am running into a similar issue and have had no luck with any of the recommended resolutions provided. If someone could be so kind to take a look and point out exactly what it is I am doing wrong it would be much appreciated!!! https://github.com/kylebober/kbss – Kyle S. Bober Mar 24 '15 at 18:20
  • 4
    I found that if I have a file src/main/resources/public/style.css, then the url for that is /style.css and not /public/style.css as I expected. – Dave Apr 03 '15 at 04:28
  • 2
    webapp ended up being the folder that worked for me to serve static content with no hassle. – Mike Emery Jul 31 '15 at 19:51
  • 1
    Can you check your application.properties file value of this server.servlet-path=, and change your url to http://localhost:8080//images/head.png – sreemanth pulagam Nov 10 '15 at 22:28
  • Refer to https://github.com/spring-guides/tut-spring-security-and-angular-js/tree/master/modular – EpicPandaForce Oct 13 '16 at 14:18
  • @AndyWilkinson 2nd comment - I had a controller with mapping to "/". Which was the problem. – crmepham Aug 30 '18 at 17:30
  • OP, my answer is clearly the most popular :) It'd be nice if you accepted it, that way you show some appreciation for the effort, and the question would be rated higher in SO search results (I think), thus allowing people to find it more easily. – Abhijit Sarkar Oct 08 '18 at 21:31
  • please find an answer @ [enter link description here](https://stackoverflow.com/questions/38788459/spring-boot-static-content-with-context-path/54112835#54112835) – Bhukailas Jan 09 '19 at 14:57
  • If this happens in the final runtime, double-check that you have the parent of the `static`, `public` or whatever resource dir on the classpath! – Janaka Bandara Jan 16 '20 at 13:53

26 Answers26

209

Not to raise the dead after more than a year, but all the previous answers miss some crucial points:

  1. @EnableWebMvc on your class will disable org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration. That's fine if you want complete control but otherwise, it's a problem.

  2. There's no need to write any code to add another location for static resources in addition to what is already provided. Looking at org.springframework.boot.autoconfigure.web.ResourceProperties from v1.3.0.RELEASE, I see a field staticLocations that can be configured in the application.properties. Here's a snippet from the source:

    /**
     * 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. As mentioned before, the request URL will be resolved relative to these locations. Thus src/main/resources/static/index.html will be served when the request URL is /index.html. The class that is responsible for resolving the path, as of Spring 4.1, is org.springframework.web.servlet.resource.PathResourceResolver.

  4. Suffix pattern matching is enabled by default which means for a request URL /index.html, Spring is going to look for handlers corresponding to /index.html. This is an issue if the intention is to serve static content. To disable that, extend WebMvcConfigurerAdapter (but don't use @EnableWebMvc) and override configurePathMatch as shown below:

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

IMHO, the only way to have fewer bugs in your code is not to write code whenever possible. Use what is already provided, even if that takes some research, the return is worth it.

Edit July 2021:

  1. WebMvcConfigurerAdapter has been deprecated since Spring 5. Implement WebMvcConfigurer and annotate with @Configuration.
Abhijit Sarkar
  • 21,927
  • 20
  • 110
  • 219
  • And don't extend `DelegatingWebMvcConfiguration` which has the same effect as using `@EnableWebMvc` – Aner Mar 03 '16 at 21:54
  • 4
    this answer is indeed after much research. A great one to read to – Ekansh Rastogi Jun 18 '16 at 09:36
  • 4
    If I was pivotal I would take this answer and put it in the Spring Boot documentation – aliopi Aug 23 '17 at 14:23
  • @aliopi K I can take this answer and put it in Boot docs; so can you – Abhijit Sarkar Aug 23 '17 at 16:04
  • 2
    @Abhijit Sarkar I meant the company _Pivotal_, sorry for any bad feelings, but it wasn't intended. Pivotal is the owner of Spring if I'm correct. I could document it, but they have people who get paid for this, so they should do it :P – aliopi Aug 23 '17 at 16:12
  • 1
    @aliopi Spring is an open source project. – Abhijit Sarkar Aug 23 '17 at 16:58
  • How to counter "Spring Boot adds [@EnableWebMvc] automatically when it sees spring-webmvc on the classpath"? No way to not use @EnableWebMvc in that case. – Kees de Kooter Oct 05 '17 at 09:33
  • 3
    _the only way to have fewer bugs in your code is not to write code[...]_ really like this. – Clijsters Nov 17 '17 at 10:10
  • 1
    Hmm.. I've tried to apply this but [it's still not working](https://stackoverflow.com/questions/48934844/index-html-is-not-showing-up-after-refactoring-the-project). – Stefan Falk Feb 22 '18 at 18:47
  • you've nailed it! tks. – Reginaldo Santos Oct 08 '18 at 15:53
  • 1
    `WebMvcConfigurerAdapter` is deprecated. – Faizan Mubasher Dec 28 '18 at 06:48
  • @FaizanMubasher Good to know. – Abhijit Sarkar Dec 28 '18 at 08:51
  • 1
    I agree that not having @EnableWebMvc is probably best in this case but Spring Auto-configuration is really fragile imo. Bumping/removing/adding a library can easily change crucial behavior of your application and unless you keep track of the effective auto-configuration you might not even notice until it has gone into production. – Mikael Vandmo Dec 07 '20 at 17:06
  • 1
    Here were are in 2021, still \@EnableWebMvc will still totally destroy the fragile Spring auto-configuration. I needed one simple resourceHandler for a location on the filesystem. So, I implemented a WebMvcConfigurer and used a @Configuration annotation as seen in the answer below https://stackoverflow.com/a/25878939/1181043 – robododge Feb 04 '21 at 00:54
102

Unlike what the spring-boot states, to get my spring-boot jar to serve the content: I had to add specifically register my src/main/resources/static content through this config class:

@Configuration
public class StaticResourceConfiguration implements WebMvcConfigurer {

    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);
    }
}
Emad Razavi
  • 1,903
  • 2
  • 17
  • 24
Francois
  • 1,851
  • 1
  • 13
  • 15
  • 4
    I have the same issue, same version of Spring Boot but this didn't work for me either – greyfox Jul 28 '15 at 18:09
  • Fixed my problem in version 1.2.5!! thank you so much.. vote this up!! – mrclrchtr Oct 13 '15 at 22:48
  • This hack works... weird that the auto configuration fails – Allan Vital Dec 02 '17 at 21:50
  • Regrettably, this hack doesn't work for me which is a shame due the elegance. I am not sure if the root cause is the paths to the resource. Perhaps, since I am running it in windows, they need to be formatted differently? – acarlstein Apr 18 '19 at 18:47
  • Notice that WebMvcConfigurer is deprecated now – FishingIsLife Dec 07 '20 at 16:00
  • org.springframework.web.servlet.config.annotation.WebMvcConfigurer is not deprecated (Spring-webmvc-5.3.3.jar) . This solution still works, except I used it to add an additional handler/path combo "/reports/**", "file:/mnt/somedir/reports/" Have to keep the slashes on the ends for Linux – robododge Feb 04 '21 at 00:52
52

I had a similar problem, and it turned out that the simple solution was to have my configuration class extend WebMvcAutoConfiguration:

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

I didn't need any other code to allow my static content to be served, however, I did put a directory called public under src/main/webapp and configured maven to point to src/main/webapp as a resource directory. This means that public is copied into target/classes, and is therefore on the classpath at runtime for spring-boot/tomcat to find.

Software Engineer
  • 15,457
  • 7
  • 74
  • 102
  • With this way static resources not working in another profiles. for example I have a profile for release that use another IP address. I get 404 error for all of my resources. – Mahdi Jul 16 '17 at 11:41
29

Look for Controllers mapped to "/" or with no path mapped.

I had a problem like this, getting 405 errors, and banged my head hard for days. The problem turned out to be a @RestController annotated controller that I had forgot to annotate with a @RequestMapping annotation. I guess this mapped path defaulted to "/" and blocked the static content resource mapping.

ppeterka
  • 20,583
  • 6
  • 63
  • 78
Johannes
  • 390
  • 3
  • 7
  • 2
    Solved it for me! I had a controller annotated with @RestController("/blubb") which is obviously wrong, but somestimes you don't see the wood for the trees. Changing it to @RestController @RequestMapping("/blubb") solved it – krinklesaurus Jul 30 '15 at 14:19
  • I'm glad it helped, and amused by the notion that the expression "Can't see the woods for all the trees" exists in german as well as swedish :) – Johannes Aug 06 '15 at 12:24
  • 2
    You can also explicitly add @RequestMapping("/") if the intent is to both serve static content and to have a dynamic handler for root requests. – mjj1409 Feb 17 '16 at 11:12
  • I have a controller method mapped to "/". But what solved my problem is to add auto config in main class. EnableAutoConfiguration SpringBootApplication – Shafiul Oct 23 '16 at 15:10
  • 1
    Wow....Spent 2 wasted days on this one. My spring boot mvc application uses spring security and was not seeing the styles.css file. I believe the security was not allowing the .jsp's to access the styles.css file. I had a @RequestMapping({"","/", "/home"}) in my controller. Took out the "" and "/" and my MVC started working perfectly...Very Strange. – skmansfield Dec 26 '16 at 21:17
  • 4
    @Shafiul No Adding both EnableAutoConfiguration and SpringBootApplication is redundant! "@SpringBootApplication" contains the "@EnableAutoConfiguration" – Dehan Jul 27 '17 at 08:17
22

The configuration could be made as follows:

@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcAutoConfigurationAdapter {

// specific project configuration

}

Important here is that your WebMvcConfig may override addResourceHandlers method and therefore you need to explicitly invoke super.addResourceHandlers(registry) (it is true that if you are satisfied with the default resource locations you don't need to override any method).

Another thing that needs to be commented here is that those default resource locations (/static, /public, /resources and /META-INF/resources) will be registered only if there isn't already a resource handler mapped to /**.

From this moment on, if you have an image on src/main/resources/static/images named image.jpg for instance, you can access it using the following URL: http://localhost:8080/images/image.jpg (being the server started on port 8080 and application deployed to root context).

Francisco Spaeth
  • 23,493
  • 7
  • 67
  • 106
  • 1
    It is perhaps important to comment that although you /can/ override addResourceHandlers, you don't actually need to in order to solve the OP's problem. – Software Engineer Sep 28 '14 at 18:41
  • @EngineerDollery thanks for the comment, that was my intention but I explicitly added the explanation – Francisco Spaeth Sep 28 '14 at 19:31
  • I moved my css/js into the src/main/resources/static folder and the errors are no longer there, but I'm still not able to to get the css to display in my page. – Hatem Jaber Apr 01 '15 at 15:48
  • 1
    Dude, I traveled the depths of the internet to find this working solution. It seems the key was the combination of `@EnableWebMvc` and `WebMvcAutoConfigurationAdapter`. Thanks big time! – Ian Newland Aug 22 '16 at 20:57
  • It didn't work out of the box for me either. I had to add this as well. I just add my commentary here because I had two problems. I also had a controller that mapped "/" as @Johannes mentions. Doing this and removing my "/" controller solved my problems. – loyalBrown Apr 12 '17 at 11:36
13

I was having this exact problem, then realized that I had defined in my application.properties:

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

Which was overriding everything else I had tried. In my case, I wanted to keep both, so I just kept the property and added:

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

Which served files from src/main/resources/static as localhost:{port}/file.html.

None of the above worked for me because nobody mentioned this little property that could have easily been copied from online to serve a different purpose ;)

Hope it helps! Figured it would fit well in this long post of answers for people with this problem.

S. Jacob Powell
  • 396
  • 2
  • 9
  • 1
    I am using Spring Boot 2.0.5.RELEASE and putting `spring.resources.static-locations=file:/var/www/static,classpath:static` into my application.properties, but it did not work for me. I am using `@EnableWebMvc` on my configuration class. – N. Ngo Sep 27 '18 at 19:55
  • 1
    This was the one that solved my issue. along with `security.ignored` and `security.publicPaths` – JoSSte Dec 10 '19 at 10:15
11

Did you check the Spring Boot reference docs?

By default Spring Boot will serve static content from a folder called /static (or /public or /resources or /META-INF/resources) in the classpath or from the root of the ServletContext.

You can also compare your project with the guide Serving Web Content with Spring MVC, or check out the source code of the spring-boot-sample-web-ui project.

matsev
  • 32,104
  • 16
  • 121
  • 156
  • 3
    Yes I did, those are the places I tried, just as instructed by the docs. But nothing works. I don't get why the resource is not found at all. I've tried to look into the samples, oddly there's no sample that uses the structure proposed by the docs. The one you've just pasted uses a templates folder, I'm assuming that is for a thymeleaf config or velocity. – Vinicius Carvalho Jul 09 '14 at 19:24
  • The Web UI sample (https://github.com/spring-projects/spring-boot/tree/v1.1.3.RELEASE/spring-boot-samples/spring-boot-sample-web-ui) serves static content. – Andy Wilkinson Jul 09 '14 at 20:19
  • 2
    I agree with @ViniciusCarvalho, I have tried every combination possible to get the css/js in the right place and can't seem to do that. Even if I visit localhost:8089/css/styles.css i don't see anything. I only have a single rule to change the body color. – Hatem Jaber Apr 01 '15 at 15:53
7

I think the previous answers address the topic very well. However, I'd add that in one case when you have Spring Security enabled in your application, you might have to specifically tell Spring to permit requests to other static resource directories like for example "/static/fonts".

In my case I had "/static/css", "/static/js", "/static/images" permited by default , but /static/fonts/** was blocked by my Spring Security implementation.

Below is an example of how I fixed this.

@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
    }
.....
}
RemusS
  • 1,395
  • 1
  • 11
  • 9
6

This solution works for me:

First, put a resources folder under webapp/WEB-INF, as follow structure

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

Second, in spring config file

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

Then, you can access your resource content, such as http://localhost:8080/resource/image/yourimage.jpg

ldeng
  • 93
  • 1
  • 4
6

Just to add yet another answer to an old question... People have mentioned the @EnableWebMvc will prevent WebMvcAutoConfiguration from loading, which is the code responsible for creating the static resource handlers. There are other conditions that will prevent WebMvcAutoConfiguration from loading as well. Clearest way to see this is to look at the source:

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 my case, I was including a library that had a class that was extending from WebMvcConfigurationSupport which is a condition that will prevent the autoconfiguration:

@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)

It's important to never extend from WebMvcConfigurationSupport. Instead, extend from WebMvcConfigurerAdapter.

UPDATE: The proper way to do this in 5.x is to implement WebMvcConfigurer

Bal
  • 2,027
  • 4
  • 25
  • 51
  • WebMvcConfigurerAdapter is deprecated as of Spring Boot 5.0. Googling it turns up this in the Javadocs for that class: "as of 5.0 WebMvcConfigurer has default methods (made possible by a Java 8 baseline) and can be implemented directly without the need for this adapter." So I *think* one implements WebMvcConfigurer now. – Marvo May 10 '19 at 22:48
  • @Marvo that is exactly right. The proper way to do this in 5.x is to implement `WebMvcConfigurer`. – Bal May 14 '19 at 11:47
4

Put static resources under the directory:

/src/main/resources/static

add this property in application.properties file

server.servlet.context-path=/pdx

You can access from http://localhost:8080/pdx/images/image.jpg

enter image description here

dasunse
  • 2,839
  • 1
  • 14
  • 32
  • 1
    I don't know how to say **Thanks** to you. Brother you are great. I tried almost all the solutions above but this is the best one and the shortest. – U-Dev Dec 22 '19 at 05:14
  • With files store in static folder: **/src/main/resources/static** You can define simple like this: `server.servlet.context-path=/`. And use like below: `` – Leo N Jun 05 '22 at 12:52
3

There are 2 things to consider (Spring Boot v1.5.2.RELEASE)- 1) Check all Controller classes for @EnableWebMvc annotation, remove it if there is any 2) Check the Controller classes for which annotation is used - @RestController or @Controller. Do not mix Rest API and MVC behaviour in one class. For MVC use @Controller and for REST API use @RestController

Doing above 2 things resolved my issue. Now my spring boot is loading static resources with out any issues. @Controller => load index.html => loads static files.

@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>
gjp
  • 111
  • 4
3

I'm using Spring Boot 2.2 and not getting any of my static content. I discovered two solutions that worked for me:

Option #1 - Stop using @EnableWebMvc annotation This annotation disables some automatic configuration, including the part that automatically serves static content from commonly-used locations like /src/main/resources/static. If you don't really need @EnableWebMvc, then just remove it from your @Configuration class.

Option #2 - Implement WebMvcConfigurer in your @EnableWebMvc annotated class and implementaddResourceHandlers() Do something like this:

@EnableWebMvc
@Configuration
public class SpringMVCConfiguration implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/");
        registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css/");
        registry.addResourceHandler("/vendor/**").addResourceLocations("classpath:/static/vendor/");
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
    }

}

Just remember that your code is now in charge of managing all static resource paths.

Jim Tough
  • 14,843
  • 23
  • 75
  • 96
2

In case the issue surfaces when launching the application from within an IDE (i.e. starting from Eclipse or IntelliJ Idea), and using Maven, the key to the solution is in the Spring-boot Getting Started documentation:

If you are using Maven, execute:

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

The important part of which is adding the package goal to be run before the application is actually started. (Idea: Run menu, Edit Configrations..., Add, and there select Run Maven Goal, and specify the package goal in the field)

Community
  • 1
  • 1
ppeterka
  • 20,583
  • 6
  • 63
  • 78
2

I was facing the same issue in spring boot 2.1.3 saying that resource not found 404. I removed below from applicatiion.properties.

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

Removed @enableWebMVC and removed any WebMvcConfigurer overriding

//@EnableWebMvc

Also make sure you have @EnableAutoConfiguration in your config.

And put all static resources into src/main/resources/static and it just worked like magic finally..

Debadatta
  • 689
  • 1
  • 8
  • 23
  • my spring version in 2.2.6 and I have @EnableAutoConfiguration and files under src/main/resources/static but it doesn't work and throws 500. – shivani thakur May 07 '20 at 17:28
2

Requests to /** are evaluated to static locations configured in resourceProperties.

adding the following on application.properties, might be the only thing you need to do...

spring.resources.static-locations=classpath:/myresources/

this will overwrite default static locations, wich is:

ResourceProperties.CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
        "classpath:/resources/", "classpath:/static/", "classpath:/public/" };

You might not want to do that and just make sure your resources end up in one of those default folders.

Performing a request: If I would have example.html stored on /public/example.html Then I can acces it like this:

<host>/<context-path?if you have one>/example.html

If I would want another uri like <host>/<context-path>/magico/* for files in classpath:/magicofiles/* you need a bit more config

@Configuration
class MyConfigClass implements WebMvcConfigurer

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/magico/**").addResourceLocations("/magicofiles/");
}
Sven Dhaens
  • 1,916
  • 1
  • 15
  • 10
1

I am using 1.3.5 and host a bunch of REST-services via Jersey implementation. That worked fine until I decided to add a couple of HTMLs + js files. None of answers given on this forum helped me. However, when I added following dependency in my pom.xml all the content in src/main/resources/static was finally showing via browser:

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

It seems spring-web / spring-webmvc is the important transitive dependency that makes spring boot auto config turn on.

Jeff
  • 43
  • 5
LilleElefant
  • 422
  • 1
  • 5
  • 14
1

FYI: I also noticed I can mess up a perfectly working spring boot app and prevent it from serving contents from the static folder, if I add a bad rest controller like so

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

In this example, after adding the bad controller to the project, when the browser asks for a file available in static folder, the error response is '405 Method Not Allowed'.

Notice paths are not mapped in the bad controller example.

Ganesh
  • 44
  • 1
  • 6
1

using spring boot 2.*, i have a controller that maps to routes GetMapping({"/{var}", "/{var1}/{var2}", "/{var1}/{var2}/{var3}"}) and boom my app stop serving resources.

i know it is not advisable to have such routes but it all depends on the app you are building (in my case, i have no choice but to have such routes)

so here is my hack to make sure my app serve resources again. I simply have a controller that maps to my resources. since spring will match a direct route first before any that has variable, i decided to add a controller method that maps to /imgaes/{name} and repeated same for other resources

@GetMapping(value = "/images/{image}", produces = {MediaType.IMAGE_GIF_VALUE, MediaType.IMAGE_JPEG_VALUE, MediaType.IMAGE_PNG_VALUE})
    public @ResponseBody
    byte[] getImage(@PathVariable String image) {
        ClassPathResource file = new ClassPathResource("static/images/" + image);
        byte[] bytes;
        try {
            bytes = StreamUtils.copyToByteArray(file.getInputStream());
        } catch (IOException e) {
            throw new ResourceNotFoundException("file not found: " + image);
        }
        return bytes;
    }

and this solved my issue

Raines
  • 93
  • 2
  • 11
1

In my case I have a spring boot application which is kind of mixing spring and jaxrs. So I have a java class which inherits from the class org.glassfish.jersey.server.ResourceConfig. I had to add this line to the constructor of that class so that the spring endpoints are still called: property(ServletProperties.FILTER_FORWARD_ON_404, true).

Matthew Darton
  • 551
  • 1
  • 7
  • 27
0

Had the same problem, using gradle and eclipse and spent hours trying to figure it out.

No coding required, the trick is that you must use the menu option New->Source Folder (NOT New -> Folder) to create the static folder under src/main/resources. Don't know why this works, but did new -> source folder then i named the folder static (then source folder dialog gives an error for which you must check: Update exclusion filters in other source folders to solve nesting). The my new static folder I added index.html and now it works.

0

Well sometimes is worth to check did you override the global mappings by some rest controller. Simple example mistake (kotlin):

@RestController("/foo")
class TrainingController {

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

}

In the above case you will get when you request for static resources:

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

The reason for it could be that you wanted to map @PostMapping to /foo but forget about @RequestMapping annotation on the @RestController level. In this case all request are mapped to POST and you won't receive static content in this case.

Przemek Nowak
  • 7,173
  • 3
  • 53
  • 57
0

Given resources under src/main/resources/static, if you add this code, then all static content from src/main/resources/static will be available under "/":

@Configuration
public class StaticResourcesConfigurer implements WebMvcConfigurer {
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/resources/static/");
    }
}
mmirwaldt
  • 843
  • 7
  • 17
0

In my case, some static files were not served, like .woff fonts and some images. But css and js worked just fine.

Update: A much better solution to make Spring Boot serve the woff fonts correctly is to configure the resource filtering mentioned in this answer, for example (note that you need both includes and excludes):

<resources>
    <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
        <excludes>
            <exclude>static/aui/fonts/**</exclude>
        </excludes>
    </resource>
    <resource>
        <directory>src/main/resources</directory>
        <filtering>false</filtering>
        <includes>
            <include>static/aui/fonts/**</include>
        </includes>
    </resource>
</resources>

----- Old solution (working but will corrupt some fonts) -----

Another solution was to disable suffix pattern matching with setUseSuffixPatternMatch(false)

@Configuration
public class StaticResourceConfig implements WebMvcConfigurer {
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        // disable suffix matching to serve .woff, images, etc.
        configurer.setUseSuffixPatternMatch(false);
    }
}

Credits: @Abhiji did point me with 4. in the right direction!

LukeSolar
  • 3,795
  • 4
  • 32
  • 39
0

Works for Thymeleaf, you can link the stylesheet using

    <link th:href="@{/css/style.css}" rel="stylesheet" />
-1

As said above, the file should be in $ClassPath/static/images/name.png, (/static or /public or /resources or /META-INF/resources). This $ClassPath means main/resources or main/java dir.

If your files are not in standard dirs, you can add the following configuration:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/lib/**"); // like this
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        // ... etc.
}
...

}

Mavlarn
  • 3,807
  • 2
  • 37
  • 57