首页 > 技术文章 > Protobuf

zincredible 2022-02-21 23:33 原文

<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java</artifactId>
    <version>3.19.1</version>
</dependency>
<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java-util</artifactId>
    <version>3.19.1</version>
</dependency>

参考

https://www.cnblogs.com/ranandrun/p/protobuf.html

protocol编译工具下载:https://github.com/protocolbuffers/protobuf/releases

idea插件安装

 

 

 proto文件编写

syntax = "proto2";

//生成的类会放在protoc.exe同目录下的tutorial
//如果.proto文件中写了java_package,就以java_package为准。
package com;
//生成的类会放在protoc.exe同目录下的com.proto.tutorial下
//option java_package = "com";
//最终成的类名
option java_outer_classname = "MyTest";


//要生成的类Person
message Data {
    required string name = 1; 
    optional string email = 2;
    optional int32 age = 3;
}
syntax = "proto2";

//生成的类会放在protoc.exe同目录下的tutorial
//如果.proto文件中写了java_package,就以java_package为准。
package com;
//生成的类会放在protoc.exe同目录下的com.proto.tutorial下
//option java_package = "com";
//最终成的类名
option java_outer_classname = "PersonTest";


//要生成的类Person
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 phone = 4;

}
//使用 proto3 语法 ,未指定则使用proto2
syntax = "proto3";

// proto 文件包名
package com;

//生成 proto 文件所在包路径,一般来说是和文件包名一致就可以
//option java_package = "com.wxw.notes.protobuf.proto";

//生成 proto 的文件名
option java_outer_classname="UserProto";


//创建一个 User 对象
message User{
    //自身属性
    int32 id = 1;
    string code = 2;
    string name = 3;

    // 对象
    NickName nickName = 4;

    //list 引用类型
    repeated string strList = 5;

    // 定义简单的 Map string
    map<string, string> map = 6;

    // 定义复杂的 Map 对象
    map<string, MapVauleObject> mapObject = 7;
}

// 定义一个新的Name对象
message NickName {
    string nickName = 1;
}

// 定义 Map 的 value 对象
message MapVauleObject {
    string code = 1;
    string name = 2;
}

编译生成

 

 

 

测试

package com;

import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.MessageOrBuilder;
import com.google.protobuf.TextFormat;

import java.util.Arrays;

/**
 * https://blog.csdn.net/wxw1997a/article/details/116758401
 *
 * @author: zzzzz
 * @date: 2022/2/21
 */
public class Test {
    public static void main(String[] args) {
        //convertProto(1);
        //convertProto2(1);
        convertProto3(3);
    }

    public static void convertProto(int value) {
        //1.通过build创建消息构造器
        MyTest.Data.Builder bulder = MyTest.Data.newBuilder();

        //Data.Builder dataBuilder = Data.newBuilder();
        //2.设置字段值
        bulder.setName("zzzzz");
        bulder.setEmail("xx@126.com");
        bulder.setAge(100);
        //dataBuilder.setInt32(value);
        //3.通过消息构造器构造消息对象
        // Data data = dataBuilder.build();
        //4.序列化
        byte[] bytes = bulder.build().toByteArray();
        System.out.println(value + "序列化后的数据:" + Arrays.toString(bytes) + ",字节个数:" + bytes.length);
        //5.反序列化
        try {
            MyTest.Data parseFrom = MyTest.Data.parseFrom(bytes);
            System.out.println("还原后的数据=" + parseFrom.toString());

        } catch (InvalidProtocolBufferException e) {
            e.printStackTrace();
        }
    }

    public static void convertProto2(int value) {
        //1.通过build创建消息构造器
        PersonTest.Person.Builder bulder = PersonTest.Person.newBuilder();

        //Data.Builder dataBuilder = Data.newBuilder();
        //2.设置字段值
        bulder.setName("zzzz11");
        bulder.setEmail("x11x@126.com");
        bulder.setId(100000);

        PersonTest.Person.PhoneNumber.Builder pb = PersonTest.Person.PhoneNumber.newBuilder();
        pb.setNumber("100245450");
        pb.setType(PersonTest.Person.PhoneType.MOBILE);
        bulder.addPhone(pb);
        bulder.addPhone(pb);
        bulder.addPhone(pb);
        //dataBuilder.setInt32(value);
        //3.通过消息构造器构造消息对象
        // Data data = dataBuilder.build();
        //4.序列化
        byte[] bytes = bulder.build().toByteArray();
        System.out.println(value + "序列化后的数据:" + Arrays.toString(bytes) + ",字节个数:" + bytes.length);
        //5.反序列化
        try {
            MyTest.Data parseFrom = MyTest.Data.parseFrom(bytes);
            System.out.println("还原后的数据=" + System.lineSeparator() + parseFrom.toString());

        } catch (InvalidProtocolBufferException e) {
            e.printStackTrace();
        }
    }


    public static void convertProto3(int value) {

        //初始化数据
        UserProto.User.Builder user = UserProto.User.newBuilder();
        user.setId(1)
                .setCode("001")
                .setName("张三")
                .build();

        //内部对象
        UserProto.NickName.Builder nickName = UserProto.NickName.newBuilder();
        user.setNickName(nickName.setNickName("昵称").build());

        //简单 list
        user.addStrList("01");
        user.addStrList("02");


        //简单 map
        user.putMap("key1", "value1");
        user.putMap("key2", "value2");

        //object map
        UserProto.MapVauleObject.Builder objectMap1 = UserProto.MapVauleObject.newBuilder();
        user.putMapObject("objectMap1", objectMap1.setCode("code1").setName("name1").build());

        UserProto.MapVauleObject.Builder objectMap2 = UserProto.MapVauleObject.newBuilder();
        user.putMapObject("objectMap2", objectMap2.setCode("code2").setName("name2").build());


        //序列化
        UserProto.User build = user.build();
        //转换成字节数组
        byte[] s = build.toByteArray();
        System.out.println("protobuf数据bytes[]:" + Arrays.toString(s));
        System.out.println("protobuf序列化大小: " + s.length);


        UserProto.User user1 = null;
        String jsonObject = null;
        try {
            //反序列化
            user1 = UserProto.User.parseFrom(s);
            System.out.println("反序列化:\n" + user1.toString());
            System.out.println("中文反序列化:\n" + printToUnicodeString(user1));

        } catch (InvalidProtocolBufferException e) {
            e.printStackTrace();
        }
//        System.out.println("***********************************************");
//        //中文反序列化时会转成八进制,可采用 TextFormat.printToUnicodeString 进行转换
//        System.out.println("直接反序列化:\n" + printToUnicodeString(user1));
    }

    public static String printToUnicodeString(MessageOrBuilder message) {
        return TextFormat.printer().escapingNonAscii(false).printToString(message);
    }
}

 

推荐阅读