如何从 JSF 支持 bean 提供文件下载?
有什么方法可以从 JSF 支持 bean 操作方法提供文件下载吗? 我已经尝试了很多事情。主要问题是我无法弄清楚如何获取响应的 OutputStream
以便写入文件内容。我知道如何使用 Servlet
来完成此操作,但这不能从 JSF 表单调用,并且需要新的请求。
如何从当前 FacesContext
获取响应的 OutputStream
?
Is there any way of providing a file download from a JSF backing bean action method?
I have tried a lot of things. Main problem is that I cannot figure how to get the OutputStream
of the response in order to write the file content to. I know how to do it with a Servlet
, but this cannot be invoked from a JSF form and requires a new request.
How can I get the OutputStream
of the response from the current FacesContext
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
简介
你可以通过
ExternalContext
获取所有内容。有一堆getResponseXxx()
和setResponseXxx()
方法委托给在幕后使用的HttpServletResponse
。在响应中,您应该设置
Content-Type
标头,以便客户端知道哪个应用程序与提供的文件关联。并且,您应该设置Content-Length
标头,以便客户端可以计算下载进度,否则将未知。而且,如果您想要“另存为”对话框,则应将Content-Disposition
标头设置为attachment
,否则客户端将尝试内联显示它。最后只需将文件内容写入响应输出流即可。最重要的部分是调用
FacesContext #responseComplete()
通知 Jakarta Faces 在将文件写入响应后不应执行导航和渲染,否则结束响应将被页面的 HTML 内容污染,或者在较旧的 Faces 版本中,您将收到IllegalStateException
,其中包含类似getoutputstream() 已为此响应调用
的消息> 当 Faces 实现调用getWriter()
来呈现 HTML 时。关闭阿贾克斯!
您只需确保操作方法不是由 ajax 请求调用,而是在您使用
和
。由
/
触发的 Ajax 请求由 JavaScript 处理,而出于安全原因,默认情况下没有任何设施可以处理 Ajax 请求。强制与 ajax 响应内容进行另存为对话。如果您使用的是 PrimeFaces
,那么您需要确保通过ajax="false"
属性显式关闭 ajax。
也不能使用。如果您使用 ICEfaces,则需要在命令组件中嵌套
。如果您使用的是 PrimeFaces 10 或更高版本,则可以使用
在下载文件时使用onstart
、<代码>更新,<代码>oncomplete等等。通用操作方法示例
常见静态文件示例
如果您需要从本地磁盘文件系统流式传输静态文件,请替换如下代码:
常见动态文件示例
如果您需要流式传输动态生成的文件,例如 PDF 或 XLS ,然后只需在所使用的 API 需要
OutputStream
的地方提供output
即可。例如 iText PDF:
例如 Apache POI HSSF:
请注意,您不能在此处设置内容长度。因此,您需要删除设置响应内容长度的行。这在技术上没有问题,唯一的缺点是最终用户将看到未知的下载进度。如果这很重要,那么您确实需要先写入本地(临时)文件,然后按照上一章所示提供它。
实用方法
如果您使用 Faces 实用程序库 OmniFaces,那么您可以使用三个方便的
Faces#sendFile()
方法采用Path
、File
、InputStream 或 byte[]
,并指定文件应作为附件下载 (true
) 还是内联下载 (false
)。是的,这段代码是完整的。您不需要自己调用
responseComplete()
等。此方法还可以正确处理 IE 特定的标头和 UTF-8 文件名。您可以找到 源代码在这里。Introduction
You can get everything through
ExternalContext
. There are a bunch ofgetResponseXxx()
andsetResponseXxx()
methods which delegate to theHttpServletResponse
being used under the covers.On the response, you should set the
Content-Type
header so that the client knows which application to associate with the provided file. And, you should set theContent-Length
header so that the client can calculate the download progress, otherwise it will be unknown. And, you should set theContent-Disposition
header toattachment
if you want a Save As dialog, otherwise the client will attempt to display it inline. Finally just write the file content to the response output stream.Most important part is to call
FacesContext#responseComplete()
to inform Jakarta Faces that it should not perform navigation and rendering after you've written the file to the response, otherwise the end of the response will be polluted with the HTML content of the page, or in older Faces versions, you will get anIllegalStateException
with a message likegetoutputstream() has already been called for this response
when the Faces implementation callsgetWriter()
to render HTML.Turn off Ajax!
You only need to make sure that the action method is not called by an ajax request, but that it is called by a normal request as you fire with
<h:commandLink>
and<h:commandButton>
. Ajax requests fired by<f:ajax>
/<h:commandScript>
are handled by JavaScript which in turn has, due to security reasons, by default no facilities to force a Save As dialogue with the content of the ajax response.In case you're using e.g. PrimeFaces
<p:commandXxx>
, then you need to make sure that you explicitly turn off ajax viaajax="false"
attribute. The<p:remoteCommand>
can also not be used. In case you're using ICEfaces, then you need to nest a<f:ajax disabled="true" />
in the command component.In case you're using PrimeFaces 10 or newer, then you can use
<p:fileDownload>
to simulate Ajax-like behavior when downloading a file, withonstart
,update
,oncomplete
and all.Generic action method example
Common static file example
In case you need to stream a static file from the local disk file system, substitute the code as below:
Common dynamic file example
In case you need to stream a dynamically generated file, such as PDF or XLS, then simply provide
output
there where the API being used expects anOutputStream
.E.g. iText PDF:
E.g. Apache POI HSSF:
Note that you cannot set the content length here. So you need to remove the line to set response content length. This is technically no problem, the only disadvantage is that the enduser will be presented an unknown download progress. In case this is important, then you really need to write to a local (temporary) file first and then provide it as shown in previous chapter.
Utility method
If you're using Faces utility library OmniFaces, then you can use one of the three convenient
Faces#sendFile()
methods taking eitherPath
,File
,InputStream
, orbyte[]
, and specifying whether the file should be downloaded as an attachment (true
) or inline (false
).Yes, this code is complete as-is. You don't need to invoke
responseComplete()
and so on yourself. This method also properly deals with IE-specific headers and UTF-8 filenames. You can find source code here.这对我有用:
This is what worked for me:
这是我的解决方案,BalusC 的答案的扩展
This is my solution, an extension of BalusC's answer
这是完整的代码片段http://bharatonjava。 wordpress.com/2013/02/01/downloading-file-in-jsf-2/
如果您希望在运行时生成文件,您可以更改文件读取逻辑。
here is the complete code snippet http://bharatonjava.wordpress.com/2013/02/01/downloading-file-in-jsf-2/
You may change the file reading logic in case you want file to get generated at runtime.