Skip to content

Commit ed6c5c6

Browse files
committed
feat: Use UploadHandler in documentation
fixes #4304
1 parent 9fe6464 commit ed6c5c6

File tree

3 files changed

+195
-95
lines changed

3 files changed

+195
-95
lines changed

articles/components/upload/file-handling.adoc

Lines changed: 161 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -14,118 +14,210 @@ The uploading of files may be handled either with Vaadin Flow using Java, or wit
1414

1515
== Handling Uploaded Files in Flow
1616

17-
The Java Flow Upload component provides an API to handle directly uploaded file data, without having to set up an endpoint or a servlet. It uses a [classname]`Receiver` implementation to write the incoming file data into an [classname]`OutputStream`.
17+
The Java Flow Upload component provides an API to handle directly uploaded file data, without having to set up an endpoint or a servlet. It uses a [classname]`UploadHandler` implementation to handle the incoming file data.
1818

19-
The following built-in implementations of [classname]`Receiver` are available:
19+
The [classname]`UploadHandler` is a functional interface that only requires the [methodame]`handleUploadRequest(UploadEvent)` to be implemented for receiving data or use one of the built-in implementations.
2020

21-
- [classname]`MemoryBuffer`;
22-
- [classname]`MultiFileMemoryBuffer`;
23-
- [classname]`FileBuffer`; and
24-
- [classname]`MultiFileBuffer`.
21+
The following built-in implementations of [classname]`UploadHandler` are available:
2522

26-
These are described in the sub-sections that follow.
23+
- [classname]`InMemoryUploadHandler`, Stores uploaded files in memory
24+
- [classname]`FileUploadHandler`, Saves uploaded files to the file system
25+
- [classname]`TemporaryFileUploadHandler`, Saves uploaded files to temporary files
2726

27+
These are described in the sub-sections that follow.
28+
All of the build-in implementations extend [classname]`TransferProgressAwareHandler` and support <<add-progress-listener, adding progress listeners>>.
2829

29-
=== MemoryBuffer
30+
=== InMemoryUploadHandler
3031

31-
The [classname]`MemoryBuffer` can handle a single file upload at once. It does so by writing the file data into an in-memory buffer.
32+
The [classname]`InMemoryUploadHandler` stores uploaded files in memory as byte arrays.
3233

33-
Using [classname]`MemoryBuffer` will configure the component so that only a single file can be selected.
34+
The handler is given a `successhandler` of type `SerializableBiConsumer<UploadMetadata, byte[]> successHandler` that is called for each successful upload.
35+
The `successhandler` callback contains [classname]`UploadMetadata` with information on the uploaded file and a `byte[]` that contains the actual data from the upload.
3436

3537
[source,java]
3638
----
37-
MemoryBuffer memoryBuffer = new MemoryBuffer();
39+
InMemoryUploadHandler inMemoryHandler = UploadHandler.inMemory(
40+
(metadata, data) -> {
41+
// Get other information about the file.
42+
String fileName = event.getFileName();
43+
String mimeType = event.getMIMEType();
44+
long contentLength = event.getContentLength();
3845
39-
Upload upload = new Upload(memoryBuffer);
40-
upload.addSucceededListener(event -> {
41-
// Read the data from the buffer.
42-
InputStream fileData = memoryBuffer.getInputStream();
46+
// Do something with the file data...
47+
});
4348
44-
// Get other information about the file.
45-
String fileName = event.getFileName();
46-
String mimeType = event.getMIMEType();
47-
long contentLength = event.getContentLength();
4849
49-
// Do something with the file data...
50-
});
50+
Upload upload = new Upload(inMemoryHandler);
5151
----
5252

53+
=== FileUploadHandler
54+
55+
The [classname]`FileUploadHandler` saves the upload as a file to the file system.
5356

54-
=== MultiFileMemoryBuffer
57+
The handler is given a `successhandler` of type `SerializableBiConsumer<UploadMetadata, File> successHandler` that is called for each successful upload and a [classname]`FileFactory`.
58+
The `successhandler` callback contains [classname]`UploadMetadata` with information on the uploaded file and the actual [classname]`File` where the data was written.
5559

56-
The [classname]`MultiFileMemoryBuffer` is the same as [classname]`MemoryBuffer`, but it can handle multiple file uploads at once. It writes the file data into a set of in-memory buffers.
60+
The file used is defined with [classname]`FileFactory` that gets the filename for the upload and should return the [classname]`File` to store the data into.
5761

5862
[source,java]
5963
----
60-
MultiFileMemoryBuffer multiFileMemoryBuffer = new MultiFileMemoryBuffer();
61-
62-
Upload upload = new Upload(multiFileMemoryBuffer);
63-
upload.addSucceededListener(event -> {
64-
// Determine which file was uploaded
65-
String fileName = event.getFileName();
66-
67-
// Read the data for that specific file.
68-
InputStream fileData = multiFileMemoryBuffer
69-
.getInputStream(fileName);
70-
71-
// Get other information about the file.
72-
String mimeType = event.getMIMEType();
73-
long contentLength = event.getContentLength();
64+
SerializableBiConsumer<UploadMetadata, File> successHandler = (metadata, file) ->
65+
System.out.printf("File saved to: %s%n", file.getAbsolutePath());
66+
FileFactory fileFactory = (fileName) -> new File("/path/to/uploads", fileName);
67+
FileUploadHandler fileHandler = UploadHandler.toFile(successHandler, fileFactory);
7468
75-
// Do something with the file data...
76-
});
69+
Upload upload = new Upload(fileHandler);
7770
----
7871

72+
=== TemporaryFileUploadHandler
7973

80-
=== FileBuffer
74+
The [classname]`TemporaryFileUploadHandler` works the same as [classname]`FileUploadHandler`, except that instead of taking in a [classname]`FileFactory`, it stores the data into a temporary file in the system default temporary-file directory.
8175

82-
The [classname]`FileBuffer` can handle a single file upload at once. It saves the file on the file system, in the current working directory of the Java application.
83-
84-
Using [classname]`FileBuffer` will configure the component so that only a single file can be selected.
76+
The handler is given a `successhandler` of type `SerializableBiConsumer<UploadMetadata, File> successHandler` that is called for each successful upload and a [classname]`FileFactory`.
77+
The `successhandler` callback contains [classname]`UploadMetadata` with information on the uploaded file and the actual [classname]`File` where the data was written.
8578

8679
[source,java]
8780
----
88-
FileBuffer fileBuffer = new FileBuffer();
81+
SerializableBiConsumer<UploadMetadata, File> successHandler = (metadata, file) ->
82+
System.out.printf("File saved to: %s%n", file.getAbsolutePath());
8983
90-
Upload upload = new Upload(fileBuffer);
91-
upload.addSucceededListener(event -> {
92-
// Get information about the file that was
93-
// written to the file system.
94-
FileData savedFileData = fileBuffer.getFileData();
95-
String absolutePath = savedFileData.getFile().getAbsolutePath();
84+
TemporaryFileUploadHandler temporaryFileHandler = UploadHandler.toTempFile(successHandler);
9685
97-
System.out.printf("File saved to: %s%n", absolutePath);
98-
});
86+
Upload upload = new Upload(temporaryFileHandler);
9987
----
10088

89+
=== Custom UploadHandler Implementations
10190

102-
=== MultiFileBuffer
91+
For more advanced use cases, you can provide custom implementations for [classname]`UploadHandler`.
92+
You might do this, for example, to save files into a specific directory, or to upload them to cloud storage.
10393

104-
The [classname]`MultiFileBuffer` works the same as [classname]`FileBuffer`, except that it can handle multiple file uploads at once. For each file, it saves the file on the file system, in the current working directory of the Java application.
94+
[classname]`UploadHandler` is a [annotationname]`FuncionalInterface` so it can be implemented or just be a lambda expression.
10595

10696
[source,java]
10797
----
108-
MultiFileBuffer fileBuffer = new MultiFileBuffer();
109-
110-
Upload upload = new Upload(fileBuffer);
111-
upload.addSucceededListener(event -> {
112-
// Determine which file was uploaded successfully
113-
String uploadFileName = event.getFileName();
114-
115-
// Get information for that specific file
116-
FileData savedFileData = multiFileBuffer
117-
.getFileData(uploadFileName);
118-
String absolutePath = savedFileData.getFile().getAbsolutePath();
98+
public class CustomUploadHandler implements UploadHandler {
99+
@Override
100+
public void handleUploadRequest(UploadEvent event) {
101+
try (InputStream inputStream = event.getInputStream()) {
102+
// Process the uploaded file
103+
// ...
104+
} catch (IOException e) {
105+
throw new UncheckedIOException(e);
106+
}
107+
}
108+
109+
@Override
110+
public void responseHandled(boolean success, VaadinResponse response) {
111+
// Set your own custom response value for success/fail by overriding this method.
112+
// Default responses are 200 ok for success and 500 internal server error for failure
113+
}
114+
}
115+
----
119116

120-
System.out.printf("File saved to: %s%n", absolutePath);
121-
});
117+
[source,java]
118+
----
119+
UploadHandler uploadHandler = (event) -> {
120+
try (InputStream inputStream = event.getInputStream()) {
121+
// Process the uploaded file
122+
// ...
123+
} catch (IOException e) {
124+
throw new UncheckedIOException(e);
125+
}
126+
};
122127
----
123128

129+
== Upload Progress Tracking
124130

125-
=== Custom Receiver Implementations
131+
To add progress tracking to a custom upload handler, you can extend [classname]`TransferProgressAwareHandler`:
126132

127-
For more advanced use cases, you can provide custom implementations for [classname]`Receiver` or [classname]`MultiFileReceiver`. You might do this, for example, to save files into a specific directory, or to upload them to cloud storage.
133+
[source,java]
134+
----
135+
public class CustomUploadHandler
136+
extends TransferProgressAwareHandler<UploadEvent, CustomUploadHandler>
137+
implements UploadHandler {
138+
@Override
139+
public void handleUploadRequest(UploadEvent event) {
140+
try (InputStream inputStream = event.getInputStream();
141+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();) {
142+
// Use the TransferProgressListener.transfer method to copy the data
143+
// to notify progress listeners
144+
TransferProgressListener.transfer(
145+
inputStream,
146+
outputStream,
147+
getTransferContext(event),
148+
getListeners());
149+
// Process the data
150+
byte[] data = outputStream.toByteArray();
151+
// ...
152+
} catch (IOException e) {
153+
// Notify listeners of the error
154+
notifyError(event, e);
155+
throw new UncheckedIOException(e);
156+
}
157+
}
158+
@Override
159+
protected TransferContext getTransferContext(UploadEvent event) {
160+
return new TransferContext(
161+
event.getRequest(),
162+
event.getResponse(),
163+
event.getSession(),
164+
event.getFileName(),
165+
event.getOwningElement(),
166+
event.getFileSize());
167+
}
168+
}
169+
----
170+
With this you can add a [classname]`TransferProgressListener` to the handler or use the shortcut methods for handling specific progress events.
128171

172+
[[add-progress-listener]]
173+
.Add a TransferProgressListener
174+
[source,java]
175+
----
176+
TransferProgressListener progressListener = new TransferProgressListener() {
177+
@Override
178+
public void onStart(TransferContext context) {
179+
System.out.println("Upload started");
180+
}
181+
182+
@Override
183+
public void onProgress(TransferContext context,
184+
long transferredBytes, long totalBytes) {
185+
double percentage = (double) transferredBytes / totalBytes * 100;
186+
System.out.printf("Upload progress: %.2f%%\n", percentage);
187+
}
188+
189+
@Override
190+
public void onError(TransferContext context, IOException reason) {
191+
System.out.println("Upload failed");
192+
}
193+
194+
@Override
195+
public void onComplete(TransferContext context,
196+
long transferredBytes) {
197+
System.out.println("Upload completed successfully");
198+
}
199+
};
200+
201+
uploadHandler.addTransferProgressListener(progressListener);
202+
----
203+
204+
.Add progress handlers through shortcuts
205+
[source,java]
206+
----
207+
CustomUploadHandler uploadHandler = new CustomUploadHandler()
208+
.whenStart(() -> System.out.println("Upload started"))
209+
.onProgress((transferredBytes, totalBytes) -> {
210+
double percentage = (double) transferredBytes / totalBytes * 100;
211+
System.out.printf("Upload progress: %.2f%%\n", percentage);
212+
})
213+
.whenComplete((success) -> {
214+
if (success) {
215+
System.out.println("Upload completed successfully");
216+
} else {
217+
System.out.println("Upload failed");
218+
}
219+
});
220+
----
129221

130222
== Handling Upload Requests in Lit and React
131223

articles/flow/advanced/stream-resources.adoc

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
title: UploadHandler
3+
page-title: How to use UploadHandler in Vaadin Flow
4+
description: Using UploadHandler to receive an incoming data stream.
5+
meta-description: Learn to receive content using ElementRequestHandler in Vaadin Flow.
6+
order: 130
7+
---
8+
9+
10+
= Using UploadHandler to Receive an Incoming Data Stream
11+
12+
To receive an upload from the client, you need to register an [classname]`UploadHandler` that accepts a URL to handle receiving an upload stream.
13+
14+
To create an [classname]`UploadHandler`, you need implement the [methodname]`handleUploadRequest` to handle the upload or use one of the pregenerated UploadHandlers.
15+
The existing [classname]`UploadHandler` implementations can be gotten through the static methods in [classname]`UploadHandler`, e.g. `UploadHandler.toTempFile(SerializableBiConsumer<UploadMetadata, File> successHandler)`
16+
17+
[NOTE]
18+
When receiving a multipart upload the [methodname]`handleUploadRequest` will be called separately for each file in the upload.
19+
20+
Then the handler can be registered through the [classname]`Element` API after registering it to the [classname]`StreamResourceRegistration`.
21+
22+
[source,java]
23+
----
24+
List<File> outputFiles = new ArrayList<>(1);
25+
UploadHandler uploadHandler = UploadHandler.toTempFile((uploadMetadata, file) -> outputFiles.add(file));
26+
27+
StreamRegistration streamRegistration = VaadinSession.getCurrent()
28+
.getResourceRegistry()
29+
.registerResource(uploadHandler, getElement());
30+
31+
getElement().setAttribute("target", streamRegistration);
32+
----
33+
34+
[discussion-id]`4482D0BF-E742-4FEA-A888-854B758FE576`

0 commit comments

Comments
 (0)