Protobuf系列-2-在Java项目中使用

Posted by AlstonWilliams on February 17, 2019

在上一篇文章中,我们介绍了如何安装Protoc,以及编译一个proto文件.

在这篇文章中,我们将会介绍如何在项目中使用这些编译出来的文件.

创建一个maven项目

通过下面这条命令创建一个最简单的maven项目就好: mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

它会在当前目录下生成一个名为my-app的项目.

这个项目的初始结构如下:

我们可以看到,其中生成的的App.java以及AppTest.java,我们并不需要,所以直接给删掉就好了.

然后,我们需要向其中添加一个protobuf的依赖,因为生成的Java文件需要这个依赖中的内容.

pom.xml中添加如下内容:

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

注意上面的那个版本应该跟你安装的protoc版本一致.

创建proto文件并生成Java文件

我们在项目的根目录下,创建一个src/main/java/proto文件夹,并编写一个名为addressbook.proto的文件:

syntax = "proto3";

package com.mycompany.app;

option java_package = "com.mycompany.app";
option java_multiple_files = true;
option java_outer_classname = "AddressBookProtos";

message Person {

    string name = 1;
    int32 id = 2;
    string email = 3;

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

    message PhoneNumber {

        string number = 1;
        PhoneType type = 2;

    }

    repeated PhoneNumber phones = 4;

}

message AddressBook {

    repeated Person people = 1;

}

注意上面的这个文件中,option java_package部分,应该给你的项目中你想存放生成的文件的包名一致.

通过protoc –java_out=. addressbook.proto命令,可以生成Java源文件.

然后,我们需要将生成的这些源文件拷贝到项目根目录下的src/main/java/com/mycompany/app目录中.

这里需要注意的是,如果你在写proto文件时,其中option java_package选项指定的目录跟你想存放的目录不一样的话,需要手动修改一下生成的文件中的包名.

然后,我们在src/main/java/com/mycompany/app下,创建一个Java源文件,其内容如下:

package com.mycompany.app;

import java.io.*;

public class AddPerson {

    static Person promptForAddress(BufferedReader stdin, PrintStream stdout) throws IOException {

        Person.Builder person = Person.newBuilder();

        stdout.print("Enter person ID: ");
        person.setId(Integer.valueOf(stdin.readLine()));

        stdout.print("Enter name: ");
        person.setName(stdin.readLine());

        stdout.print("Enter email address (blank for none): ");
        String email = stdin.readLine();
        if (email.length() > 0)
            person.setEmail(email);

        while (true) {

            stdout.print("Enter a phone number (or leave blank to finish)");
            String telephone = stdin.readLine();
            if (telephone.length() == 0)
                break;

            Person.PhoneNumber.Builder phoneNumber = Person.PhoneNumber.newBuilder();
            phoneNumber.setNumber(telephone);

            stdout.print("Is this a mobile, home, or work phone? ");
            String type = stdin.readLine();
            if (type.equals("mobile"))
                phoneNumber.setType(Person.PhoneType.MOBILE);
            else if (type.equals("home"))
                phoneNumber.setType(Person.PhoneType.HOME);
            else if (type.equals("work"))
                phoneNumber.setType(Person.PhoneType.WORK);
            else {
                stdout.print("Unknown phone type. Using default");
                phoneNumber.setType(Person.PhoneType.HOME);
            }

            person.addPhones(phoneNumber);

        }

        return person.build();

    }

    public static void main(String[] args) throws Exception {

        if (args.length != 1) {
            System.err.println("Usage: AddPerson ADDRESS_BOOK_FILE");
            System.exit(-1);
        }

        AddressBook.Builder addressBook = AddressBook.newBuilder();

        try {
            addressBook.mergeFrom(new FileInputStream(args[0]));
        } catch (FileNotFoundException e) {
            System.out.println(args[0] + " doesn't exist. Creating file.");
        }

        addressBook.addPeople(promptForAddress(new BufferedReader(new InputStreamReader(System.in)), System.out));

        FileOutputStream fileOutputStream = new FileOutputStream(args[0]);
        addressBook.build().writeTo(fileOutputStream);
        fileOutputStream.close();

    }

}

它的作用是,让你输入一个Person的信息,并且保存到你指定的文件中.

那么如何编译这个文件呢?

进入到src/main/java这个目录下,执行下面的命令:

** javac -cp .:/opt/mvn/resp/com/google/protobuf/protobuf-java/3.4.0/protobuf-java-3.4.0.jar com/mycompany/app/AddPerson.java**

其中你需要把protbuf-java的路径换成你的机器上的路径.

编译完成后,通过java -cp .:/opt/mvn/resp/com/google/protobuf/protobuf-java/3.4.0/protobuf-java-3.4.0.jar com/mycompany/app/AddPerson hello这条命令来运行刚刚AddPerson文件.输入完Person的信息后,我们会看到在当前目录下,会生成一个十六进制的hello文件.

我们打开这个16进制文件,可以看到其中的内容为:

0A 08 0A 04 66 73 64 61 10 01

其中保存了一些元数据以及我输入的数据的十六进制编码.

就这样就完成了.

总结

在这篇文章中,我们一步步介绍了如何创建一个Java并和protobuf结合.

这篇文章中,我只介绍了一部分用法,很不全面.

请去查看官方文档来获取更加全面的信息.

关于Protobuf的官方文档,后续我可能会翻译出来,也是放在这个系列中.