0 前言
Protobuf作为一种轻量、高效、可扩展的数据存储语言,被广泛应用于数据传输中。目前对于Proto编辑及编译,最传统的方法是先基于文本编辑软件撰写proto文件,再通过Google提供的protoc程序以命令行的形式编译成java类文件,最后再将生成的java类文件移至project的相应位置。传统的方法比较麻烦,本文将基于IDEA讲述一种一站式编辑及编译的方法。
1 安装
1、下载protoc解析器:protobuf-java-3.14.0.zip
2、在IDEA中安装插件。包括GenProtobuf和Protocol Buffer Editor,前者用于一键转换proto文件,后者用于编辑proto文件(未安装前,IDEA不支持对proto语法,没有高亮显示和自动补全提示)。
注意:如果没有在IDEA的插件市场中搜到以上两个插件,可能是IDEA的版本低了,因此需要升级IDEA到2020版。
2 配置
1、配置Maven
pom.xml文件中添加如下依赖包:
<dependencies>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.9.1</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.9.1</version>
</dependency>
</dependencies>
2、配置GenProtobuf
IDEA菜单栏 --> Tools --> Configure GenProtobuf --> 配置地址
- protoc path是下载的protoc.exe的地址。
- 本文的目的是将proto生成java类,因此生成对象选为java,并填写相应地址。
3 使用
1、编辑proto
安装好Protocol Buffer Editor插件后,无需配置即可使用,由图可见,proto语法的关键字高亮显示了,便于编辑。
2、编译proto
右键proto文件,可以看见两个跟proto有关的选项,一个是“quick gen protobuf here”,另一个是“quick gen protobuf rules”。前者表示在proto所在的文件路径下生成java文件,后者表示按配置的地址生成java文件。
前文已经配置好了java生成的路径,我们选择后者生成即可,效果如图:
其中,MyTest即为test.proto生成的java类。
4 测试
生成了java类文件后,我们就可以测试其序列化和反序列化功能,如果可以正常运行并解析正确,说明我们的操作无误。
测试代码:
package learnProto.selfTest;
import com.google.protobuf.InvalidProtocolBufferException;
import learnProto.selfTest.MyTest.*;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
convertProto(1);
}
public static void convertProto(int value) {
//1.通过build创建消息构造器
Data.Builder dataBuilder = Data.newBuilder();
//2.设置字段值
dataBuilder.setInt32(value);
//3.通过消息构造器构造消息对象
Data data = dataBuilder.build();
//4.序列化
byte[] bytes = data.toByteArray();
System.out.println(value+"序列化后的数据:" + Arrays.toString(bytes)+",字节个数:"+bytes.length);
//5.反序列化
try {
Data parseFrom = Data.parseFrom(bytes);
System.out.println("还原后的数据="+parseFrom.getInt32());
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
}
}
运行结果:
1序列化后的数据:[24, 1],字节个数:2
还原后的数据=1
5 应用
以上的内容足以应付一个简单的proto项目的一站式开发,但如果你正在处理一个较复杂的proto项目,项目中不仅有一个proto文件,其中可能包含多个,且之间有依赖关系,那么通过以上方法一键编译时(假设你写的proto文件的语法都正确),可能会遇到如下错误(即xxx.proto is not defined):
为什么呢?别着急,我们从一个较复杂的案例开始,展示完整的处理流程。
案例的框架如下:
data.proto代码如下:
// Google Protocol Buffers Version 3.
syntax = "proto3";
// Package name.
package prcticeProto.messages;
// Options for code generation.
option java_package = "learnProto.practiceTest.protoModel";
option java_outer_classname = "SchoolModel";
option java_multiple_files = true;
// import packages
import "google/protobuf/any.proto";
import "practiceProto/categories/student.proto";
message School {
message Location{
string name=1;
uint32 id=2;
}
Location schoolLocation = 1;
bool isOpen =2;
repeated categories.Student allStudents = 3;
google.protobuf.Any extend =4;
}
student.proto代码如下:
// Google Protocol Buffers Version 3.
syntax = "proto3";
// Package name.
package prcticeProto.categories;
// Options for code generation.
option java_package = "learnProto.practiceTest.protoModel";
option java_outer_classname = "StudentModel";
option java_multiple_files = true;
// import packages
import "practiceProto/base/person.proto";
message Student {
base.Person baseInfo = 1;
fixed32 calssId = 2;
sint32 score = 3;
}
person.proto代码如下:
// Google Protocol Buffers Version 3.
syntax = "proto3";
// Package name.
package prcticeProto.base;
// Options for code generation.
option java_package = "learnProto.practiceTest.protoModel";
option java_outer_classname = "PersonModel";
option java_multiple_files = true;
message Person{
message Location{
string placeName=1;
uint64 placeId=2;
}
enum Gender{
man=0;
woman=1;
}
string name = 1;
int32 age=2;
Gender gender=3;
float height=4;
double weight=5;
Location location=6;
}
从代码中可知,data依赖student,student依赖person。
注意:
- package:指proto文件的包名
- java_package:指proto生成的java文件的包名
- java_outer_classname:指生成的java文件的类名
- proto与proto之间的依赖关系通过import导入
在一键编译java类之前,需要将编辑好的proto文件,复制到protoc的include目录(从protoc path的地址可知protoc的地址,往上一级即可找到include目录)中:
再一键编译即可!
这一步就是解决上面说到的undefined问题的方法,因为proto文件中有import其他proto文件,那么你就得告诉编译器文件是什么,怎么告诉呢,就是将文件放在编译器的include目录中。
6 参考文献
[1] protobuf那些事(一)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。