※ gRPC Server에서 작성한 .proto파일과 동일하게 작성한다.
syntax = "proto3";
package com.example.grpc;
option java_outer_classname = "BiddingModel";
message BidRequest {
string userId = 1;
int32 bidPrice = 2;
}
message BidResponse {
int32 bidPrice = 1;
}
service BidService {
rpc bidding(BidRequest) returns (BidResponse);
rpc winBidding(BidRequest) returns (stream BidResponse);
rpc streamBidding(stream BidRequest) returns (stream BidResponse);
}
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.5'
id 'io.spring.dependency-management' version '1.1.4'
// protobuf 플러그인
id 'com.google.protobuf' version '0.8.15'
}
repositories {
mavenCentral()
}
group = 'com.grpc'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'javax.annotation:javax.annotation-api:1.3.2'
// grpc
// grpc-java는 netty서버를 embedded하여 사용합니다
implementation 'io.grpc:grpc-netty-shaded:1.36.0'
implementation 'io.grpc:grpc-protobuf:1.36.0'
implementation 'io.grpc:grpc-stub:1.36.0'
// protobuf
implementation "com.google.protobuf:protobuf-java-util:3.8.0"
implementation "com.google.protobuf:protobuf-java:3.8.0"
//mapstruct
implementation "org.mapstruct:mapstruct:1.4.2.Final"
implementation 'org.projectlombok:lombok-mapstruct-binding:0.2.0'
// grpc test
testImplementation group: 'io.grpc', name: 'grpc-testing', version: '1.36.0'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor "org.mapstruct:mapstruct-processor:1.4.2.Final"
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.12.0'
}
plugins {
grpc {
artifact = 'io.grpc:protoc-gen-grpc-java:1.36.0'
}
}
generateProtoTasks {
all()*.plugins {
grpc {}
}
}
}
sourceSets {
main {
// 빌드된 폴더를 인텔리제이가 인식할수 있도록 소스폴더로 포함
java {
srcDirs += [ './build/generated/source/proto/main/grpc', './build/generated/source/proto/main/java' ]
}
// 프로토콜버퍼 파일의 위치를 지정
proto {
srcDir 'src/main/resources/proto'
}
}
}
jar {
enabled = false
}
@Slf4j
@RestController
@RequestMapping("/api/v1/client")
@RequiredArgsConstructor
public class GrpcClientController {
private final GrpcClientService clientService;
@PostMapping("/bidding")
public BiddingModel.BidResponse bidding(@RequestBody GrpcClientRequest grpcClientRequest) throws Exception {
return clientService.bidding(grpcClientRequest);
}
@PostMapping("/winBidding")
public void winBidding(@RequestBody GrpcClientRequest grpcClientRequest) throws Exception {
clientService.winBidding(grpcClientRequest);
}
@PostMapping("/streamBidding")
public void streamBidding(@RequestBody GrpcClientRequest grpcClientRequest) throws Exception {
clientService.streamBidding(grpcClientRequest);
}
}
@Slf4j
@Service
@RequiredArgsConstructor
public class GrpcClientService {
private final BidServiceGrpc.BidServiceBlockingStub blockingStub;
private final BidServiceGrpc.BidServiceStub stub;
public BiddingModel.BidResponse bidding(GrpcClientRequest grpcClientRequest) {
// 받아온 파라미터를 gRPC 모델로 매핑
BiddingModel.BidRequest bidRequest = ClientMapper.instance.toBiddingModelRequest(grpcClientRequest);
// 단방향 RPC 호출
BiddingModel.BidResponse response = blockingStub.bidding(bidRequest);
return response;
}
public void winBidding(GrpcClientRequest grpcClientRequest) {
// 받아온 파라미터를 gRPC 모델로 매핑
BiddingModel.BidRequest bidRequest = ClientMapper.instance.toBiddingModelRequest(grpcClientRequest);
stub.winBidding(bidRequest, new StreamObserver<BiddingModel.BidResponse>() {
@Override
public void onNext(BiddingModel.BidResponse value) {
System.out.println(value);
}
@Override
public void onError(Throwable t) {
throw new RuntimeException(t);
}
@Override
public void onCompleted() {
System.out.println("서버 스트리밍 완료");
}
});
}
public void streamBidding(GrpcClientRequest grpcClientRequest) {
// 받아온 파라미터를 gRPC 모델로 매핑
BiddingModel.BidRequest bidRequest = ClientMapper.instance.toBiddingModelRequest(grpcClientRequest);
StreamObserver<BiddingModel.BidRequest> requestStreamObserver = stub.streamBidding(new StreamObserver<BiddingModel.BidResponse>() {
GrpcClientResponse grpcClientResponse = new GrpcClientResponse();
@Override
public void onNext(BiddingModel.BidResponse value) {
System.out.println(value);
}
@Override
public void onError(Throwable t) {
throw new RuntimeException(t);
}
@Override
public void onCompleted() {
System.out.println("양방향 스트리밍 완료");
}
});
requestStreamObserver.onNext(bidRequest);
requestStreamObserver.onNext(bidRequest);
requestStreamObserver.onCompleted();
}
}
@Component
@RequiredArgsConstructor
public class ClientConfig {
@Value("${grpc.host}")
private String host;
@Value("${grpc.port}")
private Integer port;
@Bean
public BidServiceGrpc.BidServiceBlockingStub blockingStub() {
ManagedChannel managedChannel = getChannel();
return BidServiceGrpc.newBlockingStub(managedChannel);
}
@Bean
public BidServiceGrpc.BidServiceStub stub() {
ManagedChannel managedChannel = getChannel();
return BidServiceGrpc.newStub(managedChannel);
}
private ManagedChannel getChannel() {
ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext()
.build();
return managedChannel;
}
}