在我的Vaadin Flow网络应用程序(版本14或更高版本)中,我想向我的用户显示下载数据文件的链接。
此下载内容可能很大。因此,我不想一次全部实现内存中的全部内容。我想连续产生大量的内容,一次提供一个下载块,以最大程度地减少内存的使用。例如,想象一下,数据库中有很多行,我们一次将一行送入下载。
我知道Vaadin Flow中的Anchor
小部件。但是,如何将一些动态创建的内容挂接到此类小部件?
此外,鉴于此数据是动态动态生成的,因此我希望用户计算机上已下载文件的名称默认为某个前缀,后跟YYYYMMDDTHHMMSS格式的当前日期时间。
注意:在这件事上我不是专家。我在这里提供的示例代码似乎运行正常。通过研究有限的文档并阅读了网络上的许多其他文章,我将这种解决方案拼凑在一起。矿山可能不是最好的解决方案。
有关更多信息,请参见Vaadin手册的Anchor
页面。
我们在您的问题中有三大部分:
如问题中所述,我们确实使用了Dynamic Content小部件(请参阅Anchor
)。
我们在布局上定义一个成员变量。
Javadoc
我们通过传递private Anchor anchor;
对象实例化。此类在Vaadin中定义。它的工作是包装我们制作的类,该类将产生扩展Java类StreamResource
的实现。
输入流通过从其StreamResource
方法返回一个InputStream
来一次提供一个八位位组的数据,其值是所需八位位组的数字,即0-255。到达数据末尾时,InputStream
返回负数。
在我们的代码中,我们已经实现了一个read
方法来充当int
工厂。
read
[实例化我们的makeStreamOfContent
时,我们传递了一个引用该InputStream
方法的方法引用。由于没有输入流或任何数据尚未生成,因此我们在这里变得有点抽象。我们只是在准备舞台;该操作稍后发生。
传递给private InputStream makeInputStreamOfContent ( )
{
return GenerativeInputStream.make( 4 );
}
的第一个参数是要在用户客户端计算机上创建的文件的默认名称。在此示例中,我们使用的是StreamResource
的虚构名称。
makeInputStreamOfContent
接下来,我们在HTML5 new StreamResource
元素上设置report.text
的属性。此属性向浏览器指示当用户单击链接时我们打算下载目标。
anchor =
new Anchor(
new StreamResource( "report.text" , this :: makeInputStreamOfContent ) ,
"Download generated content"
)
;
您可以通过将锚点控件包装在download
中来显示图标。
download
如果使用这样的图标,则应从anchor
小部件中删除文本标签。而是将任何所需的文本放在anchor.getElement().setAttribute( "download" , true );
中。因此,我们将空字符串(Button
)传递给Button
,并将标签文本作为第一个参数传递给downloadButton = new Button( new Icon( VaadinIcon.DOWNLOAD_ALT ) );
anchor.add( downloadButton );
。
Anchor
我们需要实现一个Button
子类,以提供给我们的下载小部件。
""
抽象类提供了除其中一种方法外的所有方法的实现。我们只需要实现new Anchor
方法即可满足我们项目的需求。
这里是一种可能的实现方式。实例化new Button
对象时,传递要生成的行数。一次生成一行数据,然后逐个八位字节地将数据提供给客户端。完成该行后,将生成另一行。因此,我们一次只处理一行就可以节省内存。
馈给客户端的八位位组是构成我们行的anchor =
new Anchor(
new StreamResource( "report.text" , this :: makeInputStreamOfContent ) ,
""
)
;
anchor.getElement().setAttribute( "download" , true );
downloadButton =
new Button(
"Download generated content" ,
new Icon( VaadinIcon.DOWNLOAD_ALT )
)
;
anchor.add( downloadButton );
文本的八位位组。预期文本的每个字符都可以包含一个或多个八位字节。如果您不明白这一点,请阅读Joel Spolsky的有趣且内容丰富的文章InputStream
。
InputStream
我找不到完成最后一部分的方法,默认文件名包含生成内容的那一刻。
我什至在此发表了关于堆栈溢出的问题:InputStream
问题是,在加载页面并实例化read
小部件时,链接小部件背后的URL仅创建了一次。之后,在用户阅读页面时,时间流逝。当用户最终单击链接以开始下载时,当前时刻晚于URL中记录的时刻。
似乎没有简单的方法可以将该URL更新到用户的click事件或download事件的当前时刻。
顺便说一句,对于实际工作,我自己不会写导出的文件。我会改用read
之类的库来编写GenerativeInputStream
或UTF-8内容。