最新要闻
- 赫德-德普官司以一百万美元赔偿和解
- 百度地图首发自研“北斗高精”技术 升级“真”车道级导航
- 【环球时快讯】中国版“猛禽”!长城山海炮大型皮卡实车现身:配自研3.0T、9AT
- 上海首张城市高级辅助驾驶地图许可来了 百度率先获批
- 环球快看点丨伊朗男子65厘米创吉尼斯最矮纪录:站起来才到到成人膝盖处
- 【世界时快讯】安卓抄错了?iPhone 15 Pro最新概念图:告别纯直边
- 当前关注:网络谣言别再传了!短视频中梅西抱的不是母亲:是阿根廷队女厨师
- 天天通讯!微软、谷歌之后 欧盟反垄断又对美国Meta下手:可罚款上百亿美元
- 每日视讯:4K游戏串流没了 NVIDIA删除使用9年的GameStream功能引用户不满
- 2022最后一跌!今起油价下调:加满一箱92号汽油少花19.5元
- 消息!苹果App Store被法国罚款100万美元:Epic CEO、扎克伯格都曾痛批
- 多次骂新能源!丰田再度质疑汽车全面电动化:中国品牌弯道超车
- 35岁本泽马宣布从法国队退役:球迷唏嘘 祝福俱乐部继续精彩
- 环球播报:北京等多地天空疑现震撼的火箭夜光云:原理科普
- 年出货3亿只、逛店必买的一次性碱性电池:被宜家正式停售了
- 环球新资讯:抖音在世界杯上下的功夫 远不止撒币10亿买版权这么简单
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
焦点速读:proto IDL管理工具buf使用实践
proto是在当今使用最广泛的IDL之一,起因是dubbo3的Triple协议需要用到proto文件来生成统一规范的跨语言代码,Grpc也有类似的问题,想想一个团队有很多的业务模块,涉及到一些相互调用依赖的问题,如 A模块需要用到B模块的接口,就需要找到B模块开发者,请告知一下 B模块相关的proto文件是哪些,我需要copy到A模块来生成客户端调用代码,虽说这个场景单看起来条理是清晰的,后续如果越来越多的模块需要相互引用依赖,版本变更 ,昨天提供给你的proto文件 今天已经被提供者加了字段 或者删减了字段,需要一一通知到位,并需要重新copy最新的proto文件给使用者,如果B模块又依赖了C模块,这个时候如果使用者要用到B模块的时候 需要把B、C相关的proto都要提供,处理这类繁琐易错的问题还是相当复杂的。所以让buf
来帮你解决这个问题。
(资料图片仅供参考)
buf 可以解决
- 统一管理proto文件 类似git一样 区分仓库 Buf Schema Registry(BSR)支持远程拉取、推送、提交。
- 检查proto依赖以及语法问题
- 检查兼容性问题
- 生成多语言代码 根据buf.gen.yaml 自定义配置非常很方便
buf安装
以下软件环境均在linux x64,需要安装go环境。官方提供源码、二进制包、Tarball 3种安装方式 为了方便这里使用官方二进制包方式。
BIN="/usr/local/bin" && \VERSION="1.10.0" && \ curl -sSL \ "https://github.com/bufbuild/buf/releases/download/v${VERSION}/buf-$(uname -s)-$(uname -m)" \ -o "${BIN}/buf" && \ chmod +x "${BIN}/buf"
验证buf命令是否安装成功 能输出一系类的命令使用帮助表示安装就没问题。
buf --help Available Commands: beta Beta commands. Unstable and likely to change. breaking Verify that the input location has no breaking changes compared to the against location. build Build all Protobuf files from the specified input and output a Buf image. completion Generate auto-completion scripts for commonly used shells. convert Convert a message from binary to JSON or vice versa export Export the files from the input location to an output location. format Format all Protobuf files from the specified input and output the result. generate Generate stubs for protoc plugins using a template. help Help about any command lint Verify that the input location passes lint checks. ls-files List all Protobuf files for the input. mod Manage Buf modules. push Push a module to a registry. registry Manage assets on the Buf Schema Registry.
再安装一个protoc 针对后面java 、c++语言的生成代码演示 如果只是为了生成grpc go的话可以不安装
wget https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-x86_64.zip#把protoc可执行文件放再 /usr/local/bin 方便直接执行cp bin/protoc /usr/local/bin/#验证protoc --version
输出libprotoc 3.21.12 表示安装成功。
安装protoc go grpc代码生成工具 用于后续生成go代码
go install google.golang.org/protobuf/cmd/protoc-gen-go@latestgo install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latestexport PATH="$PATH:$(go env GOPATH)/bin"
build ls-files
clone示例proto文件仓库用于下面演示
git clone https://github.com/DemoHubs/bufbuilddemo.git
该演示项目大概是一个宠物服务的API接口定义。目录中有2个文件夹 start目录表示为你准备演示工作的proto文件, finish目录表示 start相关演示执行后的目录的样子 这里先不关注finish目录 。
ls-files用于查询目录下的proto文件列表
cd bufbuilddemo buf ls-files-----------输出---------finish/paymentapis/payment/v1alpha1/payment.protofinish/petapis/pet/v1/pet.protostart/petapis/google/type/datetime.protostart/petapis/pet/v1/pet.proto
你也可以用仓库clone到本地 用远程输入仓库的方式查询 还是非常方便的
buf ls-files "https://github.com/DemoHubs/bufbuilddemo.git#branch=main,subdir=start/petapis"------------输出---------start/petapis/google/type/datetime.protostart/petapis/pet/v1/pet.proto
其中远程输入的地址加了参数
branch
表示查看的是哪个分支 这里是main分支
subdir
表示查询的文件加是哪一个 支持多层级查找 这里查询的是 仓库种start/petapis目录下包含的proto文件列表
输入文档类型 支持 git dir mod tar zip 等主流的方式。
配置一个新的buf空间
进入bufbuilddemo/start/petapis,执行 buf mod init 会在当前目录中生成默认的buf.yaml文件,如果是一个新模块 就从这里开始让buf来管理你的proto文件。
cd bufbuilddemo/start/petapisbuf mod init----- 生成的buf.yaml文件--------------version: v1breaking: use: - FILElint: use: - DEFAULT
lint 检查你的proto规范
回到示例仓库 。进入bufbuilddemo/start/petapis 。
buf lint ------输出--------------google/type/datetime.proto:17:1:Package name "google.type" should be suffixed with a correctly formed version, such as "google.type.v1".pet/v1/pet.proto:44:10:Field name "petID" should be lower_snake_case, such as "pet_id".pet/v1/pet.proto:49:9:Service name "PetStore" should be suffixed with "Service".
上面输入的可读性很差 可以指定以json的方式输出就好看多了。
buf lint --error-format=json------输出----------{"path":"google/type/datetime.proto","start_line":17,"start_column":1,"end_line":17,"end_column":21,"type":"PACKAGE_VERSION_SUFFIX","message":"Package name \"google.type\" should be suffixed with a correctly formed version, such as \"google.type.v1\"."}{"path":"pet/v1/pet.proto","start_line":44,"start_column":10,"end_line":44,"end_column":15,"type":"FIELD_LOWER_SNAKE_CASE","message":"Field name \"petID\" should be lower_snake_case, such as \"pet_id\"."}{"path":"pet/v1/pet.proto","start_line":49,"start_column":9,"end_line":49,"end_column":17,"type":"SERVICE_SUFFIX","message":"Service name \"PetStore\" should be suffixed with \"Service\"."}
可以看到规范检查输出了错误,这些buf默认的规范检查定义 在buf.yaml中可以看到 lint.use=DEFAULT。当然也是可以去掉某些规则
第1个错误 google/type/datetime.proto 第17行后缀不对。规则 PACKAGE_VERSION_SUFFIX
第2个错误 pet/v1/pet.proto 文件44行petID命名不对。规则 FIELD_LOWER_SNAKE_CASE
第3个错误 pet/v1/pet.proto 文件49行PetStore命名不对 必须要以Service结尾。规则 SERVICE_SUFFIX
添加except节点 人为的排除掉一些lint规则 如下 把这3个规则都排除了。重新执行buf lint就没有看到任何输出就证明 通过了lint检查。
还有更暴力的忽略检查ignore
指定Proto文件配置 在一些特殊场景可以使用
version: v1breaking: use: - FILElint: use: - DEFAULT ignore: - google/type/datetime.proto except:# - PACKAGE_VERSION_SUFFIX - FIELD_LOWER_SNAKE_CASE - SERVICE_SUFFIX
为了验证修复 先把节点去掉 except 。不排除默认lint规则。
43 message DeletePetRequest { 44 string pet_id = 1; //petID 改为 pet_id 45 }
49 service PetStoreService {//PetStore改为PetStoreService50 rpc GetPet(GetPetRequest) returns (GetPetResponse) {}
改了之后 在执行buf lint 就没有错误了。
breaking 兼容性中断检查
上面lint主要是检查proto语法相关的规范,但是如果 Pet
中的属性 pet_type 是PetType 类型 已经提供给使用者在用了,这个时候如果改变了数据类型 就兼容不正在使用的客户端,所以用breaking来解决对历史版本的兼容性问题筛查。
为了演示 把Pet的pet_type类型 从PerType变更为string。
message Pet { string pet_type = 1;//PetType pet_type = 1; string pet_id = 2; string name = 3; google.type.DateTime created_at = 4;}
执行中段检查命令 需要传入一个against参数 用于本地和主干文件做对比 同样也支持像上面的设置分支和目录
buf breaking --against "https://github.com/DemoHubs/bufbuilddemo.git#branch=main,subdir=start/petapis" --error-format=json -----------输出------------{"path":"pet/v1/pet.proto","type":"SERVICE_NO_DELETE","message":"Previously present service \"PetStore\" was deleted from file."}{"path":"pet/v1/pet.proto","start_line":20,"start_column":3,"end_line":20,"end_column":9,"type":"FIELD_SAME_TYPE","message":"Field \"1\" on message \"Pet\" changed type from \"enum\" to \"string\"."}{"path":"pet/v1/pet.proto","start_line":44,"start_column":3,"end_line":44,"end_column":21,"type":"FIELD_SAME_JSON_NAME","message":"Field \"1\" with name \"pet_id\" on message \"DeletePetRequest\" changed option \"json_name\" from \"petID\" to \"petId\"."}{"path":"pet/v1/pet.proto","start_line":44,"start_column":10,"end_line":44,"end_column":16,"type":"FIELD_SAME_NAME","message":"Field \"1\" on message \"DeletePetRequest\" changed name from \"petID\" to \"pet_id\"."}
这里主要关注第2个错误"Pet" changed type from "enum" to "string"。就明确提示了 由enum变更为string。其它的错误是因为我们修复了默认的lint的几个规则。
generate code 生成代码
生成代码也是我们用这个工具的核心功能。回到start目录中 配置生成代码的模板规则文件buf.gen.yaml
代码生成
cd ../vim buf.gen.yaml-------- 输入模板内容------version: v1plugins: - plugin: cpp out: gen/proto/cpp - plugin: java out: gen/proto/java - plugin: go out: gen/proto/go opt: paths=source_relative - plugin: go-grpc out: gen/proto/go opt: paths=source_relative
这里配置了4个插件 分别的cpp java go go-grpc 用于生成c++ java go grpc代码
c++ 生成的源码放到gen/proto/cpp中
java 生成的源码放到 gen/proto/java中
go生成的源码放到 gen/proto/go中
go-grpc生成的源码放到 gen/proto/go中
执行生成代码命令 --template参数是指定模板的路径 不指定默认会在当前执行目录查找buf.gen.yaml
# buf generate perapis --template buf.gen.yamlbuf generate petapis
如果没有报错 当前目录中 gen代码生成成功。使用 tree gen 查看gen目录以下文件树形的方式展开。可以看到c++ java go代码均生成成功
tree gengen└── proto ├── cpp │ ├── google │ │ └── type │ │ ├── datetime.pb.cc │ │ └── datetime.pb.h │ └── pet │ └── v1 │ ├── pet.pb.cc │ └── pet.pb.h ├── go │ └── pet │ └── v1 │ ├── pet_grpc.pb.go │ └── pet.pb.go └── java ├── com │ └── google │ └── type │ ├── DateTime.java │ ├── DateTimeOrBuilder.java │ ├── DateTimeProto.java │ ├── TimeZone.java │ └── TimeZoneOrBuilder.java └── pet └── v1 └── PetOuterClass.java
使用远程插件生成代码
上面在生成代码的时候配置了plugin插件,比如go 我需要先安装好,这里可以直接使用远程插件。像这样 在buf.gen.yaml中把plugin的地址写为远程的地址即可。
version: v1 plugins: - plugin: buf.build/protocolbuffers/go:v1.28.1 out: gen/proto/go opt: paths=source_relative - plugin: buf.build/grpc/go:v1.2.0 out: gen/proto/go opt: paths=source_relative
代码托管配置模式
代码托管配置模式就是对特定语言代码的参数做一个自定义的控制 不需要写死的proto文件中。让buf自己去管理特有的特性。同样是在buf.gen.yaml文件中配置
managed: enabled: true cc_enable_arenas: false java_multiple_files: true
enable 启用配置托管模式
java_multiple_files 生成的java代码 多文件模式 就是不用内部类的方式了
关于更多语言的配置 参考 https://docs.buf.build/generate/managed-mode
远程仓库 BSR
BSR全称 Buf Schema Registry。可以理解为和maven的中央仓库、github这种仓库有点类似。只是bsr是用于buf远程管理仓库。要使用远程仓库功能 需要先注册https://buf.build/login 注册之后需要在 设置中添加API TOKEN https://buf.build/settings/user 用于buf cli连接到BSR的凭证。
buf cli 登录到BSR
buf registry login
按提示 输入注册的用户名 和 设置的api token。输出 Credentials saved to /root/.netrc. 后 表示登录成功。身份信息存储在/root/.netrc文件中。
buf cli 退出登录
退出登录后 自动删除了/root/.netrc文件
buf registry logout------------ 输出-----------All existing BSR credentials removed from /root/.netrc.
推送到远程BSR
目前 buf cli 好像还不能搭建自己的私有仓库服务。所以默认的仓库服务由buf提供。统一域名为buf.build。
仓库地址组成由 buf.build/\(buf_username/\)rep_name
buf_username 为上面注册buf的用户名
rep_name 为仓库的名称。
把演示的proto项目推送到BSR 这里 我的用户名为peachyy 仓库名为 bufbuilddemo --visibility 表示仓库的权限为公开。
buf beta registry repository create buf.build/peachyy/bufbuilddemo --visibility public ------------- 输出----------- WARN This command is in beta. It is unstable and likely to change. To suppress this warning, set BUF_BETA_SUPPRESS_WARNINGS=1Full name Createdbuf.build/peachyy/bufbuilddemo 2022-12-19T10:12:01Z
仓库创建成功了,访问buf.build/peachyy/bufbuilddemo 能看到仓库文件信息。当前还是个空仓库。
准备推送proto文件到远程
进入 petapis 目录 为buf.yaml 新增name属性 值为上面创建的远程仓库全路径
version: v1name: buf.build/peachyy/bufbuilddemobreaking: use: - FILE.....
执行推送到主干 输出的字符串则为版本号。现在刷新在网页上刷新仓库能看到proto文件了。
buf push-----------输出--------63458f6007e64ac0936d88c9caeae212
如果你推送不想影响到主干 可能你的proto文件还有变更 不是很完善的时候 可以先提交草稿。同样的也会返回一个版本号
buf push --draft draft001---------------- 输出---------------8745a3039aa7403c8f1420a68a4b5f3e
BSR还有像github中readme文件一样 用来描述这个Proto项目。它叫 buf.md
依赖管理
可以看到 pet/v1/pet.proto 文件依赖了一个DateTime类型, DateTime类型的源文件位于 google/type/datetime.proto 。
19 message Pet { 20 string pet_type = 1;//PetType pet_type = 1; 21 string pet_id = 2; 22 string name = 3; 23 google.type.DateTime created_at = 4; //这里依赖了 google/type/datetime.proto 源文件。DateTime类型 24 }
尝试把datetime.proto文件删除后 执行buf build。可以看到报错了 因为 datetime.proto不存在
buf build------------输出--------------pet/v1/pet.proto:5:8:google/type/datetime.proto: does not exist
添加远程依赖到本地
新增依赖配置 deps 值是一个仓库列表
version: v1name: buf.build/peachyy/bufbuilddemodeps: - buf.build/googleapis/googleapis #指定了远程依赖仓库地址 这个是官方提供的示例代码 直接拿来引用一下breaking: use: - FILElint: use: - DEFAULT except: # - PACKAGE_VERSION_SUFFIX # - FIELD_LOWER_SNAKE_CASE # - SERVICE_SUFFIX ignore: - google/type/datetime.proto
再次执行buf build。同样是错误输出 但是多了一个警告 意思是你deps依赖库不在buf.lock中。运行 buf mod update
生成buf.lock文件 这个文件保存了deps依赖信息。
buf build -------------输出----------WARN Specified deps are not covered in your buf.lock, run "buf mod update": - buf.build/googleapis/googleapispet/v1/pet.proto:5:8:google/type/datetime.proto: does not exist
执行buf mod update 执行后生成的buf.lock文件记录了依赖的 远程服务地址、用户名、仓库名称、提交版本号。
buf mod update ----------buf.lock文件内容--------version: v1deps: - remote: buf.build owner: googleapis repository: googleapis commit: 75b4300737fb4efca0831636be94e517
如果想指定依赖具体的版本号的仓库可以指定提交id 格式 仓库地址:提交版本ID
deps: - buf.build/peachyy/bufbuilddemo:63458f6007e64ac0936d88c9caeae212
再次执行bud build 就不报错了。说明成功引用到了远程仓库,以后不需要copy到本地后再生成代码。
buf build
buf的编译构建的时候 会生成缓存在$HOME/.cache目录中。
工作空间
buf.work.yaml使用
新创建一个支付api模块定义 用于购买宠物的时候支付使用。
mkdir -p paymentapis/payment/v1alpha1vim paymentapis/payment/v1alpha1/payment.proto
paymentapis/payment/v1alpha1/payment.proto 定义了一个枚举PaymentProvider 和 order结构对象。
syntax = "proto3"; package payment.v1alpha1;option go_package = "github.com/bufbuild/buf-tour/petstore/gen/proto/go/payment/v1alpha1;paymentv1alpha1";//import "google/type/money.proto";// PaymentProvider represents the supported set// of payment providers.enum PaymentProvider { PAYMENT_PROVIDER_UNSPECIFIED = 0; PAYMENT_PROVIDER_STRIPE = 1; PAYMENT_PROVIDER_PAYPAL = 2; PAYMENT_PROVIDER_APPLE = 3;}// Order represents a monetary order.message Order { string order_id = 1; string recipient_id = 2; //google.type.Money amount = 3; PaymentProvider payment_provider = 4;}
回到petapis模块 ,修改文件petapis/pet/v1/pet.proto ,新增一个支付rpc PurchasePet方法。支付请求参数引用了paymentapis模块的实体。
import "payment/v1alpha1/payment.proto";..........service PetStoreService { rpc GetPet(GetPetRequest) returns (GetPetResponse) {} rpc PutPet(PutPetRequest) returns (PutPetResponse) {} rpc DeletePet(DeletePetRequest) returns (DeletePetResponse) {} rpc PurchasePet(PurchasePetRequest) returns (PurchasePetResponse) {} //新增支付方法}message PurchasePetRequest { //支付请求参数 string pet_id = 1; payment.v1alpha1.Order order = 2; //该实体在paymentapis模块定义}message PurchasePetResponse {//支付响应值}
工作空间配置文件是在buf.work.yaml中进行配置, 用directories属性列表来引入目录。这里指定了petapis paymentapis。在刚刚修改的代码中 依赖关系是petapis 依赖了paymentapis。
vim buf.work.yaml-------buf.work.yaml内容----------version: v1directories: - paymentapis - petapis
执行buf build ,并没有报错 这种工作空间的方式让petapis 成员引用到了paymentapis模块。 如果把buf.work.yaml中 - paymentapis注释后 执行buf build就提示找不到petapis/pet/v1/pet.proto:6:8:payment/v1alpha1/payment.proto: does not exist错误
buf build
同样的道理工作空间的方式,其他buf操作命令也是如此,包括buf {breaking,build,generate,ls-files}
工作空间关于Push远程的问题
尝试操作推送 可是报错了。
cd petapis && buf push-----------输出-----------Failure: pet/v1/pet.proto:6:8:payment/v1alpha1/payment.proto: does not exist
解决这个问题需要先把paymentapis模块推送到远程后 在petapis 模块中使用deps的方法加入paymentapis地址才能push。
但是buf build命令却没有问题 因为工作区就在你本地能找到,推送远程的时候 paymentapis 模块远程找不到 所以才有这个问题。
参考 https://docs.buf.build/introduction
示例仓库
https://buf.build/peachyy/bufbuilddemo
https://buf.build/peachyy/bufbuilddemo-paymentapis
-
全球观点:Xml转Java实体类对象 xml转Javabena 对象 且多级嵌套 复杂嵌套
最近在做企微开发,遇到了一个比较复杂的xml然后要去我将xml转成实体类xml如下<xml><ToUserName><![CDAT...
来源: 焦点速读:proto IDL管理工具buf使用实践
P2329 栅栏
全球观点:Xml转Java实体类对象 xml转Javabena 对象 且多级嵌套 复杂嵌套
世界动态:用Python写一个一次性计算出加减乘除的运算小程序
世界热文:实验一:获取主机信息
全球播报:MySQL-InnoDB磁盘结构
今日热议:pkg对egg项目打包
天天精选!java的final关键字
环球快报:【验证码逆向专栏】某片滑块、点选验证码逆向分析
环球热议:别再用 JWT 作为 Session 系统了,问题重重,后果很危险!
全球球精选!Osx10.14升级watchman踩坑记
时讯:二分法
用Python来写个小型购物车程序
天天观速讯丨基于 Dubbo Admin 动态进行流量隔离
赫德-德普官司以一百万美元赔偿和解
百度地图首发自研“北斗高精”技术 升级“真”车道级导航
【环球时快讯】中国版“猛禽”!长城山海炮大型皮卡实车现身:配自研3.0T、9AT
上海首张城市高级辅助驾驶地图许可来了 百度率先获批
环球快看点丨伊朗男子65厘米创吉尼斯最矮纪录:站起来才到到成人膝盖处
热门:如何基于 Spring Boot 快速开发一个 Dubbo 微服务应用
【世界时快讯】安卓抄错了?iPhone 15 Pro最新概念图:告别纯直边
当前关注:网络谣言别再传了!短视频中梅西抱的不是母亲:是阿根廷队女厨师
天天通讯!微软、谷歌之后 欧盟反垄断又对美国Meta下手:可罚款上百亿美元
每日视讯:4K游戏串流没了 NVIDIA删除使用9年的GameStream功能引用户不满
2022最后一跌!今起油价下调:加满一箱92号汽油少花19.5元
消息!苹果App Store被法国罚款100万美元:Epic CEO、扎克伯格都曾痛批
多次骂新能源!丰田再度质疑汽车全面电动化:中国品牌弯道超车
35岁本泽马宣布从法国队退役:球迷唏嘘 祝福俱乐部继续精彩
Python单元测试框架unittest
环球播报:北京等多地天空疑现震撼的火箭夜光云:原理科普
年出货3亿只、逛店必买的一次性碱性电池:被宜家正式停售了
环球新资讯:抖音在世界杯上下的功夫 远不止撒币10亿买版权这么简单
差评如潮!《三体》动画评分暴跌至6.4:网友"口吐芬芳"
快讯:Epic与美国FTC和解:36.6亿元摆平两起官司
Spring IOC官方文档学习笔记(二)之Bean概述
焦点观察:FreeSWITCH学习笔记:通道变量
焦点关注:32开书本大小!华硕新款12代酷睿i7迷你机PC发布:零噪音
环球即时:内蒙古上空巨大发光体划破天际 网友:像手电筒一样
192个框框的怪兽!AMD Zen4线程撕裂者7000来了
世界快报:Django框架:9、Ajax简介、基本语法、数据编码格式、携带文件数据
马斯克现身世界杯观战阿根廷对法国:赛后发出灵魂拷问
【环球播资讯】梅西夺冠穿的黑纱是什么登上热搜:官方科普涨知识 意义非凡
今日快讯:小米13 Pro 8.38mm机身塞入太多强悍功能!雷军:相当不容易
当前快播:明年初亮相 全新东风标致408X即将发布:最美法系车来了
被裁员工报仇?近60%人赞成!马斯克将卸任推特CEO 没继承者还是我掌权
今日快讯:真值200+一张票价吗?《阿凡达2》用户评分:特效很棒 剧情稀烂
观察:小姐姐最爱!小米米家首款无线直板夹上架:30秒速热 369元
环球速看:Java关键词final解读
环球视点!简单排序
全球观焦点:数据结构与算法概念
AMD/Intel CES 2023新品发布会官宣:5大CPU齐飞
《阿凡达2:水之道》若大卖 《阿丽塔:战斗天使》续作可能有戏了!
OPPO首款竖向折叠屏Find N2 Flip评测:电池不再是遗憾 媲美传统直板手机
【环球播资讯】你能接受么?微软计划推出更廉价XGP:广告是代价
确认了!小米13系列没有砍掉Wi-Fi 7:将择机打开功能
安装VScode
linux设备树实现多个中断父(interrupt-parent)节点
当前观点:阿根廷夺冠 花16万现场看世界杯决赛的男子哭着说值了
热文:家长注意!2岁男童将硬币塞进电动车充电口 手被炸黑
天天最新:手工耿自制钓鱼佬智能快乐竿:外形酷似大狙 上钩主动提醒
当前头条:【活动预告】网易数帆首场低代码线上沙龙即将开启,报名从速!
全球头条:美国核聚变重要突破 “人造太阳”10年后有望实现发电 我国企业呢?
天天报道:联想USB 3.0扩展坞仅29元:4个USB接口 支持Type-C供电
环球滚动:颠覆认知的研究!人类可能在树上就学会了直立行走
天天快资讯:温和洁肤 六神茗茶植萃沐浴露:25.9元买一送一
满满维生素 乐源100%纯果汁大促:到手每瓶3块钱
全球头条:java中的代码块
天天观点:大数据 - DWD&DIM 业务数据
环球热点!springboot通过Referer防止跨站点请求伪造
天天微动态丨Tarjan算法求割点
最新快讯!腾讯游戏AI能帮医生看片了:超大尺寸扫描病理图像诊断成功验证
【天天报资讯】号称可以火星上穿的衣服全网首开:胸前一个大洞 自带呕吐袋
环球讯息:管好右手 摩托车弯道狂飙超车撞上护栏:骑手生死未卜
【全球聚看点】2022第三季度耳机手环出货量都跌了!因为苹果 手表逆势增长
国产龙鳞甲电池2023年装车量产:续航可达1000公里 安全没问题
环球最新:零基础入门 Java 后端开发,有哪些值得看的视频?
NVIDIA CES新品发布会官宣:RTX 4070 Ti、RTX 40笔记本显卡要来了
当前关注:美国侧目:俄罗斯生产首颗百分百国产通信卫星
观点:226MB你用吗?微信键盘正式版上线 张小龙:更好保护用户隐私
快报:新的全球制造中心越南、印度正崛起:想取代我们为时尚早
环球微资讯!30万级美系大SUV 福特探险者混动版曝光:电池来自比亚迪
天天热资讯!SIT-board 远程交互式白板的实现
洛谷 P6580 [Ynoi 2019] 美好的每一天~ 不连续的存在 题解
热头条丨火山引擎 DataTester 科普:A/B 实验常见名词解释
世界报道:Shell 变量知多少?
全球今头条!在Windows Linux中 安装 anaconda
讯息:无线投屏(智慧教室)
天天看热讯:二分的边界问题
Controller 层代码就该这么写,简洁又优雅!
SAP根据excel表格数据将数据导入表中
全球快看:JS中的相等性判断
半夜是指什么时间?半夜是指什么生肖?
三浴是什么意思?三浴锻炼是指哪三浴?
45号钢抗拉强度极限是多少?45号钢抗拉强度极限一览
今日看点:Redis——01 学习
每日看点!基于 Dubbo Admin 临时踢除问题服务实例
教材是什么意思?教材的作用有哪些?
受权人是什么意思?被授权人与受权人的区别是什么?
春风十里不如你结局是什么?春风十里不如你演员表
什么是环保型材料?环保型材料有哪些?