48
48
*/
49
49
public abstract class BodyExtractors {
50
50
51
- private static final ResolvableType FORM_TYPE =
51
+ private static final ResolvableType FORM_MAP_TYPE =
52
52
ResolvableType .forClassWithGenerics (MultiValueMap .class , String .class , String .class );
53
53
54
- private static final ResolvableType MULTIPART_TYPE = ResolvableType .forClassWithGenerics (
54
+ private static final ResolvableType MULTIPART_MAP_TYPE = ResolvableType .forClassWithGenerics (
55
55
MultiValueMap .class , String .class , Part .class );
56
56
57
+ private static final ResolvableType PART_TYPE = ResolvableType .forClass (Part .class );
58
+
57
59
58
60
/**
59
61
* Return a {@code BodyExtractor} that reads into a Reactor {@link Mono}.
@@ -133,15 +135,16 @@ public static <T> BodyExtractor<Flux<T>, ReactiveHttpInputMessage> toFlux(Resolv
133
135
public static BodyExtractor <Mono <MultiValueMap <String , String >>, ServerHttpRequest > toFormData () {
134
136
return (serverRequest , context ) -> {
135
137
HttpMessageReader <MultiValueMap <String , String >> messageReader =
136
- formMessageReader ( context );
138
+ messageReader ( FORM_MAP_TYPE , MediaType . APPLICATION_FORM_URLENCODED , context );
137
139
return context .serverResponse ()
138
- .map (serverResponse -> messageReader .readMono (FORM_TYPE , FORM_TYPE , serverRequest , serverResponse , context .hints ()))
139
- .orElseGet (() -> messageReader .readMono (FORM_TYPE , serverRequest , context .hints ()));
140
+ .map (serverResponse -> messageReader .readMono (FORM_MAP_TYPE , FORM_MAP_TYPE , serverRequest , serverResponse , context .hints ()))
141
+ .orElseGet (() -> messageReader .readMono (FORM_MAP_TYPE , serverRequest , context .hints ()));
140
142
};
141
143
}
142
144
143
145
/**
144
- * Return a {@code BodyExtractor} that reads form data into a {@link MultiValueMap}.
146
+ * Return a {@code BodyExtractor} that reads multipart (i.e. file upload) form data into a
147
+ * {@link MultiValueMap}.
145
148
* @return a {@code BodyExtractor} that reads multipart data
146
149
*/
147
150
// Note that the returned BodyExtractor is parameterized to ServerHttpRequest, not
@@ -150,10 +153,29 @@ public static BodyExtractor<Mono<MultiValueMap<String, String>>, ServerHttpReque
150
153
public static BodyExtractor <Mono <MultiValueMap <String , Part >>, ServerHttpRequest > toMultipartData () {
151
154
return (serverRequest , context ) -> {
152
155
HttpMessageReader <MultiValueMap <String , Part >> messageReader =
153
- multipartMessageReader ( context );
156
+ messageReader ( MULTIPART_MAP_TYPE , MediaType . MULTIPART_FORM_DATA , context );
154
157
return context .serverResponse ()
155
- .map (serverResponse -> messageReader .readMono (MULTIPART_TYPE , MULTIPART_TYPE , serverRequest , serverResponse , context .hints ()))
156
- .orElseGet (() -> messageReader .readMono (MULTIPART_TYPE , serverRequest , context .hints ()));
158
+ .map (serverResponse -> messageReader .readMono (MULTIPART_MAP_TYPE ,
159
+ MULTIPART_MAP_TYPE , serverRequest , serverResponse , context .hints ()))
160
+ .orElseGet (() -> messageReader .readMono (MULTIPART_MAP_TYPE , serverRequest , context .hints ()));
161
+ };
162
+ }
163
+
164
+ /**
165
+ * Return a {@code BodyExtractor} that reads multipart (i.e. file upload) form data into a
166
+ * {@link MultiValueMap}.
167
+ * @return a {@code BodyExtractor} that reads multipart data
168
+ */
169
+ // Note that the returned BodyExtractor is parameterized to ServerHttpRequest, not
170
+ // ReactiveHttpInputMessage like other methods, since reading form data only typically happens on
171
+ // the server-side
172
+ public static BodyExtractor <Flux <Part >, ServerHttpRequest > toParts () {
173
+ return (serverRequest , context ) -> {
174
+ HttpMessageReader <Part > messageReader =
175
+ messageReader (PART_TYPE , MediaType .MULTIPART_FORM_DATA , context );
176
+ return context .serverResponse ()
177
+ .map (serverResponse -> messageReader .read (PART_TYPE , PART_TYPE , serverRequest , serverResponse , context .hints ()))
178
+ .orElseGet (() -> messageReader .read (PART_TYPE , serverRequest , context .hints ()));
157
179
};
158
180
}
159
181
@@ -191,26 +213,15 @@ private static <T, S extends Publisher<T>> S readWithMessageReaders(
191
213
});
192
214
}
193
215
194
- private static HttpMessageReader <MultiValueMap <String , String >> formMessageReader (BodyExtractor .Context context ) {
216
+ private static <T > HttpMessageReader <T > messageReader (ResolvableType elementType ,
217
+ MediaType mediaType , BodyExtractor .Context context ) {
195
218
return context .messageReaders ().get ()
196
- .filter (messageReader -> messageReader
197
- .canRead (FORM_TYPE , MediaType .APPLICATION_FORM_URLENCODED ))
219
+ .filter (messageReader -> messageReader .canRead (elementType , mediaType ))
198
220
.findFirst ()
199
- .map (BodyExtractors ::<MultiValueMap <String , String >>cast )
200
- .orElseThrow (() -> new IllegalStateException (
201
- "Could not find HttpMessageReader that supports " +
202
- MediaType .APPLICATION_FORM_URLENCODED_VALUE ));
203
- }
204
-
205
- private static HttpMessageReader <MultiValueMap <String , Part >> multipartMessageReader (BodyExtractor .Context context ) {
206
- return context .messageReaders ().get ()
207
- .filter (messageReader -> messageReader
208
- .canRead (MULTIPART_TYPE , MediaType .MULTIPART_FORM_DATA ))
209
- .findFirst ()
210
- .map (BodyExtractors ::<MultiValueMap <String , Part >>cast )
221
+ .map (BodyExtractors ::<T >cast )
211
222
.orElseThrow (() -> new IllegalStateException (
212
- "Could not find HttpMessageReader that supports " +
213
- MediaType . MULTIPART_FORM_DATA ));
223
+ "Could not find HttpMessageReader that supports \" " + mediaType +
224
+ " \" and \" " + elementType + " \" " ));
214
225
}
215
226
216
227
private static MediaType contentType (HttpMessage message ) {
0 commit comments