【项目实战】SpringBoot整合Protobuf,实现基于RestTemplate的模拟客户端与服务端的远程调用
迪丽瓦拉
2024-05-31 22:32:00
0

一、背景说明

项目中使用到了Protobuf,但是因为不知道怎么使用它,所以看起来很高大上,现在写一个简单的Demo来实现基于RestTemplate的模拟客户端与服务端的远程调用!

二、实操代码

2.1 定义依赖POM文件

org.springframework.bootspring-boot-starter-web2.3.2.RELEASEcom.google.protobufprotobuf-java3.19.4com.google.protobufprotobuf-java-util3.19.4com.googlecode.protobuf-java-formatprotobuf-java-format1.4org.apache.httpcomponentshttpclient4.5.13trueorg.apache.httpcomponentshttpcore4.4.15true

2.2 定义protobuf-maven-plugin

该配置先使用os-maven-plugin插件,该插件主要是为了识别不同的操作系统,这样插件可以根据不同的平台加载不同protoc编译器文件。google的protobuf团队也是用该插件来识别protoc的运行操作系统信息

org.xolstice.maven.pluginsprotobuf-maven-plugin0.6.1D:\Project\protobuf\protoc-3.19.4-win64\bin\protoc.exeprotoc-java${project.basedir}/src/main/resources/proto${project.basedir}/src/main/javafalse

2.3 定义BurtProtoController

@RestController
public class BurtProtoController {private final Logger logger = LoggerFactory.getLogger(BurtProtoController.class);@Resourceprivate RestTemplate restTemplate;@PostMapping(value = "/protobuf/message", consumes = "application/x-protobuf", produces = "application/x-protobuf")public BurtProto.Response message(HttpEntity requestPayload) {BurtProto.Request request = requestPayload.getBody();logger.info("Received following request: \n{}", request);BurtProto.Resource requestResource = BurtProtoParser.extractResource(request.getResourcesList(), "AAAAA");logger.info("BurtProto.Resource: AAAAA: \n{}", requestResource);BurtProto.Resource responseResource = BurtProto.Resource.newBuilder().setChannelId(requestResource.getChannelId()).setValue("Successful").build();return BurtProto.Response.newBuilder().addResources(responseResource).build();}@GetMapping(value = "/helloProtoBuf")public BurtProto.Response test() {String url = "http://127.0.0.1:8080/protobuf/message";BurtProto.Resource responseResource000 = BurtProto.Resource.newBuilder().setChannelId("AAAAA").setValue("AAAAA ChannelId Request").build();BurtProto.Resource responseResource001 = BurtProto.Resource.newBuilder().setChannelId("BBBBB").setValue("BBBBB ChannelId Request").build();BurtProto.Request request = BurtProto.Request.newBuilder().addAllResources(Lists.newArrayList(responseResource000, responseResource001)).build();HttpHeaders headers = new HttpHeaders();headers.add(HttpHeaders.CONTENT_TYPE, "application/x-protobuf");HttpEntity httpEntity = new HttpEntity<>(request, headers);final ResponseEntity responseEntity = restTemplate.postForEntity(url, httpEntity, BurtProto.Response.class);logger.info("ResponseEntity: \n{}", responseEntity.getBody());return responseEntity.getBody();}
}

2.4 定义BurtProto

syntax = "proto3";package com.demo.protobuf;option java_package = "com.demo.protobuf.proto";
option java_outer_classname = "BurtProto";message Request {repeated Resource resources = 1;
}message Response {repeated Resource resources = 1;
}message Resource {string channelId = 1;string value = 2;
}

这个由IDEA生成即可,参考文章
【项目实战】Protobuf入门介绍以及如何生成proto对象文件

2.5 定义MessageProtoParser

public class MessageProtoParser {private MessageProtoParser() {}public static MessageProto.Resource extractResource(List resources, String channelId) {return resources.stream().filter(res -> Objects.equals(channelId, res.getChannelId())).findFirst().orElse(null);}
}

2.6 添加protobuf序列化支持

@EnableWebMvc
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List> converters) {converters.add(protobufHttpMessageConverter());converters.add(mappingJackson2HttpMessageConverter());}/*** protobuf 序列化*/@Beanpublic ProtobufHttpMessageConverter protobufHttpMessageConverter() {return new ProtobufHttpMessageConverter();}/*** protobuf 反序列化*/@Beanpublic RestTemplate restTemplate(ProtobufHttpMessageConverter protobufHttpMessageConverter) {return new RestTemplate(Lists.newArrayList(protobufHttpMessageConverter));}@Beanpublic MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {return new MappingJackson2HttpMessageConverter();}
}

三、功能验证

看到响应体的内容返回为protobuf格式的内容。说明完成了一次请求与交互
在这里插入图片描述
注意Content-Type是:application/x-protobuf

这个格式是APIFOX不支持的格式哦、

在这里插入图片描述

以下是控制台中所有的输出,

2023-03-09 23:04:25.925  INFO 26644 --- [nio-8080-exec-2] c.d.p.controller.BurtProtoController     : Received following request: 
resources {channelId: "AAAAA"value: "AAAAA ChannelId Request"
}
resources {channelId: "BBBBB"value: "BBBBB ChannelId Request"
}2023-03-09 23:04:25.926  INFO 26644 --- [nio-8080-exec-2] c.d.p.controller.BurtProtoController     : BurtProto.Resource: AAAAA: 
channelId: "AAAAA"
value: "AAAAA ChannelId Request"2023-03-09 23:04:25.928  INFO 26644 --- [nio-8080-exec-3] c.d.p.controller.BurtProtoController     : ResponseEntity: 
resources {channelId: "AAAAA"value: "Successful"
}

解释一下,A发送给B一段内容,然后B将其打印出来,内容如下

resources {channelId: "AAAAA"value: "AAAAA ChannelId Request"
}
resources {channelId: "BBBBB"value: "BBBBB ChannelId Request"
}

B调用了BurtProtoParser下的extractResource方法,使用了流操作,并且只取了第一条数据findFirst(),并将其打印出来

2023-03-09 23:04:25.926  INFO 26644 --- [nio-8080-exec-2] c.d.p.controller.BurtProtoController     : BurtProto.Resource: AAAAA: 
channelId: "AAAAA"
value: "AAAAA ChannelId Request"

B将内容从“AAAAA ChannelId Request”改成了“Successful” 并且变成了响应体,传回给了A。A收到响应体的内容,并将其打印

2023-03-09 23:04:25.928  INFO 26644 --- [nio-8080-exec-3] c.d.p.controller.BurtProtoController     : ResponseEntity: 
resources {channelId: "AAAAA"value: "Successful"
}

相关内容