Spring: how to download file? - java

I want to save zip archive from server to user computer. I have web page that shows some information about this file and has a download button. In my controller action on button simply redirect on homepage but I want to get data from database and save it to user machine with path is defined by user
The issue is that I don't know how I can get this path. Could you give me an example how I can do that?

In your controller method you can add this code to get file download
File file = new File("fileName");
FileInputStream in = new FileInputStream(file);
byte[] content = new byte[(int) file.length()];
in.read(content);
ServletContext sc = request.getSession().getServletContext();
String mimetype = sc.getMimeType(file.getName());
response.reset();
response.setContentType(mimetype);
response.setContentLength(content.length);
response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
org.springframework.util.FileCopyUtils.copy(content, response.getOutputStream());

You don't have to know how to get the path, because the path is defined by the user :) But if your looking for the download path, check the source code of the website and where the download button links to. Usually you can see it in the beginning of the <form>.
If you are just looking for download a file:
public void download(String filename, String url) {
URL u;
InputStream is = null;
DataInputStream dis;
String s;
try{
u = new URL(url);
// throws an IOException
is = u.openStream();
dis = new DataInputStream(new BufferedInputStream(is));
FileWriter fstream = new FileWriter(filename);
BufferedWriter out = new BufferedWriter(fstream);
while ((s = dis.readLine()) != null) {
// Create file
out.write(s);
//Close the output stream
out.close();
}
}catch (Exception e){ //Catch exception if any
System.err.println("Error: " + e.getMessage());
}
is.close();
}
Hope this helps...

If you want to download from some external URL or from S3:::
#RequestMapping(value = "asset/{assetId}", method = RequestMethod.GET)
public final ResponseEntity<Map<String, String>> fetch(#PathVariable("id") final String id)
throws IOException {
String url = "<AWS-S3-URL>";
HttpHeaders headers = new HttpHeaders();
headers.set("Location", url);
Map<String, String> map = null;
ResponseEntity<Map<String, String>> rs =
new ResponseEntity<Map<String, String>>(map, headers, HttpStatus.MOVED_PERMANENTLY);
return rs;
}

Related

How to ZIP the downloaded file using spring boot

I am beginner in java and would like some assistance with zipping a downloaded file using rest api call to MSSQL backend. Below is the code snippet which takes the ID as input parameter, fetches the record specific for that ID and downloads it locally.
I now need the code modified to Zip the file when it is downloading.
#GetMapping("/message/save")
#CrossOrigin(origins = "*")
public ResponseEntity<byte[]> download(#RequestParam("id") Long id) throws Exception {
Optional<MessageEntity> messageRecord = messageRepository.findById(id);
MessageEntity messageEntity = messageRecord.get();
ObjectMapper objectMapper = new ObjectMapper();
String xml = objectMapper.writeValueAsString(messageEntity);
byte[] isr = xml.getBytes();
String fileName = "message.zip";
HttpHeaders respHeaders = new HttpHeaders();
respHeaders.setContentLength(isr.length);
respHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
respHeaders.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);
return new ResponseEntity<byte[]>(isr, respHeaders, HttpStatus.OK);
}
I expect the output to be a zipped file.
I'm not sure that I understood your problem clearly. But I assume that you need just make zip from string:
#GetMapping("/message/save")
#CrossOrigin(origins = "*")
public void download(#RequestParam("id") Long id, HttpServletRequest request,
HttpServletResponse response) throws Exception {
MessageEntity messageEntity = messageRepository.findById(id).orElseThrow(() -> new Exception("Not found!"));
String xml = new ObjectMapper().writeValueAsString(messageEntity);
String fileName = "message.zip";
String xml_name = "message.xml";
byte[] data = xml.getBytes();
byte[] bytes;
try (ByteOutputStream fout = new ByteOutputStream();
ZipOutputStream zout = new ZipOutputStream(fout)) {
zout.setLevel(1);
ZipEntry ze = new ZipEntry(xml_name);
ze.setSize(data.length);
zout.putNextEntry(ze);
zout.write(data);
zout.closeEntry();
bytes = fout.getBytes();
}
response.setContentType("application/zip");
response.setContentLength(bytes.length);
response.setHeader("Content-Disposition",
"attachment; "
+ String.format("filename*=" + StandardCharsets.UTF_8.name() + "''%s", fileName));
ServletOutputStream outputStream = response.getOutputStream();
FileCopyUtils.copy(bytes, outputStream);
outputStream.close();
}

Spring REST - Damaged/Blank File being downloaded

I am trying to create a endpoint to render/serve PDF file.
I have gone through the following links to build the API, but still facing some issues.
link 1
link 2
Following is my code :
byte[] targetArray = null;
InputStream is = null;
InputStream objectData = object.getObjectContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(objectData));
char[] charArray = new char[8 * 1024];
StringBuilder builder = new StringBuilder();
int numCharsRead;
while ((numCharsRead = reader.read(charArray, 0, charArray.length)) != -1) {
builder.append(charArray, 0, numCharsRead);
}
reader.close();
objectData.close();
object.close();
targetArray = builder.toString().getBytes();
is = new ByteArrayInputStream(targetArray);
return ResponseEntity.ok().contentLength(targetArray.length).contentType(MediaType.APPLICATION_PDF)
.cacheControl(CacheControl.noCache()).header("Content-Disposition", "attachment; filename=" + "testing.pdf")
.body(new InputStreamResource(is));
When I hit my API using postman, I am able to download PDF file but the problem is it is totally blank. What might be the issue ?
There are multiple ways to download files from server, you can use ResponseEntity<InputStreamResource>, HttpServletResponse.Below are the two methods to download.
#GetMapping("/download1")
public ResponseEntity<InputStreamResource> downloadFile1() throws IOException {
File file = new File(FILE_PATH);
InputStreamResource resource = new InputStreamResource(new FileInputStream(file));
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment;filename=" + file.getName())
.contentType(MediaType.APPLICATION_PDF).contentLength(file.length())
.body(resource);
}
OR
You can use StreamingResponseBody to download large files. In this case server writes data to OutputStream at same time Browser read data which means its parallel.
#RequestMapping(value = "downloadFile", method = RequestMethod.GET)
public StreamingResponseBody getSteamingFile(HttpServletResponse response) throws IOException {
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=\"demo.pdf\"");
InputStream inputStream = new FileInputStream(new File("C:\\demo-file.pdf"));
return outputStream -> {
int nRead;
byte[] data = new byte[1024];
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
System.out.println("Writing some bytes..");
outputStream.write(data, 0, nRead);
}
};
}
You can try to use apache commons IOUtils. Why reinvent wheel :)
1. Open a connection to remote server
2. Copy the inputStream to the destination file outputStream.
public void downloadFileFromRemoteLocation(String serverlocation, File destinationFile) throws IOException
{
try (FileOutputStream fos = new FileOutputStream( destinationFile )){
URL url = new URL(serverlocation);
URLConnection connection = url.openConnection();
IOUtils.copy( connection.getInputStream(), fos);
}
}
if you want to stick to just Java then look at snippet below
try {
// Get the directory and iterate them to get file by file...
File file = new File(fileName);
if (!file.exists()) {
context.addMessage(new ErrorMessage("msg.file.notdownloaded"));
context.setForwardName("failure");
} else {
response.setContentType("APPLICATION/DOWNLOAD");
response.setHeader("Content-Disposition", "attachment"+
"filename=" + file.getName());
stream = new FileInputStream(file);
response.setContentLength(stream.available());
OutputStream os = response.getOutputStream();
os.close();
response.flushBuffer();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Spring OutputStream - download pptx with IE

I use this Java code to download files from a web application:
#RequestMapping(value = "/filedownloads/filedownload/{userid}/{projectid}/{documentfileid}/{version}/", method = RequestMethod.GET)
public void filesDownload(final #PathVariable("userid") String userId, final #PathVariable("projectid") String projectId,
final #PathVariable("documentfileid") String documentFileId, final #PathVariable("version") String version,
final HttpServletResponse response) throws IOException, BusinessException {
...
final String fileName = "filename=" + documentFile.getFileName();
final InputStream is = new FileInputStream(filePath);
response.setHeader("Content-Disposition", "inline; " + fileName);
IOUtils.copy(is, response.getOutputStream());
response.flushBuffer();
}
if I will download a pptx- file I get the following IE- page:
What I want to do is to open the downloaded file in Powerpoint.
My question now would be if there is a header setting in order to open this file with the right application (in this case Powerpoint)
Simply try to set the Content Type header properly which is application/vnd.openxmlformats-officedocument.presentationml.presentation in case a pptx, as next:
response.setContentType(
"application/vnd.openxmlformats-officedocument.presentationml.presentation"
);
response.setHeader(
"Content-Disposition",
String.format("inline; filename=\"%s\"", documentFile.getFileName())
);
response.setContentLength((int) new File(filePath).length());
Here is the list of mime types corresponding to Office 2007 documents.
Here is a little sample code from a Spring MVC Controller:
#RequestMapping("/ppt")
public void downloadPpt(HttpServletRequest request, HttpServletResponse response) throws IOException {
Resource resource = new ClassPathResource("Presentation1.pptx");
InputStream resourceInputStream = resource.getInputStream();
response.setHeader("Content-Disposition", "attachment; filename=\"Presentation1.pptx\"");
response.setContentLengthLong(resource.contentLength());
byte[] buffer = new byte[1024];
int len;
while ((len = resourceInputStream.read(buffer)) != -1) {
response.getOutputStream().write(buffer, 0, len);
}
}
By setting the Content-Disposition to attachment, you're telling the browser to download this file as an attachment and by supplying the correct file name with extension, you're telling the Operating System to use whatever application the user normally uses to open a file of this type. In this case it will be MS Power Point.
This way you can get away with not knowing exactly what version of Power Point the file was created with.
I have tested code in IE-11 its work fine. See below code i.e
#RequestMapping(value = "/downloadfile", method = RequestMethod.GET)
#ResponseBody
public void downloadfile(HttpServletRequest request, HttpServletResponse response) throws Exception {
ServletOutputStream servletOutputStream = null;
try {
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=downloadppt.pptx");
byte[] ppt = downloadFile();
servletOutputStream = response.getOutputStream();
servletOutputStream.write(ppt);
} catch (Exception e) {
throw e;
} finally {
servletOutputStream.flush();
servletOutputStream.close();
}
}
Generate bytes from saved pptx file.
public byte[] downloadFile() throws IOException {
InputStream inputStream = new FileInputStream(new File("e:/testppt.pptx"));
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
// Transfer bytes from source to destination
byte[] buf = new byte[1024];
int len;
while ((len = inputStream.read(buf)) > 0) {
byteArrayOutputStream.write(buf, 0, len);
}
inputStream.close();
byteArrayOutputStream.close();
return byteArrayOutputStream.toByteArray();
}
That's it, you are able to download pptx file. Hope code help you, if you have any query or doubt then we can discuss or if any suggestions. Thank you

how to provide download option for the dynamically generated file in java

I am creating pdf file using jasper reports. The code for generating the pdf file runs fine and the file is created on a specified path. But I want the file to be downloaded rather than to be stored on some drive of a client. I use word dynamically in my question because it is generated from jasper reports when user clicks on download. I googled for this and I got that response.setHeader is responsible for downloading but it needs a source or we can say that path of the storage. The code for generating pdf is given below.
String ip="D:\\workspace\\Jsaper1\\src\\Coll.jasper";
String op="D:\\workspace\\Jsaper1\\src\\Timesheet.pdf";
try
{
File file=new File(ip);
InputStream is=new FileInputStream(file);
Map<String, Object> params = new HashMap<String, Object>();
Datasource da=new Datasource();
JRDataSource jrdsource=new JRBeanCollectionDataSource(da.getDataSource());
JasperReport jreport=(JasperReport) JRLoader.loadObject(file);
JasperPrint jasperPrint = JasperFillManager.fillReport(jreport, params, da.getDataSource1());
JasperExportManager.exportReportToPdfFile(jasperPrint, op);
sos.flush();
sos.close();
}
catch(Exception e)
{
e.printStackTrace();
}
Since the generated file is already written in the disk, you can just open it then write to the response' OutputStream. Use IOUtils#copy from Apache to copy the content of input stream to an output stream avoiding the boilerplate. It also does internal buffering so no need to wrap your InputStream with BufferedInputStream.
public class DownloadServlet extends HttpServlet{
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("application/octet-stream; charset=windows-1252");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
InputStream input = null;
OutputStream output = null;
try {
input = new FileInputStream(new File("file-path-where-generated-pdf-is-stored"));
output = response.getOutputStream();
IOUtils.copy(input, output);
output.flush();
} catch (IOException e) {
//log it
} finally{
close(input);
close(output);
input = null;
output = null;
}
}
//Right way to close resource
public static void close(Closeable c) {
if (c == null) return;
try {
c.close();
}catch (IOException e) {
//log it
}
}
}
Here is a solution for you
Insert this code in your html/Interface file. You could do something like this:
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=output.pdf");
ServletOutputStream sosStream = response.getOutputStream();
JasperPrint jasperPrint = (JasperPrint) session.getAttribute("jasperPrint");
JasperExportManager.exportReportToPdfStream(jasperPrint, sosStream);
File tempFile = File.createTempFile("TempFile.pdf",".tmp",new File("."));
InputStream isStream = null;
isStream = new FileInputStream(tempFile);
int ibit = 256;
while ((ibit) >= 0)
{
ibit = isStream.read();
sosStream.write(ibit);
}
sosStream.flush();
sosStream.close();
isStream.close();
out.clear();
out = pageContext.pushBody();
Notes :-
1. Response contentype and Header is set.
2. You can set jasperprint in session and retrieve it.
3. JasperExportManager.exportReportToPdfStream is called on the fly. This will take create an outpoutstream of pdf.
4. Rest of the code does writing jobs from stream to temp file.
You can call this code on click action of a button for download and a pop-up for download file will emerge asking for save location.
Try using the below sample as reference
ByteArrayOutputStream baos = new ByteArrayOutputStream();
JRAbstractExporter exporter = new JRPdfExporter();
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
ByteArrayOutputStream baos = exporter.exportReport();
OutputStream os = null;
try {
response.setContentType(mimeType);
response.setHeader("Content-disposition", "attachment; filename=\"Timesheet.pdf");
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
os = response.getOutputStream();
response.setContentLength(baos.size());
baos.writeTo(os);
} finally {
os.flush();
os.close();
}
Please use ByteArrayOutputStream obj in report method , I have implemented in Dynamic report(Jasper Api) , Its working for me :-
#RequestMapping(value="/pdfDownload", method = RequestMethod.GET)
public void getPdfDownload(HttpServletResponse response) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
report().columns().setDataSource().show()
.toPdf(buffer);
byte[] bytes = buffer.toByteArray();
InputStream inputStream = new ByteArrayInputStream (bytes);
IOUtils.copy(inputStream, response.getOutputStream());
response.setHeader("Content-Disposition", "attachment; filename=Accepted1.pdf");
response.flushBuffer();
}
You can use bellow code. Here is complete Example using java servlet
I have add bellow code. you can use bellow code to download pdf file from servlet..
Please download bellow jar file
Please download bellow jar file
1. jasperreports-5.0.1.jar
2. commons-logging-1.1.2.jar
3. commons-digester-2.1.jar
4. commons-collections-3.2.1-1.0.0.jar
5. commons-beanutils-1.8.3.jar
6. groovy-all-2.1.3.jar
7. com.lowagie.text-2.1.7.jar
8. your database library
Now use bellow code in servlet in doGet
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String path = "D:\\Software\\iReport-5.0.0-windows-installer\\u\\report4.jrxml";
JasperReport jasReport = JasperCompileManager.compileReport(path);
System.out.println("Jasper Report : " + jasReport);
//Database connection
Connection con = /*Your Datase Connection*/ ;
System.out.println(con);
//If You have paramerter add here
Map paramMap = new HashMap();
paramMap.put("id", request.getParameter("id"));
//if your have any parmeter add null to paramMap
JasperPrint jasPrint = JasperFillManager.fillReport(jasReport, null, con); //, mapParam, con);
System.out.println("Jasper Print : " + jasPrint);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
response.setContentType("application/x-download");
response.addHeader("Content-disposition", "attachment; filename=creditcard.pdf");
ServletOutputStream sos = response.getOutputStream();
JasperExportManager.exportReportToPdfStream(jasPrint, sos);
} catch (JRException ex) {
Logger.getLogger(Tests.class.getName()).log(Level.SEVERE, null, ex);
}
}

Downloaded File Size 0

I'm trying here to add a specific dialog bean for action on Alfresco Explorer that supposed to download a specific docx file. The code is working fine when I hit the download action, it downloads the file but as mentioned in my question title, the file size is 0 bytes.
I'm using this to do that:
public class NewFormDialog extends BaseDialogBean {
protected String aspect;
protected String finishImpl(FacesContext context, String outcome)
throws Exception {
download(aspect);
// // get the space the action will apply to
// NodeRef nodeRef = this.browseBean.getActionSpace().getNodeRef();
//
// // resolve the fully qualified aspect name
// QName aspectToAdd = Repository.resolveToQName(this.aspect);
//
// // add the aspect to the space
// getNodeService().addAspect(nodeRef, aspectToAdd, null);
//
// // return the default outcome
return outcome;
}
public boolean getFinishButtonDisabled() {
return false;
}
public String getFinishButtonLabel() {
return "Download";
}
public void download(String pAspect) throws ServletException, IOException {
String filename = pAspect;
String filepath = "\\";
BufferedInputStream buf = null;
ServletOutputStream myOut = null;
try {
FacesContext fc = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) fc
.getExternalContext().getResponse();
myOut = response.getOutputStream();
File myfile = new File(filepath + filename);
// set response headers
response.setContentType("application/octet-stream");
response.addHeader("Content-Disposition", "attachment; filename="
+ filename);
response.setContentLength((int) myfile.length());
FileInputStream input = new FileInputStream(myfile);
buf = new BufferedInputStream(input);
int readBytes = 0;
// read from the file; write to the ServletOutputStream
while ((readBytes = buf.read()) != -1)
myOut.write(readBytes);
myOut.flush();
response.flushBuffer();
} catch (IOException ioe) {
throw new ServletException(ioe.getMessage());
} finally {
// close the input/output streams
if (myOut != null)
myOut.close();
if (buf != null)
buf.close();
FacesContext.getCurrentInstance().responseComplete();
}
}
public String getAspect() {
return aspect;
}
public void setAspect(String aspect) {
this.aspect = aspect;
}
}
I tried every solution that I found by none works.
Thank you in advance.
The File.length() method returns 0 if the file does not exist. Check to make sure that the file exists.
Tip: The Apache Commons IO library simplifies many I/O related tasks. For example, the following code snippet streams the contents of a file to the servlet response:
HttpServletResponse response = ...
File myfile = ...
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(myfile);
out = response.getOutputStream();
IOUtils.copy(in, out);
} finally {
IOUtils.closeQuietly(in); //checks for null
IOUtils.closeQuietly(out); //checks for null
}

Categories