2015-09-28 70 views
0

我正在使用此代碼從JSF頁面下載文件。從JSF頁面下載具有適當擴展名的文件

public String downloadFile(String fileName) { 
    try { 

     String reportPath = "/opt/download" + File.separator + selectedDownloadValue + File.separator + fileName; 

     FacesContext facesContext = FacesContext.getCurrentInstance(); 
     HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse(); 
     // use this code if the package is located insight the WAR package 

     File file = new File(reportPath); 

     if (!file.exists()) { 
      response.sendError(HttpServletResponse.SC_NOT_FOUND, "No file " + reportPath); 
     } 

     int DEFAULT_BUFFER_SIZE = 10240; 
     response.setBufferSize(DEFAULT_BUFFER_SIZE); 
     response.setHeader("Content-Length", String.valueOf(file.length())); // Display file size during download 
     response.setHeader("Content-Type", "application/octet-stream"); 
     response.setHeader("Content-Transfer-Encoding", "Binary"); 
     response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); 

     BufferedInputStream bIn = new BufferedInputStream(new FileInputStream(file)); 

     int rLength = -1; 

     byte[] buffer = new byte[1000]; 

     while ((rLength = bIn.read(buffer, 0, 100)) != -1) { 
      response.getOutputStream().write(buffer, 0, rLength); 
     } 

     FacesContext.getCurrentInstance().responseComplete(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    return null; 
} 

但對於我下載某些原因,文件擴展名爲some_file.exe.xht我試圖添加額外的信息,但是沒有結果。 也許在下載之前需要獲取文件擴展名?有沒有解決方法?

回答

3

爲了獲得最佳的跨瀏覽器的兼容性,以獲得下載使用正確的文件名,特別是如果你想覆蓋的Internet Explorer以及,文件名必須是實際的URL觸發下載的路徑名。這不適用於JSF表單,因爲它們默認提交給JSF頁面本身的URL。

實現,最好的辦法是創建監聽像/file/*/download/*等前綴的網址模式,使文件名可以作爲URL的路徑名來提供一個獨立文件的servlet。根據您當前的JSF的方法,下面是獨立的文件servlet可以看起來怎麼樣,在這裏和那裏的一些改進,以減少樣板和廢話,和bug修復,以404行爲:

@WebServlet("/download/*") 
public class FileServlet extends HttpServlet { 

    @Override 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
     String fileName = request.getPathInfo().substring(1); 
     String selectedDownloadValue = request.getParameter("selectedDownloadValue"); 
     String reportPath = "/opt/download/" + selectedDownloadValue + "/" + fileName; 
     File file = new File(reportPath); 

     if (!file.exists()) { 
      response.sendError(HttpServletResponse.SC_NOT_FOUND, "No file " + reportPath); 
      return; 
     } 

     response.setHeader("Content-Length", String.valueOf(file.length())); 
     response.setHeader("Content-Type", getServletContext().getMimeType(fileName)); 
     response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); 
     Files.copy(file.toPath(), response.getOutputStream()); 
    } 

} 

沒有進一步的配置/改變是必要的前提是你已經上最小的Java 7和Java EE 6

以上的servlet可通過/download/filename.ext?selectedDownloadValue=foo,將在另存被設置爲作爲filename.ext在所有瀏覽器,包括Internet Explorer,誰頑固地忽略Content-Disposition標題中的文件名,實際上更喜歡URL中的路徑名稱a s的默認文件名。

現在,爲了從你的JSF支持bean調用上面的servlet,只需做一個重定向。

public void downloadFile(String fileName) throws IOException { 
    ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext(); 
    ec.redirect(ec.getRequestContextPath() + "/download/" + fileName + "?selectedDownloadValue=" + URLEncoder.encode(selectedDownloadValue, "UTF-8")); 
} 

如果可能的話,按您的業務需求(即沒有JSF表單/轉換/確認/ * somemagic *必要的,一切都只是「靜態」),那麼你甚至可以只是直接通過一個普通鏈接鏈接到它或者GET表單,而不需要中介JSF支持bean。

<h:outputLink value="#{request.contextPath}/download/#{bean.fileName}"> 
    <f:param name="selectedDownloadValue" value="foo" /> 
    Download 
</h:outputLink> 
<form action="#{request.contextPath}/download/#{bean.fileName}"> 
    <input type="hidden" name="selectedDownloadValue" value="foo" /> 
    <input type="submit" value="Download" /> 
</form> 
+0

謝謝你的答覆。一個問題是什麼包,我需要包括因爲該行'Files.copy(文件,response.getOutputStream());'我得到的錯誤'沒有合適的方法找到了副本(文件,ServletOutputStream的) 方法Files.copy(路徑,路徑,CopyOption ......)不適用 (參數不匹配;文件無法轉換爲路徑) 方法Files.copy(的InputStream,OutputStream的)是不是applicable' –

+0

剛剛從標準的Java SE:'java.nio.file。 Files'。我只忘記輸入'toPath()',我解決了答案。 – BalusC

相關問題