idea构建grpc项目

转载请注明出处:

安装protocbuf插件

idea 建议下载一个 protobuf的插件, 可以有代码提示. 这里直接去pluging里搜就行了.

在idea的plugins中搜索proto,然后下载如下的插件就行(最多下载的那个),点击install,然后重启就可以。

gRPC项目构建

新建Maven项目并修改pom.xml

首先用IDEA新建一个maven项目

                    

 修改pom.xml,注意这个build标签和properties标签都是最顶级标签的直接子标签。

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

接着继续在pom.xml中添加一些,这些依赖是构造gRPC-java项目必须用到的(来自官方文档)

<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> <!-- necessary for Java 9+ -->
  <groupId>org.apache.tomcat</groupId>
  <artifactId>annotations-api</artifactId>
  <version>6.0.53</version>
  <scope>provided</scope>
</dependency>

添加.proto文件

  proto文件用来描述rpc请求体、响应体、以及rpc提供的服务。通过插件可以根据.proto文件生成Java类。

  这里面有个非常重要的点要注意,就是proto文件存放的位置。一定要在和src/main/java源文件目录同级的proto源文件目录才可以。如下图所示:

                       

   添加一个proto文件:helloworld.proto

syntax = "proto3"; // 协议版本

// 选项配置
option java_package = "com.chenj.protobuf";
option java_outer_classname = "RPCDateServiceApi";
option java_multiple_files = true;

// 定义包名
package com.chenj.protobuf;

// 服务接口.定义请求参数和相应结果    
service RPCDateService {
    rpc getDate (RPCDateRequest) returns (RPCDateResponse) {
    }
}

// 定义请求体
message RPCDateRequest {
    string userName = 1;
}

// 定义响应内容
message RPCDateResponse {
    string serverDate = 1;
}

根据.proto文件生成消息体类文件和XXXGrpc类文件

  使用maven命令.

     在第一步修改的pom.xml的路径下,首先执行

    mvn protobuf:compile 生成消息体类文件

                             

 

  接着执行:

    mvn protobuf:compile-custom 生成XXXGrpc类文件

                       

   使用maven插件, 编译.

     

   第一个命令执行完. 在 target目录里找就行了. 第二个命令也是找就行了. 然后将生成的Java文件拷贝到你的目录里.就可以了

编写接口实现类

package com.chenj;

import com.chenj.grpc.api.RPCDateRequest;
import com.chenj.grpc.api.RPCDateResponse;
import com.chenj.grpc.api.RPCDateServiceGrpc;
import io.grpc.stub.StreamObserver;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

// RPCDateServiceGrpc.RPCDateServiceImplBase 这个就是接口.
// RPCDateServiceImpl 我们需要继承他的,实现方法回调
public class RPCDateServiceImpl extends RPCDateServiceGrpc.RPCDateServiceImplBase {
    @Override
    public void getDate(RPCDateRequest request, StreamObserver<RPCDateResponse> responseObserver) {
        //请求结果,我们定义的
        RPCDateResponse rpcDateResponse = null;
        //
        String userName = request.getUserName();
        String response = String.format("你好:%s,今天是%s.", userName,LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        try {
            // 定义响应,是一个builder构造器.
            rpcDateResponse = RPCDateResponse.newBuilder()
                    .setServerDate(response)
                    .build();
            //int i = 10/0;
        } catch (Exception e) {
            responseObserver.onError(e);
        } finally {
            
            responseObserver.onNext(rpcDateResponse);
        }

        responseObserver.onCompleted();

    }
}

定义服务端

package com.chenj;

import io.grpc.Server;
import io.grpc.ServerBuilder;

import java.io.IOException;

public class GRPCServer {
    private static final int port = 9999;

    public static void main(String[] args) throws IOException, InterruptedException {
        //设置service端口
        Server server = ServerBuilder.forPort(port)
                .addService(new RPCDateServiceImpl())
                .build().start();
        System.out.println(String.format("GRpc服务端启动成功, 端口号: %d.", port));

        server.awaitTermination();


    }
}

定义客户端

package com.chenj;

import com.chenj.grpc.api.RPCDateRequest;
import com.chenj.grpc.api.RPCDateResponse;
import com.chenj.grpc.api.RPCDateServiceGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

public class GRPCClient {
    private static final String host = "localhost";
    private static final int serverPort = 9999;
    public static void main(String[] args) {
        //1,拿到一个通信channel
        ManagedChannel channel = ManagedChannelBuilder.forAddress(host, serverPort).
                usePlaintext()//无需加密或认证
                .build();
        try {
            //2.拿到stub对象
            RPCDateServiceGrpc.RPCDateServiceBlockingStub rpcDateService  = RPCDateServiceGrpc.newBlockingStub(channel);
            RPCDateRequest rpcDateRequest = RPCDateRequest.newBuilder()
                    .setUserName("JACK")
                    .build();
            //3,请求
            RPCDateResponse rpcDateResponse = rpcDateService.getDate(rpcDateRequest);
            //4,输出结果
            System.out.println(rpcDateResponse.getServerDate());
        } finally {
            // 5.关闭channel, 释放资源.
            channel.shutdown();
        }

    }
}

  然后先启动Server:  再启动Client:  可以看到执行成功。一个简单的gRPC helloworld工程就搭建好了。

本文转载于网络 如有侵权请联系删除

相关文章

  • 实现导航Tab栏悬浮功能之改进版

    在上一篇博文中,我们用WindowManager的方法实现了Tab栏的悬浮功能。如果你没有看过上篇博文,请点击[《轻松实现app中的导航Tab栏悬浮功能》][url]。 [url]:/2016/01/12/%E8%BD%BB%E6%9D%BE%E5%AE%9E%E7%8E%B0app%E4%B8%AD%E7%9A%84%E5%AF%BC%E8%88%AATab%E6%A0%8F%E6%82%AC%E6%B5%AE%E5%8A%9F%E8%83%BD/当然,用WindowManager来实现由一个缺点就是当没有显示悬浮窗的权限时,该功能就无法体现出来。而在本篇博文中,我们用第二种方法,也就是不断地重新设置Tab栏的布局位置来实现悬浮功能,弥补了第一种方法的缺点。效果图这里就不放了,相信大家都看过啦。不废话了,直接上代码。activity_main.xml:<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.andr

  • Golang语言情怀-第15期 Go 语言设计模式 创建模式-生成器

    在应用系统中,常见的的应用场景就是调用一个生成器:生成订单号,序列号,随机数等。golanggoroutine为这种需求提供了强大的武器。1.简单的生成器packagemain import( "fmt" "math/rand" ) funcGenerateIntA()chanint{ ch:=make(chanint,10) gofunc(){ for{ ch<-rand.Int() } }() returnch } funcmain(){ ch:=GenerateIntA() fmt.Println(<-ch) fmt.Println(<-ch) }复制2.叠加增强型资源生成器可以使用多路复用技术进行堆积叠加,增加服务能力 可以使用缓冲chan增加服务能力packagemain import( "fmt" "math/rand" ) funcGenerateIntA()chanint{ ch:=make(chanint,10) gofunc(){ for{ ch<-ra

  • angular 在指令里把组件当服务,并订阅组件的事件

    -Module import{ExampleDirective,TabBodyComponent}from'./example.component'; @NgModule({ declarations:[ExampleDirective,TabBodyComponent], providers:[TabBodyComponent] }) exportclassExampleModule{} +AppComponent @Component({ selector:'app-component', template:` <tab-bodyexample></tab-body> ` }) exportclassAppComponent{} *ExampleComponent,TabBody在一个文件里,下面注入时用forwardRef import{Subscription}from'rxjs'; @Directive({ selector:'example,[example]' }) e

  • LeetCode 87. Scramble String

    题目一开始我读错了题意,以为是二分,结果却是动态规划的区间DP我都状态数组是dp[i1][j1][i2][j2],表示第一个字符串的i1到j1区间和第二个字符串的i2到j2区间,是符合条件,是可以旋转转换的。string最大的长度也不过50多个吧。所以险过。状态转移方程,很简单啦,将区间划分,有两种情况,一种是交换子树,一种是没交换。判断划分区间后的子区间if(dp[i1][i1+k][i2][i2+k]==1 &&dp[i1+k+1][j1][i2+k+1][j2]==1) { dp[i1][j1][i2][j2]=1; } if(dp[i1][i1+k][j2-k][j2]==1 &&dp[i1+k+1][j1][i2][j2-k-1]==1) { dp[i1][j1][i2][j2]=1; }复制k就是划分的区间。完整的c++代码classSolution{ public: intdp[55][55][55][55]; boolisScramble(strings1,strings2){ intlen1=s1.length(); intl

  • vb.net ExcelHelper类(三)

    接上两条内容!'''<summary>'''插行(在指定行上面插入指定数量行)'''</summary>'''<paramname="rowIndex"></param>'''<paramname="count"></param>PublicSubInsertRows(rowIndexAsInteger,countAsInteger)TryDimnAsInteger=1Whilen<=Me.WorkSheetCountworkSheet=CType(workBook.Worksheets(n),Excel.Worksheet)range=CType(workSheet.Rows(rowIndex,Me.missing),Excel.Range)DimiAsInteger=0Whilei<countrange.Inse

  • 几个方法帮你加快Python运行速度

    Python运行的慢是历来被诟病的,一方面和语言有关,另一方面可能就是你代码的问题。语言方面的问题我们解决不了,所以只能在编程技巧上来提高程序的运行效率。下面就给大家分享几个提高运行效率的编程方法。首先,我们需要来衡量代码的时间和空间的复杂性,不然仅仅用我们的肉眼很难感受代码时间长短的变化。python中的profiler可以帮助我们测量程序的时间和空间复杂度。使用时通过-o参数传入可选输出文件以保留性能日志。具体使用方法如下:python-mcProfile[-ooutput_file]my_python_file.py复制01使用哈希表的数据结构如果在程序中遇到大量搜索操作时,并且数据中没有重复项,则可以使用查找而不是循环。举例如下:items=['a','b',..,'100m']#1000sofitems found=False foriinitems: if(i=='100m'): found=True复制可以改写为items={'a':'a','

  • CJ刚结束,这些新鲜出炉的厂商专访不容错过!

    刚刚过去的CJ还是一如既往的人从众!即使台风突袭,也并未吓退观众们慕名而来的热情。今年的CJ依旧吸引了来自世界各地的无数发烧友、游戏迷、技术宅、二次元粉丝们前来“朝圣”,就连国民校长王思聪也来了(这大约已是第4次?CJ果然是最容易偶遇王思聪的地方)。 今年的ChinaJoy(以下简称:CJ)小编也很忙。逛了CJ展、参加了爱奇艺《无主之城VR》的媒体专场体验,还在CJ现场对顶级游戏引擎厂商EpicGames、游戏开发商唯晶科技和响山科技,进行了相关采访。接下来,就将这些精彩内容为小伙伴们双手奉上! VR相关回顾:硬件、内容体验、系统更新 等信息汇总 参展内容这一块,作为常客的VR/AR当然也不能缺席。今年CJ的VR/AR参展厂商带来的硬件与内容体验,可谓是颜值与质量均在线。 硬件方面 Pico带来小怪兽2VR一体机及其旗舰一体机PicoNeo;小霸王公布miniVR眼镜,以及与AMD深度合作打造的VR-Ready电脑小霸王Z+;联想展示MirageAR头显;而诺亦腾NoitomHi5VR动作捕捉手套的体验现场也相当火热。 诺亦腾NoitomHi5VR体验现场 内容体验方面 HTCVive

  • java : 调用ImageIO.writer从BufferedImage生成jpeg图像的坑

    生成jpeg图像这是个非常非常简单的东西了,网上很多介绍是直接用com.sun.image.codec.jpeg.JPEGImageEncoder来实现,如下:/** *将原图压缩生成jpeg格式的数据 *@paramsource *@return */ publicstaticbyte[]wirteJPEGBytes(BufferedImagesource){ if(null==source) thrownewNullPointerException(); ByteArrayOutputStreamoutput=newByteArrayOutputStream(); JPEGImageEncoderjencoder=JPEGCodec.createJPEGEncoder(output); JPEGEncodeParamparam=jencoder.getDefaultJPEGEncodeParam(source); param.setQuality(0.75f,true); jencoder.setJPEGEncodeParam(param); try{ jencoder.encod

  • 腾讯云消息队列RocketMQ版角色与鉴权

    名词解释角色(role):TDMQ的“角色”是TDMQ内专有的概念,区别于腾讯云的“角色”,是用户自行在TDMQ内部做权限划分的最小单位,用户可以添加多个角色并为其赋予不同命名空间下的生产和消费权限。密钥(token):TDMQ的“密钥”是一种鉴权工具,用户可以通过在客户端中添加密钥来访问TDMQ进行消息的生产消费。密钥和角色一一对应,每种角色都有其对应的唯一密钥。TDMQRocketMQ版继承了这些概念,在TDMQRocketMQ版中,开源client中定义的ACL_ACCESS_KEY对应TDMQ的密钥(token)。使用场景用户需要安全地使用TDMQ进行消息的生产消费。用户需要对不同的命名空间设置不同角色的生产消费权限。例如:一个公司有A部门和B部门,A部门的系统产生交易数据,B部门的系统根据这些交易数据做数据分析和展示。那么遵循权限最小化原则,可以配置两种角色,A部门角色只授予往交易系统命名空间中生产消息的权限,B部门则只授予消费消息的权限。这样可以很大程度避免由于权限不清带来的数据混乱、业务脏数据等问题。操作步骤新增角色1.登录TDMQ控制台,在左侧导航栏单击角色管理,进入角

  • Java实现神经网络激活函数Sigmoid

    /** *@Author。。。源 *@Emailapple_dzy@163.com *@Bloghttps://www.findmyfun.cn *@Date2021/12/249:16 *@Version1.0 */ publicclassSigmoidUtils{ //Sigmoid publicstaticdoublesigmoid(doublevalue){ //Math.E=e;Math.Pow(a,b)=a^b doubleey=Math.pow(Math.E,-value); doubleresult=1/(1+ey); returnresult; } //Sigmoid求导 publicstaticdoublesigmoidDerivative(doublevalue){ doubleA=sigmoid(value); doubleB=1-sigmoid(value); doubleresult=A*B; returnresult; } }复制版权属于:。。。源 本文链接:https://www.findmyfun.cn/java-implementation-of

  • Django Admin管理入门

    Django最强大的部分之一是自动管理界面。它从模型中读取元数据,以提供快速,以模型为中心的界面,受信任的用户可以在其中管理您网站上的内容。管理员的推荐用途仅限于组织的内部管理工具。它不是用于构建整个前端。 管理员有许多用于自定义的钩子,但要注意尝试专门使用这些钩子。如果您需要提供一个更加以流程为中心的接口来抽象出数据库表和字段的实现细节,那么可能是时候编写自己的视图了。 1创建Django项目 django-adminstartprojectcrm_v1复制 2创建并注册app pythonmanage.pystartappbms复制 修改settings.py INSTALLED_APPS=[ 'django.contrib.admin', ...... 'bms.apps.BmsConfig', ]复制 3  创建模型 modles.py 在Django里写一个数据库驱动的Web应用的第一步是定义模型-也就是数据库结构设计和附加的其它元数据。 设计哲学 模型是真实数据的简单明确的描述。它包含了储存的数据所必要的字段和行为。Djan

  • springboot-springmvc-requestParam

    springmvc请求方式 1、直接写在形参中:基本类型 @RequestMapping("/testRequestParam1") publicModelAndViewtestRequestParam1(Stringname){ ModelAndViewmv=newModelAndView(); System.out.println(name); mv.setViewName("helloworld"); returnmv; } 复制   2、直接写在形参中:pojo /** *页面请求实例: *<formaction="http://localhost:8080/hello/testRequestParam4"method="post"> *<inputtype="text"name="id"/><inputtype="text"name="name"/> *<inputtype="submit"value="提交"/></form> */ @RequestMapping("/testRequest

  • vue 项目使用百度地图画行走的路线

    首先安装百度地图的npm vue-baidu-map npmi--savevue-baidu-map复制 安装完之后 在main.js引用 importBaiduMapfrom'vue-baidu-map' Vue.use(BaiduMap,{ ak:'ne52jEbvgvLx7kdY0O1g6LXrVhNLEGhhg'//百度地图密钥 });复制   然后在需要的页面上调用,示例如下 <template> <divclass="content"> <baidu-mapclass="map":center="map.center":zoom="map.zoom"@ready="handler"> <!--缩放--> <bm-navigationanchor="BMAP_ANCHOR_TOP_LEFT"></bm-navigation> <!--定位--> <bm-geolocationanchor="BMAP_ANCHOR_BOTTOM_RIGHT":sh

  • C++11的tuple元组

    tuple元组 是一个固定大小的不同类型的集合,是泛华的std::pair。和C#中的tuple类似,但是比C#的tuple强大得多。 我们也可以把它作一个通用的结构体来用,不需要创建结构体有获取结构体的特征,在某些情况下可以取代结构体,使程序更简洁、直观。 下面看看tuple的基本用法: 先构造一个tuple: tuple<constchar,int>tp=make_tuple(sendPack,nSendSize);//构造一个tuple 这个tuple等价于一个结构体 structA { charp; intlen; } 用tuple<constchar*,int>tp就可以不用创建这个结构体了,而作用使一样的。还有一种方法是使用std::tie,它会创建一个元组的左值引用。 intx=1; inty=2; strings="aa"; autotp=std::tie(x,s,y); //tp的类型实际是:std::tuple<int&,string&,int&> 再看看如何获取元组的值: constchar*data=t

  • Django框架请求生命周期

    先看一张图吧!  1、请求生命周期 -wsgi,他就是socket服务端,用于接收用户请求并将请求进行初次封装,然后将请求交给web框架(Flask、Django) -中间件,帮助我们对请求进行校验或在请求对象中添加其他相关数据,例如:csrf、request.session -路由匹配 -视图函数,在视图函数中进行业务逻辑的处理,可能涉及到:orm、templates=>渲染 -中间件,对响应的数据进行处理。 -wsgi,将响应的内容发送给浏览器。 2、什么wsgi wsgi:web服务网关接口  实现该协议的模块: -wsgiref(测试版本,性能特别差) -werkzurg -uwsig wsgiref示例: fromwsgiref.simple_serverimportmake_server defrun_server(environ,start_response): start_response('200OK',[('Content-Type','text/html')]) retu

  • Hadoop基本概念

    Hadoop:   1HDFS(分布式文件系统) 2HBase/Sqoop/Flume(数据导入与导出) 3MapReduce/Spark(并行计算架构) 4Pig/Hive(Hadoop编程) 5ZooKeeper/Oozie(系统管理架构) 6Ambari/Whirr(系统部署管理) 7Mahout(机器学习/算法库) 8Impala(查询系统) Hadoop是一个大家族,是一个开源的生态系统,是一个分布式运行系统,是基于Java编程语言的架构。不过它最高明的技术还是HDFS和MapReduce,使得它可以分布式处理海量数据。 1HDFS(分布式文件系统): 它与现存的文件系统不同的特性有很多,比如高度容错(即使中途出错,也能继续运行),支持多媒体数据和流媒体数据访问,高效率访问大型数据集合,数据保持严谨一致,部署成本降低,部署效率提交等,如图是HDFS的基础架构 2HBase/Sqoop/Flume(数据导入与导出): HBase是运行在HDFS架构上的列存储数据库,并且已经与Pig/Hive很好地集成。通过JavaAPI可以近无缝地使用HBase。 Sqoop

  • 案例:tab栏切换案例

    切换tab栏并且显示出tab栏的内容 <!DOCTYPEhtml> <htmllang="en"> <head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width,initial-scale=1.0"> <title>Document</title> <style> .tab{ width:600px; height:50px; text-align:center; margin:100pxauto; } .tab_list{ width:1000px; text-align:center; } .tab_listli{ background-color:pink; width:auto; /*float:left;*/ height:39px; line-height:39px; padding:020px; text-align:center; cursor:pointer; display:i

  • linux cat 模糊查询日志命令

    catlog.txt|grep'你想要查询的字符串'-C50   C50表示关键字前后50行 A50表示关键字前50行 B50表示关键字后50行   信息太多一屏幕显示不下,此时可使用管道符加more或者less catlog.txt|grep'你想要查询的字符串'-C50|more catlog.txt|grep'你想要查询的字符串'-C50|less   less可以向前查看,more只能往后查看 

  • Java 获取图片 的几种方式

    我使用过的Java获取图片的方式有三种 java.awt.Toolkit.getDefaultToolkit()复制    javax.imageio.ImageIO;    ImageIcon 1publicclassWormStage{ 2publicstaticImagebackground; 3publicstaticImagefoodImage; 4publicstaticImagecellImage; 5 6publicWormStage(){ 7//这种为跨文件夹获取图片 8background=Toolkit.getDefaultToolkit().getImage("WormImg/bg.png"); 9//这种只能获取当前代码文件夹的图片 10foodImage=Toolkit.getDefaultToolkit().createImage(getClass().getResource("food.png")); 11 12} 13}复制 publicclassImages{ publicst

  • linux学习3章-管道符、重定向与环境变量

    2019年11月16日 1.重定向:首先重定向,我们分为输入重定向和输出重定向输出重定向:是指把原本要输出到屏幕的数据信息写入到指定文件中。输出重定向中用到的符号及其作用   符号 作用 命令>文件 将标准输出重定向到一个文件中(清空原有文件的数据) 命令2>文件 将错误输出重定向到一个文件中(清空原有文件的数据) 命令>>文件 将标准输出重定向到一个文件中(追加到原有内容的后面) 命令2>>文件 将错误输出重定向到一个文件中(追加到原有内容的后面) 命令>>文件2>&1 或命令&>>文件 将标准输出与错误输出共同写入到文件中(追加到原有内容的后面) 输入重定向:把文件导入到命令中输入重定向中用到的符号及其作用 符号 作用 命令<文件 将文件作为命令的标准输入 命令<<分界符 从标准输入中读入,直到遇见分界符才停止 命令<文件1>文件2 将文件1作为命令的标准输入并将标准输出到文件

  • JavaScript中的作用域

    【转载】 1、定义 作用域scope 1)某样事物执行、操作、拥有控制权的那么一个区域 2)编写程序时,程序之中变量的可见度;例如,一个函数能否使用另外一个函数所创建的变量。 2、例子演示 打开firefox,弹出firebug,点击consoletab。在Firefox状态栏上面看到有>>>提示的地方就可以输入了。 functionfn(){alert(11);}复制 然后回车。一切安然...你刚才做的实际上是定义了一个函数fn。接着试试: fn();复制 然后回车。得到11的警告窗口,接着试试: window.fn(); this.fn();复制 得到一样的结果吧?这是因为函数fn是window对象的一个方法,在第二行的"this"的作用域实际指向了window对象。不过多数情况中你不需要像这样window.myFunction(...)地调用函数,这样太麻烦了,程序员工作起来会很不方便。 window对象 window对象总是存在的,你可理解其为一个浏览器窗口对象。它包含了其它所有的对象如document和所有的全局变量。 你可以打开Firebug,

相关推荐

推荐阅读