一、目的
在一次接口开发中。某个团队的http接口是用pb实现的pb序列化。我们需要在java代码中实现能用okhttp请求支持pb序列化的api接口。pb序列化不清楚的同学可以先了解下再看看这篇操作步骤会更容易理解。
二、步骤
2.1 让对方提供他的请求体和返回结果的proto文件
对方使用pb序列化,让他提供他接口的请求体与返回结果的proto文件,例如下面这个MixData.proto文件
syntax = "proto3";
// 引入别的proto文件
import "a/core/Ext.proto";
// 目录结构按照单一文件的方式生成 true则是你有几个内部类就有几个平铺的类
option java_multiple_files = true;
// 指定生成的包
package adproto;
// 指定生成的java类包路径
option java_package = "com.xx.xx.xx.xx.xx";
// 入参
message MixData {
string a = 1; // 属性1
string b = 2; // 属性2 这些里面的属性 你需要就留下,如果你不需要 直接去掉
core.Ext ext = 3; // 属性3 是由import "a/core/Ext.proto";引进来 如果你需要这个参数要让对方继续提供Ext.proto这个文件 如果不需要则去掉
}
2.2 下载protoc到本机
对方提供给了proto文件给你之后,你需要想办法把这个proto文件转成你使用的代码语言。我用的是java开发,所以我要把proto文件转成java类。转化的工具就是protoc。
下载git地址:github.com/protocolbuf…
我是windows,所以我是直接下载win64下来。
2.3 idea上下载插件GenProtobuf
我用的开发工具是idea,所以我用idea上的插件来实现用protoc在idea中把protoc生成java文件。
2.4 引入google protobuf maven依赖
引入的maven的版本,一定要跟你的protoc的版本要对的上,比如说我这里引入的版本是3.19.6我下载的protoc的版本也必须是3.19.6,不然最后你生成的java类会出现找不到某某方法的问题。这个就是编译器和运行文件代码版本对不上导致的。所以你需要好好检查一下这个版本是不是对上了。
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.19.6</version>
</dependency>
2.5 改造proto文件
对方把proto文件给你之后,你可能需要改造一下。
syntax = "proto3";
// 目录结构按照单一文件的方式生成 true则是你有几个内部类就有几个平铺的类
option java_multiple_files = false;
// 指定生成的java类包路径
option java_package = "com.xx.xx.xx.xx.xxx";
// 指定生成的java类名
option java_outer_classname = "XXRequest";
// 入参
message MixData {
string a = 1; // 属性1
}
2.6 把proto文件生成java类
用GenProtobuf插件来生成,首先把idea的Tools -> Configure GenProtobuf进行设置
右键你项目中的proto文件,然后点击quick gen protobuf here
我的建议是把proto文件中的option java_multiple_files = false;这样只会生成一个文件,方便你操作。
2.7 proto生成的java类set Null对象 工具类改造
pb文件生成的java类,你如果set Null值了会报错,所以我写了一个工具类来避免setNull值
public class ProtostuffUtil {
private static final Logger logger = LoggerFactory.getLogger(ProtostuffUtil.class);
public static <T> byte[] serialize(T obj) {
byte[] data = null;
try {
data = ProtostuffUtils.serialize(obj);
} catch (Exception e) {
logger.error("serialize error", e);
}
return data;
}
public static <T> T deserialize(byte[] data, Class<T> clazz) {
if (null == data) {
return null;
}
T obj = null;
try {
obj = ProtostuffUtils.deserialize(data, clazz);
} catch (Exception e) {
logger.error("deserialize error", e);
}
return obj;
}
public static <T> void safeSet(T value, Consumer<T> setter) {
if (value != null) {
setter.accept(value);
}
}
}
2.8 构建请求体与用okhttp发起请求与接收请求
// 构建请求类
MixData.Builder mixData = MixData.newBuilder();
ProtostuffUtil.safeSet(yourClass.getA(), mixHeader::setA);
MixData mixData = mixData.build();
// 发起请求
// 将 Protobuf 数据序列化为字节数组
byte[] protobufData = mixData.toByteArray();
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://example.com/yourApi")
.post(RequestBody.create(protobufData, MediaType.parse("application/x-protobuf")))
.build();
Response response = client.newCall(request).execute();
byte[] responseBytes = response.body().bytes();
// 解析响应
MixResponse responseMessage = MixResponse.parseFrom(responseBytes);
// 您现在可以处理 MixResponse 中的数据