Spring Boot Rest接口返回带附加字段的MultipartFile报500错误如何解决?
问题结论
Multipart响应完全支持同时携带二进制文件和其他文本附加字段,你遇到的500错误是服务端和客户端均存在配置缺失导致的。
服务端配置缺失点
- 你的
@PostMapping标注了produces = MediaType.MULTIPART_FORM_DATA_VALUE,但Spring MVC默认没有注册「自定义POJO转Multipart响应」的消息转换器,不能直接把FileDownloadResponse作为返回值,需要手动构建ResponseEntity<MultiValueMap<String, Object>>类型的响应,每个字段作为Multipart的一个独立Part。 - 原代码的本质问题是Spring找不到匹配的转换器,无法同时输出JSON字段和文件流,最终抛出无响应体的500错误。
修复后服务端代码
@PostMapping(path = "/downloadFile", produces = MediaType.MULTIPART_FORM_DATA_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<MultiValueMap<String, Object>> downloadFile(@RequestBody FileDownloadRequest request) { MultiValueMap<String, Object> form = new LinkedMultiValueMap<>(); File file = new File("c:/fileLocation/"+request.getFileName()); try (InputStream stream = new FileInputStream(file)) { byte[] bytes = IOUtil.toByteArray(stream); // 普通文本字段直接存入Map form.add("fileName", file.getName()); form.add("checkSum", calculateCheckSum(bytes)); // 文件字段使用自定义的FileSystemResource form.add("fileContents", new FileSystemResource(bytes, file.getName())); } catch (Exception e) { e.printStackTrace(); return ResponseEntity.internalServerError().build(); } return ResponseEntity.ok() .contentType(MediaType.MULTIPART_FORM_DATA) .body(form); } // 原有FileSystemResource代码可以直接复用,无需修改 public static class FileSystemResource extends ByteArrayResource { private String fileName; public FileSystemResource(byte[] byteArray , String filename) { super(byteArray); this.fileName = filename; } public String getFilename() { return fileName; } public void setFilename(String fileName) { this.fileName= fileName; } }
客户端配置缺失点
- 不能直接把响应反序列化为自定义的
FileDownloadResponseClient类,Spring RestTemplate默认不会自动把Multipart的每个Part映射到POJO字段,需要先把响应类型指定为MultiValueMap,拿到响应后手动解析每个Part赋值到POJO。 - 原代码存在拼写错误:
Mediatype.ALL应为MediaType.ALL,也是潜在的报错点。
修复后客户端代码
public class FileDownloadResponseClient { private String fileName; private Long checkSum; // 优先用Resource接收文件,可按需转换为MultipartFile private Resource fileContents; // 省略getter/setter } public FileDownloadResponseClient download(FileDownloadRequest request) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); // 修正拼写错误,明确指定接受Multipart类型响应 headers.setAccept(Collections.singletonList(MediaType.MULTIPART_FORM_DATA)); HttpEntity<FileDownloadRequest> requestEntity = new HttpEntity<>(request, headers); // 先获取MultiValueMap类型的响应 ResponseEntity<MultiValueMap> response = restTemplate.postForEntity(downloadUrl, requestEntity, MultiValueMap.class); MultiValueMap<String, Object> body = response.getBody(); // 手动解析字段赋值到自定义POJO FileDownloadResponseClient result = new FileDownloadResponseClient(); result.setFileName((String) body.getFirst("fileName")); result.setCheckSum(Long.valueOf(body.getFirst("checkSum").toString())); result.setFileContents((Resource) body.getFirst("fileContents")); return result; }
如果确实需要用MultipartFile类型接收文件,可以用以下工具方法转换:
// 生产环境可引入commons-fileupload依赖使用CommonsMultipartFile替代MockMultipartFile private MultipartFile resourceToMultipartFile(Resource resource) throws IOException { return new MockMultipartFile( resource.getFilename(), resource.getFilename(), MediaType.APPLICATION_OCTET_STREAM_VALUE, resource.getInputStream() ); }
内容的提问来源于stack exchange,提问作者Sabari
相关产品推荐
相关产品推荐

