在Vaadin中通过PostgreSQL下载CSV

问题描述

我有一个Vaadin 14应用程序,该应用程序从Postgresql 11数据库检索数据。 将Java 8与9.4-1202-jdbc42一起使用。

我尝试实现数据库表的下载功能。我创建了一个带有以下代码片段的按钮。它正在运行,我可以下载示例数据。

StreamResource resource = new StreamResource("foo.csv",() -> new ByteArrayInputStream("foo,foo2,foo3\nboo,boo2,boo3".getBytes()));
Button button = new Button("Click to download");
FileDownloadWrapper buttonWrapper = new FileDownloadWrapper(resource);
buttonWrapper.wrapComponent(button);
add(buttonWrapper);

但是我想从Postgresql数据库下载数据,而不是一些静态输入。因此,我使用copyManager(org.postgresql.copy.copyManager)进行“ copY ... TO STDOUT”请求。

String sql = "SELECT * FROM table";
copyManager.copyOut("copY (" + sql + ") TO STDOUT WITH (FORMAT CSV,HEADER)",outputStream);

编辑: 现在可以创建StreamResource,但是Postgresql不喜欢我的sql语句。 当前,此操作仅使用表头创建一个空的csv。

copyOut copiedData = copyManager.copyOut(sqlRequest);
ByteArrayInputStream stream = new ByteArrayInputStream(copiedData.readFromcopy());
return new StreamResource("foo.csv",() -> stream);

Postgresql对PgAdmin中相同的sql请求的响应:

copY (SELECT * FROM table) TO STDOUT WITH (FORMAT CSV,HEADER)
ERROR:  can't execute copY TO: use the copy_to() method instead

如果我将STDOUT替换为文件名,则可以在PgAdmin中使用

copY (SELECT * FROM table) TO 'D:\test.csv' WITH (FORMAT CSV,HEADER);
copY 63
Query returned successfully in 881 msec.

尽管我知道在PgAdmin控制台中使用STDOUT并没有多大意义,但它应该可以通过JDBC使用,对吧?

我的sql语句怎么了?我找不到有关copy_to()方法的任何好信息。

解决方法

您可以使用OpenCSV library从ResultSet中创建CSV文件,而不是直接从数据库查询中创建CSV文件。

但是,您实际上并不需要文件系统中的物理文件。甚至还有一些潜在的严重弊端-文件吃光了有限的磁盘空间,I / O昂贵,并且有可能意外地将一个用户的文件链接到另一个用户。 StreamResource接受任何类型的输入流,因此最好将整个操作都保留在内存中,而无需中间的物理文件。