我已经完成了以下工作:
现在我需要让第4步工作:
任何人都可以给我一个提示吗?我试图了解我在谷歌上发现的东西,但它并没有像预期的那样发挥作用。我是否必须设置内容类型?当我设置应用程序/八位字节流时,只有txt和csv文件会正确显示(在浏览器中,而不是我想要的下载弹出窗口),其他文件将无效...
JSP:
<a4j:commandLink value="Download" action="#{appController.downloadFile}" rendered="#{!file.directory}">
<f:param name="file" value="#{file.absoluteFilename}" />
</a4j:commandLink>
AppController的:
public String downloadFile() {
String filename = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("file");
File file = new File(filename);
HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
writeOutContent(response, file, file.getName());
FacesContext.getCurrentInstance().responseComplete();
return null;
}
private void writeOutContent(final HttpServletResponse res, final File content, final String theFilename) {
if (content == null) {
return;
}
try {
res.setHeader("Pragma", "no-cache");
res.setDateHeader("Expires", 0);
res.setHeader("Content-disposition", "attachment; filename=" + theFilename);
FileInputStream fis = new FileInputStream(content);
ServletOutputStream os = res.getOutputStream();
int bt = fis.read();
while (bt != -1) {
os.write(bt);
bt = fis.read();
}
os.flush();
fis.close();
os.close();
} catch (final IOException ex) {
Logger.getLogger(ApplicationController.class.getName()).log(Level.SEVERE, null, ex);
}
}
答案 0 :(得分:8)
您的具体问题是您正在尝试通过Ajax下载文件。这是不正确的。 JavaScript无法处理二进制响应,也没有任何强制另存为对话的工具。你需要让它成为一个正常的同步请求,这样它就是webbrowser本身必须处理它的。
<h:commandLink value="Download" action="#{appController.downloadFile}" rendered="#{!file.directory}">
<f:param name="file" value="#{file.absoluteFilename}" />
</h:commandLink>
关于设置内容类型,如果您手边有一个带扩展名的文件名,则可以使用ServletContext#getMimeType()
根据<mime-mapping>
中的web.xml
解析它(服务器的默认的一个或你的webapp的一个。)
ServletContext servletContext = (ServletContext) externalContext.getContext();
String contentType = servletContext.getMimeType(file.getName());
if (contentType == null) {
contentType = "application/octet-stream";
}
response.setContentType(contentType);
// ...
(请注意,我假设你正在使用JSF 1.x,看看你如何获得servlet响应,你可以,因为JSF 2.x否则也使用ExternalContext#getMimeType()
)
答案 1 :(得分:4)
我几周前完成了第4步,让我给你一些建议:
使用链接html标记组件。为此,我建议使用a4j:htmlCommandLink
标记组件(它与公共h:commandLink
类似,区别在于<f:param />
组件始终呈现,您可以在component documentation中查看更多内容
如果您不知道要下载的文件类型(),则必须将内容设置为 application / octet-stream 。
在设置要下载到您的回复的文件后,您应该设置回复已完成。
我会将此Backing Bean代码用于此请求:
public void descargaArchivo() {
//sorry but the programming standard says that we MUST declare
//our variables at the beginning of any function =(
HttpServletResponse objResponse;
FileInputStream objFileInputStream;
String strNombreCompletoArchivo, strNombreArchivo;
byte[] arrDatosArchivo;
try {
//Here I get the <f:param> with the full name of the file. It encapsulates
// the Faces.getCurrentInstance... call.
strNombreCompletoArchivo = UManejadorSesionWeb.obtieneParametro("nombreCompletoArchivo");
//The function obtieneNombreArchivo retrieves the name of the file
//based on the full name and the file separator (/ for Windows, \ for Linux)
strNombreArchivo = UFuncionesGenerales.obtieneNombreArchivo(strNombreCompletoArchivo);
//Getting the response from Faces.getCurrentInstance...
objResponse = UManejadorSesionWeb.obtieneHttpResponse();
//Setting up the response content type and header (don't set the length!)
objResponse.setContentType("application/octet-stream");
objResponse.setHeader("Content-Disposition", "attachment; filename=\"" + strNombreArchivo + "\"");
//Create the FileInputStream for the file to download
objFileInputStream = new FileInputStream(strNombreCompletoArchivo);
//Setting the file on the response
arrDatosArchivo = new byte[UConstante.BUFFER_SIZE];
while(objFileInputStream.read(arrDatosArchivo, 0, UConstante.BUFFER_SIZE) != -1) {
objResponse.getOutputStream().write(arrDatosArchivo, 0, UConstante.BUFFER_SIZE);
}
objFileInputStream.close();
objResponse.getOutputStream().flush();
objResponse.getOutputStream().close();
//Telling the framework that the response has been completed.
FacesContext.getCurrentInstance().responseComplete();
} catch (Exception objEx) {
//manage the errors...
}
}
//The constant used for byte array size
public class UConstante {
public static final int BUFFER_SIZE = 2048;
}
我使用的jsp片段如下所示:
<a4j:htmlCommandLink rendered="#{documento.rutaDestino != null}"
action="#{documentoRequerido.descargaArchivo}">
<f:param name="nombreCompletoArchivo" value="#{documento.rutaDestino}" />
<h:graphicImage value="/Resource/iconos/mover-abajo.png" styleClass="pic" />
</a4j:htmlCommandLink>
希望这会对你有所帮助。
编辑:我有空闲时间,抱歉,但我们有点忙于这个项目。 Java代码在IE8,Firefox 9和10以及Chrome 16中进行了更新和测试。对于缓冲区大小常数的值,我做了一些研究并在this站点找到了一个很好的答案。P.S。:我不认为这是一场比赛,我只是尽力帮助别人。如果我的代码不好,那么感谢让我知道,这是让每个人都能更好,更健康地成长的更好方式:)。
编辑:感谢@lisa
要手动完成以下操作,只需在代码段中更改此部分
即可//strNombreCompletoArchivo = UManejadorSesionWeb.obtieneParametro("nombreCompletoArchivo");
String parameterStr = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap.get("nombreCompletoArchivo");
strNombreCompletoArchivo = parameterStr;
答案 2 :(得分:3)
下载时不需要richfaces a4j:commandLink标记,标准的jsf标记h:commandLink就足够了。
然后确保在响应中设置了以下标题(您可以在firefox中使用firebug进行检查):
内容 - 处置附件;文件名= “your_file_name.xxx”
Content-Type application / xxx
内容长度1234
Content-Length:字节数。