Reputation: 120
I have a Spring Boot application that simply has an HTML page to allow users to upload images and another page to see the uploaded images.
Here is my project structure:
With my Windows computer works fine, then I created a service on a Ubuntu server that runs the Spring Boot app, here the image upload works fine but on the other HTML page, the images are not shown and show this:
I tried to stop the service and restart it and the images are correctly shown !!!
so at runtime don't see the new images but when I restart it the images appear.
How can I solve this problem?
Here is my web configuration:
@Configuration
public class WebConfiguration extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/static/");
}
}
Here is my image saver:
public static void saveFile(String uploadDirImg, String fileName, MultipartFile image) throws IOException {
Path pathForSavingImg = Paths.get("src", "main", "resources", "static", "db_images");
Path filePath = pathForSavingImg.resolve(fileName);
image.transferTo(filePath);
}
Upvotes: 0
Views: 2128
Reputation: 513
First let's explain why this behavior happens. You're using Maven to build and manage your project. To simplify, each time you build and run your application, Maven outputs the build result in /target
directory. You can find it in /backend/target in your filesystem.
At app runtime, the app runs from /target
folder, so the classpath is /target/classes/
and not /src/main/resources
. This is very important, because of what you are doing is the following (I've added comments to your class):
@Configuration
public class WebConfiguration extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
// here you match any resource path from the URL
.addResourceHandler("/**")
// to search in the classpath:/static/ folder, which in your build
// is "/target/static" and NOT "/src/main/resources/static"
.addResourceLocations("classpath:/static/");
}
}
I guess you can see the problem now and the explanation of the app's behavior. Basically you upload files (images) in the /src/main/resources/static/db_images
folder, while the app when it's running searches for them in the /backend/target/static/db_images
.
When you reload the application, the images work because the app rebuilds again the rebuild process copies db_images
folder from /src/main/resources/static/
to /target/static/
and the earlier upload can be found.
The solve the problem, a good recommendation and a known practice is using a filesystem folder outside of the project and reference it by absolute path. The upload folders are usually something you want out of your app's sources and for good reason (size of the folder is the first it comes to mind).
So if you have different environments you can add some property in application.properties to control the upload path, something like this:
# For Windows OS
upload.folder.path=D:/db_images/
or
# For Unix-like OS
upload.folder.path=/srv/db_images/
Then your WebConfiguration should look something like:
@Configuration
public class WebConfiguration extends WebMvcConfigurationSupport {
@Value("${upload.folder.path}")
private String uploadFolderPath;
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/**")
.addResourceLocations("file:" + uploadFolderPath);
}
}
Of course, the image saver should account for this and be modified accordingly.
public static void saveFile(String uploadDirImg, String fileName, MultipartFile image) throws IOException {
Path pathForSavingImg = Paths.get(uploadFolderPath);
Path filePath = pathForSavingImg.resolve(fileName);
image.transferTo(filePath);
}
Upvotes: 3