77

I have a Spring Boot web application, and I would like to serve static content located in a shared Dropbox directory on my Linode VPS (~/Dropbox/images). I've read that Spring Boot will automatically serve static content from

"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/",

but of course my Dropbox directory is not on the classpath.

Although I could configure Apache to serve the images in my Dropbox folder, I would like to take advantage of Spring Security to restrict access of the static content to authenticated users.

Shannon Kendrick
  • 777
  • 1
  • 6
  • 7

12 Answers12

81

You can add your own static resource handler (it overwrites the default), e.g.

@Configuration
public class StaticResourceConfiguration extends WebMvcConfigurerAdapter {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("file:/path/to/my/dropbox/");
    }
}

There is some documentation about this in Spring Boot, but it's really just a vanilla Spring MVC feature.

Also since spring boot 1.2 (I think) you can simply set spring.resources.staticLocations.

kaliatech
  • 17,579
  • 5
  • 72
  • 84
Dave Syer
  • 56,583
  • 10
  • 155
  • 143
  • I'm not finding the super class WebMvcAdapter in your example above. Which Spring JAR contains that class? – Shannon Kendrick Jan 14 '14 at 23:20
  • I extended WebMvcConfigurerAdapter instead. – Shannon Kendrick Jan 15 '14 at 03:05
  • 7
    As @kaliatech mentioned, don't forget the trailing slash on the Resource Location path. – 1in9ui5t May 07 '15 at 18:57
  • 1
    To leave default resources mapping and add dropbbox folder as addition resources is recomended rename resourceHandler path, for sample: registry.addResourceHandler("/files/**").addResourceLocations("file:/path/to/my/dropbox/"); – Dmitry Stolbov Nov 30 '16 at 06:17
  • link for page not found. Since this is the accepted answer with a significant amount of votes may I suggest an update on this? – PaulB Jul 19 '17 at 17:59
  • It even works for relative directory with "file:./dir/" – Ondřej Stašek Mar 27 '19 at 13:43
  • Make sure that the `addResourceLocations` paths ends with `/`, otherwise, it causes 404 – NevinJ Apr 22 '19 at 06:38
  • FYI this has at least one caveat: it will not map `/` to `/index.html` WelcomePageHandlerMapping uses `resource.static-locations` so it's harder to simulate via code. – zeratul021 Mar 09 '20 at 19:59
  • 1
    Is this still the best way to do this in 2020? Given "WebMvcConfigurerAdapter" is deprecated in newer versions of spring. – z atef Nov 13 '20 at 07:28
  • `WebMvcConfigurerAdapter` was only deprecated in favour of its interface (read the javadocs). So it's the same. – Dave Syer Feb 18 '21 at 09:48
35

Springboot (via Spring) now makes adding to existing resource handlers easy. See Dave Syers answer. To add to the existing static resource handlers, simply be sure to use a resource handler path that doesn't override existing paths.

The two "also" notes below are still valid.

. . .

[Edit: The approach below is no longer valid]

If you want to extend the default static resource handlers, then something like this seems to work:

@Configuration
@AutoConfigureAfter(DispatcherServletAutoConfiguration.class)
public class CustomWebMvcAutoConfig extends
                    WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter {

  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    String myExternalFilePath = "file:///C:/Temp/whatever/m/";

    registry.addResourceHandler("/m/**").addResourceLocations(myExternalFilePath);

    super.addResourceHandlers(registry);
  }

}

The call to super.addResourceHandlers sets up the default handlers.

Also:

  • Note the trailing slash on the external file path. (Depends on your expectation for URL mappings).
  • Consider reviewing the source code of WebMvcAutoConfigurationAdapter.
Community
  • 1
  • 1
kaliatech
  • 17,579
  • 5
  • 72
  • 84
  • Awesome, thanks for this! I'd also mention that it's important to include the trailing /** on the resource handler mapping as well, I forgot to add that and I kept getting 404 errors – Trevor Feb 10 '16 at 18:20
  • This solution goes in the right direction, however it's not possible to inherit from WebMvcAutoConfigurationAdapter because the constructor arguments are not all public. – Geoffroy Warin Feb 21 '17 at 17:46
  • @GeoffroyWarin This answer was originally written for older versions. I edited it just now to indicate that. See Dave Syer's answer. To add to existing resource handlers simply be sure not to override existing resource paths. – kaliatech Feb 22 '17 at 13:47
21

Based on @Dave Syers answer I add the following class to my Spring Boot project:

@Configuration
public class StaticResourceConfiguration extends WebMvcConfigurerAdapter {

 private static final Logger LOG = LoggerFactory.getLogger(StaticResourceConfiguration.class);

 @Value("${static.path}")
 private String staticPath;

 @Override
 public void addResourceHandlers(ResourceHandlerRegistry registry) {

    if(staticPath != null) {
        LOG.info("Serving static content from " + staticPath);
        registry.addResourceHandler("/**").addResourceLocations("file:" + staticPath);
    }
 }

 // see https://stackoverflow.com/questions/27381781/java-spring-boot-how-to-map-my-my-app-root-to-index-html
 @Override
 public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/").setViewName("redirect:/index.html");
 }
}

This allows me to start my spring boot app with the parameter --static.path like

java -jar spring-app-1.0-SNAPSHOT.jar --static.path=/path/to/my/static-files/

This can be very handy for development and testing.

asmaier
  • 11,132
  • 11
  • 76
  • 103
10

There's a property spring.resources.staticLocations that can be set in the application.properties. Note that this will override the default locations. See org.springframework.boot.autoconfigure.web.ResourceProperties.

Abhijit Sarkar
  • 21,927
  • 20
  • 110
  • 219
  • 1
    `spring.resources.staticLocations` is deprecated, but you can use `spring.web.resources.staticLocations` instead. – RiZKiT Apr 07 '22 at 14:13
9

Based on @Dave Syer, @kaliatech and @asmaier answers the springboot v2+ way would be:

@Configuration
@AutoConfigureAfter(DispatcherServletAutoConfiguration.class)
public class StaticResourceConfiguration implements WebMvcConfigurer  {

  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    String myExternalFilePath = "file:///C:/temp/whatever/m/";

     registry.addResourceHandler("/m/**").addResourceLocations(myExternalFilePath);

  }

}
Vojtech Ruzicka
  • 16,384
  • 15
  • 63
  • 66
s.ijpma
  • 930
  • 1
  • 11
  • 23
9
  • OS: Win 10
  • Spring Boot: 2.1.2

I wanted to serve static content from c:/images

Adding this property worked for me:

spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:///C:/images/

I found the original value of the property in the Spring Boot Doc Appendix A

This will make c:/images/image.jpg to be accessible as http://localhost:8080/image.jpg

Igorski
  • 428
  • 9
  • 16
  • 1
    `spring.resources.static-locations` is deprecated, but you can use `spring.web.resources.static-locations` instead. – RiZKiT Apr 07 '22 at 14:14
  • is it not spring.web.resources.static-locations instead of spring.resources.static-locations? – Iorweth333 Nov 25 '22 at 16:30
8

@Mark Schäfer

Never too late, but add a slash (/) after static:

spring.resources.static-locations=file:/opt/x/y/z/static/

So http://<host>/index.html is now reachable.

Leonardo Alves Machado
  • 2,747
  • 10
  • 38
  • 53
JC Remy
  • 101
  • 1
  • 2
2

To serve from file system

I added spring.resources.static-location=file:../frontend/build in application.properties

index.html is present in the build folder

Use can also add absolute path

spring.resources.static-location=file:/User/XYZ/Desktop/frontend/build

I think similarly you can try adding Dropbox folder path.

LAXIT KUMAR
  • 459
  • 6
  • 7
1

For the current Spring-Boot Version 1.5.3 the parameter is

spring.resources.static-locations

Update I configured

`spring.resources.static-locations=file:/opt/x/y/z/static``

and expected to get my index.html living in this folder when calling

http://<host>/index.html

This did not work. I had to include the folder name in the URL:

http://<host>/static/index.html

Mark Schäfer
  • 925
  • 1
  • 12
  • 23
1

FWIW, I didn't have any success with the spring.resources.static-locations recommended above; what worked for me was setting spring.thymeleaf.prefix:

report.location=file:/Users/bill/report/html/
spring.thymeleaf.prefix=${report.location}
Bill Horvath
  • 1,336
  • 9
  • 24
1

Note that WebMvcConfigurerAdapter is deprecated now (see WebMvcConfigurerAdapter). Due to Java 8 default methods, you only have to implement WebMvcConfigurer.

coseos
  • 144
  • 1
  • 3
0

You can place your folder in the root of the ServletContext.

Then specify a relative or absolute path to this directory in application.yml:

spring:
  resources:
    static-locations: file:some_temp_files/

The resources in this folder will be available (for downloading, for example) at:

http://<host>:<port>/<context>/your_file.csv