3

Problem Context:

I am trying to persist a file, uploaded by the user, to file system.

Description:

Actually, I am using Spring MVC (3.0) and this is how I am trying to persist the file,

String orgName = file.getOriginalFilename();
String filePath = "/Uploads/MyUploads/"+ new Date().getTime()+orgName;// Unique Image Name
File dest = new File(filePath);
file.transferTo(dest);

I have a folder Uploads\MarketplaceUploads, at the root of my application. But still I am getting FileNotFoundException "\Uploads\MyUploads\loading.gif (The system cannot find the path specified)".

Below is the directory structure:

enter image description here

Adeel Ansari
  • 39,541
  • 12
  • 93
  • 133
Imran Qadir Baksh - Baloch
  • 32,612
  • 68
  • 179
  • 322

3 Answers3

4

You should not store uploaded files in public web content.

  • It will not work in any way when the WAR is not expanded by the container (this is configureable at server level and not controllable whenever it's a 3rd party host). You simply can't write the uploaded file to it in any way.
  • All uploads will get lost whenever you redeploy (an update) of the WAR. You need to remember to backup them everytime.
  • In some servers, all uploads will also get lost whenver the server is restarted. You have no control over this whenever it's a 3rd party host.

Store them outside the server's webapps folder. Provide the root of this location as an absolute disk file system path to your webapp, e.g. by a properties file or a VM argument. An alternative is to store them in a database, this is often the only solution if it's a 3rd party host which doesn't offer access to a fixed location outside the web content.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Is you mean that I should give absolute path, e.g, C:\webapps\.... But I think this is a bad idea because I do not know the absolute location until the application is deployed in the original server. – Imran Qadir Baksh - Baloch Sep 28 '11 at 03:20
  • 2
    That's exactly why you need to make it configureable by e.g. a properties file or VM argument, as stated in the answer. If you find this a bad idea, fine, but don't complain at me once you lose all the uploaded files at some point. – BalusC Sep 28 '11 at 03:25
  • Thanks. However I don't see these type of problems in ASP.NET Frameworks., like, ASP.NET MVC. – Imran Qadir Baksh - Baloch Sep 28 '11 at 03:47
  • @user960567: ASP.NET or anything else, the suggestion still holds. – Adeel Ansari Sep 28 '11 at 06:46
  • @adeel-ansari: What do you mean?. BTW, I agree with balus that I should use a configuration key to store the root absolute path or use database instead. – Imran Qadir Baksh - Baloch Sep 28 '11 at 06:50
  • @adeel-ansari, this is really pain full for OP that you guys are down voting the question. Is the question does not make any sense? – Imran Qadir Baksh - Baloch Sep 28 '11 at 06:54
  • @user960567: Revoked the negative and reinstated the positive vote, after improving your question. You can fix it, if you find anything wrong with what I have written. BTW, I meant the directory having users uploads should not be the part of web application whatsoever. No matter if it is ASP.NET or Python. – Adeel Ansari Sep 28 '11 at 09:17
  • @adeel-ansari why? There is always a security risk to saving the file outside the application. This is the one of reason why third party host don't allow this. – Imran Qadir Baksh - Baloch Sep 28 '11 at 11:06
3

Ensure you add the web-app context path before using the file

String orgName = file.getOriginalFilename();
String filePath = getServletContext().getRealPath("/") + "/Uploads/MyUploads/"+ new Date().getTime()+orgName;// Unique Image Name
File dest = new File(filePath);
file.transferTo(dest);

From the javadoc of getRealPath()

Gets the real path corresponding to the given virtual path. For example, if path is equal to /index.html, this method will return the absolute file path on the server's filesystem to which a request of the form http://://index.html would be mapped, where corresponds to the context path of this ServletContext. The real path returned will be in a form appropriate to the computer and operating system on which the servlet container is running, including the proper path separators. Resources inside the /META-INF/resources directories of JAR files bundled in the application's /WEB-INF/lib directory must be considered only if the container has unpacked them from their containing JAR file, in which case the path to the unpacked location must be returned. This method returns null if the servlet container is unable to translate the given virtual path to a real path.

epoch
  • 16,396
  • 4
  • 43
  • 71
  • Thanks it work's. But still the file is saving in build directory. Is there is any way to save this image inside root application. Because every time I build the project all the uploaded file cleaned. So I need to save this image inside root or inside web folder(with CSS and Js folder). PLease help – Imran Qadir Baksh - Baloch Sep 27 '11 at 07:36
  • @user960567, when your application is deployed in production your root wont be available (i.e.) your development version, you will need to use a database to store your information, alternatively, the files wont disappear in production because you wont be redeploying. – epoch Sep 27 '11 at 08:04
2

Try this instead,

String orgName = file.getOriginalFilename();
// the leading slash is important
String filePath = "/Uploads/MyUploads/"+ new Date().getTime()+orgName; 
File dest = new File(req.getServletContext().getResource(filePath).toURI());
file.transferTo(dest);

Using getRealPath() is, indeed, a bad idea. Simply, because you are trying to read a resource which actually resides inside the application. Therefore, we need not use getRealPath(). Furthermore, if the application is being run from a bundled .war file, getRealPath() will return null.

Resources:

Community
  • 1
  • 1
Adeel Ansari
  • 39,541
  • 12
  • 93
  • 133
  • This is not working. I am getting the same error. I am looking actually the same which we use in ASP.NET environment, like Server.MapPath or string started with ~ sign – Imran Qadir Baksh - Baloch Sep 27 '11 at 07:41
  • @Adeel Ansari, can you please explain why it is a bad idea? – epoch Sep 27 '11 at 08:02
  • @epoch: Simply because you are trying to read a resource which actually resides inside the application. We need not use `getRealPath()`. Further, if the application is being run from a bundled `.war` file, `getRealPath()` will return `null`. – Adeel Ansari Sep 27 '11 at 08:11
  • @AdeelAnsari, that does not make it a bad idea, i use this in production systems, and it ensures the virtual path is correctly mapped to your application root.Further, that is not true, the web container still has a servlet context, the only reason it will return null is if the context does not exist or the translation cannot be performed – epoch Sep 27 '11 at 08:15
  • @epoch: Hope this thread, http://stackoverflow.com/questions/536228/why-does-getrealpath-return-null-when-deployed-with-a-war-file, will make things clear. Can't help much. – Adeel Ansari Sep 27 '11 at 08:31
  • @AdeelAnsari, Thanks adeel, the reason why it works for us is because our .war file is always expanded. I understand now that it will not work if the .war file is not expanded. – epoch Sep 27 '11 at 08:46
  • @AdeelAnsari, then what should I use. Your method is not working. – Imran Qadir Baksh - Baloch Sep 27 '11 at 09:13
  • @user960567: Try to keep your `Uploads` directory at the same level as your `WEB-INF` directory. – Adeel Ansari Sep 27 '11 at 09:33
  • It is in the same level. See above image, – Imran Qadir Baksh - Baloch Sep 27 '11 at 09:45
  • new Date().getTime() is just used for making the file name unique. I know there may be many other ways(like GUID,etc). With getRealPath everything is working just fine. – Imran Qadir Baksh - Baloch Sep 27 '11 at 10:06
  • @AdeelAnsari: serveletContext.getResource(filePath) is null. FYI, the file is not exist yet. I am uploading a file and saving it in disk. – Imran Qadir Baksh - Baloch Sep 27 '11 at 12:56