如何从JSF支持bean提供文件下载?
有没有办法从JSF支持bean操作方法提供文件下载? 我试过很多东西。主要问题是,我无法找到如何获取响应的如何从JSF支持bean提供文件下载?,jsf,jsf-2,download,backing-beans,Jsf,Jsf 2,Download,Backing Beans,有没有办法从JSF支持bean操作方法提供文件下载? 我试过很多东西。主要问题是,我无法找到如何获取响应的OutputStream,以便将文件内容写入。我知道如何使用Servlet,但这不能从JSF表单调用,需要一个新的请求 如何从当前的FacesContext获取响应的OutputStream?简介 你可以把一切都搞定。在JSF1.x中,您可以通过以下方式获得原始HttpServletResponse对象。在JSF2.x中,您可以使用一系列新的委托方法,如,而无需从JSF框架下获取HttpSe
OutputStream
,以便将文件内容写入。我知道如何使用Servlet
,但这不能从JSF表单调用,需要一个新的请求
如何从当前的FacesContext
获取响应的OutputStream
?简介
你可以把一切都搞定。在JSF1.x中,您可以通过以下方式获得原始HttpServletResponse
对象。在JSF2.x中,您可以使用一系列新的委托方法,如,而无需从JSF框架下获取HttpServletResponse
在响应中,您应该设置内容类型
标题,以便客户端知道要将哪个应用程序与提供的文件关联。而且,您应该设置内容长度
标题,以便客户端可以计算下载进度,否则它将是未知的。而且,如果需要另存为对话框,则应将内容处置
标题设置为附件
,否则客户端将尝试以内联方式显示它。最后,只需将文件内容写入响应输出流
最重要的部分是调用通知JSF在将文件写入响应后不应执行导航和呈现,否则响应的结尾将被页面的HTML内容污染,或者在旧的JSF版本中,当JSF实现调用getWriter()
来呈现HTML时,您将得到一个IllegalStateException
,其中有一条消息,如已为此响应调用了getoutputstream()
关闭ajax/不要使用远程命令!
您只需确保操作方法不是由ajax请求调用的,而是在使用
和
启动时由普通请求调用的。Ajax请求和远程命令由JavaScript处理,由于安全原因,JavaScript没有强制与Ajax响应内容进行另存为对话的功能
如果您正在使用PrimeFaces
,那么您需要确保通过ajax=“false”
属性显式关闭ajax。如果您使用的是ICEfaces,则需要在命令组件中嵌套一个
通用JSF2.x示例
通用JSF1.x示例
通用静态文件示例
如果需要从本地磁盘文件系统流式传输静态文件,请按以下方式替换代码:
File file = new File("/path/to/file.ext");
String fileName = file.getName();
String contentType = ec.getMimeType(fileName); // JSF 1.x: ((ServletContext) ec.getContext()).getMimeType(fileName);
int contentLength = (int) file.length();
// ...
Files.copy(file.toPath(), output);
通用动态文件示例
如果您需要对动态生成的文件(如PDF或XLS)进行流式处理,则只需在此处提供输出
,其中使用的API需要输出流
例如,iText PDF:
String fileName = "dynamic.pdf";
String contentType = "application/pdf";
// ...
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, output);
document.open();
// Build PDF content here.
document.close();
例如,Apache POI HSSF:
String fileName = "dynamic.xls";
String contentType = "application/vnd.ms-excel";
// ...
HSSFWorkbook workbook = new HSSFWorkbook();
// Build XLS content here.
workbook.write(output);
workbook.close();
请注意,您不能在此处设置内容长度。因此,您需要删除该行以设置响应内容长度。这在技术上没有问题,唯一的缺点是最终用户将收到未知的下载进度。如果这很重要,那么您确实需要首先写入本地(临时)文件,然后按照上一章所示提供它
实用方法
如果您使用的是JSF实用程序库,那么您可以使用三种方便的方法之一,即使用文件
,或输入流
,或字节[]
,并指定该文件应作为附件(true
)或内联(false
)下载
是的,此代码按原样完整。您不需要自己调用responseComplete()
等等。此方法还正确处理IE特定的头和UTF-8文件名。您可以找到。这是完整的代码片段
@ManagedBean(name=“formBean”)
@会议范围
公共类FormBean实现了可序列化
{
私有静态最终长serialVersionUID=1L;
/**
*下载文件。
*/
public void downloadFile()引发IOException
{
File File=新文件(“C:\\docs\\instructions.txt”);
InputStream fis=新文件InputStream(文件);
字节[]buf=新字节[1024];
整数偏移=0;
int numRead=0;
而((偏移量=0))
{
偏移量+=numRead;
}
fis.close();
HttpServletResponse=
(HttpServletResponse)FacesContext.getCurrentInstance()
.getExternalContext().getResponse();
setContentType(“应用程序/八位字节流”);
setHeader(“内容处置”、“附件;文件名=instructions.txt”);
response.getOutputStream().write(buf);
response.getOutputStream().flush();
response.getOutputStream().close();
FacesContext.getCurrentInstance().responseComplete();
}
}
如果希望在运行时生成文件,您可以更改文件读取逻辑。这对我来说很有用:
public void download() throws IOException
{
File file = new File("file.txt");
FacesContext facesContext = FacesContext.getCurrentInstance();
HttpServletResponse response =
(HttpServletResponse) facesContext.getExternalContext().getResponse();
response.reset();
response.setHeader("Content-Type", "application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=file.txt");
OutputStream responseOutputStream = response.getOutputStream();
InputStream fileInputStream = new FileInputStream(file);
byte[] bytesBuffer = new byte[2048];
int bytesRead;
while ((bytesRead = fileInputStream.read(bytesBuffer)) > 0)
{
responseOutputStream.write(bytesBuffer, 0, bytesRead);
}
responseOutputStream.flush();
fileInputStream.close();
responseOutputStream.close();
facesContext.responseComplete();
}
public void downloadFile(String filename) throws IOException {
final FacesContext fc = FacesContext.getCurrentInstance();
final ExternalContext externalContext = fc.getExternalContext();
final File file = new File(filename);
externalContext.responseReset();
externalContext.setResponseContentType(ContentType.APPLICATION_OCTET_STREAM.getMimeType());
externalContext.setResponseContentLength(Long.valueOf(file.lastModified()).intValue());
externalContext.setResponseHeader("Content-Disposition", "attachment;filename=" + file.getName());
final HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
FileInputStream input = new FileInputStream(file);
byte[] buffer = new byte[1024];
final ServletOutputStream out = response.getOutputStream();
while ((input.read(buffer)) != -1) {
out.write(buffer);
}
out.flush();
fc.responseComplete();
}
很容易!我一直想知道如何根据PrimeFaces的showcase为其提供下载,因为它需要InputStream
基础结构才能下载p:fileDownload
,而我还没有设法将OutputStream
转换为InputStream
。现在很明显,即使是操作侦听器也可以更改响应内容类型,然后响应将在用户代理端作为文件下载。非常感谢。有没有办法使用HTTP GET而不是HTTP POST(h:commandButton和h:commandLink)?@Alfredo:有,在无标记视图中使用preRenderView
侦听器。这里回答了下载(好吧,服务)JSON的类似问题:链接断开了。也许这一个是合适的:@BalusC你涵盖了每一个jsf主题-谢谢你的支持
public void download() throws IOException {
Faces.sendFile(file, true);
}
@ManagedBean(name = "formBean")
@SessionScoped
public class FormBean implements Serializable
{
private static final long serialVersionUID = 1L;
/**
* Download file.
*/
public void downloadFile() throws IOException
{
File file = new File("C:\\docs\\instructions.txt");
InputStream fis = new FileInputStream(file);
byte[] buf = new byte[1024];
int offset = 0;
int numRead = 0;
while ((offset < buf.length) && ((numRead = fis.read(buf, offset, buf.length -offset)) >= 0))
{
offset += numRead;
}
fis.close();
HttpServletResponse response =
(HttpServletResponse) FacesContext.getCurrentInstance()
.getExternalContext().getResponse();
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=instructions.txt");
response.getOutputStream().write(buf);
response.getOutputStream().flush();
response.getOutputStream().close();
FacesContext.getCurrentInstance().responseComplete();
}
}
public void download() throws IOException
{
File file = new File("file.txt");
FacesContext facesContext = FacesContext.getCurrentInstance();
HttpServletResponse response =
(HttpServletResponse) facesContext.getExternalContext().getResponse();
response.reset();
response.setHeader("Content-Type", "application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=file.txt");
OutputStream responseOutputStream = response.getOutputStream();
InputStream fileInputStream = new FileInputStream(file);
byte[] bytesBuffer = new byte[2048];
int bytesRead;
while ((bytesRead = fileInputStream.read(bytesBuffer)) > 0)
{
responseOutputStream.write(bytesBuffer, 0, bytesRead);
}
responseOutputStream.flush();
fileInputStream.close();
responseOutputStream.close();
facesContext.responseComplete();
}
public void downloadFile(String filename) throws IOException {
final FacesContext fc = FacesContext.getCurrentInstance();
final ExternalContext externalContext = fc.getExternalContext();
final File file = new File(filename);
externalContext.responseReset();
externalContext.setResponseContentType(ContentType.APPLICATION_OCTET_STREAM.getMimeType());
externalContext.setResponseContentLength(Long.valueOf(file.lastModified()).intValue());
externalContext.setResponseHeader("Content-Disposition", "attachment;filename=" + file.getName());
final HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
FileInputStream input = new FileInputStream(file);
byte[] buffer = new byte[1024];
final ServletOutputStream out = response.getOutputStream();
while ((input.read(buffer)) != -1) {
out.write(buffer);
}
out.flush();
fc.responseComplete();
}