0

我们正在开发一个 Vaadin 应用程序,在 oc4j 10.1.3 上运行它。有一个窗口,可以将查询结果导出为 csv 文件。将 csv 文件创建为 vaadin FileResource 后,打开文件失败。这是片段:

File file = exporter.exportToFile();
final FileResource resource = new FileResource(file, getApplication());
resource.setCacheTime(0);
resource.getStream().setParameter("Content-Disposition", "attachment;filename=\""+file.getName()+"\"");
event.getButton().getWindow().open(resource);

此时,资源的uri为:app://APP/1/xy.csv

我们有一个过滤器用于重定向“/VAADIN”的“/”路径。当这个过滤器被调用时,文件的 uri/VAADIN/APP/1/xy.csv不是/APP/1/xy.csv,所以我删除了不必要的 /VAADIN 部分,并requestdispatcher.forward使用新的 uri 调用。但有趣的是,应用程序仍然失败,它在日志中说:

Aug 13, 2012 1:55:58 PM com.vaadin.terminal.gwt.server.AbstractApplicationServlet serveStaticResourcesInVAADIN
INFO: Requested resource [VAADIN/APP/1/xy.csv] not found from filesystem or through class loader. Add widgetset and/or theme JAR to your classpath or add files to WebContent/VAADIN folder.

所以uri又错了。它出现在地址栏中,应用程序重置到主页。但是,由于此 uri 仍在地址栏中,当我尝试再次创建 csv 文件时,在应用程序中执行与其他一些查询相同的操作时,导出部分确实会返回一个文件,即先前生成的文件。如果我尝试再次进行另一个查询(之前的 url 仍在浏览器的地址栏中),它似乎会生成新的 csv 文件,但会再次返回第一个文件。

它是一个 vaadin 错误还是一些 oc4j 魔法?:)

4

1 回答 1

0

Vaadin 框架在服务器端工作。那么为什么需要在服务器上创建不必要的临时 CSV 文件呢?尝试将所需数据直接导出到流中。

如果您需要导出少量数据,只需使用 ByteArrayOutputStream 和 Vaadin StreamResource。将您的 CSV 值写入 OutputStream 并将此流赋予如下功能:

    public void openResourceFromStream(final OutputStream out, String filename) {
    StreamSource streamSource = new StreamSource() {
        private static final long serialVersionUID = 1L;

        @Override
        public InputStream getStream() {
            ByteArrayOutputStream byteStream = (ByteArrayOutputStream) out;
            return new ByteArrayInputStream(byteStream.toByteArray());
        }
    };

    Resource sr = new StreamResource(streamSource, filename, getApplication());
    getWindow().open(sr, "_parent");
    }

如您所见,此代码执行从 OutputStream 到 InputStream 的简单对话,并使用结果 InputStream 来创建 Vaadin StreamResource 对象。

'filename' 参数设置将加载到客户端浏览器中的文件的默认名称(注意,用户始终可以使用“始终显示保存对话框”浏览器选项“即时”重命名文件)。

当然,这个变体有点难看,因为它将所有导出的数据保存在内存中。

如果您需要导出大量数据并且不想将它们全部保存在内存中,则可以使用 PipedOutputStream 或自定义循环缓冲区而不是 ByteArrayOutputStream 字节缓冲区。算法将是相同的。有关更多信息,请参阅有关 OutputStream 到 InputStream 对话的文章有关资源的 Vaadin 书籍章节

PS不要忘记在数据导出成功后完全关闭输入和输出流。

于 2012-08-14T23:12:20.827 回答