Spring Boot project with static content generates 404 when running jar
Solution 1
It turns out that whilst Spring Boot is being clever at adding the various resource directories to the classpath, Maven is not and it's up to you to deal with that part. By default, only src/main/resources
will be included in your JAR. If you create a folder called /static
in the root of your project (as implied by the blog post) then it will work fine whilst using the spring-boot:run Maven goal but not once you create a JAR.
The easiest solution is to create your /static
folder inside /src/main/resources
and then Maven will include it in the JAR. Alternative you can add additional resource locations to your Maven project:
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>static</directory>
<targetPath>static</targetPath>
</resource>
</resources>
I hope this is useful to someone, it's kind of obvious when you step back and look at how Maven works but it might stump a few people using Spring Boot as it's designed to be pretty much configuration free.
Solution 2
I am banging my head against the wall trying to figure out how to do this with gradle. Any tips?
EDIT: I got it to work by adding this to my build.gradle:
// Copy resources into the jar as static content, where Spring expects it.
jar.into('static') {
from('src/main/webapp')
}
Solution 3
I was going around few pages to understand how to serve static content in Spring boot environment. Mostly all advises was around placing the static files with in /static /resources/ src/main/webapp etc. Thought of sharing below approach.
-
Allow spring boot to auto configure Dispatcher Servlet - Make sure DispatcherServletAutoConfiguration is not in the exclude for AutoConfiguration.
@EnableAutoConfiguration(exclude = { //DispatcherServletAutoConfiguration.class, })
-
Inject your external directory for static content routing
@Value("${static-content.locations:file:C:/myprj/static/") private String[] staticContentLocations;
3.Override WebMvcAutoConfiguration using WebMvcConfigurerAdapter to advice spring not to use default resource Location but use what we instruct it.Like below
@Bean
public WebMvcConfigurerAdapter webMvcConfigurerAdapter()
{
return new WebMvcConfigurerAdapter()
{
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
if (!registry.hasMappingForPattern("/**"))
{
// if this is executed spring won't add default resource
// locations - add them to the staticContentLocations if
// you want to keep them
// default locations:
// WebMvcAutoConfiguration.RESOURCE_LOCATIONS
registry.addResourceHandler("/**").addResourceLocations(
staticContentLocations);
}
}
};
}
If C:/myprj/static has index.html , then http://localhost:portno/index.html should work. Hope that helps.
Solution 4
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("/welcome")
public String welcome(Map<String, Object> model) {
model.put("message", this.message);
return "welcome";
}
@RequestMapping("/")
public String home(Map<String, Object> model) {
model.put("message", this.message);
return "index";
}
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Hello</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>
Solution 5
I had to add thymeleaf dependency to pom.xml. Without this dependency Spring boot didn't find static resources.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
![Robert Hunt](https://i.stack.imgur.com/tIhlA.jpg?s=256&g=1)
Robert Hunt
Updated on October 01, 2020Comments
-
Robert Hunt almost 4 years
The recent blog post (https://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot) by Spring regarding the use of static web content in Spring Boot projects indicates that several resource directories may be used:
- /META-INF/resources/
- /resources/
- /static/
- /public/
This is thanks to the WebMvcAutoConfiguration class which automatically adds these directories to the classpath. This all seems fine and appears to work when using the spring-boot-maven-plugin spring-boot:run goal, all of your static content is working (eg: /index.html).
When you package your Spring Boot project and allow the spring-boot-maven-plugin to create the enhanced JAR then attempt to run your project using
java -jar my-spring-boot-project.jar
you find that your static content now returns a 404 error. -
Dave Syer over 10 yearsJust for the record: I think you misread the blog because it doesn't mention maven at all, and isn't using a jar archive. If you do exactly as Roy did in the blog it would work.
-
Dave Syer over 10 yearsGradle uses "src/main/resources" by default as well. What's wrong with using that?
-
kgreenek over 10 yearsThat is true, putting it in the resources directly will get your files copied into the jar. However, in order for Spring to recognize and serve your files as static content, you need to package it under a directory called "static", "public", "resources", or "/META-INF/resources/" in the jar file. If you simply put your files in the resources directory, they all get copied to the root directory in the jar and Spring serves 404's when you try to access them.
-
Dave Syer over 10 yearsRight, so the simplest (least configuration, maximum functionality) solution is to put your static resources in "src/main/resourecs/static". That's all I meant.
-
Chris DaMour about 10 yearsdo you have an example project somewhere so i can see...i still can't get it to work
-
hellboy over 8 yearscan you please edit the answer to remove the "/" in front of the directory path? it should be <directory>src/main/resources</directory> and <directory>static</directory>
-
Robert Hunt over 8 yearsThere is an easier way to do this, you can simply specify your location as the value of the
spring.resources.static-locations
property inside yourapplication.properties
/application.yml
file or even pass it as a command line argument. -
Busata over 7 yearsIf you let the npm/frontend build task depend on the jar however, it will have already collected the /resources/static into the /build/lib blabla, so you need to let it depend on compileJava, so that your static stuff is already build (for future visitors, just had the same issue)
-
ug_ about 7 yearsThis wasn't working for me, adding a resource in the pom.xml wasn't enough. Instead I had to configure the Spring boot plugin with
<addResources>true</addResources>
. See this SO answer stackoverflow.com/questions/24762657/… -
Robert Hunt almost 7 yearsI think your problem may have been due to using
@RestController
- this annotation is identical to@Controlller
but also adds@ResponseBody
to every method which would mean anything you return from your controller methods ends up in the response body, possibly transformed by a converter. In your case it would probably mean you see "welcome" or "index" being returned in the browser as a String rather than it loading "welcome.html" or "index.html" views. -
tm1701 almost 7 yearsSUPERB !!!! I had trouble getting my index.html at work. I removed a @EnableWebMvc and it worked !!! THANX SO MUCH!
-
Cody Pritchard over 3 yearsThank you. I was trying to host static content from Javadoc and JaCoCo. I got it work locally, but once I deployed, the links were giving 404 response. I could not figure out why, but adding this dependency made it work.