Using Spring BootSpring Boot comes with a pre-configured implementation of ResourceHttpRequestHandler to facilitate serving static resources. By default, this handler serves static content from any of the /static, /public, /resources, and /META-INF/resources directories that are on the classpath.
Not to raise the dead after more than a year, but all the previous answers miss some crucial points:
@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.
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;
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
.
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:
WebMvcConfigurerAdapter
has been deprecated since Spring 5. Implement WebMvcConfigurer
and annotate with @Configuration
.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);
}
}
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.
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.
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).
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With