从JSF页面下载具有适当扩展名的文件

时间:2015-09-28 07:41:04

标签: html5 jsf jsf-2 jsf-2.2

我正在使用此代码从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,我尝试添加其他标头但没有结果。 也许在下载之前我需要获取文件扩展名?有没有解决方案?

1 个答案:

答案 0 :(得分:3)

为了获得最佳的跨浏览器兼容性,以获得具有正确文件名的下载,特别是如果您还要覆盖Internet Explorer,则文件名必须是触发下载的实际URL的路径名。这不适用于JSF表单,因为它们默认提交到JSF页面本身的URL。

实现这一目标的最佳方法是创建一个独立的文件servlet,它监听前缀URL模式,如/file/*/download/*等,以便文件名可以作为路径名提供。 URL。根据您当前的JSF方法,下面是独立文件servlet的外观,以及减少样板和废话的一些改进,以及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下使用,并将在所有浏览器中以<{em>另存为的形式提供给所有浏览器,包括Internet Explorer,后者顽固地忽略{{1}中的文件名1}}标题并且实际上更喜欢URL中的路径名作为默认文件名。

现在,为了从JSF支持bean调用上述servlet,只需执行重定向。

filename.ext

如果可能,根据您的业务要求(即没有JSF表格/转换/验证/ * somemagic *必要;所有只是“静态”),那么您甚至可以直接通过普通链接或GET表单链接到它无需中间的JSF支持bean。

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