参考博客:https://www.cnblogs.com/dkblog/archive/2012/03/27/2419010.html
参考博客:https://blog.csdn.net/carson_ho/category_9272167.html
官网文档:https://developers.google.cn/protocol-buffers/docs/proto





package person;
option java_package = "com.carson.proto";
// 定义:Java包名
// 作用:指定生成的类应该放在什么Java包名下
// 注:如不显式指定,默认包名为:按照应用名称倒序方式进行排序
option java_outer_classname = "Demo";
// 定义:类名
// 作用:生成对应.java 文件的类名(不能跟下面message的类名相同)
// 注:如不显式指定,则默认为把.proto文件名转换为首字母大写来生成
// 如.proto文件名="my_proto.proto",默认情况下,将使用 "MyProto" 做为类名
option optimize_for = ***;
// 作用:影响 C++ & java 代码的生成
// ***参数如下:
// 1. SPEED (默认)::protocol buffer编译器将通过在消息类型上执行序列化、语法分析及其他通用的操作。(最优方式)
// 2. CODE_SIZE::编译器将会产生最少量的类,通过共享或基于反射的代码来实现序列化、语法分析及各种其它操作。
// 特点:采用该方式产生的代码将比SPEED要少很多, 但是效率较低;
// 使用场景:常用在 包含大量.proto文件 但 不追求效率 的应用中。
//3. LITE_RUNTIME::编译器依赖于运行时 核心类库 来生成代码(即采用libprotobuf-lite 替代libprotobuf)。
// 特点:这种核心类库要比全类库小得多(忽略了 一些描述符及反射 );编译器采用该模式产生的方法实现与SPEED模式不相上下,产生的类通过实现 MessageLite接口,但它仅仅是Messager接口的一个子集。
// 应用场景:移动手机平台应用
option cc_generic_services = false;
option java_generic_services = false;
option py_generic_services = false;
// 作用:定义在C++、java、python中,protocol buffer编译器是否应该 基于服务定义 产生 抽象服务代码(2.3.0版本前该值默认 = true)
// 自2.3.0版本以来,官方认为通过提供 代码生成器插件 来对 RPC实现 更可取,而不是依赖于“抽象”服务
optional repeated int32 samples = 4 [packed=true];
// 如果该选项在一个整型基本类型上被设置为真,则采用更紧凑的编码方式(不会对数值造成损失)
// 在2.3.0版本前,解析器将会忽略 非期望的包装值。因此,它不可能在 不破坏现有框架的兼容性上 而 改变压缩格式。
// 在2.3.0之后,这种改变将是安全的,解析器能够接受上述两种格式。
optional int32 old_field = 6 [deprecated=true];
// 作用:判断该字段是否已经被弃用
// 作用同 在java中的注解@Deprecated
// 消息对象用message修饰
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
message AddressBook {
repeated Person person = 1;
}
message person{
required int32 id=1;
optional string userName=2;
required double check=3;
repeated string sex=4;
}
由于历史原因,repeated标量数字类型的字段(例如 , , int32)没有尽可能高效地编码。新代码应该使用特殊选项来获得更有效的编码。例如:int64enum[packed = true]


// 基本数据类型
// message:定义消息模型,java基本实体类
message person{
// 必须
// 字段修饰符 字段类型 字段名 标识符
required int32 id=1;
// 可选
optional string userName=2;
// 必须
required double check=3;
// 必须
required string sex=4;
}
// 基本数据类型,message:定义消息模型
message person{
// 必须
required int32 id=1;
// 可选
optional string userName=2;
required double check=3;
// 可复用赋值
repeated string sex=4;
// 性别枚举类
enum SexType{
man=1;
woman=2;
}
}
package person;
option java_package="com.shu.proto";
option java_outer_classname="Person";
// 编码格式
option java_string_check_utf8=true;
// 是否生成hash与equal方法
option java_generate_equals_and_hash=true;
// 基本数据类型,message:定义消息模型
message person{
// 必须
required int32 id=1;
// 可选
optional string userName=2;
required double check=3;
// 可复用赋值
repeated string sex=4;
// 性别枚举类
enum SexType{
man=1;
woman=2;
}
// 嵌套消息模型
message Person_Sex {
optional SexType type = 2 [default = man];
}
}
package person;
option java_package="com.shu.proto";
option java_outer_classname="Person";
// 编码格式
option java_string_check_utf8=true;
// 是否生成hash与equal方法
option java_generate_equals_and_hash=true;
// 基本数据类型,message:定义消息模型
message person{
// 必须
required int32 id=1;
// 可选
optional string userName=2;
required double check=3;
// 可复用赋值
repeated string sex=4;
// 性别枚举类
enum SexType{
man=1;
woman=2;
}
// 嵌套消息模型
message Person_Sex {
optional SexType type = 2 [default = man];
}
}
// 外部消息
message AddressBook {
repeated person person = 1;
// 直接使用了 Person消息类型作为消息字段
}
import "myproject/other_protos.proto"
// 在A.proto 文件中添加 B.proto文件路径的导入声明
// ProtocolBuffer编译器 会在 该目录中 查找需要被导入的 .proto文件
// 如果不提供参数,编译器就在 其调用的目录下 查找
message Foo {
reserved 2, 15, 9 to 11;
reserved "foo", "bar";
}
// 保留最大值
enum Foo {
reserved 2, 15, 9 to 11, 40 to max;
reserved "FOO", "BAR";
}
message person{
required int32 id=1;
// 设置默认值
optional string userName=2[default = '测试'];
required string sex=3;
}
package person;
option java_package="com.shu.proto";
option java_outer_classname="Person";
// 编码格式
option java_string_check_utf8=true;
// 是否生成hash与equal方法
option java_generate_equals_and_hash=true;
// 返回参数
message person{
required int32 id=1;
optional string userName=2;
repeated string sex=3;
}
// 查询参数
message SearchRequest {
repeated int32 id = 1;
}
// 定义RPC服务
service SearchPersonService {
rpc Search (SearchRequest) returns (person);
}
// // 生成命令 protoc -I=E:\Project\Java\src\Demo --java_out=E:\Project E:\Project\Java\src\Demo\Person.proto

// 在 终端 输入下列命令进行编译
protoc -I=$SRC_DIR --xxx_out=$DST_DIR $SRC_DIR/addressbook.proto
// 参数说明
// 1. $SRC_DIR:指定需要编译的.proto文件目录 (如没有提供则使用当前目录)
// 2. --xxx_out:xxx根据需要生成代码的类型进行设置
// 对于 Java ,xxx = java ,即 -- java_out
// 对于 C++ ,xxx = cpp ,即 --cpp_out
// 对于 Python,xxx = python,即 --python_out
// 3. $DST_DIR :编译后代码生成的目录 (通常设置与$SRC_DIR相同)
// 4. 最后的路径参数:需要编译的.proto 文件的具体路径
// 编译通过后,Protoco Buffer会根据不同平台生成对应的代码文件
// eg:protoc -I=E:\Project\Java\src\Demo --java_out=E:\Project E:\Project\Java\src\Demo\Person.proto
<dependency>
<groupId>com.google.protobufgroupId>
<artifactId>protobuf-javaartifactId>
<version>2.5.0version>
dependency>
<-- 方式1:直接序列化和反序列化 消息 -->
protocolBuffer.toByteArray();
// 序列化消息 并 返回一个包含它的原始字节的字节数组
protocolBuffer.parseFrom(byte[] data);
// 从一个字节数组 反序列化(解析) 消息
<-- 方式2:通过输入/ 输出流(如网络输出流) 序列化和反序列化消息 -->
protocolBuffer.writeTo(OutputStream output);
output.toByteArray();
// 将消息写入 输出流 ,然后再 序列化消息
protocolBuffer.parseFrom(InputStream input);
// 基本的get与set方法
package com.example.thrift.proto;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
/**
* @Author shu
* @Date: 2022/03/01/ 13:39
* @Description proto方法
**/
public class PersonTest {
public static void main(String[] args) {
// 通过 消息类的内部类Builder类 构造 消息类的消息构造器
Person.person.Builder builder = Person.person.newBuilder();
// 设置值
builder.setId(1);
builder.setUserName("xiaoMing");
// 通过 消息构造器 创建 消息类 对象
Person.person person = builder.build();
/**
* 直接序列化
*/
// 序列化
byte[] array = person.toByteArray();
// 打印日志
System.out.println(Arrays.toString(array));
// 反序列化消息
try {
Person.person parse = Person.person.parseFrom(array);
// 当接收到字节数组byte[] 反序列化为 person消息类对象
System.out.println(parse.getId());
System.out.println(parse.getUserName());
// 输出反序列化后的消息
} catch (IOException e) {
e.printStackTrace();
}
/**
* 流序列化
*/
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
person.writeTo(output);
// 将消息序列化 并写入 输出流(此处用 ByteArrayOutputStream 代替)
} catch (IOException e) {
e.printStackTrace();
}
byte[] byteArray = output.toByteArray();
// 通过 输出流 转化成二进制字节流
// b. 反序列化
ByteArrayInputStream input = new ByteArrayInputStream(byteArray);
// 通过 输入流 接收消息流(此处用 ByteArrayInputStream 代替)
try {
Person.person parse = Person.person.parseFrom(input);
// 通过输入流 反序列化 消息
System.out.println(parse.getId());
System.out.println(parse.getUserName());
// 输出消息
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 通过 消息类的内部类Builder类 构造 消息类的消息构造器
Person.person.Builder builder = Person.person.newBuilder();
// 通过 消息构造器 创建 消息类 对象
Person.person person = builder.build();
public Builder isInitialized()
// 检查所有 required 字段 是否都已经被设置
public Builder toString() :
// 返回一个人类可读的消息表示(用于调试)
public Builder mergeFrom(Message other)
// 将 其他内容 合并到这个消息中,覆写单数的字段,附接重复的。
public Builder clear()
package com.example.thrift.proto;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
/**
* @Author shu
* @Date: 2022/03/01/ 13:39
* @Description proto方法
**/
public class PersonTest {
public static void main(String[] args) {
// 通过 消息类的内部类Builder类 构造 消息类的消息构造器
Person.person.Builder builder = Person.person.newBuilder();
// 设置值
builder.setId(1);
builder.setUserName("xiaoMing");
// 通过 消息构造器 创建 消息类 对象
Person.person person = builder.build();
/**
* 直接序列化
*/
// 序列化
byte[] array = person.toByteArray();
// 打印日志
System.out.println(Arrays.toString(array));
// 反序列化消息
try {
Person.person parse = Person.person.parseFrom(array);
// 当接收到字节数组byte[] 反序列化为 person消息类对象
System.out.println(parse.getId());
System.out.println(parse.getUserName());
// 输出反序列化后的消息
} catch (IOException e) {
e.printStackTrace();
}
/**
* 流序列化
*/
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
person.writeTo(output);
// 将消息序列化 并写入 输出流(此处用 ByteArrayOutputStream 代替)
} catch (IOException e) {
e.printStackTrace();
}
byte[] byteArray = output.toByteArray();
// 通过 输出流 转化成二进制字节流
// b. 反序列化
ByteArrayInputStream input = new ByteArrayInputStream(byteArray);
// 通过 输入流 接收消息流(此处用 ByteArrayInputStream 代替)
try {
Person.person parse = Person.person.parseFrom(input);
// 通过输入流 反序列化 消息
System.out.println(parse.getId());
System.out.println(parse.getUserName());
// 输出消息
} catch (IOException e) {
e.printStackTrace();
}
}
}
该Message接口定义了允许您检查、操作、读取或写入整个消息的方法。除了这些方法,Foo该类还定义了以下静态方法: