【问题标题】:How to download a file stored in a database with JSF 2.0如何使用 JSF 2.0 下载存储在数据库中的文件
【发布时间】:2011-07-26 18:50:02
【问题描述】:

我需要下载一个存储在数据库中的文件。我想我做了正确的查询并调用它我只是不知道如何将它连接到 JSF 页面中的按钮。 我也想知道,在将它传递到 JSF 页面之前,我是否必须将该图像保存在服务器的文件夹中。如果是这样,我该怎么做?

这是我用来从数据库返回 byte[] 的查询:

@NamedQuery(name = "downloadGarbage", query = "SELECT g.file FROM Garbage g WHERE g.id :idParam")
@Entity
public class Garbage implements Serializable {
@Lob
@Column(nullable = false)
private byte[] file;
....

这是一个简单的 EJB,它调用该查询然后获取 id:

@Stateless(name = "ejbs/FileDownloaderEJB")
public class FileDownloaderEJB implements IFileDownloaderEJB {

@PersistenceContext
private EntityManager em;

public byte[] downloadGarbage(Long id) {
    Query query = em.createNamedQuery("downloadGarbage");
    query.setParameter("idParam", id);

    Object o = query.getSingleResult();
    byte[] tmpArray = (byte[]) o; 
    return tmpArray;
}

现在这是让我感到困惑的部分,我怎么能在上面的 JSF 页面和托管 bean 中做到这一点?

@ManagedBean
@RequestScoped
public class DownloadController {

@EJB
private FileDownloaderEJB fileDownloaderEJB;

    ...

    private Garbage garbage;

public void startDownload(Long id) {
    fileDownloaderEJB.downloadGarbage(id);
//HOW TO START THE DOWNLOAD?
//Other Get Set Methods...

}

}

另外,我如何从命令按钮中的 JSF 将那个长 id 传递给 managedBean?这是否允许?

<!-- How to pass the value of id from -->
<h:commandButton action="downloadController.startDownload(#{garbage.id})">

【问题讨论】:

    标签: java jsf jpa jakarta-ee download


    【解决方案1】:

    仅当web.xml 被声明为 Servlet 3.0 并且 servletcontainer 也支持它(Glassfish 3、JBoss AS 6、Tomcat 7 等)时,在 EL 中传递参数才有效。您的尝试中只有一个语法错误,这是正确的方法:

    <h:commandButton action="#{downloadController.startDownload(garbage.id)}" />
    

    您甚至可以传递整个对象,这在这种特殊情况下会更好。

    <h:commandButton action="#{downloadController.startDownload(garbage)}" />
    

    然后,startDownload() 方法应该设置响应标头,以便网络浏览器了解响应正文代表的内容类型以及如何处理它,最后将内容写入响应正文。您可以在ExternalContext 的帮助下完成这一切。这是一个启动示例:

    public void startDownload(Garbage garbage) {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ExternalContext externalContext = facesContext.getExternalContext();
        externalContext.setResponseHeader("Content-Type", garbage.getContentType());
        externalContext.setResponseHeader("Content-Length", garbage.getContent().length);
        externalContext.setResponseHeader("Content-Disposition", "attachment;filename=\"" + garbage.getFileName() + "\"");
        externalContext.getResponseOutputStream().write(garbage.getContent());
        facesContext.responseComplete();
    }
    

    FacesContext#responseComplete() 的最后一行是强制性的,以便 JSF 了解它不应该导航到某个视图,从而可能导致之后与另一个 JSF 页面的响应出现错误。

    【讨论】:

    • 如果是 .doc 文件,ContentType 应该是什么。该方法 getContentType() 应该返回“text/xml”还是“text/plain”?
    • 哦,Word 文档当然不是文本文件。对于.doc,它是application/msword,对于.docx,它是application/vnd.openxmlformats-officedocument.wordprocessingml.document。如果您想根据文件名以编程方式确定它,您可以使用ServletContext#getMimeType()。另见stackoverflow.com/questions/2426773/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-28
    • 2011-07-18
    • 2020-06-13
    • 2021-10-02
    相关资源
    最近更新 更多