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
}
Related
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();
}
}
}
I have a rest method for downloading files which works. But, it seems that the download doesn't start on the web client until the file is completely copied to the output stream, which can take a while for large files.
#GetMapping(value = "download-single-report")
public void downloadSingleReport(HttpServletResponse response) {
File dlFile = new File("some_path");
try {
response.setContentType("application/pdf");
response.setHeader("Content-disposition", "attachment; filename="+ dlFile.getName());
InputStream inputStream = new FileInputStream(dlFile);
IOUtils.copy(inputStream, response.getOutputStream());
response.flushBuffer();
} catch (FileNotFoundException e) {
// error
} catch (IOException e) {
// error
}
}
Is there a way to "stream" the file such that the download starts as soon as I begin writing to the output stream?
I also have a similar method that takes multiple files and puts them in a zip, adding each zip entry to the zip stream, and the download also only begins after the zip has been created:
ZipEntry zipEntry = new ZipEntry(entryName);
zipOutStream.putNextEntry(zipEntry);
IOUtils.copy(fileStream, zipOutStream);
You can use InputStreamResource to return stream result. I tested and it is started copying to output immediately.
#GetMapping(value = "download-single-report")
public ResponseEntity<Resource> downloadSingleReport() {
File dlFile = new File("some_path");
if (!dlFile.exists()) {
return ResponseEntity.notFound().build();
}
try {
try (InputStream stream = new FileInputStream(dlFile)) {
InputStreamResource streamResource = new InputStreamResource(stream);
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_PDF)
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + dlFile.getName() + "\"")
.body(streamResource);
}
/*
// FileSystemResource alternative
FileSystemResource fileSystemResource = new FileSystemResource(dlFile);
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_PDF)
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + dlFile.getName() + "\"")
.body(fileSystemResource);
*/
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
The second alternative is a partial download method.
#GetMapping(value = "download-single-report-partial")
public void downloadSingleReportPartial(HttpServletRequest request, HttpServletResponse response) {
File dlFile = new File("some_path");
if (!dlFile.exists()) {
response.setStatus(HttpStatus.NOT_FOUND.value());
return;
}
try {
writeRangeResource(request, response, dlFile);
} catch (Exception ex) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
}
}
public static void writeRangeResource(HttpServletRequest request, HttpServletResponse response, File file) throws IOException {
String range = request.getHeader("Range");
if (StringUtils.hasLength(range)) {
//http
ResourceRegion region = getResourceRegion(file, range);
long start = region.getPosition();
long end = start + region.getCount() - 1;
long resourceLength = region.getResource().contentLength();
end = Math.min(end, resourceLength - 1);
long rangeLength = end - start + 1;
response.setStatus(206);
response.addHeader("Accept-Ranges", "bytes");
response.addHeader("Content-Range", String.format("bytes %s-%s/%s", start, end, resourceLength));
response.setContentLengthLong(rangeLength);
try (OutputStream outputStream = response.getOutputStream()) {
try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) {
StreamUtils.copyRange(inputStream, outputStream, start, end);
}
}
} else {
response.setStatus(200);
response.addHeader("Accept-Ranges", "bytes");
response.setContentLengthLong(file.length());
try (OutputStream outputStream = response.getOutputStream()) {
try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) {
StreamUtils.copy(inputStream, outputStream);
}
}
}
}
private static ResourceRegion getResourceRegion(File file, String range) {
List<HttpRange> httpRanges = HttpRange.parseRanges(range);
if (httpRanges.isEmpty()) {
return new ResourceRegion(new FileSystemResource(file), 0, file.length());
}
return httpRanges.get(0).toResourceRegion(new FileSystemResource(file));
}
Spring Framework Resource Response Process
Resource response managed by ResourceHttpMessageConverter class. In writeContent method, StreamUtils.copy is called.
package org.springframework.http.converter;
public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter<Resource> {
..
protected void writeContent(Resource resource, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
try {
InputStream in = resource.getInputStream();
try {
StreamUtils.copy(in, outputMessage.getBody());
}
catch (NullPointerException ex) {
// ignore, see SPR-13620
}
finally {
try {
in.close();
}
catch (Throwable ex) {
// ignore, see SPR-12999
}
}
}
catch (FileNotFoundException ex) {
// ignore, see SPR-12999
}
}
}
out.write(buffer, 0, bytesRead); sends data immediately to output (I have tested on my local machine). When whole data is transferred, out.flush(); is called.
package org.springframework.util;
public abstract class StreamUtils {
..
public static int copy(InputStream in, OutputStream out) throws IOException {
Assert.notNull(in, "No InputStream specified");
Assert.notNull(out, "No OutputStream specified");
int byteCount = 0;
int bytesRead;
for(byte[] buffer = new byte[4096]; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) {
out.write(buffer, 0, bytesRead);
}
out.flush();
return byteCount;
}
}
Use
IOUtils.copyLarge(InputStream input, OutputStream output)
Copy bytes from a large (over 2GB) InputStream to an OutputStream.
This method buffers the input internally, so there is no need to use a BufferedInputStream.
The buffer size is given by DEFAULT_BUFFER_SIZE.
or
IOUtils.copyLarge(InputStream input, OutputStream output, byte[] buffer)
Copy bytes from a large (over 2GB) InputStream to an OutputStream.
This method uses the provided buffer, so there is no need to use a BufferedInputStream.
http://commons.apache.org/proper/commons-io/javadocs/api-2.4/org/apache/commons/io/IOUtils.html
You can use "StreamingResponseBody" File download would start immediately while the chunks are written to the output stream. Below is the code snippet
#GetMapping (value = "/download-single-report")
public ResponseEntity<StreamingResponseBody> downloadSingleReport(final HttpServletResponse response) {
final File dlFile = new File("Sample.pdf");
response.setContentType("application/pdf");
response.setHeader(
"Content-Disposition",
"attachment;filename="+ dlFile.getName());
StreamingResponseBody stream = out -> FileCopyUtils.copy(new FileInputStream(dlFile), out);
return new ResponseEntity(stream, HttpStatus.OK);
}
I'm trying to create a video platform with Spring MVC and Angular2. But I can not get this video going backwards or forwards. I also have not got the rest controller to send the video to pieces of bytes, just send it whole.
#RequestMapping(value = "/method2/{name}", method = RequestMethod.GET)
public void getDownload(HttpServletResponse response, HttpServletRequest request,#PathVariable String name)
throws IOException, ServletException {
String filePath;
if (name.contains("webm")) {
filePath = webm;
System.out.println("WEBM");
} else if (name.contains("mp4")) {
filePath = mp4;
System.out.println("MP4");
} else {
filePath = mkv;
System.out.println("MKV");
}
// Get your file stream from wherever.
ServletContext context = request.getServletContext();
File downloadFile = new File(filePath);
FileInputStream inputStream = new FileInputStream(downloadFile);
// Set the content type and attachment header.
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"", downloadFile.getName());
response.setHeader(headerKey, headerValue);
String mimeType = context.getMimeType(filePath);
if (mimeType == null) {
// set to binary type if MIME mapping not found
mimeType = "application/octet-stream";
}
response.setContentType(mimeType);
// Copy the stream to the response's output stream.
IOUtils.copy(inputStream, response.getOutputStream());
response.flushBuffer();
}
ant my html
<video width='360' height='240' [vgMedia]="media" #media id="singleVideo" preload="auto" crossorigin>
<source src="********/movies/method2/mp4" type="video/mp4">
</video>
I've looked at many posts right here and none has worked for me to get this.
EDIT1. Method3
#RequestMapping(method = RequestMethod.GET, value = "/method3/{name}")
public StreamingResponseBody stream(#PathVariable String name) throws FileNotFoundException {
String filePath;
if (name.contains("webm")) {
filePath = webm;
System.out.println("WEBM");
} else if (name.contains("mp4")) {
filePath = mp4;
System.out.println("MP4");
} else {
filePath = mkv;
System.out.println("MKV");
}
File videoFile = new File(filePath);
final InputStream videoFileStream = new FileInputStream(videoFile);
return (os) -> {
readAndWrite(videoFileStream, os);
};
}
private void readAndWrite(final InputStream is, OutputStream os) throws IOException {
byte[] data = new byte[2048];
int read = 0;
while ((read = is.read(data)) > 0) {
os.write(data, 0, read);
}
os.flush();
}
Thanks.
Have a look this post which I wrote sometime back on how to play streaming video by using StreamingResponseBody available in Spring.
I have file on the server & that I want to download on my machine using browser. But I am not getting an option from browser to download the file.
My code is
JSP
<div id="jqgrid">
<table id="grid"></table>
<div id="pager"></div>
</div>
JS
jq("#grid").jqGrid({
....
onCellSelect: function(rowid, index, contents, event) {
...
var fileName = jQuery("#grid").jqGrid('getCell',rowid,'fileName');
$scope.downloadFile(fileName);
}
});
$scope.downloadFile = function(fileName) {
$http({
url: "logreport/downLoadFile",
method: "GET",
params: {"fileName": fileName}
});
};
Controller
#RequestMapping(value = "/downLoadFile", method = RequestMethod.GET)
public void downLoadFile(HttpServletRequest request, HttpServletResponse response) {
try {
String fileName = request.getParameter("fileName");
File file = new File(filePath +"//"+fileName);
InputStream in = new BufferedInputStream(new FileInputStream(file));
response.setContentType("application/xlsx");
response.setHeader("Content-Disposition", "attachment; filename="+fileName+".xlsx");
ServletOutputStream out = response.getOutputStream();
IOUtils.copy(in, out);
response.flushBuffer();
} catch (Exception e) {
e.printStackTrace();
}
}
I am not getting any exception but not sure why browser dialog is not opening to download the file. Also where is it exactly downloading the file?
#SotiriosDelimanolis was right. File download is not possible using ajax request.
Simply use 'window.location'.
$scope.downloadFile = function(fileName) {
window.location.href = 'logreport/downLoadFile?fileName=asdad1';
};
I didn't have enough credit to give a comment so wiritting here.. Thanks user1298426. I was strugling like anything for this. I was trying with AJAX. With window.location.href, I can download file in browser...
MY javascript code is as follows:
jQuery('#exportToZip').click(function() {
window.location.href = '*****';
});
*****: is the url mapping that I have in controller.
#RequestMapping(value = "/****")
#ResponseBody
public void downloadRequesthandler(HttpServletRequest request,HttpServletResponse response) {
String status;
try {
filedownloader.doGet(request, response);
} catch (ServletException e) {
status="servlet Exception occured";
e.printStackTrace();
} catch (IOException e) {
status="IO Exception occured";
e.printStackTrace();
}
//return status;
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = request.getServletContext();
// construct the complete absolute path of the file
File downloadFile = new File(filePath);
System.out.println("downloadFile path: "+ filePath);
FileInputStream inputStream = new FileInputStream(downloadFile);
// get MIME type of the file
String mimeType = context.getMimeType(fullPath);
if (mimeType == null) {
// set to binary type if MIME mapping not found
mimeType = "application/octet-stream";
}
System.out.println("MIME type: " + mimeType);
response.setContentLength((int) downloadFile.length());
// set headers for the response
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"",downloadFile.getName());
response.setHeader(headerKey, headerValue);
OutputStream outStream = response.getOutputStream();
byte[] buffer = new byte[BUFFER_SIZE];
System.out.println("buffer: "+ buffer.length);
int bytesRead = -1;
// write bytes read from the input stream into the output stream
//be carefull in this step. "writebeyondcontentlength" and "response already committed" error is very common here
while ((bytesRead = inputStream.read(buffer))!=-1 ) {
outStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outStream.close();
}
Trying to download file with ajax is a blunder....
cheers......
Instead of using IOUtils copy method
ServletOutputStream out = response.getOutputStream();
IOUtils.copy(in, out);
You can use following :
ServletOutputStream out = response.getOutputStream();
byte[] bytes = IOUtils.toByteArray(in);
out.write(bytes);
out.close();
out.flush();
Hope this will work.
i have a result set which has got some values, i want to export the data which is there in result set as a text file with the save dialog.
how to do this in java?.
I have done the above requirement for excel and java like the following.
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-disposition", "attachment; filename=\"" + reportName + ".xls\"");
and
response.setHeader("Content-disposition", "attachment; filename=\"" + reportName + ".pdf\"");
response.setContentType("application/pdf");
UPDATE :
if(exportTo.equals("text")){
response.setContentType("text/plain");
response.setHeader("Content-disposition", "attachment; filename=\"" + reportName + ".txt\"");
try {
} catch (Exception e) {
// TODO: handle exception
}
}
in this
in try block how to set the contents which are avilable from resultset to a output stream and make it available.
the only difference is this :
response.setContentType("text/plain");
You can see a full example here ( http://www.mkyong.com/servlet/servlet-code-to-download-text-file-from-website-java/ )
UPDATE
This is a demo that I have developed and tested and works perfectly fine:
public class ServletDownloadDemo extends HttpServlet {
private static final int BYTES_DOWNLOAD = 1024;
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
response.setContentType("text/plain");
response.setHeader("Content-Disposition", "attachment;filename=downloadname.txt");
String s = "Test\n\nText file contects!!";
InputStream input = new ByteArrayInputStream(s.getBytes("UTF8"));
int read = 0;
byte[] bytes = new byte[BYTES_DOWNLOAD];
OutputStream os = response.getOutputStream();
while ((read = input.read(bytes)) != -1) {
os.write(bytes, 0, read);
}
os.flush();
os.close();
}
}
It downloads a text file named downloadname.txt with the contents of String s.
UPDATE 2
String s = "";
while (rs.next()) {
s += rs.getString("column_name");
}
if (exportTo.equals("text")) {
response.setContentType("text/plain");
response.setHeader("Content-Disposition", "attachment;filename=downloadname.txt");
try {
InputStream input = new ByteArrayInputStream(s.getBytes("UTF8"));
int read = 0;
byte[] bytes = new byte[BYTES_DOWNLOAD];
OutputStream os = response.getOutputStream();
//data form resultset
while ((read = input.read(bytes)) != -1) {
os.write(bytes, 0, read);
}
os.flush();
os.close();
} catch (Exception e) {
// TODO: handle exception
}
}
You have to populate your ResultSet and place what you need in String s. That's all.