Storing files in project directory using Spring - java

I am trying to work through Spring tutorials on file uploads. What I'm trying to do is have the file be saved to a folder within the project. The folder is called "files" and is separate from the src folder.
|bin
|build
|src
|files
I have this code which accepts a file upload:
public #ResponseBody String handleFileUpload(#RequestParam("name") String name,
#RequestParam("file") MultipartFile file){
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
BufferedOutputStream stream =
new BufferedOutputStream(new FileOutputStream(new File(name)));
stream.write(bytes);
stream.close();
//file.transferTo(); help?
return "You successfully uploaded " + name + "!";
What I want to do is use transferTo()to move the file to the "files" directory. When I try the true path, or try some sort of relative path I get this error which is created in the web window I am uploading files in.
Failed to upload file => "uploadedFileName/directory" does not exist
I am not sure why the file name is being appended to the directory path. Any assistance on this is much appreciated.

When you are trying to save the uploaded file to the file "uploadedFileName/directory", you are using relative file path. It's relative to the current working directory of the java process (java process, running your Tomcat Application Server or whatever appserver you are using). And that current working directory is not your project root. The following code:
System.out.println(new File(name).getAbsolutePath())
will print you the exactly path where you are trying to save your uploaded file.
To fix that issue you have to explicitly specify your project root:
File rootDir = new File("C:/Projects/myTestProject");
File uploadedFile = new File(rootDir, name);
file.transferTo(uploadedFile);
In real project you will want not to hardcode that rootDir path, but to retrieve it from some configuration file.
Don't rely to the current working directory of the application server. It could point to any directory.
PS that's out of scope of this question, but please be careful with saving data to the user-provided file names. Malicious user could post file with name "../../../../../../../../SomeSensitiveDirectory/SomeFile" and will overwrite that file unless you explicitly check that input parameter name for bad characters.

When you upload a file, you have to save it to another file.
You should use File#createTempFile() which takes a directory instead.
<p style="border-style:solid; border-color:#FFFFFF;">
<br>
File file = File.createTempFile("upload-", ".bin", new File("/path/to/your/uploads"));
<br><br>
item.write(file);
<br><br></p>

Related

Unable to access the resources file in jar after packaging : FileSystemNotFoundException

Hi I am working on developing a small java application (kinda new to this ) which takes an input file and gives out an web page. Here the HTML template and an image file to the web page are in resource folder.
Below is the way I am accessing the html template file in my code.(I need to read the HTML template as an string)
{
String htmlString;
ClassLoader classLoader = getClass().getClassLoader();
URL fileurl = classLoader.getResource("template.html");
htmlString = String.join("\n", Files.readAllLines(Paths.get(fileurl.toURI())));
}
the code works fine when ran from eclipse but fails when I run it as an jar.(java.nio.file.NoSuchFileException:)
kindly help me in accessing the template file from resources folder and also note that the html takes an image from the same folder. Now the template and image file must be packaged and should be able to run as a single JAR .
update :
Extracted the jar file with 7-zip to see the contents. I can see the files in resources are available with the jar
Thanks!
You have packaged everything into a jar so the pathnames to resources is no longer a valid path to a file. If you added this logging you would see that the path to the jar entry says something like jar:file:/C:/path/to/your.jar!/template.html which cannot be opened by Files.readAllLines:
URI uri = fileurl.toURI();
System.out.println("uri="+uri);
The solution is easy, just locate the resource as InputStream which must be on the classpath:
String htmlString;
ClassLoader classLoader = getClass().getClassLoader();
try(InputStream in = classLoader.getResourceAsStream("template.html")) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
in.transferTo(out);
htmlString = new String(out.toByteArray()); // as platform encoding
}
This works if the res directory is part of your classpath when you run the code in exploded directory, and works in JAR file if the contents of "res" are inside the jar.

How can I get the Url of file that is outside the jar?

I have deployed spring boot app in exploded mode using maven-assembly-plugin. I have made config folder from project’s resource folder.
The problem is that I am not able to get the url to access the file that is in the config folder.
How can I get the url of the file that I have uploaded and stored at this config folder.
File structure
Target folder:
+springdemo-0.0.1-application.zip
+config
+myfolder
-oldfile.png
+springdemo-0.0.1.jar //running this jar file
+start.sh
-springdemo-0.0.1.jar
I want URL of files stored in myfolder. This url will be accessed by 3rd party(for ex. Picasso) to get file data. I am unable to get correct url pointing to this myfolder files.
Its easy, you need to provide the full path of the external application.properties file than what is present in your source code during the startup of the spring-boot.jar application at runtime.
Example: java -jar -Dspring.config.location=file://<>
This external file takes precedence over the one in our jar file.
Note: Not a SpringBoot-specific answer, just the simple Java way.
You can only try to guess the location of the file because there's no way to know the working directory when a Java application is run.
For example, you could try a very simple approach if you control how the Java application is executed:
var configFile = new File("config/application.properties");
This will works as long as the process is started from the same directory where start.sh is (which seems like what you intend).
If it doesn't work, try printing the working directory like this first:
System.out.println("WRK DIR = " + new File(".").getAbsolutePath());
This will tell you what the relative path to your file should be.
So, if this prints <root-dir>/springdemo and you know your config file is under <root-dir>/springdemo/mydir/config/, then the file path should be:
new File("mydir/config/application.properties");
By the way, you can easily read the file with:
// read file into List of lines
Files.readAllLines(configFile);
// specifically, for properties file
var props = new Properties();
props.load(new FileInputStream(configFile));
If for whatever reason you need an URL object instead of a File, it's easy, just call:
URL url = configFile.toURI().toURL()
If you want ALL files under the config dir, you can list them first with:
File[] files = configFile.getParentFile().listFiles();
if (files != null) {
for (File file : files) {
// use file?
}
}

File only accessible when placed in a location where it will be erased from the jar

I'm new to NetBeans IDE, and am struggling with accessing a file after building the jar file. After reading through many posts on this topic, I decided to try the following code:
BufferedReader read = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/file.txt")));
This works fine when my file is placed inside the "build" folder of the project where the .class files are, but of course this is a problem because it is erased in the "clean and build" process when the jar file is created. I have tried placing it in the src folder, in a separate "resources" package, and in the root of directory. I have also tried calling getResourceAsStream() with "file.txt" and "/src/file.txt," but it only works in the above configuration when the file is with the .class files. Any tips would be much appreciated!
Why not have your file folder inside the tomcat bin and refer the directory from your code. So maven clean will not alter the files and you can remove, update file without needing to restart the application. ( here i have file inside etc )
Path: /Users/username/Documents/apache-tomcat-8.5.15/bin/etc
ArrayList<String> readList = null;
String workingDir = System.getProperty("user.dir");
String fileName = "File.txt";
File file = new File(workingDir+"/etc/" + fileName);
readList = resourceReader.readFile(file.getAbsolutePath());
I have method readFile to parse some data and build the ArrayList in the above example.
Read about System Properties
Turns out the solution was really simple...I had been trying to manually create a resources folder, but the contents kept being deleted upon building of the jar. Instead, I created a resources package and put the file into the auto-generated folder inside the src folder, which packaged the file into the jar. Thanks everyone!

Where the file will be located while using IO Streams in Java In Eclipse IDE?

I want to print the output in a file. I am using PrintWriter IO stream to add the data to file. When I want to check it, I don't know where the file is located. I am using Eclipse IDE.
PrintWriter writer=new PrintWriter("output.txt","UTF-8");
writer.println("Barcode Reader");
So can any one point me to where the file will be located?
I had this problem initially when I switched to using Eclipse. The current relative path is set to the project directory. The following code snippet will explain this better.
Path currentRelativePath = Paths.get("");
String myPath = currentRelativePath.toAbsolutePath().toString();
System.out.println("Current relative path is: " + myPath);
Note that the Path object is received from a get method in Paths((plural)). They are located in java.nio.file.
Further information about this can be found in the Path Operations page.
Does that solve your problem?
It will be present in your project's root folder.
Just open your project folder from your workspace using Explorer and it will be there.
With a filename like "output.txt" it will be placed into the current working directory.
Unless you specify otherwise, in Eclipse that will be the root directory of your project.
You may have to click "Refresh" for it to show up in the File Explorer.
If you give you file name directly like C:\java\workspace\ocpjp7 (a Windows
directory) or /home/nblack/docs (the docs directory of user nblack on UNIX), you can find your file in those directories. But if you don't give the full path, it will be in your current working directory.
"output.txt" -> root
"src/resources/output.txt" -> in resources package
At first you should create this file with File in directory you want.Next step to write data into the file. Your file will be located in directory you want , you set when file has created.
Also check this class FileInputStream

Trying to update the file in src/web/prod folder (jsp)

I am using jboss, eclipse and svn together. I have to files in my test folder: test/create.jsp and test/data.txt . What I want to do is when I call my create.jsp it will update my data.txt . Obviously I want my data.txt to stay where it is as other scripts are tryong to read from it.
I have tried dozens of new ways to put the path to my File object but for some reason it creates the file under jboss war folders.
Tried:
ServletContext app = getServletContext();
String path1 = app.getRealPath("/");
File f = new File(path1);
// AND
File f = new File("../../data.txt");
Assuming that /test folder is located in the webcontent, then you need the following:
String absolutePath = getServletContext().getRealPath("/test/data.txt");
File file = new File(absolutePath);
or
String webcontentRoot = getServletContext().getRealPath("/");
File file = new File(webcontentRoot, "test/data.txt");
Do you see it? The Java IO only understands local disk file system paths, not URL's or paths outside the context. The ServletContext#getRealPath() is to be used to convert a relative web path to an absolute local disk file system path which in turn can be used further in the usual Java IO stuff. You should never use relative paths in Java IO stuff. You will be dependent on the current working directory which may differ per environment/situation.
That said, you normally don't want to write files to the webcontent. They will get lost whenever you redeploy the WAR. Rather create a fixed disk file system path somewhere else outside the webapp and make use of it. Or even better, make use of an independent SQL database :)

Categories