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

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

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


Spring framework/Spring boot

SpringBoot gRPC 체험 후기 - 2 (파일, File)

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2023. 3. 8.

 

* 이전내용 : https://lts0606.tistory.com/654

 

SpringBoot gRPC 체험 후기 - 1

gRPC는 데이터를 주고받기 위한 HTTP프로토콜을 "서비스(Serivice)" 라는 개념으로 정의한 개념의 규칙 입니다. 구글링하면 워낙 훌륭한 글 들이 많아서... 자세한 기능과 설명은 여러 포스팅을 보는

lts0606.tistory.com

 

gRPC를 활용하여 파일을 주고받는 방법도 어렵지 않습니다.

proto 파일의 내용에서 파일 형식의 응답객체와, 해당 객체를 사용하는 메서드를 추가하여 줍니다.

* proto 파일 내용

syntax = "proto3";

option java_multiple_files = true;
option java_package = "kr.com.rts.proto";
option java_outer_classname = "HelloPrt";

package protocc;

service MyProtoService {
    rpc giveMeData1(RequestMessage) returns (ResponseMessageStyle1); //송신 및 수신용 메소드1
    rpc giveMeData2(RequestMessage) returns (ResponseMessageStyle2); //송신 및 수신용 메소드2
    rpc giveMeData3(RequestMessage) returns (stream ResponseMessageStyle3); //stream 제어가 붙은 파일용 메소드
}

message RequestMessage { //요청하는 객체
    string id = 1;
    string name = 2;
    float price = 3;
}

message ResponseMessageStyle1 {  //결과받는 객체1
    string result = 1;
    string status = 2;
}


message ResponseMessageStyle2 { //결과받는 객체2
    string result = 1;
    string status = 2;
    float statusCode = 3;
    RequestMessage yourRequest = 4;
}

message ResponseMessageStyle3 { //파일용 바이트 객체
    bytes file = 3;
}

 

기존의 proto 파일에서(새로 만들어도 됩니다) 파일과 관련된 항목을 추가 하였습니다.

bytes 자료형을 추가하면 해당 데이터는 파일을 주고받기 위한 바이트 데이터로 사용 할 수 있으며,

해당 파일을 통해 사용하는 메서드에 stream이라는 제어자를 붙여주면 스트림 객체로 데이터를 가져올 수 있습니다.

maven update 또는 maven generate-source를 통해서 신규 또는 변경된 내용을 적용받도록 해 준 다음에, 해당 내용을 서비스 클래스에 추가하여 봅니다.

 

* 사용하는 서비스

import io.grpc.stub.StreamObserver;
import kr.com.rts.proto.*;
import kr.com.rts.proto.RequestMessage;
import kr.com.rts.proto.ResponseMessageStyle1;
import kr.com.rts.proto.ResponseMessageStyle2;
import kr.com.rts.proto.ResponseMessageStyle3;

public class TestService extends MyProtoServiceGrpc.MyProtoServiceImplBase {

    //생략..

    @Override
    public void giveMeData3(RequestMessage request, StreamObserver<ResponseMessageStyle3> responseObserver) {
        File filePath = new File("보낼파일위치");
        try (FileInputStream fis = new FileInputStream(filePath); BufferedInputStream bis = new BufferedInputStream(fis)) {
            int bufferSize = 256 * 1024;// 256k
            byte[] buffer = new byte[bufferSize];
            int length;
            while ((length = bis.read(buffer, 0, bufferSize)) != -1) {  //스트림에 byte가 남아있지 않을 때 까지
                responseObserver.onNext(ResponseMessageStyle3.newBuilder().setFile(ByteString.copyFrom(buffer, 0, length)).build());  //파일내용을 추가합니다.
            }
            responseObserver.onCompleted();
        } catch (IOException e) {
            e.printStackTrace();
        }        
    }

}

 

원하는 파일을 위 코드 예제처럼 stream으로 가져와서 proto 타입에서 정의한  file 이름으로 추가하여 줍니다.

아래 처럼 file이름으로 주었기 때 문에 setFile 메서드를 통해 데이터를 넣어주면 됩니다.

 

이제 사용자의 요청 뒤에 파일을 전달해 주는 테스트 코드만 남았습니다.

기존 테스트 코드에서 아래 내용을 추가하였습니다.

* 테스트용 클래스

import static org.assertj.core.api.Assertions.assertThat;

import java.io.File;
import java.util.Iterator;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import com.google.common.io.ByteSink;
import com.google.common.io.FileWriteMode;
import com.google.common.io.Files;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import kr.com.rts.proto.MyProtoServiceGrpc;
import kr.com.rts.proto.RequestMessage;
import kr.com.rts.proto.ResponseMessageStyle1;
import kr.com.rts.proto.ResponseMessageStyle2;
import kr.com.rts.proto.ResponseMessageStyle3;

@SpringBootTest
class GRpcJavaApplicationTests {

	@Test
	void contextLoads() {
        String url = "127.0.0.1:10777";
        try {
            ManagedChannel channel = ManagedChannelBuilder.forTarget(url).usePlaintext().build();

            RequestMessage req2 = RequestMessage.newBuilder().setId("두번째 메시지").setName("두번째 메시지2").setPrice(554f)
                    .build();

            MyProtoServiceGrpc.MyProtoServiceBlockingStub stub = MyProtoServiceGrpc.newBlockingStub(channel);

            // 파일 요청 및 받기
            ByteSink byteSink = Files.asByteSink(new File("저장할위치와이름"), FileWriteMode.APPEND);
            Iterator<ResponseMessageStyle3> response3 = stub.giveMeData3(req2);
            while (response3.hasNext()) {  //데이터가 존재 할 때 까지
                byteSink.write(response3.next().getFile().toByteArray());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

	}

}

 

데이터를 가져오는 기능을 Files 클래스를 통해서 쉽게 구현하였습니다.  * ByteSink는 Java 14부터 지원합니다.

코드 자체가 거의 직관적이라 그리 어렵지는 않았습니다.

 

아래 깃허브 주소는 위 내용에 사용된 소스코드를 올려놓은 주소 입니다.

https://github.com/TaeSeungRyu/sample/tree/main/gRPC샘플코드

 

GitHub - TaeSeungRyu/sample

Contribute to TaeSeungRyu/sample development by creating an account on GitHub.

github.com

 

SpringBoot gRPC 체험 후기를 작성 해 보았습니다.

아직까지 이것저것 해 보는 중이라 내용이 다소 틀릴 수 있습니다.

틀린 부분 또는 다른 의견은 언제든 환영 입니다! 👻

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

댓글