1
1
/*
2
- * Copyright 2002-2016 the original author or authors.
2
+ * Copyright 2002-2017 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
29
29
import org .springframework .core .io .buffer .DataBuffer ;
30
30
import org .springframework .http .MediaType ;
31
31
import org .springframework .http .ReactiveHttpOutputMessage ;
32
+ import org .springframework .http .client .reactive .ClientHttpRequest ;
32
33
import org .springframework .http .codec .HttpMessageWriter ;
33
34
import org .springframework .http .codec .ServerSentEvent ;
34
35
import org .springframework .http .codec .UnsupportedMediaTypeException ;
35
36
import org .springframework .http .server .reactive .ServerHttpResponse ;
36
37
import org .springframework .util .Assert ;
38
+ import org .springframework .util .MultiValueMap ;
37
39
38
40
/**
39
41
* Implementations of {@link BodyInserter} that write various bodies, such a reactive streams,
@@ -49,6 +51,10 @@ public abstract class BodyInserters {
49
51
private static final ResolvableType SERVER_SIDE_EVENT_TYPE =
50
52
ResolvableType .forClass (ServerSentEvent .class );
51
53
54
+ private static final ResolvableType FORM_TYPE =
55
+ ResolvableType .forClassWithGenerics (MultiValueMap .class , String .class , String .class );
56
+
57
+
52
58
private static final BodyInserter <Void , ReactiveHttpOutputMessage > EMPTY =
53
59
(response , context ) -> response .setComplete ();
54
60
@@ -109,16 +115,16 @@ public static <T, P extends Publisher<T>> BodyInserter<P, ReactiveHttpOutputMess
109
115
* If the resource can be resolved to a {@linkplain Resource#getFile() file}, it will be copied
110
116
* using
111
117
* <a href="https://en.wikipedia.org/wiki/Zero-copy">zero-copy</a>
112
- * @param resource the resource to write to the response
118
+ * @param resource the resource to write to the output message
113
119
* @param <T> the type of the {@code Resource}
114
120
* @return a {@code BodyInserter} that writes a {@code Publisher}
115
121
*/
116
122
public static <T extends Resource > BodyInserter <T , ReactiveHttpOutputMessage > fromResource (T resource ) {
117
123
Assert .notNull (resource , "'resource' must not be null" );
118
- return (response , context ) -> {
124
+ return (outputMessage , context ) -> {
119
125
HttpMessageWriter <Resource > messageWriter = resourceHttpMessageWriter (context );
120
126
return messageWriter .write (Mono .just (resource ), RESOURCE_TYPE , null ,
121
- response , context .hints ());
127
+ outputMessage , context .hints ());
122
128
};
123
129
}
124
130
@@ -143,10 +149,11 @@ public static <T, S extends Publisher<ServerSentEvent<T>>> BodyInserter<S, Serve
143
149
144
150
Assert .notNull (eventsPublisher , "'eventsPublisher' must not be null" );
145
151
return (response , context ) -> {
146
- HttpMessageWriter <ServerSentEvent <T >> messageWriter = sseMessageWriter (context );
147
- return messageWriter .write (eventsPublisher , SERVER_SIDE_EVENT_TYPE ,
148
- MediaType .TEXT_EVENT_STREAM , response , context .hints ());
149
- };
152
+ HttpMessageWriter <ServerSentEvent <T >> messageWriter =
153
+ findMessageWriter (context , SERVER_SIDE_EVENT_TYPE , MediaType .TEXT_EVENT_STREAM );
154
+ return messageWriter .write (eventsPublisher , SERVER_SIDE_EVENT_TYPE ,
155
+ MediaType .TEXT_EVENT_STREAM , response , context .hints ());
156
+ };
150
157
}
151
158
152
159
/**
@@ -183,13 +190,45 @@ public static <T, S extends Publisher<T>> BodyInserter<S, ServerHttpResponse> fr
183
190
Assert .notNull (eventsPublisher , "'eventsPublisher' must not be null" );
184
191
Assert .notNull (eventType , "'eventType' must not be null" );
185
192
return (outputMessage , context ) -> {
186
- HttpMessageWriter <T > messageWriter = sseMessageWriter (context );
187
- return messageWriter .write (eventsPublisher , eventType ,
188
- MediaType .TEXT_EVENT_STREAM , outputMessage , context .hints ());
193
+ HttpMessageWriter <T > messageWriter =
194
+ findMessageWriter (context , SERVER_SIDE_EVENT_TYPE , MediaType .TEXT_EVENT_STREAM );
195
+ return messageWriter .write (eventsPublisher , eventType ,
196
+ MediaType .TEXT_EVENT_STREAM , outputMessage , context .hints ());
189
197
190
- };
198
+ };
191
199
}
192
200
201
+ /**
202
+ * Return a {@code BodyInserter} that writes the given {@code MultiValueMap} as URL-encoded
203
+ * form data.
204
+ * @param formData the form data to write to the output message
205
+ * @return a {@code BodyInserter} that writes form data
206
+ */
207
+ public static BodyInserter <MultiValueMap <String , String >, ClientHttpRequest > fromFormData (MultiValueMap <String , String > formData ) {
208
+ Assert .notNull (formData , "'formData' must not be null" );
209
+
210
+ return (outputMessage , context ) -> {
211
+ HttpMessageWriter <MultiValueMap <String , String >> messageWriter =
212
+ findMessageWriter (context , FORM_TYPE , MediaType .APPLICATION_FORM_URLENCODED );
213
+ return messageWriter .write (Mono .just (formData ), FORM_TYPE ,
214
+ MediaType .APPLICATION_FORM_URLENCODED , outputMessage , context .hints ());
215
+ };
216
+ }
217
+
218
+ private static <T > HttpMessageWriter <T > findMessageWriter (BodyInserter .Context context ,
219
+ ResolvableType type ,
220
+ MediaType mediaType ) {
221
+
222
+ return context .messageWriters ().get ()
223
+ .filter (messageWriter -> messageWriter .canWrite (type , mediaType ))
224
+ .findFirst ()
225
+ .map (BodyInserters ::<T >cast )
226
+ .orElseThrow (() -> new IllegalStateException (
227
+ "Could not find HttpMessageWriter that supports " + mediaType ));
228
+ }
229
+
230
+
231
+
193
232
/**
194
233
* Return a {@code BodyInserter} that writes the given {@code Publisher<DataBuffer>} to the
195
234
* body.
@@ -204,16 +243,6 @@ public static <T extends Publisher<DataBuffer>> BodyInserter<T, ReactiveHttpOutp
204
243
return (outputMessage , context ) -> outputMessage .writeWith (publisher );
205
244
}
206
245
207
- private static <T > HttpMessageWriter <T > sseMessageWriter (BodyInserter .Context context ) {
208
- return context .messageWriters ().get ()
209
- .filter (messageWriter -> messageWriter
210
- .canWrite (SERVER_SIDE_EVENT_TYPE , MediaType .TEXT_EVENT_STREAM ))
211
- .findFirst ()
212
- .map (BodyInserters ::<T >cast )
213
- .orElseThrow (() -> new IllegalStateException (
214
- "Could not find HttpMessageWriter that supports " +
215
- MediaType .TEXT_EVENT_STREAM_VALUE ));
216
- }
217
246
218
247
private static <T , P extends Publisher <?>, M extends ReactiveHttpOutputMessage > BodyInserter <T , M > bodyInserterFor (P body , ResolvableType bodyType ) {
219
248
0 commit comments