Right now I have a simple Spring Boot application that serves static images that I have placed in resources/static/img. This works just fine for displaying the actual content, but there are two things I'd like to fix:
I don't want any of these images to be bundled with the resulting .jar file, and I know that placing these images in the resources folder will do that.
Using my current setup, in order to see a new image on the webapp, I have to add it to the folder and restart it. I would instead like Spring to serve any static content that exists in a specific folder, so I can add images while the application is running and have them automatically served at localhost:8080/img/{image name}.
I attempted to solve this by setting up a resource handler, but I'm not sure if this is any different than simply serving them from resources/static. Unfortunately, I'm still struggling with getting this configured correctly, as I'm unable to see any images at all. Here's what I tried:
#Configuration
public class StaticResourceConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/img/**").addResourceLocations("file:" + Application.IMAGE_DIR);
super.addResourceHandlers(registry);
}
}
And here is my Application configuration:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
static String IMAGE_DIR;
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws IOException {
SpringApplication.run(Application.class, args);
IMAGE_DIR = new File(".").getCanonicalPath() + "/img/";
}
}
Again, my goal is to set up a folder in the root of my project called img which will store the images that I would like the webapp to serve on localhost:8080/img/{image name}. If possible, I'd like to be able to add content to this folder while the application is running and have Spring automatically serve them without having to restart it.
Does anyone have any ideas? Thanks in advance.
the problem with your approach is that you set IMAGE_DIR after spring boot application is ran and the constant IMAGE_DIR is not initialized and is null. Change it as follows:
public static void main(String[] args) throws IOException {
IMAGE_DIR = "/opt/img/";
SpringApplication.run(Application.class, args);
}
and remove all File(".").getCanonicalPath() related stuff and it will work. Your approach will fit in your needs when you have new image in selected directory it can be served.
A good solution for serving dynamic content with spring boot is to link a static content directory to a symbolic link with no cache and after that, you just need to rebuild symlink every time you need to reload. So in your case:
#Configuration
public class StaticResourceConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/img/**").addResourceLocations("file:/tmp/images/").setCacheControl(CacheControl.noCache());
super.addResourceHandlers(registry);
}
}
After that, you change your image directory like this:
Path link = Paths.get("/tmp/images"); //Symlink
Files.deleteIfExists(link);
Files.createSymbolicLink(link, Paths.get(your_new_images_directory));
The choice of symlink /tmp/images is personal, you can choose what you want. Pay attention, your application needs to have good administrator rights for symlink creation.
to solve the problem with your point 2.
Using my current setup, in order to see a new image on the webapp, I have to add it to the folder and restart it. I would instead like
Spring to serve any static content that exists in a specific folder,
so I can add images while the application is running and have them
automatically served at localhost:8080/img/{image name}.
You can create all those images under:
/resources/public
-img
-js,...
And to access just localhost:8080/img/yourImage.png
Everything under "public" folder will be accessible
Related
I have a Java Spring Application and I need to serve some static content, so I use the well documented approach as described in e.g. https://www.baeldung.com/spring-mvc-static-resources. I create a folder src/main/resources/static, I add a file test.json. I build and run the app, and I can access localhost:8080/test.json
But if I want to add another file, e.g. test2.json I need to restart the server in order for the app to serve it.
Is there a way to "force a new file search" and circumvent the caching so that I can add files at runtime without writing a new Controller?
Performance doesn't matter to me in this case.
My recommendation would be to add your dynamic files to the a location on the filesystem, and then add a custom resource handler.
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry resourceHandlerRegistry) {
resourceHandlerRegistry.addResourceHandler("/fs_resources/**")
.addResourceLocations("file:///my/path/where/i/keep/stuff")
.setCachePeriod(0);
}
}
I have a Spring Boot-based project (based on spring-boot-starter-parent and spring-boot-starter-web in which I want to both serve static content (built in another module, and copied into the project with maven-resources-plugin).
With the default configuration/conventions, it looks for static content in misc. places, like classpath:/static and classpath:/public, which is useful if the static content is to be served from the root URL, which for this project is not the case.
I want to serve it off /web/ which I have successfully done by deriving from WebMvcConfigurer (and annotated the class with #Configuration) and overridden the public void addResourceHandlers(ResourceHandlerRegistry registry) method; registry.addResourceHandler("/web/**").addResourceLocations("classpath:/static/web/");
This works when explicitly referring to the file names in the /web/-folder, but I can't figure out how I can emulate the "default document" behavior, e.g. index.html should be served for /web/. If you drop off an index.html in one of the root directories for static content, it will be handled by the WelcomePageHandlerMapping.
Found the solution; I also had to override the addViewControllers() to create an explicit mapping and fix the precedence:
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/web/").setViewName("index.html");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
I've looked all over and I can't figure out what I am doing wrong with the way I am trying to serve my index.html page in my packaged spring-boot jar file. This is my app structure:
When I run mvn clean install it packages the jar properly and actually puts the index.html file into the static folder in the jar.
Here is my MVC Conf:
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
registry.addResourceHandler("/app/**").addResourceLocations("/app/");
registry.addResourceHandler("/**").addResourceLocations("/");
}
Anything I am not doing properly?
OK I fixed it thanks to help from multiple sources! Here is what I did so it may help someone else:
1) add this resource in the POM. I am still not sure why I need this but my app will not serve without this. Spring boot should be doing this automatically but it apparently was not.
<resources>
<resource>
<directory>src/main/resources/static</directory>
<targetPath>static</targetPath>
</resource>
</resources>
2) In my MVC configuration I added this (similar to the answer below):
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);
}
after adding these two things, my app started serving files!
Try to add "classpath" to the resource location,
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
I believe you should read this, how to serve static content:
http://docs.spring.io/spring-boot/docs/1.4.2.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-static-content
To sum it up, your browser is caching your static resources, such as CSS files or html files.
In order to break this behavior, try first clean your browser cache, in google chrome you go to settings then clear browsing data.
Secondly, add these lines to your application.properties file in order to bust the cache:
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
or add this instead:
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/**
spring.resources.chain.strategy.fixed.version=v12
On spring boot project, you can get this working just by extending WebMvcConfigurerAdapter and override addResourceHandlers as below
#SpringBootApplication
public class DemoApplication extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
}
}
The index page will be accessible on http://localhost:8080/static/index.html
Background
I have a spring boot application which has the logo.png file added to the static folder of the resource file, which is eventually built into the jar file which is used in the execution.
This jar application need to be run in multiple instances for different clients. So what I did is create an external application.properties file which distinguish the settings for each users.
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Problem
But the problem is, i need to change the logo of each instance of my application. I cannot embed the customer logos into my application jar. Rather I need to keep it external like my application.properties.
For the moment, what I have done is check for the file logo.png in the same folder of jar of execution, and if excist, read the file, get base64 data and show it in the img tag.
But I want this to be done in a proper way as static content. I need the static content to be externalized. so I can let each customer have a specific instance of the jar running with different static resource content
For example. I need to keep the external static files as below and access from the urls in my view href or src attributes of the html tags.
Summary
Required folder structure
+ runtime
- myapp-0.1.0.jar
- application.properties
+ static
- logo.png
Should be able to access
<img th:src="#{/logo.png}" />
You can use resource handlers to serve external files - e.g.
#Component
class WebConfigurer extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/ext/**").addResourceLocations("file:///yourPath/static/");
}
}
The WebMvcConfigurerAdapter is deprecated. As from Spring Boot 2.x you could use WebMvcConfigurer instead.
#Configuration
public class MediaPathConfig {
// I assign filePath and pathPatterns using #Value annotation
private String filePath = "/ext/**";
private String pathPatterns = "/your/static/path/";
#Bean
public WebMvcConfigurer webMvcConfigurerAdapter() {
return new WebMvcConfigurer() {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!registry.hasMappingForPattern(pathPatterns)) {
registry.addResourceHandler(pathPatterns)
.addResourceLocations("file:" + filePath);
}
}
};
}
}
I have a simple spring boot webapp running on an embedded jetty server, i.e. the main application class:
#Configuration
#EnableAutoConfiguration
#EnableConfigurationProperties
#ComponentScan
public class SampleActuatorApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleActuatorApplication.class, args);
}
}
I have a bunch of static files and directories in one of the auto-configured locations (/static) where static content will be served from. When I hit the base URI I want to be able to view a directory index of the static content so that I can browse through it.
I have read containers including jetty usually come with a default handler that will expose this, however my app just returns 404 so I assume there is some additional steps needed when doing this via spring-boot. Can anyone suggest what I need to do / is my understanding correct?
Somehow you'll have to set the dirAllowed to true. This is done in JettyEmbeddedServletContainerFactory
Take a look at addDefaultServlet
https://github.com/spring-projects/spring-boot/blob/master/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactory.java
There is a line holder.setInitParameter("dirAllowed", "false");