项目中使用到了Protobuf,但是因为不知道怎么使用它,所以看起来很高大上,现在写一个简单的Demo来实现基于RestTemplate的模拟客户端与服务端的远程调用!
org.springframework.boot spring-boot-starter-web 2.3.2.RELEASE com.google.protobuf protobuf-java 3.19.4 com.google.protobuf protobuf-java-util 3.19.4 com.googlecode.protobuf-java-format protobuf-java-format 1.4 org.apache.httpcomponents httpclient 4.5.13 true org.apache.httpcomponents httpcore 4.4.15 true
该配置先使用os-maven-plugin插件,该插件主要是为了识别不同的操作系统,这样插件可以根据不同的平台加载不同protoc编译器文件。google的protobuf团队也是用该插件来识别protoc的运行操作系统信息
org.xolstice.maven.plugins protobuf-maven-plugin 0.6.1 D:\Project\protobuf\protoc-3.19.4-win64\bin\protoc.exe protoc-java ${project.basedir}/src/main/resources/proto ${project.basedir}/src/main/java false
@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();}
}
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对象文件
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);}
}
@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"
}