As part of a search application, I want the user to be able to download a report showing the results in a CSV file. I have the following method:
public void downloadCustomerResults(String customer) {
String output = "";
output += produceCustomerID(customer);
output += produceCustomerAddress(customer);
output += produceCustomerContactDetails(customer);
output += produceOrderHeader(customer);
output += producePayments(customer);
// Writes to server desktop, not user desktop.
try {
Writer fileWriter = new FileWriter("C:\\Users\\username\\Desktop\\SAR" + customer + "C.csv");
fileWriter.write(output);
fileWriter.flush();
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
This downloads the file to the desktop of the machine running the server, not the user's desktop (accessing the app via JSP's on Tomcat). How would I change the file path string to make this download to the users' desktop? Or would I have to pass the file to the JSP for the user to download via their browser?
Thanks.
Short answer: The server has no means of accessing the client's filesystem.
Longer answer: You might either provide a service for the client to download the file (e.g. a webservice accessible through a URI, like #Kayaman mentioned) or the client provides you a service to write the file (e.g. a remote file system, an FTP server etc.). For the latter there might be libraries providing a special java.nio.FileSystem extension.
You may also provide an application running on the client to receive the file. This client application will then have acces to the client's file systems (unless it lacks the access rights, of course).
So the answer I found was to use the JavaScript package FileSaver.js.
This accepts a blob created from a string, and then saves it with a filename of your choice to the browsers preferred download folder.
I managed to pass the string from Java to JavaScript, and then pass it through FileSaver.js in the .JSP page.
Related
I have a program that has to read a file from network location - something like this
String sFileSource = "//MyShared/location/fileName.txt" ;
File inputFile = new File(sFileSource);
try {
ffBuffer = new BufferedReader(new FileReader(inputFile));
}
catch (FileNotFoundException e) { // should never happen
}
Now, the problem is that that shared location is on the different network domain and accessible only using domain credentials
How can I embed entering the credentials into this java program ? The problem is that when ran from different PCs it fails due to login.
Reading a file like that is not a secure way to do it, because you will expose your user domain credentiels.
Reversing the java app could lead to that, so it's better to use an ftp server for that.
The way I have done it before:
Read remote file in java which needs username and password
I have Spring MVC web app running on Tomcat.
I upload a file and save it in the /tmp folder on the file system.
Then I need to show a link to that file in the view (Thymeleaf), so that the user can download the file by clicking on the link. How to do that?
I've heard about configuring Tomcat to allow a specific context to link to a folder on the FS, but not sure how to do that or if that is the only solution. Please help.
The way I approach this is slightly different. Basically I use two controller actions for handling file uploads, one for uploading, and for downloading (viewing) files.
So upload action would save files to some preconfigured directory on the file system, I assume you already have that part working.
Then declare download action similar to this
#Controller
public class FileController {
#RequestMapping("/get-file/{filename}")
public void getFileAction(#RequestParam filename, HttpServletResponse response) {
// Here check if file with given name exists in preconfigured upload folder
// If it does, write it to response's output stream and set correct response headers
// If it doesn't return 404 status code
}
}
If you want to make impossible to download file just by knowing the name, after uploading file, save some meta info to the database (or any other storage) and assign some hash (random id) to it. Then, in getFileAction, use this hash to look for file, not the original filename.
Finally, I would discourage using /tmp for file uploads. It depends on the system/application used, but generally temp directory are meant, as name suggest, for temporary data. Usually it is guaranteed data in the temp directory will stay for "reasonable time", but applications must take into account that content of temp directory can be deleted anytime.
This is the precisely setup that worked for me (Tomcat 8, SpringMVC, boot):
server.xml:
<Context docBase="C:\tmp\" path="/images" />
In the controller:
public String createNewsSource(#ModelAttribute("newsSource") NewsSource source, BindingResult result, Model model,
#RequestParam("attachment") final MultipartFile attachment) {
new NewsSourceValidator().validate(source, result);
if (result.hasErrors()) {
return "source/addNewSource";
}
if (!attachment.isEmpty()) {
try {
byte[] bytes = attachment.getBytes();
BufferedOutputStream stream = new BufferedOutputStream(
new FileOutputStream(new File("/tmp/" + attachment.getOriginalFilename())));
stream.write(bytes);
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
source.setLogo("images/" + attachment.getOriginalFilename());
newsSourceService.createNewsSourceIfNotExist(source);
return "redirect:/sources/list";
}
As you can see I am saving the file to /tmp, but in the DB (source.setLogo()), I am pointing to images as mapped in server.xml
Here's where I found about Tomcat config:
If the images are all located outside the webapp and you want to have
Tomcat's DefaultServlet to handle them, then all you basically need to
do in Tomcat is to add the following Context element to
/conf/server.xml inside tag:
This way they'll be accessible through http://example.com/images/....
SO answer to a similar question
I am developing a webapp (for mobile phones). There is one xhtml page, where I want to show a picture, which is stored locally on my hard drive (for example: D:\pictures\test.jpg).
Since browsers block images when they are located on a local harddrive, I wrote a method in my javabean, where the picture, stored on the localHD, is copied to the webApp directory, when the user enters the xhtml page. After the user leaves the page, the copied file inside the webapp should be deleted.
So when I'm running my app, copying works perfectly and the pictures are displayed correctly. However, when the files should get deleted, I get this errormessage:
java.nio.file.FileSystemException: D:\WebAppPath\src\main\webapp\resources\pics\test.jpg:
The process cannot be accessed because the file is being used by another process.
Strangely enough, after stopping and restarting the application I can delete the same image if it is still in the webApp directory. (But Only once; after re-copying it, I get the error message again.)
Also if I want to delete the file manually, by using Windows explorer, I get the error message that the file can't be deleted because it is used by Java(TM) Platform SE Binary.
So to delete the file (manually or via the bean) I have to wait for a restart of the application, which of course is not an acceptable solution for the end user.
I'm using JSF2.0 with Primefaces and Primefaces Mobile components. My IDE is Netbeans and I use Spring Webflow framework to navigate and trigger actions/methods between the xhtml pages.
Here's the code for the copying method in my JavaBean:
public void copyFotoToLocalhost() {
if (fotoList.size() > 0) {
for (int i = 0; i < fotoList.size(); i++) {
Foto tempPic = fotoList.get(i);
String tempItemName = tempPic.getItemName();
String originalFile = "D:\\localFilepath\\" + tempItemName;
String tempFileName = "D:\\WebAppPath\\src\\main\\webapp\\resources\\pics\\" + tempItemName;
File existTest = new File(tempFileName);
if (existTest.exists() == false) {
try {
File orFile = new File(originalFile);
File tempFile = new File(tempFileName);
InputStream in = new FileInputStream(orFile);
OutputStream out = new FileOutputStream(tempFile);
byte[] buf = new byte[8192];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
tempFile.setWritable(true);
System.out.println("File copied.");
} catch (FileNotFoundException ex) {
System.out.println(ex.getMessage() + " in the specified directory.");
System.exit(0);
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
}
}
Here's the code for the delete method:
public void deleteFotos() {
if (fotoList.size() > 0) {
for (int i = 0; i < fotoList.size(); i++) {
Foto tempPic = fotoList.get(i);
String tempItemName = tempPic.getItemName();
Path tempLocation = Paths.get("D:\\webAppPath\\src\\main\\webapp\\resources\\pics\\" + tempItemName);
fotoList.remove(i);
i--;
try {
Files.deleteIfExists(tempLocation);
System.out.println("sucessfully deleted" + tempPic.getItemName());
} catch (IOException ex) {
Logger.getLogger(WundDokuBean.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Fail # " + tempPic.getItemName());
}
}
fotoList.clear();
}
Do you have an idea, how to fix this?
I hope you understand my problem, if not please tell me which information you need, I'll try to provide it.
There is one xhtml page, where I want to show a picture, which is stored locally on my hard drive (for example: D:\pictures\test.jpg). Since browsers block images when they are located on a local harddrive (...)
I want to clear out a conceptual misunderstanding first: You seem to expect that it would work fine when the browser wouldn't have blocked it. This is completely untrue. You seem to expect that images are inlined in the HTML output. No, they are downloaded individually and independently from the HTML page. If you had continued to use local disk file system paths, then it would have worked only and only if your webpage visitor has also exactly the same file at exactly the same location at their disk file system. In reality, this is obviously not the case. It would only work if both the webbrowser and webserver runs at physically the same machine.
Coming back to your concrete problem of being unable to delete the file, it's is caused because the servletcontainer usually locks the files in expanded WAR folder. I can't tell the exact reason, but that's not relevant here as this whole approach is wrong anyway. This approach would fail when the deployed WAR file is not expanded on disk file system, but instead in server's memory. Also, hardcoding environment-specific disk file system paths is a bad idea. You'd need to edit, rewrite, recompile, rebuild the whole WAR everytime you change the environment. In other words, your webapp is not portable.
You need to keep the files there where they originally are and make them publicly available by a real URL. This can be achieved in 2 general ways:
Add a virtual host to the server config, pointing to D:\localFilepath\. How to achieve that depends on the server used. You didn't tell anything about the server make/version used, but using Spring suggests that you're not being able to use full Java EE stack and are likely using a barebones JSP/Servlet container such as Tomcat. In that case, it's a matter of adding the following line to its /conf/server.xml:
<Context docBase="D:\localFilepath" path="/fotos" />
This way they are available by http://localhost:8080/fotos/*.
Create a servlet which reads files from D:\localFilepath and writes to HTTP response. With Servlet 3.0 and Java 7 it's really a breeze. Here's a kickoff example (nullchecks/file-exist-checks/doHead()/caching/resuming omitted for brevity):
#WebServlet("/fotos/*")
public class FotosServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletExcpetion, IOException {
File file = new File("D:/localFilepath", request.getPathInfo().substring(1));
response.setHeader("Content-Type", getServletContext().getMimeType(file.getName()));
response.setHeader("Content-Length", String.valueOf(file.length()));
Files.copy(file.toPath(), response.getOutputStream());
}
}
That's basically it. This way they're available on http://localhost:8080/contextname/fotos/*.
I have a scheduled task running in JBoss 5.1 on a daily basis for sending birthday wishes.
The mail content is HTML and I embed images in the mail.
Now I would like to get the path of that image for embedding, how would it be possible to get path of image in a non-servelt environment.
Ofcourse I could have placed the images at a static location and accessed them, for which I don't want to hardcode the path.
The image is at "WebContent/images/birthday.jpg" location.
How are you generating the email content? Are these also static html files?
If you are going to use simple static html files, you will have to hard code the image paths. There is no other way around it.
You could write a simple Java application, which runs as a standalone application (without any servers,servlets etc), which will create the email content.
The java code can send out the emails for you too if you want.
These are some of the things you can do, if you use java
Use property files to specify the location of images. These are files which hold simple key/value pairs.
You can easily create multiple email content to different users, with the same template.
You will be able to easily redesign the html content for multiple users.
An example of using property files.
Create a file ex: "email_template.properties"
Enter the following into the file and save it.
image_server=http://www.mywebsite.com
image_folder=/WebContent/images/
Create a jave program to create your html email, and use the property file to generate the image locations.
Properties properties = new Properties();
try
{
properties.load(new FileInputStream("C://email_template.properties")); //specify path here
String sServerLocation = properties.getProperty("image_server");
String sImageFolder = properties.getProperty("image_folder");
StringBuilder strEmail = new StringBuilder();
strEmail.append("<html><body> <img src=\"" + sServerLocation + sImageFolder +"birthday.jsp\""> </body> </html>" );
// Write code to generate complete email dynamically
// write code to send out the email or to save as html file to you machine, where you can send it manually.
} catch (IOException e)
{
//
}
You get the idea. using plain html you will have to hard code.
However if you use a simple java file you can get more flexibility.
If you need code to send out email from java, check this link out.
How can I send an email by Java application using GMail, Yahoo, or Hotmail?
What is the best way to upload a directory in grails ?
I try this code :
def upload = {
if(request.method == 'POST') {
Iterator itr = request.getFileNames();
while(itr.hasNext()) {
MultipartFile file = request.getFile(itr.next());
File destination = new File(file.getOriginalFilename())
if (!file.isEmpty()) {
file.transferTo(destination)
// success
}
else
{
// failure
}
}
response.sendError(200,'Done');
}
}
Unfortunately, I can only upload file by file.
I would like to define my directory, and upload all files directly.
Any ideas ?
There is one major misconception here. The code which you posted will only work if both the server and the client runs at physically the same machine (which won't occur in real world) and if you're using the MSIE browser which has the misbehaviour to send the full path along the filename.
You should in fact get the contents of the uploaded file as an InputStream and write it to any OutputStream the usual Java IO way. The filename can be used to create a file with the same name at the server side, but you'll ensure that you strip the incorrectly by MSIE sent path from the filename.
As to your actual functional requirement, HTML doesn't provide facilities to upload complete directories or multiple files by a single <input type="file"> element. You'll need to create a client application which is capable of this and serve this from your webpage, like a Java Applet using Swing JFileChooser. There exist 3rd party solutions for this, like JumpLoader.