9

I'm new to Spring framework and Spring Boot.
I've implemented a very simple RESTful Spring Boot web application.
You can see the nearly full source code in another question: Spring Boot: How to externalize JDBC datasource configuration?

How can the app service external static HTML, css js files?
For example, the directory structure may be as follows:

MyApp\
   MyApp.jar (this is the Spring Boot app that services the static files below)
   static\
       index.htm
       images\
           logo.jpg
       js\
           main.js
           sub.js
       css\
           app.css
       part\
           main.htm
           sub.htm

I've read the method to build a .WAR file that contains static HTML files, but since it requires rebuild and redeploy of WAR file even on single HTML file modification, that method is unacceptable.

An exact and concrete answer is preferable since my knowledge of Spring is very limited.

3
  • 1
    What is it that doesn't work? Classpath resources in /static will be served as static resources by default (also in /public and a couple of other places), so you should be able to run your app and load /css/app.css for example. Commented Nov 19, 2013 at 15:44
  • @DaveSyer Actually I found that it works, when I run the MyApp.jar in the MyApp directory. I verified it when I read the source code of org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory. It has 'static' in COMMON_DOC_ROOTS. (See github.com/spring-projects/spring-boot/blob/master/spring-boot/…) But I could not find any documentation about it, so I thought that including static files in the WAR file is the only method. Commented Nov 20, 2013 at 0:27
  • @DaveSyer And I wanted to change the directory for the static files to anywhere I wanted, regardless of classpath or current directory. The directory structure of my question is only an example(which is accidentally supported by the framework). So I posted another question to view the problem from another angle. (See stackoverflow.com/questions/20069130/…) Commented Nov 20, 2013 at 0:32

3 Answers 3

6

I see from another of your questions that what you actually want is to be able to change the path to static resources in your application from the default values. Leaving aside the question of why you would want to do that, there are several possible answers.

  • One is that you can provide a normal Spring MVC @Bean of type WebMvcConfigurerAdapter and use the addResourceHandlers() method to add additional paths to static resources (see WebMvcAutoConfiguration for the defaults).
  • Another approach is to use the ConfigurableEmbeddedServletContainerFactory features to set the servlet context root path.
  • The full "nuclear option" for that is to provide a @Bean definition of type EmbeddedServletContainerFactory that set up the servlet container in the way you want it. If you use one of the existing concrete implementations they extend the Abstract* class that you already found, so they even have a setter for a property called documentRoot. You can also do a lot of common manipulations using a @Bean of type EmbeddedServletContainerCustomizer.
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for your answer. So my approach in my another question is the last one of your suggestion. For now, I will stick to it(since it works). After studying more of the Spring and Spring Boot maybe I change the approach.
Regarding the reason why I want to change the default location of the static files, it is just for the flexibility for development and deploy environment. Maybe I don't know enough of the convention of the Spring framework (even Java) for now.
Note, that for spring-boot 2.x these classes changed their names. Now it is ConfigurableTomcatWebServerFactory, TomcatServletWebServerFactory and TomcatServletWebServerFactoryCustomizer.
4

Is enough if you specify '-cp .' option in command 'java -jar blabla.jar' and in current directory is 'static' directory

2 Comments

I found this answer more simple, no code change needed. But for it to work as expected, the OP need to rename its static folder to public, because spring boot (v1.1.6 here) will look for a public folder in the classpath.
This solution was perfect for frontend development, just add a runtime dependency in the IDE. Then you can edit html/javascript stuff without having to repackage/restart the backend.
0

Take a look at this Dave Syer's answer implementation.

You can set the document root directory which will be used by the web context to serve static files using ConfigurableEmbeddedServletContainer.setDocumentRoot(File documentRoot).

Working example:

package com.example.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.io.File;
import java.nio.file.Paths;

@Configuration
public class WebConfigurer implements ServletContextInitializer, EmbeddedServletContainerCustomizer {
    private final Logger log = LoggerFactory.getLogger(WebConfigurer.class);

    private final Environment env;
    private static final String STATIC_ASSETS_FOLDER_PARAM = "static-assets-folder";
    private final String staticAssetsFolderPath;

    public WebConfigurer(Environment env, @Value("${" + STATIC_ASSETS_FOLDER_PARAM + ":}") String staticAssetsFolderPath) {
        this.env = env;
        this.staticAssetsFolderPath = staticAssetsFolderPath;
    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        if (env.getActiveProfiles().length > 0) {
            log.info("Web application configuration, profiles: {}", (Object[]) env.getActiveProfiles());
        }
        log.info(STATIC_ASSETS_FOLDER_PARAM + ": '{}'", staticAssetsFolderPath);
    }

    private void customizeDocumentRoot(ConfigurableEmbeddedServletContainer container) {
        if (!StringUtils.isEmpty(staticAssetsFolderPath)) {
            File docRoot;
            if (staticAssetsFolderPath.startsWith(File.separator)) {
                docRoot = new File(staticAssetsFolderPath);
            } else {
                final String workPath = Paths.get(".").toUri().normalize().getPath();
                docRoot = new File(workPath + staticAssetsFolderPath);
            }
            if (docRoot.exists() && docRoot.isDirectory()) {
                log.info("Custom location is used for static assets, document root folder: {}",
                        docRoot.getAbsolutePath());
                container.setDocumentRoot(docRoot);
            } else {
                log.warn("Custom document root folder {} doesn't exist, custom location for static assets was not used.",
                        docRoot.getAbsolutePath());
            }
        }
    }

    @Override
    public void customize(ConfigurableEmbeddedServletContainer container) {
        customizeDocumentRoot(container);
    }

}

Now you can customize your app with command line and profiles (src\main\resources\application-myprofile.yml):

> java -jar demo-0.0.1-SNAPSHOT.jar --static-assets-folder="myfolder"
> java -jar demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=myprofile

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.