본문 바로가기
블로그 이미지

방문해 주셔서 감사합니다! 항상 행복하세요!

  
   - 문의사항은 메일 또는 댓글로 언제든 연락주세요.
   - "해줘","답 내놔" 같은 질문은 답변드리지 않습니다.
   - 메일주소 : lts06069@naver.com


Spring framework/Spring Webflux

spring webflux 10 (웹플럭스 적용기, Multipart param, 웹플럭스 멀티파트 파라미터)

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2020. 7. 27.

웹플럭스에서 파일을 받고 보내는 것은 어렵지가 않습니다.

만약 파라미터가 존재하는 경우가 생긴다면 방법이 조금 복잡합니다.

먼저 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 메소드를 이용해야만 파일과 같이 보낸 파라미터를 받을 수 있습니다.

Part라는 인터페이스 입니다.

 

multipartData 메소드를 통해서 받는 데이터는 Mono객체에 키 값은 String, 데이터는 List형식의 Part 라는 객체로 구성되어 있습니다.

Part는 인터페이스의 일종 입니다.

그러면 간단하게 데이터를 출력하여 보겠습니다.

Part라는 인터페이스에 toString이 잘 되어 있네요!

 

위 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!

 

* 내용을 채우고 수정중입니다.

* 튜토리얼이나 가이드 목적보다도 개념정리에 목적을 두고 쓰고있습니다. 틀린부분이나 누락된 부분은 꼭 알려주세요!

 

반응형
* 위 에니메이션은 Html의 캔버스(canvas)기반으로 동작하는 기능 입니다. Html 캔버스 튜토리얼 도 한번 살펴보세요~ :)
* 직접 만든 Html 캔버스 애니메이션 도 한번 살펴보세요~ :)

댓글