You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 21:33:17