I am working with JSF and I want to open a PDF file in a new tab when I click on a button.
XHTML
<p:commandButton onclick="this.form.target = '_blank'"
actionListener="#{managedBean.openFile(file)}"
ajax="false" />
Managed bean
public void openFile( File file ) {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
// Open file.
input = new BufferedInputStream(new FileInputStream(file), 10240);
// Init servlet response.
response.reset();
// lire un fichier pdf
response.setHeader("Content-type", "application/pdf");
response.setContentLength((int)file.length());
response.setHeader("Content-disposition", "attachment; filename=" + node.getNomRepertoire());
response.setHeader("pragma", "public");
output = new BufferedOutputStream(response.getOutputStream(), 10240);
// Write file contents to response.
byte[] buffer = new byte[10240];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
// Finalize task.
output.flush();
} finally {
// Gently close streams.
output.close();
input.close();
}
}
The problem is when I use this method it only downloads the file. For your information, I'm following this post: http://balusc.omnifaces.org/2006/05/pdf-handling.html
You should change
response.setHeader("Content-disposition", "attachment; filename=" + node.getNomRepertoire());
into
response.setHeader("Content-disposition", "inline; filename=" + node.getNomRepertoire());
So, use inline instead of attachment.
See also:
How to force files to open in browser instead of download (pdf)?
Related
I have SSJS in a button that opens a pdf file, writes to some fields on it (Acroform) and then downloads the file to the user. All works great (using pdfbox) but I wanted to be a good programmer and if the original pdf file was not available then cancel the operation. Otherwise, the user still gets prompted to open the file but Adobe Reader reports the file is corrupted (obviously it will be). I do my pdf operations in a Java class that I call and pass in the outputStream of the response object. Below is my SSJS. If I test the ret value from newVal.outputPdf and put all the other code in the if statement then my XPage is just blank. I assume because the response and outputStream was already opened?
Howard
importPackage(com.tlcc);
var newVal = new PdfBoxTest();
importPackage(java.net);
importPackage(java.lang);
var con = facesContext.getExternalContext();
var response:com.ibm.xsp.webapp.XspHttpServletResponse = con.getResponse();
try {
var writer:javax.servlet.ServletOutputStream = response.getOutputStream();
//get the stream
var ret = newVal.outputPdf(writer, "http://localhost/pdfexportcc.nsf/certificate.pdf");
// setting response headers for browser
print("Good output");
response.setContentType("application/pdf");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", -1);
response.setHeader( "Content-Disposition", "attachment; filename=\"mypdf.pdf\"" );
writer.flush();
writer.close();
print("in close");
facesContext.responseComplete();
} catch (e) {
var errorMessage = "An error has occured: " + e.toString();
_dump(errorMessage);
writer.close();
response.sendError(500, errorMessage);
}
Tried again with all the work being done in Java. I called this method from a button. Works fine with a valid url but when the url is bad it throws an error. Exception Can't get a Writer while an OutputStream is already in use.
public boolean outputAllInJavaPdf() {
try {
FacesContext context = FacesContext.getCurrentInstance();
XspHttpServletResponse response = (XspHttpServletResponse) context.getExternalContext().getResponse();
ServletOutputStream writer = response.getOutputStream();
InputStream docUrl = new URL("http://localhost/pdfexportcc.nsf/certifxxicate.pdf").openStream();
pdfDoc = PDDocument.load(docUrl);
System.out.println("Number of pages is " + pdfDoc.getNumberOfPages());
setField("Student", "James Namce");
setField("CourseName", "XPages Development 2 for Notes and Domino 9");
setField("Instructor", "John Smith");
System.out.println("After set field");
pdfDoc.save(writer);
pdfDoc.close();
response.setContentType("application/pdf");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", -1);
response.setHeader("Content-Disposition", "attachment; filename=\"mypdf.pdf\"");
writer.flush();
writer.close();
context.responseComplete();
return true;
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
return false;
}
}
All depends on what you tell the browser.
You use content type of PDF file. Browser opens (downloads) PDF file. Anything you put inside, for example error page, is treated as content of PDF file.
So in case PDF generation fails, do not set that content type and redirect browser to error page, or back to original XPage with explanation.
public boolean outputAllInJavaPdf() {
try {
FacesContext context = FacesContext.getCurrentInstance();
XspHttpServletResponse response = (XspHttpServletResponse) context.getExternalContext().getResponse();
ServletOutputStream writer = response.getOutputStream();
boolean servePdf = true;
try {
InputStream docUrl = new URL("http://localhost/pdfexportcc.nsf/certifxxicate.pdf").openStream();
pdfDoc = PDDocument.load(docUrl);
// do something to validate PDF
} catch (Exception e) {
//no PDF
servePdf = false;
}
if (servePdf) {
System.out.println("Number of pages is " + pdfDoc.getNumberOfPages());
setField("Student", "James Namce");
setField("CourseName", "XPages Development 2 for Notes and Domino 9");
setField("Instructor", "John Smith");
System.out.println("After set field");
pdfDoc.save(writer);
pdfDoc.close();
response.setContentType("application/pdf");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", -1);
response.setHeader("Content-Disposition", "attachment; filename=\"mypdf.pdf\"");
} else {
// take care of no PDF response - redirect?
}
writer.flush();
writer.close();
context.responseComplete();
return true;
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
return false;
}
}
It is probably trying to render your Xpage, but you want to control the response yourself. To prevent rendering of the Xpage and take control of the writer, add rendered="false"to your Xpage.
Hi I am trying to download a file from server but at the end of my process I end up with only numbers and some weird characters on my browser. It's not downloading the file. I am using seam and JSF 1.2.
Here is my code:
public void writeBytesToResponse(UploadDefinition _instance, String path) {
FacesContext context = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) context .getExternalContext().getResponse();
try {
byte[] bytes = getFile(path);
response.reset();
response.setContentType(ContentType.PDF.getLabel());
response.setContentLength(bytes.length);
response.setHeader("Content-disposition", "attachment; filename=\"" + _instance.getFileName() + "\"");
OutputStream outputStream = response.getOutputStream();
outputStream.write(bytes);
outputStream.flush();
outputStream.close();
context.responseComplete();
} catch (Exception ex) {
ex.printStackTrace();
}
}
#SuppressWarnings("resource")
public byte[] getFile(String filePath) throws FileNotFoundException, IOException {
File file = new File(filePath);
InputStream is = new FileInputStream(file);
long length = file.length();
if (length > Integer.MAX_VALUE) {
throw new IOException("File is too large " + file.getName());
}
byte[] bytes = new byte[(int) length];
int offset = 0;
int numRead = 0;
while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
offset += numRead;
}
if (offset < bytes.length) {
throw new IOException("Could not completely read file " + file.getName());
}
is.close();
return bytes;
}
Here I call the method:
public void downloadFile() {
writeBytesToResponse(ud, path);
}
I got the answer, I was using <a4j:commandButton> on jsf and I changed it to <h:commandButton> then it worked. The point is not to use ajax.
I am having a folder, I am trying to zip it and than on a button click event it should be downloaded on the user's machine. I am able to generate the zip file correctly. I have written the code to download it also but after it is getting downloaded to the user's machine from the server. It shows unable to open zip file as it is invalid.
How is this caused and how can I solve it? Here's the code which performs the download functionality.
public String getAsZip() {
try {
FacesContext ctx = FacesContext.getCurrentInstance();
ExternalContext etx = ctx.getExternalContext();
HttpServletResponse response = (HttpServletResponse) etx
.getResponse();
ServletOutputStream zipFileOutputStream = response
.getOutputStream();
response.setContentType("application/octet-stream");
response.setHeader(
"Content-Disposition",
"attachment; filename=" + downloadLink.substring(downloadLink.lastIndexOf("\\") + 1,downloadLink.length()));
response.setHeader("Cache-Control", "no-cache");
File zipFile = new File(downloadLink);
FileInputStream stream = new FileInputStream(zipFile);
response.setContentLength(stream.available());
int length = 0;
byte[] bbuf = new byte[response.getBufferSize()];
BufferedInputStream in = new BufferedInputStream(stream);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((length = in.read(bbuf)) > 0) {
baos.write(bbuf, 0, length);
}
zipFileOutputStream.write(baos.toByteArray());
zipFileOutputStream.flush();
zipFileOutputStream.close();
response.flushBuffer();
in.close();
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
return "successZip";
}
See JSF 2.0 RenderResponse and ResponseComplete
The problem is that you do not call FacesContext#responseComplete(). That's why JSF will still render the view after you attached the download and append that to the response. This will cause the zipfile to be broken.
I tried the following code :
PortletResponse response1 = (PortletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
HttpServletResponse response = (HttpServletResponse)response1;
In a previous question the answer was to PortalUtil.getHttpServletResponse(portletResponse)
but the problem is that null pointer exception on response.getOutputStream()My full code is
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
//here is my code
PortletResponse portalResponse = (PortletResponse) externalContext.getResponse();
HttpServletResponse response = PortalUtil.getHttpServletResponse(portalResponse);
File file = new File(getFilePath(), getFileName());
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
input = new BufferedInputStream(new FileInputStream(file), DEFAULT_BUFFER_SIZE);
response.reset();
response.setHeader("Content-Type", "application/pdf");
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Disposition", "inline; filename=\"" + getFileName() + "\"");
//here where nullException is returned from response.getOutputStream()
output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
output.flush();
} finally {
close(output);
close(input);
}
facesContext.responseComplete();
which is written by #BalusC in
pdf-handling
My question is how to get this response in a portlet
I'm having a problem when I try to create a PDF file using iText and want to download it immediately afterwards. First I create a PDF file using the iText library, the file is written to a TEMP folder on the server, this all works fine. But afterwards I call a download screen for downloading the PDF file from the TEMP folder to the client, and here something goes wrong. The download screen shows a Firefox (browser) icon instead of the Acrobat icon. When I donwload the file I only get to see blank PDF pages, but the number of pages is correct. E.g. I have a PDF file of 4 pages, I get 4 blank pages as a result, there is no content. The PDF file in the TEMP folder however is correct, it has got 4 pages with the correct content.
This is my java code, it is executed when the user clicks a h:commandLink
public <E> String createPDF(E type, boolean print) throws Exception {
Document document = new Document();
// create a File name for the document
getPdfNaam(type);
try {
//create a PDF writer
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(TEMP + naam + ".pdf"));
//open the PDF document
document.open();
} catch (Exception e) {
e.printStackTrace();
}
//build the PDF file using iText
buildPDFContent(document, type);
//close the PDF document
close(document);
String downloadFile = TEMP + naam + ".pdf";
//call Servlet for download screen in the browser
ServletContext context = (ServletContext) ContextProvider.getFacesContext().getExternalContext().getContext();
HttpServletResponse response = (HttpServletResponse) ContextProvider.getFacesContext().getExternalContext().getResponse();
response.setContentType("application/force-download");
downloadFile = TEMP + naam + ".pdf";
byte[] buf = new byte[1024];
try {
File file = new File(downloadFile);
long length = file.length();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
ServletOutputStream out = response.getOutputStream();
response.setContentLength((int) length);
while ((in != null) && ((length = in.read(buf)) != -1)) {
out.write(buf, 0, (int) length);
}
in.close();
out.close();
} catch (Exception exc) {
exc.printStackTrace();
}
response.addHeader("Content-Disposition", "attachment; filename=\"" + naam + ".pdf" + "\"");
return null;
}
I found the code for calling a download screen on this website http://www.winstonprakash.com/articles/jsf/file_download_link.htm
I searched on Google and Stack Overflow, but I couldn't find any related questions. I'm using JSF 2.0 Any help would be greatly appreciated!
The content type should be set to application/pdf and the content disposition header should be set before any byte is been written to the response, otherwise it's too late to set it. Plus, you can also just write the PDF to the outputstream of the response immediately.
All with all, the method can be simplified as follows:
public <E> String createPDF(E type, boolean print) throws Exception {
getPdfNaam(type); // ??? It should *return* name, not change/set the local value.
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.setResponseHeader("Content-Type", "application/pdf");
ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + naam + ".pdf" + "\"");
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, ec.getResponseOutputStream());
document.open();
buildPDFContent(document, type);
close(document);
}
Also ensure that you're calling FacesContext#responseComplete() to signal JSF that you've already taken the response handling in your hands so that it knows that it doesn't need to navigate to some view.
FacesContext.getCurrentInstance().responseComplete();
you can you the outputstream to response immediately. The below is my code:
OutputStream out = response.getOutputStream();
response.setContentType("application/x-msdownload;charset=utf-8");
response.setHeader("Content-Disposition", "attachment;"+"filename="+System.currentTimeMillis()+".pdf");
Document document = new Document(PageSize.A4, 10, 10, 10,10);
PdfWriter.getInstance(document, out);
document.open();
//The below is document add data
//....
//close flow
if(document!=null){
document.close();
}
if(out!=null){
out.flush();
out.close();
}