2.4. Request Body
Request Body๋ Mono ๋๋ ์ฝํ๋ฆฐ ์ฝ๋ฃจํด Deferred์ ๊ฐ์ด ReactiveAdapterRegistry๊ฐ ํธ๋ค๋งํ๋ ๋ชจ๋ ๋น๋๊ธฐ ํ์
์ผ๋ก๋ถํฐ
์ธ์ฝ๋ฉ๋ ์ ์๋ค. ์๋๋ ๊ทธ ์์ ๋ค:
Java:
Mono<Person> personMono = ... ;
Mono<Void> result = client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.body(personMono, Person.class)
.retrieve()
.bodyToMono(Void.class);
Kotlin:
val personDeferred: Deferred<Person> = ...
client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.body<Person>(personDeferred)
.retrieve()
.awaitBody<Unit>()
๋ํ ๋ค์ ์์ ์ ๊ฐ์ด ๊ฐ์ฒด ์คํฌ๋ฆผ์ ์ธ์ฝ๋ฉํ ์๋ ์๋ค:
Java:
Flux<Person> personFlux = ... ;
Mono<Void> result = client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_STREAM_JSON)
.body(personFlux, Person.class)
.retrieve()
.bodyToMono(Void.class);
Kotlin:
val people: Flow<Person> = ...
client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.body(people)
.retrieve()
.awaitBody<Unit>()
๋๋ ์ค์ ๊ฐ์ ๊ฐ์ง ๊ฒฝ์ฐ์๋ bodyValue ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
Java:
Person person = ... ;
Mono<Void> result = client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(person)
.retrieve()
.bodyToMono(Void.class);
Kotlin:
val person: Person = ...
client.post()
.uri("/persons/{id}", id)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(person)
.retrieve()
.awaitBody<Unit>()
2.4.1. ํผ ๋ฐ์ดํฐ(Form Data)
ํผ ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๊ธฐ ์ํด, MultiValueMap<String, String>์ body๋ก ์ฌ์ฉํ๋ค. FormHttpMessageWriter์ ์ํด์ ์๋์ผ๋ก
application/x-www-form-urlencoded๋ก ์ฝํ
์ธ ํ์
์ด ์ค์ ๋๋ค. ๋ค์ MultiValueMap<String, String>์ ์ฌ์ฉํ๋ ์์ ๋ค:
Java:
MultiValueMap<String, String> formData = ... ;
Mono<Void> result = client.post()
.uri("/path", id)
.bodyValue(formData)
.retrieve()
.bodyToMono(Void.class);
Kotlin:
val formData: MultiValueMap<String, String> = ...
client.post()
.uri("/path", id)
.bodyValue(formData)
.retrieve()
.awaitBody<Unit>()
BodyInserters๋ฅผ ์ฌ์ฉํ์ฌ ์ธ๋ผ์ธ ํผ(form) ๋ฐ์ดํฐ๋ฅผ ๋ง๋ค ์ ์๋ค. ๋ค์์ ๊ทธ ์์ ๋ค:
Java:
import static org.springframework.web.reactive.function.BodyInserters.*;
Mono<Void> result = client.post()
.uri("/path", id)
.body(fromFormData("k1", "v1").with("k2", "v2"))
.retrieve()
.bodyToMono(Void.class);
Kotlin:
import org.springframework.web.reactive.function.BodyInserters.*
client.post()
.uri("/path", id)
.body(fromFormData("k1", "v1").with("k2", "v2"))
.retrieve()
.awaitBody<Unit>()
2.4.2. ๋ฉํฐํํธ ๋ฐ์ดํฐ(Multipart Data)
๋ฉํฐํํธ ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๋ ค๋ฉด, ๊ฐ(value)์ด ํํธ(part) ์ปจํ
์ธ ๋ฅผ ๋ํ๋ด๋ Object ๋๋ ํํธ์ ์ปจํ
์ธ ์ ํค๋๋ฅผ ๋ํ๋ด๋ HttpEntity ์ธ์คํด์ค์ธ MultiValueMap<String, ?>๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค. MultipartBodyBuilder๋ ๋ฉํฐํํธ ์์ฒญ์ ์ค๋นํ๊ธฐ ์ํ ํธ๋ฆฌํ API๋ฅผ
์ ๊ณตํ๋ค ๋ค์์ MultiValueMap<String, ?>๋ฅผ ์ด๋ป๊ฒ ์์ฑํ๋์ง ๋ณด์ฌ์ฃผ๋ ์์ ๋ค:
Java:
MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("fieldPart", "fieldValue");
builder.part("filePart1", new FileSystemResource("...logo.png"));
builder.part("jsonPart", new Person("Jason"));
builder.part("myPart", part); // Part from a server request
MultiValueMap<String, HttpEntity<?>> parts = builder.build();
Kotlin:
val builder = MultipartBodyBuilder().apply {
part("fieldPart", "fieldValue")
part("filePart1", new FileSystemResource("...logo.png"))
part("jsonPart", new Person("Jason"))
part("myPart", part) // Part from a server request
}
val parts = builder.build()
๋๋ถ๋ถ ๊ฐ ํํธ๋ง๋ค Content-Type์ ์ง์ ํ ํ์๊ฐ ์๋ค. ์ฝํ
์ธ ํ์
์ ์ง๋ ฌํํ๊ธฐ ์ํด ์ ํํ HttpMessageWriter๋ฅผ ๊ธฐ๋ฐ์ผ๋ก
๋๋ Resource์ ๊ฒฝ์ฐ ํ์ผ ํ์ฅ์์ ๊ธฐ๋ฐํ์ฌ ์๋์ผ๋ก ๊ฒฐ์ ๋๋ค. ํ์ํ๋ค๋ฉด, ์ค๋ฒ๋ก๋ฉ๋ ๋น๋ part ๋ฉ์๋ ์ค ํ๋๋ฅผ ํตํด์
๊ฐ ํํธ์์ ์ฌ์ฉํ MediaType๋ฅผ ๋ช
์์ ์ผ๋ก ์ ๊ณตํ ์ ์๋ค.
MultiValueMap์ด ์ค๋น๋๋ค๋ฉด, WebClient์ ์ ๋ฌํ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ body ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
๋ค์์ ๊ทธ ์์ ๋ค:
Java:
MultipartBodyBuilder builder = ...;
Mono<Void> result = client.post()
.uri("/path", id)
.body(builder.build())
.retrieve()
.bodyToMono(Void.class);
Kotlin:
val builder: MultipartBodyBuilder = ...
client.post()
.uri("/path", id)
.body(builder.build())
.retrieve()
.awaitBody<Unit>()
MultiValueMap์ ์ผ๋ฐ์ ์ธ ํผ ๋ฐ์ดํฐ(application/x-www-form-urlencoded)๋ฅผ ๋ํ๋ผ ์ ์๋ ๋ฌธ์์ด์ด ์๋ ๊ฐ(non-String)์ด
ํ๋๋ผ๋ ํฌํจ๋์ด ์๋ค๋ฉด, Content-Type์ multipart/form-data๋ก ์ค์ ํ ํ์๊ฐ ์๋ค. MultipartBodyBuilder๋ฅผ ์ฌ์ฉํ๋
๊ฒฝ์ฐ ํญ์ HttpEntity๋ก ๋ํํด์ฃผ๊ธฐ ๋๋ฌธ์ด๋ค.
MultipartBodyBuilder์ ๋์์ผ๋ก ๋ด์ฅ BodyInserters๋ฅผ ์ฌ์ฉํ์ฌ ์ธ๋ผ์ธ ์คํ์์ ๋ฉํฐํํธ ์ฝํ
์ธ ๋ฅผ ๋ง๋ค ์๋ ์๋ค.
๋ค์์ ๊ทธ ์์ ๋ค:
Java:
import static org.springframework.web.reactive.function.BodyInserters.*;
Mono<Void> result = client.post()
.uri("/path", id)
.body(fromMultipartData("fieldPart", "value").with("filePart", resource))
.retrieve()
.bodyToMono(Void.class);
Kotlin:
import org.springframework.web.reactive.function.BodyInserters.*
client.post()
.uri("/path", id)
.body(fromMultipartData("fieldPart", "value").with("filePart", resource))
.retrieve()
.awaitBody<Unit>()
๋ชฉ์ฐจ ๊ฐ์ด๋