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

与世无争的帅哥 提交于 2020-01-06 02:46:05

问题


I know Vaadin 14 offers the Upload component for the user to either pick a file(s) to upload or to drag-and-drop file(s).

But I am not sure how to use it. I want the contents of a plain text file on the web browser’s machine to load into memory as a String or CharSequence on the server machine.

While the description page for that component has some examples, I could use a complete yet minimal example of loading plain text.


回答1:


Here is an example view in Vaadin 14.1.0.alpha3. I am not an expert on Upload, so there may be better approaches, but this seems to be working.

Notice the @Route annotation, and adjust to suit your own app.

The 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 object is passed to our listener as our handle for the file(s) being uploaded.

The object receiving the uploaded octets is any implementation of the Vaadin Receiver interface. To load a single file into memory, use MemoryBuffer implementation. By passing a MemoryBuffer instance to our Upload instance, we are designating a place for the uploaded octets to go as they arrive on the server.

We use an InputStream to manage the flow of arriving octets. In this example we read the arriving octets one-by-one. Alternatively, there are ways to read many octets together.

Our InputStream reads each octet as an int with a value in the range from 0-255 inclusive. A value of -1 is a signal the stream of inputs has ended. So we collect these int values in a while loop until a negative one appears.

We use try-with-resources syntax to automatically close the InputStream that loads bytes from the client to the server.

We collect the arriving octets in a 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 encoding. In our case, we expect UTF-8 encoding. So we put this together by instantiating a new String object, passing to the constructor our collect octets and an enum object signifying our expectation of UTF-8: new String( bytesReceived.toByteArray() , StandardCharsets.UTF_8 ).

With our new String in hand, we echo back to the user the contents of the file by instantiating an HTML paragraph.

Here is the entire example 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.
    }
}

We can simplify the code above. Vaadin 14.1 comes bundled with 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. Pass the input stream, and specify the expected character encoding.

Revised code:

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.
    }
}

Caveat: The examples above are bare-bones minimal, as you asked. We have not done any error-handling nor react to the user canceling an upload mid-stream.


You may learn more by reading the source code of the Upload component’s demo page provided by the Vaadin Ltd company.

And read this detailed post about how Upload works in Vaadin Flow, Uploads and downloads, inputs and outputs by Matti Tahvonen.



来源:https://stackoverflow.com/questions/58493706/uploading-contents-of-a-text-file-to-a-string-in-memory-using-the-upload-widge

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!