RestTemplate上传多文件异常解决
RestTemplate上传文件方法
都知道前端往后端传文件是通过form的形式,后端web程序之间上传,也是通过form表单。使用MultiValueMap类。
MultiValueMap formData = new LinkedMultiValueMap<>();
ByteArrayResource fileAsResource = new ByteArrayResource(a.getBytes()){
@Override
public String getFilename() {
return a.getOriginalFilename();
}
@Override
public long contentLength() {
return a.getSize();
}
};
formData.add("file",fileAsResource);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity request = new HttpEntity<>(map,headers);
ResponseEntity<Object> response = restTemplate.postForEntity(url,request,Object.class);
上传多文件所遇问题
这边我需要上传多个文件,在前端传过来时,我的接口是直接用List来接收的。于是我想当然的直接将MultiPartFile列表转化成了ByteArrayResource的list。
通过这种方式上传文件之后,在消息转化器处报错了。错误描述说是不能转换ByteArrayInputStream。
问题分析
上面说到消息转换器报错,于是查看我们使用的类,ByteArrayResource。继承自AbstractResource。
再看AbstractResource继承自Resource类。
那么这个Resource的子类,是可以被ResourceHttpMessageConverter解析转换的。开始Debug RestTemplate请求流程。每个HttpMessageConverter都有自己的支持的转换类型。通过查看canRead方法,或者supports方法可以查看支持的转换类型。
debug RestTemplate处理流程,发现该次请求,使用了AllEncompassingFormHttpMessageConverter,因为我们传输的数据类型是MultiValueMap。这个转换器没有什么方法,大部分直接继承FormHttpMessageConverter,而FormHttpMessageConverter是支持Resource对象转换的,按道理来说应该是可以转换的。
继续debug,发现在写转换的时候,使用了MappingJackson2HttpMessageConverter,而没有使用ResourceHttpMessageConverter。在writePart方法中,发现转换的对象类型是List,所以调用了支持Object类型转换的Mapping转换器。
报错原因找到了,尝试改为add文件数组,看了一下form里面的对象类型,是Object,肯定不行,跑完果然还是报错。
由于通过debug发现,是由于我们传输的对象类型错误,才导致HttpMessageConverter出错,接下来聚焦到对象传输上。查看MultiValueMap的add方法,看到这个add方法,一下就找到了问题所在,它会获取当前Key的LinkedList。然后将对象add到这个list里面。那么我们传递list显然是不科学的。
改为循环add ByteArrayResource,再查看MultiValueMap,已经不是Object了,而是我们的匿名内部类。
再debug到FormHttpMessageConverter中,此时转换这个files所用的转换器,终于是ResourceHttpMessageConverter了,继续运行,果然就可以了,问题解决。
问题总结
1、RestTemplate上传多文件时,一定要循环add Resource。
2、要重写getFileName方法和contentLength方法。
本文地址:https://blog.csdn.net/weixin_43838174/article/details/109568891
上一篇: 显卡安装与使用重点注意事项
下一篇: Java8处理List的双层循环问题