I am currently working on an application, where users are given an option to browse and upload excel file, I am badly stuck to get the absolute path of the file being browsed. As location could be anything (Windows/Linux).
import org.apache.myfaces.custom.fileupload.UploadedFile;
-----
-----
private UploadedFile inpFile;
-----
getters and setters
public UploadedFile getInpFile() {
return inpFile;
}
#Override
public void setInpFile(final UploadedFile inpFile) {
this.inpFile = inpFile;
}
we are using jsf 2.0 for UI development and Tomahawk library for browse button.
Sample code for browse button
t:inputFileUpload id="file" value="#{sampleInterface.inpFile}"
valueChangeListener="#{sampleInterface.inpFile}" />
Sample code for upload button
<t:commandButton action="#{sampleInterface.readExcelFile}" id="upload" value="upload"></t:commandButton>
Logic here
Browse button -> user will select the file by browsing the location
Upload button -> on Clicking upload button, it will trigger a method readExcelFile in SampleInterface.
SampleInterface Implementation File
public void readExcelFile() throws IOException {
System.out.println("File name: " + inpFile.getName());
String prefix = FilenameUtils.getBaseName(inpFile.getName());
String suffix = FilenameUtils.getExtension(inpFile.getName());
...rest of the code
......
}
File name : abc.xls
prefix : abc
suffix: xls
Please help me in getting the full path ( as in c:.....) of the file being browsed, this absolute path would then be passed to excelapachepoi class where it will get parsed and contents would be displayed/stored in ArrayList.
Why do you need the absolute file path? What can you do with this information? Creating a File? Sorry no, that is absolutely not possible if the webserver runs at a physically different machine than the webbrowser. Think once again about it. Even more, a proper webbrowser doesn't send information about the absolute file path back.
You just need to create the File based on the uploaded file's content which the client has already sent.
String prefix = FilenameUtils.getBaseName(inpFile.getName());
String suffix = FilenameUtils.getExtension(inpFile.getName());
File file = File.createTempFile(prefix + "-", "." + suffix, "/path/to/uploads");
InputStream input = inpFile.getInputStream();
OutputStream output = new FileOutputStream(file);
try {
IOUtils.copy(input, output);
} finally {
IOUtils.closeQuietly(output);
IOUtils.closeQuietly(input);
}
// Now you can use File.
See also:
How to get the file path from HTML input form in Firefox 3
I remember to have some problem with this in the past too. If I am not mistaken, I think you cannot get the full file path when uploading a file. I think the browser won't tell you it for security purposes.
Related
I have a problem with saving files and then downloading them after generating a .war file.
I need to handle the generation of many files after pressing the button by admin in the application. The files are generated using part of the code that was sent using the POST method and second part is from the database.
The files are hundreds / thousands and it is impossible to do it manually. Admin generates files from time to time. The user should be able to download these files from the application.
When I run the application in IntelliJ, app has access to the folders on the disk, so the following code works:
(part of backend class, responfible for saving files in path)
private void saveTextToFile(String text, String fileName) {
String filePathAndName = "/static/myFiles/" + fileName+ ".txt";
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource(".").getFile() + filePathAndName );
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter(file);
PrintWriter printWriter = new PrintWriter(fileWriter);
printWriter.print(text);
printWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
The file was saved in folder:
C:\Users...\myProject\target\classes\static.
(and this is link to generated file in thymeleaf)
<html xmlns:th="http://www.thymeleaf.org">
<a th:href="#{|/myFiles/${thisIsMyFileName}|}">Download file</a>
</html>
Unfortunately, when I generate the .war file and run it, the files are not saved in the application's "resources" folder. As a result, the user cannot download this file via the link generated by thymeleaf.
In general, you do not want to upload anything into your application's files - it opens you to many security problems if someone figures out how to overwrite parts of the application, and in most application servers, it is simply not writable.
A much better approach is to have a designated server folder where you can write things. For example, you could have the following in your configuration:
myapp.base-folder = /any/server/folder/you/want
And then, in the code, you would find that folder as follows:
// env is an #AutoWired private Environment
File baseFolder = new File(env.getProperty("myapp.base-folder"));
I find this better than using a database (as #Stultuske suggested in comments), because databases are great for relations, but mostly overkill for actual files. Files can be accessed externally without firing up the database with minimal hassle, and having them separate keeps your database much easier to backup.
To generate links to the file, simply create a link as you would to any other type of request
<a th:href="#{/file/${fileId}|}">Download file</a>
-- and to handle it in the server, but returning the contents of the file:
#GetMapping(value="/file/{id}")
public StreamingResponseBody getFile(#PathVariable long id) throws IOException {
File f = new File(baseFolder, ""+id); // numerical id prevents filesytem traversal
InputStream in;
if (f.exists()) {
in = new BufferedInputStream(new FileInputStream(f));
} else {
// you could also signal error by returning a 404
in = new BufferedInputStream(getClass().getClassLoader()
.getResourceAsStream("static/img/unknown-id.jpg"));
}
return new StreamingResponseBody() {
#Override
public void writeTo(OutputStream os) throws IOException {
FileCopyUtils.copy(in, os);
}
};
}
I prefer numerical IDs to avoid hassles with path traversal - but you can easily use string filenames instead, and deal with security issues by carefully checking that the canonical path of the requested file starts with the canonical path of your baseFolder
I would like to be able to upload files in my JSF2.2 web application, so I started using the new <h:inputFile> component.
My only question is, how can I specify the location, where the files will be saved in the server? I would like to get hold of them as java.io.File instances. This has to be implemented in the backing bean, but I don't clearly understand how.
JSF won't save the file in any predefined location. It will basically just offer you the uploaded file in flavor of a javax.servlet.http.Part instance which is behind the scenes temporarily stored in server's memory and/or temporary disk storage location which you shouldn't worry about.
Important is that you need to read the Part as soon as possible when the bean action (listener) method is invoked. The temporary storage may be cleared out when the HTTP response associated with the HTTP request is completed. In other words, the uploaded file won't necessarily be available in a subsequent request.
So, given a
<h:form enctype="multipart/form-data">
<h:inputFile value="#{bean.uploadedFile}">
<f:ajax listener="#{bean.upload}" />
</h:inputFile>
</h:form>
You have basically 2 options to save it:
1. Read all raw file contents into a byte[]
You can use InputStream#readAllBytes() for this.
private Part uploadedFile; // +getter+setter
private String fileName;
private byte[] fileContents;
public void upload() {
fileName = Paths.get(uploadedFile.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
try (InputStream input = uploadedFile.getInputStream()) {
fileContents = input.readAllBytes();
}
catch (IOException e) {
// Show faces message?
}
}
Note the Path#getFileName(). This is a MSIE fix as to obtaining the submitted file name. This browser incorrectly sends the full file path along the name instead of only the file name.
In case you're not on Java 9 yet and therefore can't use InputStream#readAllBytes(), then head to Convert InputStream to byte array in Java for all other ways to convert InputStream to byte[].
Keep in mind that each byte of an uploaded file costs one byte of server memory. Be careful that your server don't exhaust of memory when users do this too often or can easily abuse your system in this way. If you want to avoid this, better use (temporary) files on local disk file system instead.
2. Or, write it to local disk file system
In order to save it to the desired location, you need to get the content by Part#getInputStream() and then copy it to the Path representing the location.
private Part uploadedFile; // +getter+setter
private File savedFile;
public void upload() {
String fileName = Paths.get(uploadedFile.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
savedFile = new File(uploads, fileName);
try (InputStream input = file.getInputStream()) {
Files.copy(input, savedFile.toPath());
}
catch (IOException e) {
// Show faces message?
}
}
Note the Path#getFileName(). This is a MSIE fix as to obtaining the submitted file name. This browser incorrectly sends the full file path along the name instead of only the file name.
The uploads folder and the filename is fully under your control. E.g. "/path/to/uploads" and Part#getSubmittedFileName() respectively. Keep in mind that any existing file would be overwritten, you might want to use File#createTempFile() to autogenerate a filename. You can find an elaborate example in this answer.
Do not use Part#write() as some prople may suggest. It will basically rename the file in the temporary storage location as identified by #MultipartConfig(location). Also do not use ExternalContext#getRealPath() in order to save the uploaded file in deploy folder. The file will get lost when the WAR is redeployed for the simple reason that the file is not contained in the original WAR. Always save it on an absolute path outside the deploy folder.
For a live demo of upload-and-preview feature, check the demo section of the <o:inputFile> page on OmniFaces showcase.
See also:
Write file into disk using JSF 2.2 inputFile
How to save uploaded file in JSF
Recommended way to save uploaded files in a servlet application
I am working on a web application in which it takes action log for every minute i.e.., any action performed will be appended into a text file with current date as its name and if no action performed then it will append current time stamp in that same file. So for everyday one new file will be created and action performed will be appended in that file for that whole day. What I want now is, all those files are present in D:\ -->(presentdate)<--.txt and when I give a particular date in the same format as that of file name in the "text field" and click on submit in my web application it has to show that file present in D drive as a hyper link(if present in the drive) and when I click on the hyperlink it should simply show the content in that file. I want to know how to search for a file in particular folder/drive without mentioning file name directly but searching for files which are having file names in specific format(Example: 27_06_2014.txt).Any suggestions will be very helpful.
Thank you.
String path = "D:" + File.pathSeparator + fileSearched + ".txt";
File f = new File(path);
if(f.exists()) {
//do your stuff
}
//I dont know why would you like to search them as a list but anyways
File dir = new File("D:");
dir.mkdir();
for(String s : dir.list()){
if(s.equalsIgnoreCase(fileSearched)){
//do your stuff
}
}
Here's the documentation for the java.io.File class
Play 2.2.3. Windows 7.
public static Result menu() throws IOException {
String path = Play.application().resource("resources/menu.json").toString();
String content = Files.toString(new File(path), Charsets.UTF_8);
return ok(content).as("JSON");
}
Got an error:
... scala-2.10\classes\resources\menu.json The filename, directory
name, or volume label syntax is incorrect
Checking that path in file-system, I'm able to find my file there:
..\target\scala-2.10\classes\resources\menu.json
I'm able to find it there. Why play can't?
--
UPDATE:
I've just figured out I can not create files on C:\ root folder on my machine. That maybe the issue. But on other hand I'm not accessing root folder, and ad trying to get read only access. And I do have write access to that file on that path anyway.
As actually you want to use your menu.json file as a static asset you can put it i.e. into public/resources/menu.json file and then read it with simple:
<script>
$.get('#routes.Assets.at("resources/menu.json")');
</script>
or just directly by request:
http://localhost:9000/assets/resources/menu.json
To do what you want via controller you need to read the InputStream by classpath (remember that finally it will be archived into jar file!) but it need to be placed in conf folder i.e.: conf/resources/menu.json then from controller:
public static Result menuViaControllerJson() {
InputStream is = Play.application().classloader().getResourceAsStream("resources/menu.json");
return (is != null)
? ok(is)
: notFound();
}
Anyway you will get exactly the same result as for common Assets.at, so consider if it's worth of effort.
Edit: If you want to use this file as custom config just use HOCON syntax file i.e.: conf/ses.conf:
foo = "bar"
and in controller:
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
....
Config cfg = ConfigFactory.parseResources(Play.application().classloader(), "ses.conf");
debug("My 'foo' is configured as: " + cfg.getString("foo"));
Using Tomcat and Struts 2.
public FileAction class
{
......
public upload()
{
.....
String fullFileName = request.getContextPath() + "/productImages/" + filename;
File theFile = new File(fullFileName);
FileUtils.copyFile(upload, theFile);
.....
}
}
The problem is when I upload an image it will not add image in localhost:8085/shoppingCart/productImages and also not give any exception.
But when i write String fullFileName="c:upload/productImages/" + filename; it will save the file at c:upload/productImages/ path
mean working normal in c:upload/productImages/ case
If you want the file uploaded to the server's context, you need to use ServletContext.getRealPath(...) to find the base directory of the deployed application. Note that this will not work if you're deploying a war file. Uploaded files should go to an absolute location on the server itself.
For downloading an uploaded image you'd write a stream result (since you're using Struts 2) and use it to load and stream the uploaded file back to the client.