初涉ProtoBuf,从Server到Client

目录:
简介
简单使用
—— 1、编写.proto 文件
—— 2、编译proto文件成目标文件(本文为java)
—— 3、将目标文件导入项目
—— 4、将依赖包导入项目
———— 自动依赖
———— 手动依赖
Maven项目
—— 创建Maven项目
—— 安装ProtoBuf插件
—— 编译proto文件
—— Java
—— Web
Android
—— 插件
—— 依赖
—— 编码
—— 结果

简介

常见的序列化协议有xml、json以及本文将介绍的protobuf。

ProtoBuf由Google出品,由其二进制格式,所以在体积和传输方面性能优越,但也因此可读性差。

简单使用

流程:
1、编写.proto 文件
2、编译proto文件成目标文件(本文为java)
3、将目标文件导入项目
4、将依赖包导入项目

1、编写.proto 文件

.proto 文件用来定义消息类型,可理解为java中的类

syntax = "proto3";//使用proto3的语法,不写默认为proto2

message SearchRequest {
  string query = 1;//数字为该字段在二进制文件中的标识(字段号),使用过一次后不应该被改变。字段号1-15占一个字节16-2047占两个字节,常用字段字段号最好用一个字节。19000-19999为保留字段号不可用
  int32 page_number = 2;
  int32 result_per_page = 3;
}

message SearchResponse {//一个.proto文件可以定义多个message
 ...
}

复杂点的

syntax = "proto2";

package tutorial;//如果没有java_package则使用此package,最好不要为空因为不同语言都会使用,java_package只java使用

option java_package = "com.example.tutorial";//生成java文件的包
option java_outer_classname = "AddressBookProtos";//生成java文件的名字

message Person {
  required string name = 1;//必填字段
  required int32 id = 2;
  optional string email = 3;//可选字段

  enum PhoneType {//枚举
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phones = 4;//java中的list
}

message AddressBook {
  repeated Person people = 1;
}

官方参考: https://developers.google.cn/protocol-buffers/docs/proto3#simple

2、编译proto文件成目标文件(本文为java)

编译前需下载protobuf的编译器,也可以下载源码。下载地址

我的机器是Mac所以下载了第一项


初涉ProtoBuf,从Server到Client_第1张图片

解压后


初涉ProtoBuf,从Server到Client_第2张图片

安装protobuf
进入到刚刚的解压目录
$ ./configure
$ make
$ make check
$ make install

成功后


编译proto文件三个参数
protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/addressbook.proto
$SRC_DIR:proto文件路径
$DST_DIR:生成java文件的路径

3、将目标文件导入项目

复制粘贴的工作,将生成的java文件连同包结构一起移到项目。如果包名与项目的包名相同则合并,不相同则在同级。

4、将依赖包导入项目

自动依赖

如果项目使用Maven或Gradle构建的,可以直接添加依赖。

Maven
        
            com.google.protobuf
            protobuf-java
            3.5.1
        
Gradle
    implementation 'com.google.protobuf:protobuf-java:3.5.1'

若不是的话,需要找jar包放入项目。哪里来的jar包呢??自己打。打包的话需要用到Maven,顺便写下安装流程

手动依赖

安装Maven

Maven下载地址

初涉ProtoBuf,从Server到Client_第3张图片

解压后重命名放在Library下


初涉ProtoBuf,从Server到Client_第4张图片

接着配置环境变量

touch ~/.bash_profile 
vi ~/.bash_profile  

具体配置:
# maven所在的目录  
export M2_HOME=/Users/mr.lin/Library/Maven  
# maven bin所在的目录  
export M2=$M2_HOME/bin  
# 将maven bin加到PATH变量中  
export PATH=$M2:$PATH

环境变量刷新
source ~/.bash_profile  

最后


初涉ProtoBuf,从Server到Client_第5张图片

参考 https://blog.csdn.net/kepoon/article/details/55251913

打包

源码已经有了,Maven也配置好了


初涉ProtoBuf,从Server到Client_第6张图片

copy一个protoc文件(上述mac安装protobuf时bin目录下的文件)到src目录下

初涉ProtoBuf,从Server到Client_第7张图片

再copy一个protoc文件到java/core/src/目录下:


初涉ProtoBuf,从Server到Client_第8张图片

然后回到java目录,执行:
mvn package

如果中途失败请注意,是否在此路径下生成过文件

protobuf-3.5.1/java/core/src/main/java/com/google/protobuf

我就失败过,将生成的文件删除重新执行即可。但失败原因不止这一个具体还要看错误信息。

最终结果


初涉ProtoBuf,从Server到Client_第9张图片

剩下的就是将jar包放入项目了

参考 https://blog.csdn.net/u010277446/article/details/79203433

Maven项目

真正做项目的时候,我们总不可能每次都按照简单使用的步骤,先写.proto文件、然后编译成java或其他语言文件才能够使用。

因此便有了自动化构建,我们只需写好.proto文件,剩下的工作交由编译器执行。

创建Maven项目

创建空的Maven项目


初涉ProtoBuf,从Server到Client_第10张图片

填写项目信息


初涉ProtoBuf,从Server到Client_第11张图片
初涉ProtoBuf,从Server到Client_第12张图片
初涉ProtoBuf,从Server到Client_第13张图片

空项目结构


初涉ProtoBuf,从Server到Client_第14张图片
初涉ProtoBuf,从Server到Client_第15张图片

安装ProtoBuf插件

初涉ProtoBuf,从Server到Client_第16张图片
初涉ProtoBuf,从Server到Client_第17张图片
初涉ProtoBuf,从Server到Client_第18张图片

编译proto文件

在pom.xml中添加依赖

    
        
            
                
                    
                    org.xolstice.maven.plugins
                    protobuf-maven-plugin
                    0.5.1
                    
                        
                            
                            
                                compile
                                test-compile
                            
                        
                    
                
            
        
        
            
                org.xolstice.maven.plugins
                protobuf-maven-plugin
            
        
    

    
        
            com.google.protobuf
            protobuf-java
            3.5.1
        
    

添加之前


初涉ProtoBuf,从Server到Client_第19张图片
image.png

添加之后


初涉ProtoBuf,从Server到Client_第20张图片

写.proto文件


初涉ProtoBuf,从Server到Client_第21张图片
初涉ProtoBuf,从Server到Client_第22张图片

参考 https://blog.csdn.net/wpengch/article/details/80192230

Java

在空项目的基础上

初涉ProtoBuf,从Server到Client_第23张图片
初涉ProtoBuf,从Server到Client_第24张图片

写程序入口main


配置启动


初涉ProtoBuf,从Server到Client_第25张图片
初涉ProtoBuf,从Server到Client_第26张图片

测试环境是否搭好


初涉ProtoBuf,从Server到Client_第27张图片

试一下使用情况

    public static void main(String[] args) {

        AddressBookProtos.Person person = AddressBookProtos.Person
                .newBuilder()
                .setName("Tom")
                .setId(1)
                .setEmail("Email")
                .addPhones(0,
                        AddressBookProtos.Person.PhoneNumber.newBuilder()
                                .setNumber("1234")
                                .setType(AddressBookProtos.Person.PhoneType.HOME)
                                .build())
                .build();

        AddressBookProtos.AddressBook addressBook = AddressBookProtos.AddressBook.newBuilder()
                .addPeople(0, person)//这是一个list所以用add,set的话同list使用
                .addPeople(1, person)
                .build();

        System.out.println(addressBook.toByteString());

        try {

            AddressBookProtos.AddressBook addressBook1 = AddressBookProtos.AddressBook.parseFrom(addressBook.toByteArray());

            System.out.println(addressBook1.toString());
        } catch (InvalidProtocolBufferException e) {
            e.printStackTrace();
        }

    }

内容已经成功打印了


初涉ProtoBuf,从Server到Client_第28张图片

Web

在空项目的基础上,创建web

初涉ProtoBuf,从Server到Client_第29张图片

修改web路径


初涉ProtoBuf,从Server到Client_第30张图片
初涉ProtoBuf,从Server到Client_第31张图片

创建Artifact


初涉ProtoBuf,从Server到Client_第32张图片

配置启动


初涉ProtoBuf,从Server到Client_第33张图片
初涉ProtoBuf,从Server到Client_第34张图片
初涉ProtoBuf,从Server到Client_第35张图片
初涉ProtoBuf,从Server到Client_第36张图片

给module添加依赖包,才可以使用servlet


初涉ProtoBuf,从Server到Client_第37张图片

参考 https://www.cnblogs.com/wql025/p/5215570.html

初涉ProtoBuf,从Server到Client_第38张图片

书写Controller


初涉ProtoBuf,从Server到Client_第39张图片

配置servlet


初涉ProtoBuf,从Server到Client_第40张图片

请求


初涉ProtoBuf,从Server到Client_第41张图片

注意:NoClassDefFoundError 与 ClassNotFoundException
NoClassDefFoundError连接时找不到
ClassNotFoundException编译时找不到

报错原因是找不到类

jar包不在了


初涉ProtoBuf,从Server到Client_第42张图片
初涉ProtoBuf,从Server到Client_第43张图片
初涉ProtoBuf,从Server到Client_第44张图片
初涉ProtoBuf,从Server到Client_第45张图片
初涉ProtoBuf,从Server到Client_第46张图片

完成之后运行!Chrome会报404但

初涉ProtoBuf,从Server到Client_第47张图片

Android

当使用kotlin编写protobuf相关当代码时

查了写资料发现protobuf不支持kotlin语言编写,发生原因与编译的顺序有关,网上也有相关的解决办法。

虽然kotlin可以与java混用,但此时此刻protobuf官方还没支持kotlin语言,所以还是乖乖用java,这里就不硬走kotlin的路线了。

插件

先来安装AndroidStudio的插件


初涉ProtoBuf,从Server到Client_第48张图片

项目插件

classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.3'
初涉ProtoBuf,从Server到Client_第49张图片

依赖

apply plugin: 'com.android.application'

apply plugin: 'com.google.protobuf'

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.ljf.protobuf_android"
        minSdkVersion 19
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    sourceSets {
        main {
            java {
                srcDir 'src/main/java'
            }
            proto {//用于识别proto文件的目录
                srcDir 'src/main/proto'
            }
        }
    }
}


protobuf {//编译proto文件的任务
    protoc {
        artifact = 'com.google.protobuf:protoc:3.5.1'
    }

    generateProtoTasks {
        all().each { task ->
            task.builtins {
                remove java
            }
            task.builtins {
                java {}
            }
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.google.protobuf:protobuf-java:3.5.1'//依赖包
}

编码

这里做了两种处理,一个是本地数据的存取,一个是获取网络数据

public class MainActivity extends Activity {

    private TextView resultTv;
    private Button readFileBt;
    private Button sendToServerBt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();

        AddressBookProtos.Person person = AddressBookProtos.Person
                .newBuilder()
                .setName("Tom")
                .setId(1)
                .setEmail("Email")
                .addPhones(0,
                        AddressBookProtos.Person.PhoneNumber.newBuilder()
                                .setNumber("1234")
                                .setType(AddressBookProtos.Person.PhoneType.HOME)
                                .build())
                .build();

        AddressBookProtos.AddressBook addressBook = AddressBookProtos.AddressBook.newBuilder()
                .addPeople(0, person)
                .addPeople(1, person)
                .build();//用protobuf生成对象
        try {
            FileOutputStream fileOutputStream = openFileOutput("proto", MODE_PRIVATE);
            fileOutputStream.write(addressBook.toByteArray());//将protobuf对象的数据存到文件
            fileOutputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void initView() {
        resultTv = findViewById(R.id.resultTv);
        readFileBt = findViewById(R.id.readFileBt);
        sendToServerBt = findViewById(R.id.sendToServerBt);

        readFileBt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    FileInputStream fileInputStream = openFileInput("proto");
                    AddressBookProtos.AddressBook addressBook = AddressBookProtos.AddressBook.parseFrom(fileInputStream);//由数据流生成protobuf对象
                    resultTv.setText("from local:\n" + addressBook.toString());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        //获取网络数据
        sendToServerBt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            URL url = new URL("http://10.2.24.243:8080/test");
                            InputStream is = url.openStream();

                            final AddressBookProtos.AddressBook addressBook = AddressBookProtos.AddressBook.parseFrom(is);
                            is.close();

                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    resultTv.setText("from net:\n" + addressBook.toString());
                                }
                            });
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        });
    }

}

结果

初涉ProtoBuf,从Server到Client_第50张图片

由于服务开在本地所以用模拟器才可以连本地服务,但注意IP地址并不是127.0.0.1。模拟器与本地是局域网关系


初涉ProtoBuf,从Server到Client_第51张图片

GitHub

你可能感兴趣的:(初涉ProtoBuf,从Server到Client)