项目设置
- 创建新的项目目录。
- 从 proto 定义中复制 food_menu.protomoney.proto localized_text.proto 的内容 作为新文件复制到项目目录的根目录下
- 安装 protoc 编译器
要从 .proto 文件生成源代码,需要 protoc 编译器。 从 Protocol Buffers GitHub 发布页面下载最新的预构建二进制文件。
解压缩该 zip 文件并将 bin 路径添加到 PATH 环境变量中,例如:
unzip protoc-22.0-linux-x86_64.zip -d /usr/local/protoc export PATH="$PATH:/usr/local/protoc/bin"
生成源代码
Python
- 安装 Python protobuf 库
pip install protobuf
- 生成客户端源代码。
创建 proto 输出目录:已生成
protoc --python_out=./generated food_menu.proto money.proto localized_text.proto
更新 PYTHONPATH 环境变量以包含生成的路径,例如:
export PYTHONPATH="$PYTHONPATH:./generated"
如果您使用的是 Bazel,可尝试使用 py_proto_library 规则来代替运行 protoc。
用法示例
点击此处可查看完整的示例项目。
"""Menu feed example used in https://developers.google.com/maps-booking/verticals/dining/guides/tutorials/tutorial-menu-feed-protos#python. """ import json from generated import food_menu_pb2 from google.protobuf.json_format import MessageToDict # create feed feed = food_menu_pb2.FoodMenuFeed() # add a menu component to feed data menuComponent = feed.data.add() menuComponent.menu.menu_id = 'menu1' menuComponent.menu.merchant_ids.append('dining-1') menuDisplayName = menuComponent.menu.display_name.text.add() menuDisplayName.text = 'Menu' menuDisplayName.language_code = 'en-us' menuComponent.menu.language = 'en-us' menuComponent.menu.last_merchant_update_time.seconds = 1633621547 for i in ['appetizers', 'dinner']: menuComponent.menu.menu_section_ids.append(i) # add a menu section component to feed data sectionComponent = feed.data.add() sectionComponent.section.menu_section_id = 'appetizers' sectionDisplayName = sectionComponent.section.display_name.text.add() sectionDisplayName.text = 'Lunch Appetizers' sectionDisplayName.language_code = 'en-us' sectionComponent.section.menu_item_ids.append('breadsticks-sauce') # add a menu item component to feed data itemComponent = feed.data.add() itemComponent.item.menu_item_id = 'breadsticks-sauce' itemDisplayName = itemComponent.item.display_name.text.add() itemDisplayName.text = 'Breadsticks & Sauce' itemDisplayName.language_code = 'en-us' itemDescription = itemComponent.item.description.text.add() itemDescription.text = 'Breakfast basket w/ side of tomato sauce (size 6 or 12)' itemDescription.language_code = 'en-us' for i in ['breadstick-sm', 'breadstick-lg']: itemComponent.item.menu_item_option_set.menu_item_option_ids.append(i) for i in [ 'http://www.example.com/photos/breadsticks.jpg', 'http://www.example.com/photos/sauce.jpg', ]: itemImage = itemComponent.item.images.add() itemImage.uri = i # add a menu item option component to feed data optionComponent = feed.data.add() optionComponent.option.menu_item_option_id: 'breadstick-sm' optionComponent.option.value.property_type = ( food_menu_pb2.MenuItemOptionProperty.PropertyType.SIZE ) optionTextValue = optionComponent.option.value.text_val.text.add() optionTextValue.text = 'Small' optionTextValue.language_code = 'en-us' optionOffer = optionComponent.option.offer_set.offers.add() optionOffer.price.currency_code = 'USD' optionOffer.price.units = 8 optionOffer.price.nanos = 0 feedJSON = json.dumps(MessageToDict(feed, preserving_proto_field_name=True)) print(feedJSON)
此代码示例展示了如何创建包含以下各个实体的 Feed 对象:
- 菜单
- MenuSection
- MenuItem
- MenuItemOption
然后,此示例展示了如何将 Feed 序列化为 JSON。
Python API 允许通过设置属性延迟初始化嵌套对象。TypeScript
-
安装 TypeScript protoc 插件。
请注意,ts-proto 不是官方支持的 Google 项目。npm init npm i -D typescript npm i ts-proto
- 创建输出目录并生成客户端源代码。
创建 proto 输出目录:src/generated
protoc --plugin="./node_modules/.bin/protoc-gen-ts_proto" --ts_proto_opt=useOptionals=all --ts_proto_opt=snakeToCamel=false --ts_proto_opt=onlyTypes=true --ts_proto_out="./src/generated" food_menu.proto money.proto localized_text.proto
如果您使用的是 Bazel,可尝试使用 js_proto_library 规则来代替运行 protoc。
用法示例
点击此处可查看完整的示例项目。
import {FoodMenuFeed, Menu, MenuItem, MenuSection, MenuItemOption, MenuItemOptionProperty_PropertyType} from './generated/food_menu'; const menu: Menu = { menu_id: 'menu1', merchant_ids: ['dining-1'], display_name: {text: [{text: 'Menu', language_code: 'en-us'}]}, language: 'en-us', menu_section_ids: ['appetizers', 'dinner'], last_merchant_update_time: new Date() }; const section: MenuSection = { menu_section_id: 'appetizers', display_name: {text: [{text: 'Lunch Appetizers', language_code: 'en-us'}]}, menu_section_ids: ['breadsticks-sauce'] }; const item: MenuItem = { menu_item_id: 'breadsticks-sauce', display_name: {text: [{text: 'Breadsticks & Sauce', language_code: 'en-us'}]}, description: { text: [{ text: 'Breakfast basket w/ side of tomato sauce (size 6 or 12)', language_code: 'en-us' }] }, menu_item_option_set: {menu_item_option_ids: ['breadstick-sm', 'breadstick-lg']}, images: [ {uri: 'http://www.example.com/photos/breadsticks.jpg'}, {uri: 'http://www.example.com/photos/sauce.jpg'} ] }; const option: MenuItemOption = { menu_item_option_id: 'breadstick-sm', value: { property_type: MenuItemOptionProperty_PropertyType.SIZE, text_val: { text: [ {text: "Small", language_code: "en-us"} ] } }, offer_set: { offers: [{ price: { currency_code: "USD", units: 8, nanos: 0 } }] } }; const feed: FoodMenuFeed = { data: [{menu}, {section}, {item}, {option}] }; console.log(JSON.stringify(feed));
此代码示例展示了如何创建包含以下各个实体的 Feed 对象:
- 菜单
- MenuSection
- MenuItem
- MenuItemOption
然后,此示例展示了如何将 Feed 序列化为 JSON。
Java
- 使用 Maven 或 Gradle 将依赖项 protobuf-java 和 protobuf-java 添加到项目中,如此处所述。
- 生成客户端源代码。
protoc --java_out=src/main/java food_menu.proto money.proto localized_text.proto
使用 Maven 时,您可以在编译时通过 protobuf-maven-plugin 生成源代码。
如果您使用的是 Bazel,可尝试使用 java_proto_library 规则来代替运行 protoc。
用法示例
点击此处可查看完整的示例项目。
package com.example; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Timestamp; import com.google.type.Money; import com.google.protobuf.util.JsonFormat; import com.google.type.LocalizedText; import food.menu.v1.FoodMenu.FoodMenuFeed; import food.menu.v1.FoodMenu.Menu; import food.menu.v1.FoodMenu.MenuComponent; import food.menu.v1.FoodMenu.MenuItem; import food.menu.v1.FoodMenu.MenuSection; import food.menu.v1.FoodMenu.TextField; import food.menu.v1.FoodMenu.MenuItemOption; import food.menu.v1.FoodMenu.MenuItemOptionProperty; import food.menu.v1.FoodMenu.OfferSet; import food.menu.v1.FoodMenu.Offer; /** * Menu feed example used in * * <p>https://developers.google.com/maps-booking/verticals/dining/guides/tutorials/tutorial-menu-feed-protos#java. */ public class Feed { public static void main(String[] args) throws InvalidProtocolBufferException { Feed feed = new Feed(); feed.createMenuFeed(); } public void createMenuFeed() throws InvalidProtocolBufferException { Menu.Builder menu = Menu.newBuilder() .setMenuId("menu1") .addMerchantIds("dining-1") .setDisplayName( TextField.newBuilder() .addText(LocalizedText.newBuilder().setText("Menu").setLanguageCode("en-us"))) .setLanguage("en-us") .setLastMerchantUpdateTime(Timestamp.newBuilder().setSeconds(1633621547)); MenuSection.Builder section = MenuSection.newBuilder() .setMenuSectionId("appetizers") .setDisplayName( TextField.newBuilder() .addText( LocalizedText.newBuilder() .setText("Lunch Appetizers") .setLanguageCode("en-us"))) .addMenuItemIds("breadsticks-sauce"); MenuItem.Builder item = MenuItem.newBuilder() .setMenuItemId("breadsticks-sauce") .setDisplayName( TextField.newBuilder() .addText( LocalizedText.newBuilder() .setText("Breadsticks & Sauce") .setLanguageCode("en-us"))) .setDescription( TextField.newBuilder() .addText( LocalizedText.newBuilder() .setText("Breadsticks & Sauce") .setLanguageCode("en-us"))); MenuItemOption.Builder option = MenuItemOption.newBuilder() .setMenuItemOptionId("breadstick-sm") .setValue( MenuItemOptionProperty.newBuilder() .setPropertyType(MenuItemOptionProperty.PropertyType.SIZE) .setTextVal(TextField.newBuilder() .addText( LocalizedText.newBuilder() .setText("Small") .setLanguageCode("en-us")))) .setOfferSet( OfferSet.newBuilder() .addOffers( Offer.newBuilder() .setPrice( Money.newBuilder() .setCurrencyCode("USD") .setUnits(8) .setNanos(0)))); FoodMenuFeed.Builder foodMenuFeed = FoodMenuFeed.newBuilder() .addData(MenuComponent.newBuilder().setMenu(menu)) .addData(MenuComponent.newBuilder().setSection(section)) .addData(MenuComponent.newBuilder().setItem(item)) .addData(MenuComponent.newBuilder().setOption(option)); String feedJSON = JsonFormat.printer() .omittingInsignificantWhitespace() .preservingProtoFieldNames() .print(foodMenuFeed); System.out.println(feedJSON); } }
此代码示例展示了如何创建包含以下各个实体的 Feed 对象:
- 菜单
- MenuSection
- MenuItem
- MenuItemOption
然后,此示例展示了如何将 Feed 序列化为 JSON。
Go
- 安装 Go 版 protoc 插件
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
更新 PATH 环境变量以包含 protoc-gen-go 插件,例如:
export PATH="$PATH:$(go env GOPATH)/bin"
- 初始化应用并生成客户端源代码。
go mod init feed/app mkdir generated protoc --go_out=./generated/ food_menu.proto money.proto localized_text.proto
如果您使用的是 Bazel,可尝试使用 go_proto_library 规则来代替运行 protoc。
用法示例
点击此处可查看完整的示例项目。
/* Menu feed example used in https://developers.google.com/maps-booking/verticals/dining/guides/tutorials/tutorial-menu-feed-protos#go. * */ package main import ( pb "feed/app/generated/food/menu/v1/proto" "fmt" localized_text "google.golang.org/genproto/googleapis/type/localized_text" money "google.golang.org/genproto/googleapis/type/money" "google.golang.org/protobuf/encoding/protojson" timestamppb "google.golang.org/protobuf/types/known/timestamppb" ) func main() { //create a menu component menu := &pb.Menu{ MenuId: "menu1", MerchantIds: []string{"dining-1"}, DisplayName: &pb.TextField{ Text: []*localized_text.LocalizedText{{ Text: "Menu", LanguageCode: "en-us", }}, }, Language: "en-us", LastMerchantUpdateTime: ×tamppb.Timestamp{ Seconds: 1633621547, }, } //create a menu section component section := &pb.MenuSection{ MenuSectionId: "appetizers", DisplayName: &pb.TextField{ Text: []*localized_text.LocalizedText{{ Text: "Lunch Appetizers", LanguageCode: "en-us", }}, }, MenuItemIds: []string{"breadsticks-sauce"}, } //create a menu item component item := &pb.MenuItem{ MenuItemId: "breadsticks-sauce", DisplayName: &pb.TextField{ Text: []*localized_text.LocalizedText{{ Text: "Breadsticks & Sauce", LanguageCode: "en-us", }}, }, Description: &pb.TextField{ Text: []*localized_text.LocalizedText{{ Text: "Breakfast basket w/ side of tomato sauce (size 6 or 12)", LanguageCode: "en-us", }}, }, Pricing: &pb.MenuItem_MenuItemOptionSet_{ MenuItemOptionSet: &pb.MenuItem_MenuItemOptionSet{ MenuItemOptionIds: []string{"breadstick-sm", "breadstick-lg"}, }, }, } imageUris := []string{ "http://www.example.com/photos/breadsticks.jpg", "http://www.example.com/photos/sauce.jpg", } for _, uri := range imageUris { image := &pb.Image{ Uri: uri, } item.Images = append(item.Images, image) } //create a menu item option option := &pb.MenuItemOption{ MenuItemOptionId: "breadstick-sm", Value: &pb.MenuItemOptionProperty{ PropertyType: pb.MenuItemOptionProperty_SIZE, Value: &pb.MenuItemOptionProperty_TextVal{ TextVal: &pb.TextField{ Text: []*localized_text.LocalizedText{{ Text: "Small", LanguageCode: "en-us", }}, }, }, }, OfferSet: &pb.OfferSet{ Offers: []*pb.Offer{{ Price: &money.Money{ CurrencyCode: "USD", Units: 8, Nanos: 0, }, }}, }, } //create feed feed := &pb.FoodMenuFeed{ Data: []*pb.MenuComponent{{ Type: &pb.MenuComponent_Menu{ Menu: menu, }, }, { Type: &pb.MenuComponent_Section{ Section: section, }, }, { Type: &pb.MenuComponent_Item{ Item: item, }, }, { Type: &pb.MenuComponent_Option{ Option: option, }, }}, } marshalOptions := protojson.MarshalOptions{ UseProtoNames: true, } jsonBytes, _ := marshalOptions.Marshal(feed) fmt.Printf("message = %s", string(jsonBytes)) }
此代码示例展示了如何创建包含以下各个实体的 Feed 对象:
- 菜单
- MenuSection
- MenuItem
- MenuItemOption
然后,此示例展示了如何将 Feed 序列化为 JSON。