一、 编写proto文件
1、idea新建java项目,在maven中引入以下依赖:
<dependencies>
<!--grpc底层通信组件-->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.42.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.42.0</version>
</dependency>
<!--存根-->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.42.0</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>annotations-api</artifactId>
<version>6.0.53</version>
<!--provided:只能作用在编译和测试时,同时没有传递性-->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.9.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
</dependencies>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.2</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.17.3:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.42.0:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
2、proto文件
syntax = "proto3";
//生成java类所在的包
option java_package = "com.cn.news.proto";
//生成多个类
option java_multiple_files = false;
//生成外层类类名
option java_outer_classname = "NewsProto";
//包名
package news;
//grpc要调用的service
service NewsService{
//list是方法名,NewsRequest代表传入参数,NewsResponse代表返回响应
rpc list(NewsRequest) returns (NewsResponse){}
}
//请求体
message NewsRequest{
string date = 1;
NewsDetail body = 2;
}
//响应体
message NewsResponse{
//repeated说明是一个集合(数组),数组每一个元素都是News对象
repeated News news = 1;
}
//News新闻实体对象
message News{
//对应java的int
int32 id = 1;
//新闻标题
string title = 2;
//新闻内容
string content = 3;
//对应java的long
int64 createTime = 4;
}
message NewsDetail{
//1表示热点新闻 2表示普通新闻
int32 msgType = 1;
//0未读 1-已读
int32 msgStatus = 2;
}
3. 编译并生成java文件
二、 编写grpc服务端
1、实现 NewsServiceGrpc.NewsServiceImplBase 接口,提供服务方法调用
package com.cn.news.service;
import com.cn.news.proto.NewsProto;
import com.cn.news.proto.NewsServiceGrpc;
import io.grpc.stub.StreamObserver;
/**
* description: NewService <br>
* date: 23.4.12 15:52 <br>
* author: cn_yaojin <br>
* version: 1.0 <br>
*/
public class NewService extends NewsServiceGrpc.NewsServiceImplBase {
@Override
public void list(NewsProto.NewsRequest request, StreamObserver<NewsProto.NewsResponse> responseObserver) {
String date = request.getDate();
System.out.println("收到客户端请求了,时间:" + date + ",参数体:" + request.getBody().getMsgType());
NewsProto.NewsResponse newList = null;
try {
NewsProto.NewsResponse.Builder newListBuilder = NewsProto.NewsResponse.newBuilder();
String title = "";
if (request.getBody().getMsgType() == 1) {
title = "实时热点";
} else if (request.getBody().getMsgType() == 2) {
title = "精准扶贫";
} else {
title = "为人民服务";
}
NewsProto.News news = NewsProto.News.newBuilder()
.setId(request.getBody().getMsgType())
.setTitle(title)
.setContent(request.getBody().getMsgType() + ":" + title)
.setCreateTime(System.currentTimeMillis())
.build();
newListBuilder.addNews(news);
newList = newListBuilder.build();
} catch (Exception e) {
e.printStackTrace();
responseObserver.onError(e);
} finally {
responseObserver.onNext(newList);
}
responseObserver.onCompleted();
}
}
2、 grpc服务端,启动
package com.cn.news.service;
import io.grpc.Server;
import io.grpc.ServerBuilder;
/**
* description: GRpcServer <br>
* date: 23.4.12 16:29 <br>
* author: cn_yaojin <br>
* version: 1.0 <br>
*/
public class GRpcServer {
public static void main(String[] args) {
try {
Server server = ServerBuilder.forPort(1031).addService(new NewService()).build().start();
System.out.println("服务已启动,端口:" + server.getPort());
server.awaitTermination();
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、 编写grpc客户端,启动
package com.cn.news.service;
import com.cn.news.proto.NewsProto;
import com.cn.news.proto.NewsServiceGrpc;
import io.grpc.Channel;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* description: GRpcClient <br>
* date: 23.4.12 16:32 <br>
* author: cn_yaojin <br>
* version: 1.0 <br>
*/
public class GRpcClient {
private NewsServiceGrpc.NewsServiceBlockingStub newsServiceImplBase;
public GRpcClient(Channel channel) {
this.newsServiceImplBase = NewsServiceGrpc.newBlockingStub(channel);
}
public static void main(String[] args) {
//初始化client与服务端的连接
ManagedChannel channel = ManagedChannelBuilder.forTarget("127.0.0.1:1031")
.usePlaintext()
.build();
GRpcClient gRpcClient = new GRpcClient(channel);
//定时任务模拟提交数据
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
//以下是构造请求参数
NewsProto.NewsDetail.Builder detail = NewsProto.NewsDetail.newBuilder();
long t = System.currentTimeMillis();
if (t % 5 == 0) {
detail.setMsgType(1);
} else if (t % 5 == 1) {
detail.setMsgType(3);
} else {
detail.setMsgType(2);
}
detail.setMsgStatus(0);
NewsProto.NewsRequest request = NewsProto.NewsRequest
.newBuilder()
.setDate(t + "")
.setBody(detail.build())
.build();
gRpcClient.list(request);
}
}, 10, 30, TimeUnit.SECONDS);
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 调用grpc的提供的服务(此处调用NewService下的list方法)
*
* @param request
*/
public void list(NewsProto.NewsRequest request) {
try {
NewsProto.NewsResponse response = newsServiceImplBase.list(request);
List<NewsProto.News> list = response.getNewsList();
if (list != null) {
for (NewsProto.News t : list) {
System.out.println(String.format("收到服务端响应了,标题:%s,内容:%s,时间:%s", t.getTitle(), t.getContent(), t.getCreateTime()));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
四、启动后的运行示例
五、 编写node客户端
const grpc = require('grpc');
const protoLoader = require('@grpc/proto-loader');
//以下proto文件与当前的index.js在同一个目录下
const PROTO_PATH = 'helloworld.proto';
const packageDefinition = protoLoader.loadSync(PROTO_PATH);
const hello_proto = grpc.loadPackageDefinition(packageDefinition).news;
function main() {
const client = new hello_proto.NewsService('127.0.0.1:1031',
grpc.credentials.createInsecure());
var detail={
msgType:2,
msgStatus:2
};
var user={
date:123123123123,
body: detail
};
client.list(user, function (err, response) {
var items = response.news
console.log('Greeting:', items);
});
}
main();