Spring Boot app not serving static content

27,079

Solution 1

Put static resources under the directory:

/src/main/resources/static

You can also use public or resources instead of static as folder name.

Explanation: your build tool (Maven or Gradle) will copy all the content from /src/main/resources/ in the application classpath and, as written in Spring Boot's docs, all the content from a directory called /static (or /public or /resources) in the classpath will be served as static content.


This directory could works also, but it is discouraged:

/src/main/webapp/

Do not use the src/main/webapp directory if your application will be packaged as a jar. Although this directory is a common standard, it will only work with war packaging and it will be silently ignored by most build tools if you generate a jar.

Solution 2

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>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>
Share:
27,079
John Douglas George
Author by

John Douglas George

Updated on July 19, 2022

Comments

  • John Douglas George
    John Douglas George almost 2 years

    I am using Spring Boot, and am trying to make my static resources (CSS, JS, Fonts) available when deployed. The source code is available for you to look at or clone from https://github.com/joecracko/StaticResourceError.

    Right now my CSS, JS, and Font files are not visible to my deployed website.

    Here is my project directory structure:

    Here is my project directory structure

    Here is the root directory of the compiled JAR: I assure you the files are present in their respective folders.

    enter image description here

    Here is the network error I am seeing:

    enter image description here

    And here are my sources provided by chrome tools. Note that bar.css appears empty here. You may look at my source code to see that it is not empty.

    enter image description here

    Here is my homepage.html

    <html xmlns:th="http://www.thymeleaf.org">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
    <title>Insert title here</title>
    
    <!-- Main Styles -->
    <link rel="stylesheet" href="/css/bar.css" />
    <script src="/js/foo.js"></script>
    
    </head>
    <body>
        <div>Welcome to Foo!</div>
    </body>
    </html>
    

    Here is my Web App Initializer (FooWebAppInitializer.java)

    public class FooWebAppInitializer implements WebApplicationInitializer {
    
        @Override
        public void onStartup(ServletContext container) {
    
            AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
            rootContext.register(ServletConfig.class);
    
            // Manage the lifecycle of the root application context
            container.addListener(new ContextLoaderListener(rootContext));
    
            //Spring Security
            container.addFilter("springSecurityFilterChain", new DelegatingFilterProxy("springSecurityFilterChain"))
                .addMappingForUrlPatterns(null, false, "/*");
    
            // Register and map the dispatcher servlet
            ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcherServlet", new DispatcherServlet(rootContext));
            dispatcher.setLoadOnStartup(1);
            dispatcher.addMapping("/*");
            dispatcher.addMapping("*.css");
            dispatcher.addMapping("*.eot");
            dispatcher.addMapping("*.svg");
            dispatcher.addMapping("*.ttf");
            dispatcher.addMapping("*.woff");
            dispatcher.addMapping("*.map");
            dispatcher.addMapping("*.js");
            dispatcher.addMapping("*.ico");
        }
    }
    

    Here is my Servlet Configuration (ServletConfig.java)

    @Configuration
    @EnableWebMvc
    @ComponentScan({"com.foo"})
    public class ServletConfig extends WebMvcAutoConfiguration{
    
        @Bean
        MultipartResolver multipartResolver() {
            return new StandardServletMultipartResolver();
        }
    
        @Bean
        public ResourceBundleMessageSource messageSource() {
            ResourceBundleMessageSource source = new ResourceBundleMessageSource();
            source.setBasename("messages");
            return source;
        }
    }
    

    And for kicks, My Spring Security Config (WebSecurityConfig.java)

    @Configuration
    @EnableWebMvcSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                    .anyRequest().permitAll();
        }
    
        @Override
        public void configure(WebSecurity web) throws Exception {
            web.ignoring().antMatchers("/resources/**"); // #3
        }
    }