文章目录
- 环境准备
- 第一步、引入POM依赖
- 第二步、指定目录
- 第三步、编写Proto文件(src/main/proto/addressbook.proto)
- 第四步、使用实体类
- 第五步、序列化
- 第六步、反序列化
- 第七步、效果图
- 参考资料
环境准备
- idea
- maven version:3.1
- JDK8
- Spring Boot version:2.1.8.RELEASE
第一步、引入POM依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xcxyz</groupId>
<artifactId>spring-cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- <protobuf.version>3.2.0rc2</protobuf.version>-->
<protobuf.version>3.15.3</protobuf.version>
<protobuf-java-format.version>1.4</protobuf-java-format.version>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>org.junit.vintage</groupId>-->
<!-- <artifactId>junit-vintage-engine</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
</dependency>
<!--序列化协议 start -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>${protobuf.version}</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${protobuf.version}</version>
</dependency>
<dependency>
<groupId>com.googlecode.protobuf-java-format</groupId>
<artifactId>protobuf-java-format</artifactId>
<version>${protobuf-java-format.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<!--序列化协议 end -->
</dependencies>
<build>
<!--序列化协议 start -->
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.3.0.Final</version>
</extension>
</extensions>
<!--序列化协议 end -->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!--序列化协议 start -->
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.0</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.0.0:exe:${os.detected.classifier}</protocArtifact>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-protobuf-generate-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>target/generated-sources/com/xcxyz/springcloud/protobuf/java</source>
</sources>
</configuration>
</execution>
<execution>
<id>add-protobuf-generate-test-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>target/generated-test-sources/com/xcxyz/springcloud/protobuf/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source> <!-- 源代码使用的开发版本 -->
<target>1.8</target> <!-- 需要生成的目标class文件的编译版本 -->
<!-- 一般而言,target与source是保持一致的,但是,有时候为了让程序能在其他版本的jdk中运行(对于低版本目标jdk,源代码中需要没有使用低版本jdk中不支持的语法),会存在target不同于source的情况 -->
<!-- 这下面的是可选项 -->
<!-- <meminitial>128m</meminitial>-->
<!-- <maxmem>512m</maxmem>-->
<!-- <fork>true</fork> <!– fork is enable,用于明确表示编译版本配置的可用 –>-->
<!--<!– <compilerVersion>1.3</compilerVersion>–>-->
<!-- <!– 这个选项用来传递编译器自身不包含但是却支持的参数选项 –>-->
<!-- <compilerArgument>-verbose -bootclasspath ${java.home}\lib\rt.jar</compilerArgument>-->
</configuration>
</plugin>
<!--序列化协议 end -->
</plugins>
</build>
</project>
第二步、指定目录
[重点] 这里默认的目录为src/main/proto
第三步、编写Proto文件(src/main/proto/addressbook.proto)
// 指定语法
syntax = "proto2";
//该.proto文件以程序包声明开头,这有助于防止不同项目之间的命名冲突。
// 在Java中,除非您已明确指定a java_package,否则包名称将用作Java包。
// 即使您提供java_package,也应该定义一个普通值package,以避免协议缓冲区名称空间以及非Java语言中的名称冲突。
package com.xcxyz.springcloud.controller;
// 包声明后,是Java特有的三个选项: java_multiple_files,java_package,和java_outer_classname。
// java_package指定所生成的类应以哪种Java包名称存在。如果未明确指定,则它仅与package声明中给出的包名称匹配,但是这些名称通常不是合适的Java包名称(因为它们通常不是以域名开头)。
// 该java_outer_classname选项定义了代表该文件的包装器类的类名。如果您没有java_outer_classname明确给出,它将通过将文件名转换为大写驼峰来生成。
// 例如,默认情况下,“ my_proto.proto”将使用“ MyProto”作为包装类名称。该java_multiple_files = true选项可以生成单独的.java每个生成的类的文件(而不是传统的行为,.java即为包装器类生成单个文件,使用包装器类作为外部类,然后将所有其他类嵌套在包装器类中)
option java_multiple_files = true;
option java_package = "com.xcxyz.springcloud.controller";
option java_outer_classname = "AddressBookProtos";
//接下来,您将拥有消息定义。消息只是包含一组类型字段的汇总。许多标准的简单数据类型都可以作为字段类型,包括bool,int32,float,double,和string。
// 您还可以通过使用其他消息类型作为字段类型来为消息添加更多的结构-在上面的示例中,Person消息包含PhoneNumber消息,而AddressBook消息包含Person消息。
// 您甚至可以定义嵌套在其他消息中的消息类型-如您所见,
// 该PhoneNumber类型在inside中定义Person。enum如果您希望某个字段具有一个预定义的值列表之一,也可以定义类型-在这里您要指定电话号码可以是MOBILE,HOME或WORK。
message Person {
optional string name = 1;
optional int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
optional string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
//每个元素上的“ = 1”,“ = 2”标记标识该字段在二进制编码中使用的唯一“标记”。标签编号1至15与较高的编号相比,编码所需的字节减少了一个字节,因此,为了进行优化,
// 您可以决定将这些标签用于常用或重复的元素,而将标签16和更高的标签用于较少使用的可选元素。重复字段中的每个元素都需要重新编码标签号,因此重复字段是此优化的最佳候选者。
//
//每个字段都必须使用以下修饰符之一进行注释:
//
//optional:可能会或可能不会设置该字段。如果未设置可选字段值,则使用默认值。对于简单类型,您可以指定自己的默认值,就像type在示例中为电话号码所做的那样。否则,将使用系统默认值:数字类型为零,字符串为空字符串,布尔值为false。对于嵌入式消息,默认值始终是消息的“默认实例”或“原型”,没有设置任何字段。调用访问器以获取未显式设置的可选(或必填)字段的值始终会返回该字段的默认值。
//repeated:该字段可以重复任意次(包括零次)。重复值的顺序将保留在协议缓冲区中。将重复字段视为动态大小的数组。
//required:必须提供该字段的值,否则该消息将被视为“未初始化”。尝试构建未初始化的消息将引发RuntimeException。解析未初始化的消息将引发IOException。除此之外,必填字段的行为与可选字段完全相同。
//永远是必需的 您将字段标记为时应格外小心required。如果您希望停止写入或发送必填字段,则将字段更改为可选字段会很麻烦–老读者会认为没有该字段的邮件是不完整的,可能会无意中拒绝或丢弃它们。您应该考虑为缓冲区编写特定于应用程序的自定义验证例程。在Google内部,required强烈反对使用字段;proto2语法中定义的大多数消息仅使用optional并且repeated。(Proto3根本不支持required字段。)
第四步、使用实体类
Person john =
Person.newBuilder()
.setId(1234)
.setName("John Doe")
.setEmail("jdoe@example.com")
.addPhones(
Person.PhoneNumber.newBuilder()
.setNumber("555-4321")
.setType(Person.PhoneType.HOME))
.build();
第五步、序列化
byte[] bytes = john.toByteArray();
第六步、反序列化
Person john2 = Person.parseFrom(bytes);
第七步、效果图
参考资料
谷歌手册:https://developers.google.com/protocol-buffers/docs/javatutorial