Spring RestTemplate调用时自定义请求/响应对象能否携带MultipartFile
问题结论
你提到的两个需求都可以通过Spring RestTemplate实现,当前报错是因为multipart表单构造方式错误、拼写错误共同导致的。
上传场景实现(问题1解决方案)
错误原因
你直接将包含MultipartFile的自定义UploadRequest对象作为整体放入MultiValueMap中,RestTemplate会尝试用Jackson序列化整个Java Bean,而MultipartFile内部包含FileDescriptor、IO流这类无法序列化的属性,就会抛出你遇到的序列化异常。此外你代码里的Content-Type拼写错误(将multipart写为mutipart)也会导致请求格式识别失败。
正确实现代码
不需要修改自定义的UploadRequest类,只需要调整表单构造逻辑,把对象属性平铺开放入表单即可,Spring接收端会自动完成参数绑定:
HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); MultiValueMap<String, Object> form = new LinkedMultiValueMap<>(); // 拆分UploadRequest属性放入表单 form.add("checkSum", uploadRequest.getCheckSum()); // MultipartFile需要转成Resource再放入表单,RestTemplate可直接识别处理 form.add("fileContents", uploadRequest.getFileContents().getResource()); HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(form, headers); ResponseEntity<UploadResponse> responseEntity = restTemplate.postForEntity(uploadUrl, requestEntity, UploadResponse.class);
接收端接口直接用@ModelAttribute UploadRequest uploadRequest即可正常接收所有参数。
下载场景实现(问题2解决方案)
不能直接在自定义响应类中声明MultipartFile属性自动接收,需要先解析响应的multipart内容,再手动组装到自定义对象中。
实现步骤
- 先给RestTemplate配置支持解析multipart响应的消息转换器:
restTemplate.getMessageConverters().add(new FormHttpMessageConverter());
- 调用接口后先解析为通用的multipart结构,再手动组装自定义响应对象:
// 声明响应类型为MultiValueMap ResponseEntity<MultiValueMap<String, Object>> resp = restTemplate.exchange( downloadUrl, HttpMethod.GET, requestEntity, new ParameterizedTypeReference<MultiValueMap<String, Object>>() {} ); MultiValueMap<String, Object> respBody = resp.getBody(); // 手动组装自定义响应对象 DownloadResponse downloadResponse = new DownloadResponse(); // 读取普通属性 downloadResponse.setCheckSum((Long) respBody.getFirst("checkSum")); downloadResponse.setRemark((String) respBody.getFirst("remark")); // 读取文件资源,可按需转为MultipartFile Resource fileResource = (Resource) respBody.getFirst("fileContents"); // 如需转为MultipartFile,可借助MockMultipartFile(需引入spring-test依赖)或自行实现MultipartFile接口 MultipartFile file = new MockMultipartFile( "fileContents", fileResource.getFilename(), MediaType.APPLICATION_OCTET_STREAM_VALUE, fileResource.getInputStream() ); downloadResponse.setFileContents(file);
内容的提问来源于stack exchange,提问作者Sabari
相关产品推荐
相关产品推荐

