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