开发者

Problem in response from servlet output stream

In my Java Based Web application, I am trying to write some files in a ZIP file and I want to prompt the user to download/cancel/save. The time when the download dialog box opens and if I click on cancel, after then if I try to access any links in my application then开发者_高级运维 the dialog box opens again. Here's my code snippet.

private void sendResponse(byte[] buf, File tempFile) throws IOException {
    long length = tempFile.length();
    HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
    String disposition = "attachment; fileName=search_download.zip";
    ServletOutputStream servletOutputStream = null;
    InputStream in = null; 
    try {
        if (buf != null) {
            in = new BufferedInputStream(new FileInputStream(tempFile));
            servletOutputStream = response.getOutputStream();
            response.setContentType("application/zip");
            response.setHeader("Content-Disposition", disposition);
            while ((in != null) && ((length = in.read(buf)) != -1)) {
                servletOutputStream.write(buf, 0, (int) length);
            }
        }
    } finally {
        if (servletOutputStream != null) {
            servletOutputStream.close();
        }
        if (in != null) {
            in.close();
        }
        if (tempFile != null) {
            tempFile.delete();
        }
    }
    context.responseComplete();
}

Also once I click on save/Open, its working as expected. I hope the problem in clearing the response object. Please help me in providing some solutions.

EDIT downloadSelected Method

      public void downloadSelected() throws IOException {

    List<NodeRef> list = init();
    StringBuffer errors = new StringBuffer("");
    ZipOutputStream out = null;

    File tempFile = null;
    byte[] buf = null;
    try {
        if (list != null && list.size() > 0) {
            tempFile = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX_ZIP);
            out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(tempFile)));
            buf = writeIntoZip(list,out);
            sendResponse(buf,tempFile);
        } else {
            errors.append("No Items Selected for Download");
            this.errorMessage = errors.toString();
        }
    } 
    catch(IOException e) {
        System.out.println("Cancelled");
    }       
}

Write into Zip method:

private byte[] writeIntoZip(List<NodeRef> list,ZipOutputStream out) throws IOException {
    String downloadUrl = "";
    InputStream bis = null;
    Node node = null;
    String nodeName = "";
    byte[] buf = null;
    Map<String,Integer> contents = new HashMap<String, Integer>();
    ContentReader reader = null;
    for (NodeRef nodeRef : list) {
        try {
            node = new Node(nodeRef);
            nodeName = node.getName();
            reader = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getContentService().getReader(nodeRef, ContentModel.PROP_CONTENT);
            bis = new BufferedInputStream(reader.getContentInputStream());
            if (bis != null) {
                contents = setFiles(contents,nodeName);
                nodeName = getUniqueFileName(contents, nodeName);
                buf = new byte[4 * 1024];
                buf = writeOutputStream(bis).toByteArray();
                out.putNextEntry(new ZipEntry(nodeName));
                out.write(buf);
            }
        } catch (Exception e) {
            e.printStackTrace();
            if(out != null) {
                out.close();
            }
        }
    }
    if(out != null) {
        out.close();
    }
    return buf;
}

Thanks, Jeya


I'm admittedly not sure of the root cause of this problem. This behaviour is not explainable based on the code posted as far. An SSCCE would definitely help more. But I spot several potential causes of this problem. Perhaps fixing one or all of them will fix the concrete problem.

  1. You've assigned JSF's FacesContext as a property of the bean. This is bad and definitely if it's a bean with a broader scope than the request scope. It should always be obtained inside the local method scope by FacesContext#getCurrentInstance(). It's returns namely a thread local variable and should never be shared among other requests. Perhaps you've put the bean in the session scope and a dangling response object of the previous request with the headers already set will be reused.

  2. You are not catching the IOException on close() methods. If the client cancels the download, then the servletOutputStream.close() will throw an IOException indicating that the client has aborted the response. In your case, the in won't be closed anymore and the tempFile won't be deleted anymore and the JSF response won't be completed anymore. You should also catch the close() and log/ignore the exception so that you can ensure that the finally finishes its job. Perhaps the presence of tempFile has consequences for your future POST actions.

  3. You are using <h:commandLink> instead of <h:outputLink> or <h:link> or plain <a> for page-to-page navigation. This uses POST instead of GET which is bad for user experience and SEO. You should use GET links instead of POST links. See also When should I use h:outputLink instead of h:commandLink?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜