Download CSV file via Rest - java

Using OpenCSV, I can successfully create a CSV file on disc, but what I really need is to allow users download the CSV with a download button, I don't need to save on disk, just download. Any ideas?
#GET
#Path("/downloadCsv")
public Object downloadCsv() {
CSVWriter writer;
FileWriter wr;
//Or should I use outputstream here?
wr= new FileWriter("MyFile.csv");
writer = new CSVWriter(wr,',');
for (Asset elem: assets) {
writer.writeNext(elem.toStringArray());
}
writer.close();
}
EDIT: I do NOT want to save/read file on disc EVER

To force "save as", you need to set the content disposition HTTP header in the response. It should look like this:
Content-Disposition: attachment; filename="whatever.csv"
It looks like you're using JAX-RS. This question shows how to set the header. You can either write the CSV to the HTTP response stream and set the header there or return a Response object like so:
return Response.ok(myCsvText).header("Content-Disposition", "attachment; filename=" + fileName).build();
You do not need to write to a File object in the middle of this process so can avoid writing to disk.

First, you code cannot be compiled, right? Method downloadCsv() declares return type Object but does not return anything.
I'd change the declaration to String downloadCsv() and return the content of CSV as string. To do this use StringWriter instead of FileWriter and then say return wr.toString().
The only thing that is missing here is content type. You annotate your method as #Produces({"text/csv"}).
I think, that's it.

response.setHeader("Content-Disposition", "attachment; filename=" + filename + ".csv");
response.setContentType("text/csv");
OutputStreamWriter osw = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
List<String[]> result = iSmsExportService.csvExport(columnNames);
CSVWriter csvWriter = new CSVWriter(osw, ';');
csvWriter.writeAll(result);
csvWriter.flush();
csvWriter.close();
Downloading of CSV file has started after this.

Related

Is there a way to provide file download without reading the file from path in Java?

In my program I have a getRequest (JavaSpark) that offers me an Excel file created in Java for download.
To do this, I create the Excel file, save it in a folder and then read the file via the path.
Works.
Code - ExcelCreation:
public void createPlanWorkbook() throws Exception {
...
...
do something with workbook...
workBook.write("C:\\Users\\Develope\\Desktop\\Excel.xlsm");
}
Code - request:
get("/excelfile", ((request, response) -> {
response.header("Content-disposition", "attachment; filename=Excel.xlsm;");
File file = new File("C:\\Users\\Develope\\Desktop\\Excel.xlsm");
OutputStream outputStream = response.raw().getOutputStream();
outputStream.write(Files.readAllBytes(file.toPath()));
outputStream.flush();
return response;
}));
I wonder if there is another way to implement this. Is the step of saving and then reading the file necessary? Or is there a way to put the file directly from Javaobject into the request.
For example:
outputStream.write(ExcelCreaterObject().getWorkbook());
It seems that you are using Apache POI SmartXls to create an Excel workbook. Looking at its Javadoc, it seems that the Workbook.write method accepts an outputstream to write to.
So, you should be able to do write to the response stream directly, something like:
get("/excelfile", ((request, response) -> {
response.header("Content-disposition", "attachment; filename=Excel.xlsm;");
File file = new File("C:\\Users\\Develope\\Desktop\\Excel.xlsm");
OutputStream outputStream = response.raw().getOutputStream();
// do some stuff with the workbook
workbook.write(outputStream);
return response;
}));

Return a file from java method

I have created a method which accepts the JSON response and export the data to Excel and CSV file. I want the method to accept the filename as a parameter, and return the File/FileHandle object from the method.
Can anyone help me regarding this?
I am using below code to export data from creteExcel and createCSV.
public void createExcel( PageModel pageModelRequest,PageModel pageModelResponse ){
FileOutputStream outputStream=new FileOutputStream(new File("GridData.xlsx"));
createGrid(pageModelResponse, sheet, workbook);
workbook.write(outputStream);
System.out.println("Excel Written");
outputStream.close();
workbook.close();
}
public void createCSV(PageModel pageModelRequest,PageModel pageModelResponse){
String csvFile = "/Users/abhinak4/Desktop/GridData.csv";
FileWriter writer = new FileWriter(csvFile);
createGrid(pageModelRequest, pageModelResponse, writer);
}
In the method createGrid, I am creating the workbook for excel, and I am appending the data, to the writer (writer.append).
I want to know, how can I accept the fileName as parameters for createExcel and createCSV method, and return the file with the same name containing the data?
I want the method to accept the filename as parameter : You can send a String, A File Object or InputStream - createExcel(PageModel req, PageModel resp, File yourFileObj) And return the File object from the method : The signature becomes: public File createExcel()
Use this way and you are able to get a file object
File file = new File(fileName);
FileOutputStream outputStream = new FileOutputStream(file);
workBook.write(outputStream);
My details explanation answer was deleted by someone so I explained here

File Download Java without Temporary file

I am trying to create a file and send as a response so that file can be downloaded. I am not sure how to do it. My current code
String fileName = "fileToBeSaved.csv";
File file = new File(fileName);
FileWriter writer = new FileWriter(file);
writer.append(data);
writer.flush();
writer.close();
Response.ResponseBuilder response = Response.ok((Object) file);
response.header("Content-Disposition","attachment; filename=\"fileName.csv\"");
return response.build();
This code creates a temporary file on my system. And when the browser receives the response it gets the path to file, like "C:/folderName/FileName"...Upon mentioning this path on the browser, I get the option to download the file.
What I want to achieve is:
I want to create a file (But don't want any temporary file to be created on my system) and send as a response. The browser should receive a prompt asking whether to download the file or not as a response.
Can some one guide me what am I doing wrong?
I finally found the way.
Response.ResponseBuilder response = Response.ok();
response.header("Content-Disposition", "attachment; filename=\"filename.csv\"");
response.entity(contentAsString);
return response.build();
If you cannot build a string out of the contents of the file, then a work-around is:
ByteArrayOutputStream bo = new ByteArrayOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(bo));
//for loop can be any content.. I am just showing a represenatation.
for (int i = 0; i < content.size(); i++) {
writer.write(content.get(i));
}
writer.flush();
Response.ResponseBuilder response = Response.ok();
response.type(MediaType.APPLICATION_OCTET_STREAM);
response.header("Content-Disposition", "attachment");
response.entity(bo.toByteArray());
return response.build();
In the above code, I am building a file and sending to GUI. No temporary file was created.
Hope it helps.
Thanks!

Create and download CSV file in a Java servlet

I am working on Java ExtJS application in which I need to create and download a CSV file.
On clicking a button I want a CSV file to be downloaded to a client's
machine.
On buttons listener I am calling a servlet using AJAX. There I am
creating a CSV file.
I don't want the CSV file to be saved in the server. I want the file should be created dynamically with a download option. I want the contents of a file to be created as a string and then I will serve the content as file in which it will open as download mode in browser (this I have achieved in other language, but not sure how to achieve it in Java).
Here is my code only to create a CSV file, but I really don't want to create or save CSV file if I can only download the file as CSV.
public String createCSV() {
try {
String filename = "c:\\test.csv";
FileWriter fw = new FileWriter(filename);
fw.append("XXXX");
fw.append(',');
fw.append("YYYY");
fw.append(',');
fw.append("ZZZZ");
fw.append(',');
fw.append("AAAA");
fw.append(',');
fw.append("BBBB");
fw.append('\n');
CSVResult.close();
return "Csv file Successfully created";
} catch(Exception e) {
return e.toString();
}
}
Can any one help me on this.
Thanks
I got the solution and I am posting it below.
public void doGet(HttpServletRequest request, HttpServletResponse response)
{
response.setContentType("text/csv");
response.setHeader("Content-Disposition", "attachment; filename=\"userDirectory.csv\"");
try
{
OutputStream outputStream = response.getOutputStream();
String outputResult = "xxxx, yyyy, zzzz, aaaa, bbbb, ccccc, dddd, eeee, ffff, gggg\n";
outputStream.write(outputResult.getBytes());
outputStream.flush();
outputStream.close();
}
catch(Exception e)
{
System.out.println(e.toString());
}
}
Here we don't need to save / store the file in the server.
Thanks
First of all you need to get the HttpServletResponse object so that you can stream a file into it.
Note : This example is something I Wrote for one of my projects and it works.Works on Java 7.
Assuming you got the HttpServletResponse you can do something like this to stream a file. This way the file will be saved into clients' machine.
public void downloadFile(HttpServletResponse response){
String sourceFile = "c:\\source.csv";
try {
FileInputStream inputStream = new FileInputStream(sourceFile);
String disposition = "attachment; fileName=outputfile.csv";
response.setContentType("text/csv");
response.setHeader("Content-Disposition", disposition);
response.setHeader("content-Length", String.valueOf(stream(inputStream, response.getOutputStream())));
} catch (IOException e) {
logger.error("Error occurred while downloading file {}",e);
}
}
And the stream method should be like this.
private long stream(InputStream input, OutputStream output) throws IOException {
try (ReadableByteChannel inputChannel = Channels.newChannel(input); WritableByteChannel outputChannel = Channels.newChannel(output)) {
ByteBuffer buffer = ByteBuffer.allocate(10240);
long size = 0;
while (inputChannel.read(buffer) != -1) {
buffer.flip();
size += outputChannel.write(buffer);
buffer.clear();
}
return size;
}
}
What this does is, get an inputstream from your source file and write that stream into the outputstream of the HttpServletResponse. This should work since it works perfectly for me. Hope this helps. Sorry for my bad English.
I would like add something to the answer by gaurav. I recently had to implment this functionality in a project of mine and using javascript was out of the question becuase we had to support IE 9. What is the problem with IE 9?
(Export to CSV using jQuery and html), see the second answer in the link.
I needed an easy way to convert a ResultSet of a database query to a string which represent the the same data in CSV format. For that I used http://opencsv.sourceforge.net/ which provided an easy way to get a String ot of the ResultSet, and the rest is as above answer did it.
THe examples in the project soruce folder give good examples.

How do I return a zip file to the browser via the response OutputStream?

In this situation, I have created a zip file containing search result files, and am trying to send it to the user. Here is the chunk of code I am currently trying to use.
File[] zippable = new File[files.size()];
File resultFile = ZipCreator.zip(files.toArray(zippable), results);
InputStream result = new FileInputStream(resultFile);
IOUtils.copy(result, response.getOutputStream());
However, this currently doesn't work quite right. Instead of returning the zip file that I have created, it returns an html file. If I manually change the file extension afterwards, I can see that the contents of the file are still the search results that I need. So the problem just lies in returning the proper extension to the response.
Does anyone have any advice for this situation?
You need to set the Content-Type response header to the value application/zip (or application/octet-stream, depending on the target browser). Additionally, you may want to send additional response headers indicating attachment status and filename.
You need to set the content type header to application/octet-stream prior to streaming the results. Depends on what implementation of response you are using on how you actually do this.
Here is some working code, just in case anyone needs it:
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
// The zip file you want to download
File zipFile = new File(zipsResourcesPath + zipFileName);
response.setContentType("application/zip");
response.addHeader("Content-Disposition", "attachment; filename=" + zipFileName);
response.setContentLength((int) zipFile.length());
try {
FileInputStream fileInputStream = new FileInputStream(zipFile);
OutputStream responseOutputStream = response.getOutputStream();
int bytes;
while ((bytes = fileInputStream.read()) != -1) {
responseOutputStream.write(bytes);
}
} catch (IOException e) {
logger.error("Exception: " + e);
}
}
And the HTML:
<a class="btn" href="/path_to_servlet" target="_blank">Download zip</a>
Hope this helps!
So I found a hack for this : ) Just add ".zip" in your filename and set your content type as application/zip. Works like a charm.
response.setContentType("application/zip");
String licenseFileName = eId;
response.setHeader("Content-disposition", "attachment; filename=\"" + licenseFileName +".zip");

Categories

Resources