Angular上传CSV至Java API时InputStream为空问题求助
解决Angular CSV上传中Java后端InputStream为空的问题
问题场景
Angular前端上传CSV文件到Java后端,FormData中已正确包含文件,但后端接口的uploadedInputStream始终为空,仅能成功获取csvdata、fileDetail、fileMetadata参数。
前端(Angular)代码
FormData构建代码
var fileInput = document.getElementById('chosenFile'); var fd = new FormData(); fd.append('fileMetadata', JSON.stringify(imgMetadata)); var file = fileInput.files[0]; fd.append('file', file);
$HTTP请求代码
$http.post(uploadurl, fd, { transformRequest: angular.identity, transformResponse: angular.identity, headers: { "X-XSRF-TOKEN": PluginHelper.getCsrfToken(), "Content-Type": undefined } }).then(function successCallback(response) { console.log("In success callback"); var status = response.status; if(status == "200") { var isValid = response.data; console.log("FIleupload function in java "+isValid); if(isValid == "filecopied") { $scope.errorText = "filecopied :"; } } }, function errorCallback(response) { console.log("In error callback"); $scope.errorText = "Error in callback file function"; });
后端(Java)原接口代码
@POST @Path("/uploadfile/{csvdata}") @Consumes(MediaType.MULTIPART_FORM_DATA) @AllowAll public Response uploadfile(@PathParam("csvdata") String csvdata, @FormDataParam("fileMetadata") String fileMetadata, @FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataContentDisposition fileDetail, FormDataMultiPart multiPartData, @FormDataParam("fd") InputStream formdata) throws Exception { try { if (uploadedInputStream == null) { log.error("Error: uploadedInputStream is null"); //return Response.status(Response.Status.BAD_REQUEST).entity("File input stream is null").build(); } if (formdata == null) { log.error("Error: formdata is null"); //return Response.status(Response.Status.BAD_REQUEST).entity("File input stream is null").build(); } else { log.error("Error: formdata is NOT null"); } // for file field final FormDataBodyPart filePart = multiPartData.getField("<file_field_name>"); final ContentDisposition fileDetails = filePart.getContentDisposition(); final InputStream fileInputStream = filePart.getValueAs(InputStream.class); log.error(filePart + "-" + fileDetails + "--" + fileInputStream); log.error("TRY FILEUPLOAD: " + csvdata); log.error("File Metadata: " + fileMetadata); // Process the uploaded file String uploadedFileLocation = "d://uploaded/" + fileDetail.getFileName(); log.error("uploadedFileLocation: " + uploadedFileLocation); log.error("fileDetail: " + fileDetail.getSize()); saveToFile(uploadedInputStream, uploadedFileLocation); return Response.status(Response.Status.OK).entity("filecopied").build(); } catch (Exception e) { log.error("catch uploadfile: " + e.toString() + "-" + e.getMessage()); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Cannot copy!!").build(); } } private void saveToFile(InputStream uploadedInputStream, String target) { try (OutputStream out = new FileOutputStream(new File(target))) { log.error("TRY saveToFile"); int read; byte[] bytes = new byte[1024]; while ((read = uploadedInputStream.read(bytes)) != -1) { out.write(bytes, 0, read); } } catch (IOException e) { log.error("catch saveToFile: " + e.toString() + "-" + e.getMessage()); } }
解决方案
1. 核心问题原因
当方法参数中声明FormDataMultiPart multiPartData时,JAX-RS会提前解析整个multipart请求并消耗请求流,导致单独的@FormDataParam("file") InputStream uploadedInputStream无法获取到有效流。
2. 修改后的后端接口代码
@POST @Path("/uploadfile/{csvdata}") @Consumes(MediaType.MULTIPART_FORM_DATA) @AllowAll public Response uploadfile(@PathParam("csvdata") String csvdata, @FormDataParam("fileMetadata") String fileMetadata, @FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataContentDisposition fileDetail) throws Exception { try { if (uploadedInputStream == null) { log.error("Error: uploadedInputStream is null"); return Response.status(Response.Status.BAD_REQUEST).entity("File input stream is null").build(); } log.error("TRY FILEUPLOAD: " + csvdata); log.error("File Metadata: " + fileMetadata); // Process the uploaded file String uploadedFileLocation = "d://uploaded/" + fileDetail.getFileName(); log.error("uploadedFileLocation: " + uploadedFileLocation); log.error("fileDetail: " + fileDetail.getSize()); saveToFile(uploadedInputStream, uploadedFileLocation); return Response.status(Response.Status.OK).entity("filecopied").build(); } catch (Exception e) { log.error("catch uploadfile: " + e.toString() + "-" + e.getMessage()); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Cannot copy!!").build(); } } private void saveToFile(InputStream uploadedInputStream, String target) { try (OutputStream out = new FileOutputStream(new File(target))) { log.error("TRY saveToFile"); int read; byte[] bytes = new byte[1024]; while ((read = uploadedInputStream.read(bytes)) != -1) { out.write(bytes, 0, read); } out.flush(); } catch (IOException e) { log.error("catch saveToFile: " + e.toString() + "-" + e.getMessage()); } }
3. 关键修复点
- 移除
FormDataMultiPart multiPartData和@FormDataParam("fd") InputStream formdata参数,避免提前消耗请求流。 - 确保
@FormDataParam("file") InputStream uploadedInputStream是唯一读取文件流的入口,此时JAX-RS会直接传递对应part的原始流。 - 在
saveToFile方法中添加out.flush(),确保所有字节都写入目标文件。
4. 前端验证(可选)
确认前端FormData中file参数的名称与后端@FormDataParam("file")的名称完全一致(大小写敏感),避免参数名不匹配导致的流无法读取。
内容的提问来源于stack exchange,提问作者Aditya Bhatnagar
相关产品推荐
相关产品推荐

