问题
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