将文件从 Vue 发送到 SpringBoot 控制器时清空 MultipartFile[]

Empty MultipartFile[] when sending files from Vue to SpringBoot controller

我正在做一个可以帮助我制作月度报告的程序,但我坚持上传其中一种报告所需的照片。由于某种原因,它没有在控制器中获得数组。 我在后端使用 Springboot RestController,在另一端使用 BootstrapVue 和 vue-resource

index.html (BootstrapVue):

  <b-form-file
    v-model="photos"
    accept="image/*"
    multiple
    placeholder="..."
  ></b-form-file>

  <b-button @click="uploadPhotos">Upload</b-button>

里面 vuemain.js:

  data: {
    photos: null,
  },
  methods: {
    uploadPhotos(){
    var formData = new FormData();
    formData.append("photos", this.photos);
    this.$http.post('reports/photo', formData).then(result => {
      ...
    })
  }, ...

控制器内部:

@PostMapping("/photo")
public void addPhoto(@RequestParam("photos") MultipartFile[] photo) {
    System.out.println(photo.length); // shows 0
}

我在浏览器的 Params 中看到的内容:

XHRPOSThttp://localhost:8080/reports-maker/reports/photo
[HTTP/1.1 500  326ms]
Request payload 
-----------------------------4469196632041005505545240657
Content-Disposition: form-data; name="photos"
[object File],[object File],[object File],[object File]
-----------------------------4469196632041005505545240657--

所以出于某种原因,此时 @RequestParam("photos") MultipartFile[] photo 它是空数组。但是,如果我将它更改为像这样的一张照片:@RequestParam("photos") MultipartFile photo 并从 js 发送一张照片:formData.append("photos", this.photos[0]); 一切正常,照片会上传到服务器。

这是我第一次使用 Vue,老实说我不想深入学习 JS,所以可能某处有一些愚蠢的错误。任何方式我都可以在 JS 方法中使用循环来将它们一个一个地上传,但那样会很难看。我希望有更好的方法来做到这一点(当然不需要任何额外的 JS 库)。

如果你使用 axios 那么你应该添加 header

var headers = {
    'Content-Type': 'multipart/form-data',
};

axios.post(
    'reports/photo', 
    formData,
    {
        headers: headers,
    }
)
...

能够将文件发送到服务器。

我在这里找到了一个可接受的解决方案 Rossi Robinsion 的代码运行良好。至少它看起来比在单独的请求中一个一个地发送文件要好。

答案基于使用 getFileNames(),这有助于在请求中迭代文件,即使它们不在数组中也是如此。

我同意,在单独的请求中一个一个地发送文件非常"ugly",但我也不喜欢不使用 Spring 引导的映射资源的想法,不得不发送所有具有不同名称的文件(似乎杂乱无章)并且必须使用 MultipartHttpServletRequest,但有一个简单的解决方案:伊恩对 this 问题的回答(与 Vue.js 没有真正相关,但很有用)适用于我:

In order for Spring to map items in a request to a list, you need to provide the same name (in the FormData.append calls) for each item when appending to the form data. This allows Spring to effectively see the request as name=value1&name=value2&name=value3 (but obviously in the form of form data). When Spring sees the same key ("name") multiple times, it can map the values into a collection.

在您的 .vue 文件中,附加同名照片:

for (let i = 0; i < this.photos.length; i++) {
    formData.append("photos", this.photos[i]);
}

在你的控制器中:

@PostMapping("/photo")
public void addPhoto(@RequestParam("photos") MultipartFile[] photo) {
    System.out.println(photo.length); // Should be greater than 0 now
}

注: 我使用 Vue Axios 消耗我的 API 并手动添加 Content-Type: multipart/form-data header。确保它在您的请求 header 列表中。