SpringBoot Kotlin 集成和使用 Protobuf

环境版本

不同的环境配置参数可能区别较大,请酌情参考。

插件或依赖版本号
SpringBoot2.7.10
Gradle7.5.1
Protobuf Gradle Plugin0.9.2
Protobuf Java3.21.9
Protoc3.21.9
Grpc1.53.0

项目是使用 IDEA 创建的 Spring Web 项目,语言 Kotlin,构建 Gradle

Protobuf 手动配置

Protobuf 的目的是将数据序列化,它提供了完善的编码工具:Protoc,可以将 .proto 定义的文件方便地转换为所需语言的类文件。

比如:Kotlin 使用 Protobuf,手动配置的流程如下:

创建 .proto 文件
运行 protoc 命令将 .proto 文件转换为 .kt 文件
使用 .kt 类方法进行序列化

但是,实践结果是生成的 .kt 文件有错误,可能是 Kotlin 版本问题。
用起来也不是很方便,所以采用 gradle plugin 的方式自动管理包和编译Proto。

添加插件和依赖

在 build.gradle.kts 中配置 Protobuf 需要的插件和依赖。

添加 protobuf gralde plugin

plugins {
    ... 
    id("com.google.protobuf") version "0.9.2"
}

该插件帮助管理 protoc 和完成文件转换。

Protobuf Gradle Plugin 的源码地址:
https://github.com/google/protobuf-gradle-plugin

添加 Protobuf 的依赖包

dependencies {
	...
	implementation("com.google.protobuf:protobuf-java:3.21.9")
	implementation("io.grpc:grpc-protobuf:1.53.0")
	implementation("io.grpc:grpc-stub:1.53.0")
}

配置 Protobuf 插件

protobuf {
	// 配置 protoc
    protoc {
        artifact = "com.google.protobuf:protoc:3.21.9"
    }
    // 配置 grpc
    plugins {
    	// 这里需要加 id,旧版本可能是这样: grpc {}
        id("grpc"){
            artifact = "io.grpc:protoc-gen-grpc-java:1.53.0"
        }
    }
    // 配置 gradle task
    generateProtoTasks {
        ofSourceSet("main").forEach {
            it.plugins {
                id("grpc") { }
            }
        }
    }
}

编写 .proto 文件

文件位置

在 src/main目录下新建目录 proto,然后在该目录下新建包名和 .proto 文件。
示例目录结构如下:

  src
	└─ main
	    ├─kotlin
	    │  └─cn.test.proj
	    ├─proto
	    │  └─cn.test.proj
	    │          Param.proto
	    │          
	    └─resources

proto 与 kotlin 在同一级,.proto 文件在相同的包下。

proto 文件编写

这里是简单示例,详细内容,请参考 proto 官方文档。

syntax = "proto3";
package cn.test.proj;
message Person {
  string id = 1;
  string name = 2;
}

package 值与目录中的包名对应

使用方法

生成 Proto 对象

在 IDEA 右侧 Gradle 窗口,执行 Tasks - other - generateProto 任务,生成 Proto 对象。

使用 Proto 对象

不像手动运行 protoc 命令会生成 .kt 文件。运行 generateProto task 之后,项目文件中没有看到对应的 .kt 文件生成,但是可以像使用 Kotlin 对象一样使用 proto 对象。

参照上文示例,我们在 Param.proto 中定义了一个 Person 对象,如果使用 Okhttp3 请求网络服务,参数是 Person,响应参数也是 Person 示例代码如下:


private const val CONTENT_TYPE = "application/x-protobuf"

fun request(){
	val requestPerson = Param.Person.newBuilder().apply{
		id = "testid"
		name = "Peter"
	}.build()
	val requestBytes = requestPerson.toByteArray() // 序列化
	val requestBody = requestBytes.toRequestBody(CONTENT_TYPE.toMediaType())
	... 
	// Okhttp 请求
	// header 中添加 "Content-Type" = CONTENT_TYPE
	// 请求响应结果 response: Response
	...
	val responseBytes = response.body?.bytes()
	val responsePerson = Param.Person.parseFrom(responseBytes) // 反序列化
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PeterGamp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值