0

I have a form that once completed opens a new tab and calls my bean method annonceReturn().

This method sends back a pdf file. The problem is that as I open a new tab with _blank, the URL ends with .xhtml. Even the filename is displayed as being in my exemple "list.xhtml" (the last part of the URL). The problem is that I can't download this file because it's not considerated as a pdf file.

This is my xhtml file :

<h:form id="form">    
    <p:commandButton id="envoiRetour" onclick="this.form.target = '_blank';"
        actionListener="#{returnCtrl.announceReturn()}" 
        value="Open PDF in new tab"
        ajax="false" />
</h:form>

This is the returnCtrl.annonceReturn() method :

public void announceReturn() throws MalformedURLException, FileNotFoundException, DocumentException, BadElementException, IOException, InterruptedException {
    String referenceAnnouncement = "C:/Users/path_to_my_pdf_file.pdf";
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
    BufferedInputStream input = null;
    BufferedOutputStream output = null;

    try {
        input = new BufferedInputStream(new FileInputStream(referenceAnnouncement), 10240);
        response.reset();
        response.setHeader("Content-type", "application/pdf"); 
        response.setContentLength((int)new File(referenceAnnouncement).length());
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setHeader("Content-disposition", "inline; filename=" + "file.pdf");
        response.setHeader("pragma", "public");

        output = new BufferedOutputStream(response.getOutputStream(), 10240);
        byte[] buffer = new byte[10240];
        int length;
        while ((length = input.read(buffer)) > 0) {
            output.write(buffer, 0, length);
        }
        output.flush();
    } finally {
        output.close();
        input.close();
    }
}

How can I do to open this PDF in a new tab and be able to download it ?

When I try to download it, it says there is a network error (and it tries to save it as xhtml file).

EDIT : this is the question that helped me : How to open a PDF file in a new tab

EDIT 2 : the problem is not that the PDF doesn't show. The problem is that it shows in the new tab but when I try to download it, the explorer wants to save it as an XHTML file.

EDIT 3 : as mentionned here -> Open PDF in new tab, saving file gives wrong file name it seems the filename is ignored if the disposition is not "attachment"... So I think I need to think about another way to do it.

Thanks for your time.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
WaLinke
  • 726
  • 2
  • 6
  • 25
  • Where is the servlet? (Other then the jsf servlet being used) and which of the many Q/A in stackoverflow did you try and why did they not help. And did you investigate the 'server error'? – Kukeltje Jan 03 '20 at 14:55
  • ever tried `p:fileDownload` ([link](https://www.primefaces.org/showcase/ui/file/download.xhtml))? – fuggerjaki61 Jan 03 '20 at 14:57
  • Do you want me to edit my post to link all the links of websites explaining how to download or open a pdf in a new tab I've read ? – WaLinke Jan 03 '20 at 14:59
  • Well the announceReturn method creates this PDF, I don't know its name before it's generated. Plus I don't want to download it, just to opens it in a new tab (that is working) but let the user be able to download it if he wants (not working because when I try to save it, it tries to save an xhtml file). – WaLinke Jan 03 '20 at 15:02
  • 2
    Your problem can be solved when using a Servlet instead of a JSF backing bean. The irony is that you mentioned in the current title of your question that you was using a Servlet but you're actually using a JSF backing bean .. – BalusC Jan 03 '20 at 16:44
  • Waouw ! I think I don't have to mention I'm not familiar with JSF yet.. I'm slowly accompanied by head first. I created a servlet DownloadPDF and it works perfectly, so thanks a lot. Just to understand better, is it the fact that the URL ends with ".xhtml" that made it impossible to download the file as a pdf ? – WaLinke Jan 06 '20 at 09:21
  • 1
    No. It's the client side which is buggy. It all works fine in normal browsers such as Chrome. This is regardless of the server side framework being used. You woud have had exactly the same problem when using PHP, C, Python, or whatever else instead of Java. – BalusC Jan 07 '20 at 07:41

3 Answers3

0

Here is my code, hope it helps.

FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();

File temp = File("./path/abc.pdf");
temp.deleteOnExit();
ec.responseReset(); 
ec.setResponseContentType("application/pdf"); 
ec.setResponseContentLength((int)temp.length()); 
ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + temp.getName() + "\""); //inline; 

OutputStream output = ec.getResponseOutputStream();

Files.copy(temp.toPath(), output);
fc.responseComplete();
Vinh Can Code
  • 407
  • 3
  • 14
0

Try 'attachment' instead of 'inline' to force the browser saving the file (instead of trying to open with the associated plugin - if installed)

 response.setHeader("Content-disposition", "attachment; filename=" + "file.pdf");

Hope it helps.

Beppe

Beppe C
  • 11,256
  • 2
  • 19
  • 41
  • Thanks for your reply. As the Content-Disposition is "attachment", the file is instantly downloaded right ? I don't want the pdf to be downloaded, I want it to opens up in a new tab, but let the user download it if he wants to. – WaLinke Jan 03 '20 at 14:44
  • I see, try to remove the 'Content-Disposition' entirely and let the browser deal with it, it should open the PDF if the plugin is enabled. – Beppe C Jan 03 '20 at 14:48
  • I tried but it doesn't change anything. It seems that the filename is not set properly. – WaLinke Jan 03 '20 at 15:24
  • Does it work with other PDF you download from the web? Just to ensure that the browser has the plugin correctly enabled – Beppe C Jan 03 '20 at 15:25
  • I have a link on my website that redirects to a pdf and it works fine because the URL ends by "pdf". In this case, the URL ends with ".xhtml" and it seems it overwrites the filename I pass in the Content-Disposition. – WaLinke Jan 03 '20 at 15:27
  • Checked one of my implementations and the URL doesnt have an extension, so you are right maybe this is the problem (the browser sees the extension and decides what to do). – Beppe C Jan 03 '20 at 15:31
  • I saw here https://stackoverflow.com/questions/56546106/open-pdf-in-new-tab-saving-file-gives-wrong-file-name?rq=1 that the filename is ignored if the disposition is not attachment – WaLinke Jan 03 '20 at 15:37
0

I have tested in my project, here is the solution:

1 - Create button

<h:commandButton
    onclick="this.form.target='_blank'"
    id="cmdOpenPDF"
    action="#{bean.openPDF(bean.code)}"
    value="New PDF">
</h:commandButton>

2 - The bean has a function with a redirect link to PDF. This sample the pdf in the root folder.

  public void openPDF(String code) throws Exception {
  String filePdfName ="";
  try {

     //Make sure that this file in root

     File pdf = new File("sample.pdf"); 

     filePdfName = pdf.getName();

     } catch (Exception ex) {
        ex.printStackTrace();
     }
     ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
     ec.redirect(ec.getRequestContextPath() + "/" + filePdfName);
}
WaLinke
  • 726
  • 2
  • 6
  • 25
Vinh Can Code
  • 407
  • 3
  • 14
  • The problem with this is that I create the PDF file in the backing bean when the user click on "submit". I cannot save it in the root folder cause everytime I will push my project in prod, I will erase all these files. – WaLinke Jan 06 '20 at 08:14
  • I think that you can create a folder like '$web-root/temp/' in production. Then modify the code ec.redirect(ec.getRequestContextPath() + "/temp/" + filePdfName); – Vinh Can Code Jan 06 '20 at 16:39
  • @VinhCanCode: Never ever store files in your webapp. Very simple solutions to prevent this have existed for over 20 years. The duplicate has all the info... A servlet... that can read from anywhere in the filesystem – Kukeltje Jan 07 '20 at 21:06