Interface PartEvent

All Known Subinterfaces:
FilePartEvent, FormPartEvent

public interface PartEvent
Represents an event for a "multipart/form-data" request. Can be a FormPartEvent or a FilePartEvent.

Server Side

Each part in a multipart HTTP message produces at least one PartEvent containing both headers and a buffer with the contents of the part.
  • Form fields will produce a single FormPartEvent, containing the value of the field.
  • File uploads will produce one or more FilePartEvents, containing the filename used when uploading. If the file is large enough to be split across multiple buffers, the first FilePartEvent will be followed by subsequent events.
The final PartEvent for a particular part will have isLast() set to true, and can be followed by additional events belonging to subsequent parts. The isLast() property is suitable as a predicate for the Flux.windowUntil(Predicate) operator, in order to split events from all parts into windows that each belong to a single part. From that, the Flux.switchOnFirst(BiFunction) operator allows you to see whether you are handling a form field or file upload. For example:
 Flux<PartEvent> allPartsEvents = ... // obtained via @RequestPayload or request.bodyToFlux(PartEvent.class)
 allPartsEvents.windowUntil(PartEvent::isLast)
   .concatMap(p -> p.switchOnFirst((signal, partEvents) -> {
       if (signal.hasValue()) {
           PartEvent event = signal.get();
           if (event instanceof FormPartEvent formEvent) {
               String value = formEvent.value();
               // handle form field
           }
           else if (event instanceof FilePartEvent fileEvent) {
               String filename = fileEvent.filename();
               Flux<DataBuffer> contents = partEvents.map(PartEvent::content);
               // handle file upload
           }
           else {
               return Mono.error(new RuntimeException("Unexpected event: " + event));
           }
       }
       else {
         return partEvents; // either complete or error signal
       }
   }))
 
Received part events can also be relayed to another service by using the WebClient. See below.

NOTE that the body contents must be completely consumed, relayed, or released to avoid memory leaks.

Client Side

On the client side, PartEvents can be created to represent a file upload. The streams returned by these static methods can be concatenated via Flux.concat(Publisher[]) to create a request for the WebClient: For instance, this sample will POST a multipart form containing a form field and a file.
 Resource resource = ...
 Mono<String> result = webClient
   .post()
   .uri("https://example.com")
   .body(Flux.concat(
     FormPartEvent.create("field", "field value"),
     FilePartEvent.create("file", resource)
   ), PartEvent.class)
   .retrieve()
   .bodyToMono(String.class);
 
Since:
6.0
Author:
Arjen Poutsma
See Also:
  • Method Summary

    Modifier and Type
    Method
    Description
    Return the content of this event.
    Return the headers of the part that this event belongs to.
    boolean
    Indicates whether this is the last event of a particular part.
    default String
    Return the name of the event, as provided through the Content-Disposition name parameter.
  • Method Details

    • name

      default String name()
      Return the name of the event, as provided through the Content-Disposition name parameter.
      Returns:
      the name of the part, never null or empty
    • headers

      HttpHeaders headers()
      Return the headers of the part that this event belongs to.
    • content

      DataBuffer content()
      Return the content of this event. The returned buffer must be consumed or released.
    • isLast

      boolean isLast()
      Indicates whether this is the last event of a particular part.