使用 Vaadin 14 中的 "Upload" 小部件将文本文件的内容上传到内存中的字符串

Uploading contents of a text file to a string in memory using the "Upload" widget in Vaadin 14

我知道 Vaadin 14 提供 Upload 组件供用户选择要上传的文件或拖放文件。

但是我不知道怎么用。我希望 Web 浏览器机器上的纯文本文件的内容作为服务器机器上的 String or CharSequence 加载到内存中。

虽然该组件的描述页面有一些示例,但我可以使用加载纯文本的完整但最小的示例。

这是 Vaadin 14.1.0.alpha3 中的示例视图。我不是 Upload 方面的专家,所以可能有更好的方法,但这似乎有效。

注意 @Route 注释,并根据您自己的应用进行调整。

Upload component is a visual widget that appears on your web page, inviting the user to drag-and-drop files(s) or to use a file-picker dialog. We add an anonymous listener object, defined here in lambda syntax, to be invoked when the user does so. A FinishedEvent 对象作为正在上传的文件的句柄传递给我们的侦听器。

接收上传八位字节的对象是 Vaadin Receiver interface. To load a single file into memory, use MemoryBuffer 实现的任何实现。通过将 MemoryBuffer 实例传递给我们的 Upload 实例,我们正在为上传的八位字节指定一个位置,因为它们到达服务器。

我们使用 InputStream 来管理到达的八位字节流。在这个例子中,我们一个一个地读取到达的八位字节。或者,有一些方法可以一起读取多个八位字节。

我们的 InputStream 将每个八位字节读取为一个 int,其值在 0-255 范围内(含 0-255)。 -1 的值表示输入流已结束。因此,我们在 while 循环中收集这些 int 值,直到出现负值。

我们使用 try-with-resources syntax to automatically close InputStream 将字节从客户端加载到服务器。

我们以 ByteArrayOutputStream. The next step is making sense of those collected octets. There is no magic here. You must know the intended content such as plain text versus formatted text versus tab-delimited data versus binary data versus document format like PDF. In this example, we expect plain text. And for text we must know the character encoding such as ASCII, UTF-8, or the legacy Windows-1252 编码收集到达的八位字节。在我们的例子中,我们期望 UTF-8 编码。因此,我们通过实例化一个新的 String 对象,将其组合在一起,将我们收集的八位字节和一个枚举对象传递给构造函数,表示我们对 UTF-8 的期望:new String( bytesReceived.toByteArray() , StandardCharsets.UTF_8 ).

有了我们的新字符串,我们通过实例化一个 HTML 段落向用户回显文件的内容。

这是整个示例 class。

package work.basil.example;

import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.upload.FinishedEvent;
import com.vaadin.flow.component.upload.Upload;
import com.vaadin.flow.component.upload.receivers.MemoryBuffer;
import com.vaadin.flow.router.Route;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

@Route ( "upload" )
public class UploadView extends VerticalLayout
{
    // Constructor
    public UploadView ( )
    {
        this.add( new H1( "Upload" ) );
        MemoryBuffer buffer = new MemoryBuffer();
        Upload upload = new Upload( buffer );  // Connect our server-side `Receiver` implementation to the client-side `Upload` widget.
        upload.addFinishedListener(
                ( FinishedEvent finishedEvent ) -> {  // Event fired when user uses the `Upload` widget on the web page.
                    try (  // Autoclosable interface used in try-with-resources syntax.
                           InputStream inputStream = buffer.getInputStream() ;
                    )
                    {
                        // read the contents of the buffer.
                        // https://www.baeldung.com/convert-input-stream-to-array-of-bytes
                        ByteArrayOutputStream bytesReceived = new ByteArrayOutputStream();
                        int content; // Represents each octet arriving on server from client.
                        while ( ( content = inputStream.read() ) != - 1 )  // The arriving octet is returned to us as an `int` in the range 0 to 255. A value of -1 signals end-of-stream. Blocks until data arrives or stream closes.
                        {
                            bytesReceived.write( content );  // Collect the arriving octets into a `ByteArrayOutputStream`.
                        }
                        // Parse the collected octets as being text in UTF-8 encoding.
                        String s = new String( bytesReceived.toByteArray() , StandardCharsets.UTF_8 );  // You must know the particular  character-encoding used in the file.
                        this.add( new Paragraph( s ) );  // Echo the file contents back to the user.
                        System.out.println( "s = " + s );
                    }
                    catch ( IOException e )
                    {
                        e.printStackTrace();
                    }
                }
        );
        this.add( upload );  // Make the `Upload` instance named `upload` appear on our Vaadin-produced web page.
    }
}

我们可以简化上面的代码。 Vaadin 14.1 与 Apache Commons IO 2.5 library. That library has a convenience method for taking an InputStream and producing a String. So can turn a chunk of our code above into one-liner. Call static method org.apache.commons.io.IOUtils.toString 捆绑在一起。传递输入流,并指定预期的字符编码。

修改后的代码:

package work.basil.example ;

import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.upload.FinishedEvent;
import com.vaadin.flow.component.upload.Upload;
import com.vaadin.flow.component.upload.receivers.MemoryBuffer;
import com.vaadin.flow.router.PreserveOnRefresh;
import com.vaadin.flow.router.Route;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

@PreserveOnRefresh
@Route ( "upload" )
public class UploadView extends VerticalLayout
{
    // Constructor
    public UploadView ( )
    {
        this.add( new H1( "Upload" ) );
        MemoryBuffer buffer = new MemoryBuffer();
        Upload upload = new Upload( buffer );  // Connect our server-side `Receiver` implementation to the client-side `Upload` widget.
        upload.addFinishedListener(
                ( FinishedEvent finishedEvent ) -> {  // Event fired when user uses the `Upload` widget on the web page.

                    try (  // Autoclosable interface used in try-with-resources syntax.
                           InputStream inputStream = buffer.getInputStream() ;
                    )
                    {
                        // Read the data arriving in the buffer via the `InputStream` to produce a `String` object.
                        String s = IOUtils.toString( inputStream , StandardCharsets.UTF_8 );
                        this.add( new Paragraph( s ) );
                        System.out.println( "s = " + s );
                    }
                    catch ( IOException e )
                    {
                        e.printStackTrace();
                    }
                }
        );
        this.add( upload );  // Make the `Upload` instance named `upload` appear on our Vaadin-produced web page.
    }
}

警告: 如您所问,上面的示例是最简单的示例。我们没有做任何错误处理,也没有对用户中途取消上传做出反应。


您可以阅读 Vaadin Ltd 公司提供的 source code of the Upload component’s demo page 了解更多信息。

并详细阅读 post 上传 如何在 Vaadin Flow 中工作,Uploads and downloads, inputs and outputs Matti Tahvonen。