RestTemplate填坑记录
背景
由于公司的项目是udp服务器需要调用外部接口读取配置,否则耦合划分就会存在问题。前期考虑简单实现,就没有引入rpc框架。虽然都是springboot项目,但是暂时还是先不考虑引入springcloud,复杂度会陡然上升。于是,就有了这次尝试。
我这里有两个项目,其中一个是中规中矩的springboot web项目,提供rest接口,另一个也是springboot项目,但是,我们剔除了web启动,使用的是netty的udp服务进行监听,所以,这个里面是没有spring.web.client依赖的。其它的,暂时就不重要了,我们开始记录填坑记录。
引入
这里我们需要在udp服务中引入RestTemplate这个类,但是我又不想引入web的autoconfig,添加web服务器,所以,我添加了如下依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
这里,我的spring的版本是5.0.8.RELEASE,我的springboot是2.0.4.RELEASE的。另外,RestTemplate是一个单独的类,并不需要进行配置就可以直接使用。我开始,调用的是postForEntity。
填坑
List泛型丢失
这里坑就开始了,第一个坑是List。进入断点调试可以看到,直接返回list或者带list的返回值,list里的内容都会变成LinkedHashMap。这事我找了老半天才找到原因。本质上的原因是因为在Json中并没有携带类型信息,而反序列化给的类型也給不进list里的泛型,所以解析后就都是LinkedHashMap。然后,你就会发现,虽然你能拿到response但是无法遍历。解决方法说来也简单,使用exchange方法就可以了。先看我最终的调用代码吧:
result=restTemplate.exchange(url, HttpMethod.POST, null, new ParameterizedTypeReference<DefaultResponse<SensorListResponse>>() {}).getBody();
但是,这里又有另外一个坑。ParameterizedTypeReference中的泛型不可以是方法或者类泛型里的T,而必须是你要的那个类型。原因应该和java的类型擦出有关,这里坑了我很久。这里因为new了ParameterizedTypeReference实例,所以会有类型信息进行反序列化,就不会有类型丢失的问题了。
序列化格式
我这里为了适应web端,在接口提供方将Date类型序列化成了yyyy-MM-dd HH:mm:ss。然后,过了上面那关后就报这个错误了。这个问题的解决其实和我web端的解决差不多。总体思路就是,提供一个restTemplate工厂方法,在工厂方法里将自定义序列化配置好。我这里采用的是将RestTemplate注册成一个bean,然后获取这个bean来进行调用。具体配置如下:
@Bean
public RestTemplate createRestTemplate() {
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
objectMapper.setDateFormat(dateFormat);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
RestTemplate restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> converters = new ArrayList<>();
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
jsonConverter.setObjectMapper(objectMapper);
converters.add(jsonConverter);
restTemplate.setMessageConverters(converters);
return restTemplate;
}
结束
总体来说,都是些会用不会用,知道和不知道的事。记录在此,备查。