SpringBoot absolute path clarification - java

I'm new to SpringBoot web dev.
I need to save an image to a directory in the current project. I have given path as "String uploaddir = "./src/main/imageuploads/"+ savedadvert.getId();" but the image not save to the "./src/main/imageuploads/" directory in eclipse project.
#RequestMapping(value="/upload", method = RequestMethod.POST)
public String FileUpload(#RequestParam("file1Url") MultipartFile multipartfile, Model model) throws IOException {
model.addAttribute("advertsim",new advertsummary());
advertsummary advert = new advertsummary();
String file1Urlname= StringUtils.cleanPath(multipartfile.getOriginalFilename());
advert.setFile1Url(file1Urlname);
advertsummary savedadvert = AdvertService.addadvert(advert);
String uploaddir = "./src/main/imageuploads/"+ savedadvert.getId();
FileUploadUtil.saveFile(multipartfile, file1Urlname, uploaddir);
return "uploadview";
}
This is the saveFile method for ref.
public static void saveFile(MultipartFile multipartFile, String fileName, String uploadDir) throws IOException {
Path uploadPath = Paths.get(uploadDir);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
try (InputStream inputStream = multipartFile.getInputStream()) {
Path filePath = uploadPath.resolve(fileName);
System.out.println(filePath.toFile().getAbsolutePath());
Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ioe) {
throw new IOException("Could not save image file: " + fileName, ioe);
}
}
I need to upload the image to this directory,
when I get the absolute path, it shows like this "/Users/chathura/eclipse/jee-2021-03/Eclipse.app/Contents/MacOS/./src/main/imageuploads/24/new file.jpg".
There is no way to go to this directory but I can access that directory using the terminal.
Please tell me what is the mistake here?
Note : I'm using macos
Thanks in advance

Could you try 'src/main/resources/imagesuploads' (without .)
Just a reminder: This directory will disappear when you package your application (production mode)
This directory should be configurable from an external file (application. properties for example)

Thank you Ali, your response gave a lead to the solution. My project sits on MacOS partition therefore, I couldn't write a file without permission. I simply changed the location to another partition and it worked.
#RequestMapping(value="/upload", method = RequestMethod.POST)
public String FileUpload(#RequestParam("file1Url") MultipartFile multipartfile, Model model) throws IOException {
model.addAttribute("advertsim",new advertsummary());
advertsummary advert = new advertsummary();
String file1Urlname= StringUtils.cleanPath(multipartfile.getOriginalFilename());
advert.setFile1Url(file1Urlname);
advertsummary savedadvert = AdvertService.addadvert(advert);
String uploaddir = "/Volumes/My Data/Fileupload"+ savedadvert.getId();
FileUploadUtil.saveFile(multipartfile, file1Urlname, uploaddir);
return "uploadview";
}
Thank you

Related

Showing an image on broswer using #ResponseBody in spring boot

Hello i have this code to display an immage saved on my filesystem on broswer:
#GetMapping(value = "/prova/img/{id}", produces = MediaType.IMAGE_JPEG_VALUE)
public #ResponseBody byte[] getImageWithMediaType(#PathVariable String id) throws IOException {
String path = uploadFolderPath +"/"+ id;
if(Files.exists(Paths.get(path)) && !Files.isDirectory(Paths.get(path))) {
InputStream in = getClass().getResourceAsStream(path);
return IOUtils.toByteArray(in);
}else {
return null; //this is just for example it should never get here
}
I'm getting this error:
Cannot invoke "java.io.InputStream.read(byte[])" because "input" is null
Any suggestion?
Your code first tests that your input exists (as a File) and is not a directory, then you go ahead and try to read it as a resource from the class path using getClass().getResourceAsStream(path). This is usually not what you want.
Try instead InputStream in = new FileInputStream(path);.
Like this:
if (Files.exists(Paths.get(path)) && !Files.isDirectory(Paths.get(path))) {
InputStream in = new FileInputStream(path);
return IOUtils.toByteArray(in);
}
PS: If you are on Java 9 or later, you don't need the IOUtils dependency, simply use readAllBytes. And as you already use Files and Path, we can clean up the code a bit like this:
Path filePath = Paths.get(path);
if (Files.exists(filePath) && !Files.isDirectory(filePath)) {
InputStream in = Files.newInputStream(filePath, StandardOpenOption.READ);
return in.readAllBytes();
}

Uploading files to S3 in Spring boot and getting stored them in classpath

I have method to upload files from user to S3 bucket. But when I'm testing it, it is both saved on S3 buckend and in my classpath.
This is my function to upload file:
public void uploadFileToNews(byte[] file, String fileName) {
File fileToSave = new File(fileName);
try(FileOutputStream fileOutputStream = new FileOutputStream(fileToSave) ) {
fileOutputStream.write(file);
amazonS3.putObject(new PutObjectRequest("gwnews", fileName, fileToSave));
} catch (IOException e) {
log.error("Error during uploading file to S3", e);
}
}
And this is function in my service:
public News addNewsImage(MultipartFile multipartFile, String newsId) throws IOException {
News news = getById(newsId);
news.setImageUrl(news.getId() + ".png");
fileService.uploadFileToNews(multipartFile.getBytes(), news.getId() + ".png");
return newsRepository.save(news);
}
Am I doing something wrong? How can I avoid saving file to my classpath?
This line is saving the content in your classpath : "fileOutputStream.write(file);"
And the next line is saving it in your S3 bucket for corresponding AWS account.

AWS S3 upload file name mismatch

I am able to upload multiple files to s3 bucket at once. However there is a mismatch in the file name the one I provided and uploaded file. I am interested in file name as I need to generate cloud front signed url based on that.
File generation code
final String fileName = System.currentTimeMillis() + pictureData.getFileName();
final File file = new File(fileName); //fileName is -> 1594125913522_image1.png
writeByteArrayToFile(img, file);
AWS file upload code
public void uploadMultipleFiles(final List<File> files) {
final TransferManager transferManager = TransferManagerBuilder.standard().withS3Client(amazonS3).build();
try {
final MultipleFileUpload xfer = transferManager.uploadFileList(bucketName, null, new File("."), files);
xfer.waitForCompletion();
} catch (InterruptedException exception) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("InterruptedException occurred=>" + exception);
}
} catch (AmazonServiceException exception) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("AmazonServiceException occurred =>" + exception);
}
throw exception;
}
}
Uploaded file name is 94125913522_image1.png. As you can see first two characters disappeared. What am I missing here. I am not able to figure out. Kindly advice.
private static void writeByteArrayToFile(final byte[] byteArray, final File file) {
try (OutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(Paths.get(file.getName())))) {
outputStream.write(byteArray);
} catch (IOException exception) {
throw new FileIllegalStateException("Error while writing image to file", exception);
}
}
The reason of the problem
You lose the first two charecters of the file names because of the third argument of this method:
transferManager.uploadFileList(bucketName, null, new File("."), files);
What happens in this case
So, what is the third argument:
/**
...
* #param directory
* The common parent directory of files to upload. The keys
* of the files in the list of files are constructed relative to
* this directory and the virtualDirectoryKeyPrefix.
...
*/
public MultipleFileUpload uploadFileList(... , File directory, ...){...}
And how will it be used:
...
int startingPosition = directory.getAbsolutePath().length();
if (!(directory.getAbsolutePath().endsWith(File.separator)))
startingPosition++;
...
String key = f.getAbsolutePath().substring(startingPosition)...
Thus, the directory variable is used to define a starting index to trim file paths to get file keys.
When you pass new File(".") as a directory, the parent directory for your files will be {your_path}.
But this is a directory, and you need to work with files inside it. So the common part, retrieved from your directory file, is {your_path}./
That is 2 symbols more than you actually need. And for this reason this method trims the 2 extra characters - an extra shift of two characters when trimming the file path.
The solution
If you only need to work with the current directory, you can pass the current directory as follows:
MultipleFileUpload upload = transferManager.uploadFileList(bucketName, "",
System.getProperty("user.dir"), files);
But if you start working with external sources, it won't work. So you can use this code, which creates one MultipleFileUpload per group of files from one directory.
private final String PATH_SEPARATOR = File.separator;
private String bucketName;
private TransferManager transferManager;
public void uploadMultipleFiles(String prefix, List<File> filesToUpload){
Map<File, List<File>> multipleUploadArguments =
getMultipleUploadArguments(filesToUpload);
for (Map.Entry<File, List<File>> multipleUploadArgument:
multipleUploadArguments.entrySet()){
try{
MultipleFileUpload upload = transferManager.uploadFileList(
bucketName, prefix,
multipleUploadArgument.getKey(),
multipleUploadArgument.getValue()
);
upload.waitForCompletion();
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
}
private Map<File, List<File>> getMultipleUploadArguments(List<File> filesToUpload){
return filesToUpload.stream()
.collect(Collectors.groupingBy(this::getDirectoryPathForFile));
}
private File getDirectoryPathForFile(File file){
String filePath = file.getAbsolutePath();
String directoryPath = filePath.substring(0, filePath.lastIndexOf(PATH_SEPARATOR));
return new File(directoryPath);
}

Upload file to Spring Boot Resource Folder, should not be that hard right

I checked all over the internet and still cannot find the correct answer. I want to upload a file to the resources folder from Spring. So I can get the file from the heroku server when I deploy it.
For example applicationname/herokuapp.com/image.jpg
The structure of my app:
I tried and got a few problems :
File not found exception
Illegal char <:> at index 2
The file path I get is in the target folder??
Can't find path
I just need to get the correct path to the resources folder but I can't get it.
My controller with the following method looks like this:
#PostMapping(value = "/sheetmusic")
public SheetMusic create(HttpServletRequest request, #RequestParam("file") MultipartFile file, #RequestParam("title") String title, #RequestParam("componist") String componist, #RequestParam("key") String key, #RequestParam("instrument") String instrument) throws IOException {
URL s = ResourceUtils.getURL("classpath:static/");
String path = s.getPath();
fileService.uploadFile(file,path);
SheetMusic sheetMusic = new SheetMusic(title,componist,key,instrument,file.getOriginalFilename());
return sheetMusicRepository.save(sheetMusic);
}
The FileService:
public void uploadFile(MultipartFile file, String uploadDir) {
try {
Path copyLocation = Paths
.get(uploadDir + File.separator + StringUtils.cleanPath(file.getOriginalFilename()));
Files.copy(file.getInputStream(), copyLocation, StandardCopyOption.REPLACE_EXISTING);
} catch (Exception e) {
e.printStackTrace();
}
}
I read something about jar but I don't understand it. I did not think it was this hard to just upload a file to a folder but I hope you guys can help me out!
EDIT :
When I add this :
String filePath = ResourceUtils.getFile("classpath:static").toString();
It will upload to the target folder which is not right.
EDIT 2 : IT IS FIXED
This is the right way to get the correct path :
String path = new File(".").getCanonicalPath() + "/src/main/webapp/WEB-INF/images/";
fileService.uploadFile(file,path);
My folder structure is the following:
main
-java
- webapp
- WEB-INF
- images
Then I had to put this code into my MainApplicationClass
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// Register resource handler for images
// Register resource handler for images
registry.addResourceHandler("/images/**").addResourceLocations("/WEB-INF/images/")
.setCacheControl(CacheControl.maxAge(2, TimeUnit.HOURS).cachePublic());
}
What you are trying to do here (replacing a file/uploading a file INTO a package .jar file) does not work, it is literally impossible.
You need to upload your file somewhere else, be that S3, some network drive etc, so that you application can reference it.

Relative path to file | Springboot

I am new to Spring-boot/Java and trying to read the contents of a file in a String.
What's the issue:
I'm getting "File not found exception" and unable to read the file. Apparently, I'm not giving the correct file path.
i've attached the directory structure and my code. I'm in FeedProcessor file and want to read feed_template.php (see image)
public static String readFileAsString( ) {
String text = "";
try {
// text = new String(Files.readAllBytes(Paths.get("/src/main/template/feed_template_head.php")));
text = new String(Files.readAllBytes(Paths.get("../../template/feed_template_head.php")));
} catch (IOException e) {
e.printStackTrace();
}
return text;
}
You need to put template folder inside resource folder. And then use following code.
#Configuration
public class ReadFile {
private static final String FILE_NAME =
"classpath:template/feed_template_head.php";
#Bean
public void initSegmentPerformanceReportRequestBean(
#Value(FILE_NAME) Resource resource,
ObjectMapper objectMapper) throws IOException {
new BufferedReader(resource.getInputStream()).lines()
.forEach(eachLine -> System.out.println(eachLine));
}
}
I suggest you to go though once Resource topic in spring.
https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/resources.html

Categories

Resources