2011-08-31 50 views
0

在我的基於Java的Web應用程序中,我試圖在ZIP文件中編寫一些文件,並且要提示用戶下載/取消/保存。下載對話框打開的時間,如果點擊取消,那麼如果我嘗試訪問我的應用程序中的任何鏈接,那麼對話框會再次打開。這是我的代碼片段。Servlet輸出流的響應問題

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(); 
} 

此外,一旦我點擊保存/打開,其按預期工作。我希望在清除響應對象時出現問題。請幫助我提供一些解決方案。

編輯 downloadSelected方法

 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"); 
    }  
} 

寫入郵編方法:

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; 
} 

感謝, Jeya

回答

1

我固然不知道這個問題的根本原因。根據迄今發佈的代碼,此行爲無法解釋。 SSCCE肯定會幫助更多。但我發現了這個問題的幾個潛在原因。也許修復其中的一個或全部將解決具體問題。

  1. 您已將JSF的FacesContext指定爲bean的屬性。這是不好並且絕對如果它是一個比請求範圍更廣的範圍的bean。應該在本地方法範圍內通過FacesContext#getCurrentInstance()獲得總是。它的返回值即線程局部變量,不應該在其他請求之間共享。也許你已經把bean放在會話範圍內,並且已經設置的頭部的前一個請求的懸掛對象將被重用。

  2. 您未收到的close()方法。如果客戶端取消下載,那麼servletOutputStream.close()將拋出一個IOException,指示客戶端已中止響應。在你的情況下,in將不會被關閉,並且tempFile將不會被刪除,並且JSF響應將不會被完成。您還應該趕上close()並記錄/忽略異常,以確保finally完成其工作。也許tempFile的存在對您未來的POST操作有影響。

  3. 您正在使用<h:commandLink>代替<h:outputLink><h:link>或純<a>的頁面到頁面的導航。這使用POST而不是GET,這是糟糕的用戶體驗和SEO。您應該使用GET鏈接而不是POST鏈接。另請參見When should I use h:outputLink instead of h:commandLink?

+0

非常感謝您的建議Balusc。你已經幫了我很多時間,現在也幫了我。非常感謝。我也嘗試過你提到的選項。我調試了我的代碼,並且毫無例外地進入finally方法,並確保Manage bean作用域是請求。我編輯了我的整個代碼以供參考。請讓我知道我做過的任何錯誤。 – i2ijeya