Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I got the following to work already:

  1. User can upload a file (i.e. a compressed archive)
  2. User can uncompress the file on the server
  3. User can execute some stuff on these files, which results in more files to be generated

Now I need to get step 4 to work:

  • User can download the files to his own computer again

Can anyone give me a hint? I tried to understand the stuff I found on Google, but it does not work quite as expected. Do I have to set a content type? When I set application/octet stream only txt and csv files would display correctly (in the browser, not as download popup as I wanted) other files would not work...

JSP:

<a4j:commandLink value="Download" action="#{appController.downloadFile}" rendered="#{!file.directory}">
   <f:param name="file" value="#{file.absoluteFilename}" />
</a4j:commandLink>

appController:

public String downloadFile() {
    String filename = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("file");
    File file = new File(filename);
    HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();  

    writeOutContent(response, file, file.getName());

    FacesContext.getCurrentInstance().responseComplete();
    return null;
}

private void writeOutContent(final HttpServletResponse res, final File content, final String theFilename) {
    if (content == null) {
        return;
    }
    try {
        res.setHeader("Pragma", "no-cache");
        res.setDateHeader("Expires", 0);
        res.setHeader("Content-disposition", "attachment; filename=" + theFilename);
        FileInputStream fis = new FileInputStream(content);
        ServletOutputStream os = res.getOutputStream();
        int bt = fis.read();
        while (bt != -1) {
            os.write(bt);
            bt = fis.read();
        }
        os.flush();
        fis.close();
        os.close();
    } catch (final IOException ex) {
        Logger.getLogger(ApplicationController.class.getName()).log(Level.SEVERE, null, ex);
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
383 views
Welcome To Ask or Share your Answers For Others

1 Answer

Your concrete problem is that you're attempting to download files by Ajax. This is not correct. JavaScript can't deal with binary responses nor has it any facilities to force a Save As dialogue. You need to make it a normal synchronous request instead so that it's the webbrowser itself who has to deal with it.

<h:commandLink value="Download" action="#{appController.downloadFile}" rendered="#{!file.directory}">
   <f:param name="file" value="#{file.absoluteFilename}" />
</h:commandLink>

As to setting the content type, if you have a file name with extension at your hands, you could use ServletContext#getMimeType() to resolve it based on <mime-mapping> in web.xml (either the server's default one or your webapp's one).

ServletContext servletContext = (ServletContext) externalContext.getContext();
String contentType = servletContext.getMimeType(file.getName());

if (contentType == null) {
    contentType = "application/octet-stream";
}

response.setContentType(contentType);
// ...

(note that I assume that you're using JSF 1.x, seeing the way how you obtained the servlet response, you could since JSF 2.x otherwise also use ExternalContext#getMimeType())


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...