spring webflux 10 (웹플럭스 적용기, Multipart param, 웹플럭스 멀티파트 파라미터)
웹플럭스에서 파일을 받고 보내는 것은 어렵지가 않습니다.
만약 파라미터가 존재하는 경우가 생긴다면 방법이 조금 복잡합니다.
먼저 request객체를 살펴보아야 합니다.
아래 코드는 파일을 사용자가 업로드를 할 때 사용하는 코드의 예제 입니다.
@Bean
public RouterFunction<ServerResponse> fileUpload() {
RequestPredicate predicate = RequestPredicates.POST("/fileUpload").and(RequestPredicates.accept(MediaType.MULTIPART_FORM_DATA));
RouterFunction<ServerResponse> response = RouterFunctions.route(predicate, (request)->{
Mono<String> mapper = request.multipartData().map(it -> it.get("files"))
.flatMapMany(Flux::fromIterable)
.cast(FilePart.class)
.flatMap(it -> it.transferTo(Paths.get("/저장경로/" + it.filename())))
.then(Mono.just("OK"));
Mono<ServerResponse> res = ServerResponse.ok().contentType(MediaType.TEXT_PLAIN).body(BodyInserters.fromProducer(mapper, String.class));
return res;
});
return response;
}
사용자가 fileUpload라는 주소를 통해서 name값을 files로 보낸 경우 입니다.
여기서 대부분 사람들은 multipart 방식으로 보낸 파라미터를 받기 위해 아래처럼 사용합니다.
@Bean
public RouterFunction<ServerResponse> fileUpload() {
RequestPredicate predicate = RequestPredicates.POST("/fileUpload").and(RequestPredicates.accept(MediaType.MULTIPART_FORM_DATA));
RouterFunction<ServerResponse> response = RouterFunctions.route(predicate, (request)->{
request.queryParams(); //이러한 방식으로 시도를 해 봅니다..
Mono<String> mapper = request.multipartData().map(it -> it.get("files"))
.flatMapMany(Flux::fromIterable)
.cast(FilePart.class)
.flatMap(it -> it.transferTo(Paths.get("/저장경로/" + it.filename())))
.then(Mono.just("OK"));
Mono<ServerResponse> res = ServerResponse.ok().contentType(MediaType.TEXT_PLAIN).body(BodyInserters.fromProducer(mapper, String.class));
return res;
});
return response;
}
리퀘스트 객체의 파라미터를 가져오는 메소드queryParmas입니다.
해당 메소드는 일반적인 요청에 대해서는 응답하지만 이미 Request객체가 Multipart 형식으로 된 경우에는 아무런 값을 주지 않습니다.
빈 값만 있다고 나올 뿐 입니다..ㅠ
request객체의 multipartData 메소드를 이용해야만 파일과 같이 보낸 파라미터를 받을 수 있습니다.
multipartData 메소드를 통해서 받는 데이터는 Mono객체에 키 값은 String, 데이터는 List형식의 Part 라는 객체로 구성되어 있습니다.
Part는 인터페이스의 일종 입니다.
그러면 간단하게 데이터를 출력하여 보겠습니다.
위 forEach부분에서 key는 일반 문자열로, value는 List형식의 Part 인터페이스로 구성되어 있습니다.
이를 반복문을 통해서 key 와 value를 출력 해 보았습니다.
전송한 데이터는,
key값 files를 통해서 파일 2개를 전송하였습니다.
그리고 param_same이라는 이름으로 값 2개를, param1, param2로 각각 데이터를 전송 해 보았습니다.
여기서 조건문을 통해서 파일을 저장하는 부분과, value를 가져오는 부분을 분리하여 보겠습니다.
public Mono<ServerResponse> fileData(ServerRequest request){
Mono<String> then = request.multipartData().map(it-> {
it.forEach( (arg1, arg2)->{
if(!arg1.equals("files")) { //파일이 아니면
arg2.forEach( body->{
body.content().subscribe(dataBuffer -> {
byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes);
DataBufferUtils.release(dataBuffer);
String valueFromMultipart = new String(bytes, StandardCharsets.UTF_8);
System.out.println("key : "+ arg1+", I'm data : "+valueFromMultipart);
});
});
} else { //파일이면,
System.out.println("key : "+ arg1+", I'm file : "+arg2);
Mono.just(it.get("files")).flatMapMany(Flux::fromIterable)
.cast(FilePart.class)
.flatMap( file -> {
return file.transferTo(Paths.get("E:/git/" + file.filename()));
}).subscribe();
}
});
return it;
}).then(Mono.just("OkOk"));
return ServerResponse.ok().body(then, String.class).onErrorResume(e -> Mono.error(new RuntimeException(e.getMessage())) );
}
body는 Part 인터페이스이며 content라는 메소드를 통해서 값을 받게하였습니다.
그리고 subscribe를 통해서 내부의 코드가 동작하게 하였습니다.
파일을 저장하는 부분은 이전내용과 동일합니다.
여기서 valueFromMultipart 의 값이 바로 전송한 데이터를 문자로 변형한 값을 의미 합니다.
이상으로 웹플럭스에서 멀티파트 형식의 요청에서의 파라미터를 받는 방법에 대해서 살펴 보았습니다.
spring webflux!
* 내용을 채우고 수정중입니다.
* 튜토리얼이나 가이드 목적보다도 개념정리에 목적을 두고 쓰고있습니다. 틀린부분이나 누락된 부분은 꼭 알려주세요!