4

问题一:

需要上传四个文件 如图:

image.png
9dbb3b14127b7e0f0b710ba35cc6ab8d.png

可以发现这个四个需要上传文件都在一个文件夹下,后面为了方便用户上传就改成了上传一整个文件夹,
如图:

image.png

出现的一些问题,后台接收文件的时候出现了报错

后台使用的是HttpServletRequest接收的一整个文件夹。

@PostMapping({"folder/img/{id}"})
    public void folderImgUpload(HttpServletRequest folderRequest,
                                @PathVariable Long id) {
        if (folderRequest != null) {
            this.invoiceOriginDataService.folderImgUpload(folderRequest, id);
        } else {
            throw new ValidationException("空文件夹");
        }
    }

public void folderImgUpload(HttpServletRequest folderRequest, Long id) {
        InvoiceOriginData invoiceOriginData = this.invoiceOriginDataRepository.findById(id).orElseThrow(EntityNotFoundException::new);
        System.out.println();
        try {
            for (Part part : folderRequest.getParts()) {
                //截取图片名称
                String newPath = invoiceOriginData.getPrefix() + invoiceOriginData.getPrefix() + this.invoiceProperty.getImagePath() + this.getFileName(part.getSubmittedFileName());
                this.minioService.deleteObjects(invoiceOriginData.getBucket(), newPath);
                this.minioService.uploadByte(invoiceOriginData.getBucket(), newPath, part.getInputStream().readAllBytes(), "image/jpeg");
            }
        } catch (Exception e) {
            throw new RuntimeException("文件夹出现问题");
        }
    }

image.png

后面经过一系列排查 最终发现是{formData}搞得鬼
image.png

最后去掉 {},就上传成功了。

uploadImgs(files: FileList, invoiceOriginDataId: number): Observable<HttpEvent<object>> {
    const formData: FormData = new FormData();
    for (let i = 0; i < files.length; i++) {
      formData.append('file', files[i]);
    }
    return this.httpClient.post(`/document/folder/img/${invoiceOriginDataId}`,
      formData ,
      {reportProgress: true, observe: 'events'});
  }

原因:
当使用 {} 作为参数时,Spring Boot 会将请求体中的 JSON 数据解析为 Java 对象。然而,文件上传通常不是以 JSON 格式传输的,而是使用 multipart/form-data 协议。因此,Spring Boot 无法正确解析包含文件的文件上传请求。

使用 formData 作为参数
FormData 类专门用于处理 multipart/form-data 类型的请求。当使用 formData 作为参数时,Spring Boot 会将 FormData 对象中的数据直接传递给控制器方法,包括文件数据。

问题二:

image.png
此问题就是文件过大引起的,可以继续看到之前是怎么上传文件的
image.png

可以看到是我们把文件方法到一起上传导致。

解决:
有多少个文件就上传多少次,不放在一起上传。

 @Action()
  uploadInvoiceImage(file: File, invoiceOriginDataId: number): Observable<HttpEvent<object>> {
    const formData: FormData = new FormData();
    formData.append('file', file);
    return this.httpClient.post(`/invoiceGroup/file/uploadInvoiceImage/${invoiceOriginDataId}`,
      formData, {reportProgress: true, observe: 'events'});
  }

c层
from(this.invoiceImgs).pipe(
        concatMap(invoiceImg => this.invoiceGroupService.uploadInvoiceImage(invoiceImg, this.invoiceOriginDataId)),
        last()
      ).subscribe(lastInvoiceImg => {
        this.invoiceGroupService.initAndPublishTasks(this.parentPath, this.invoiceOriginDataId).subscribe(invoiceGroup => {
          this.invoiceGroupService.getInvoiceGroupById(invoiceGroup.id);
        })
      });

后台更改如下:
image.png

使用from将 this.invoiceImgs (数组)转换为一个 RxJS Observable 对象。
这个 Observable 会依次发出每个发票图像对象。然后配合concatMap 会等待每个上传完成才继续处理下一个发票图像。订阅最后一个,进行后续操作。

这个时候虽然解决了问题,但是检查网络的时候发现,并不是串行传输,是并行传输
image.png

concatMap不是串行发送吗,怎么又并行执行了呢.
仔细看可以看到是一个一个发送的,不是放在一起发送的。但是从图中可以看到,第一条还没执行完,第二条就开始执行了,以此类推,导致这种结果。
image.png
排查发现:
@Action()是action弄得鬼,导致出现这种状况,因为使用了状态管理中的action,只要调用就会执行,不要在订阅了。
此时就串行传出了。

    const formData: FormData = new FormData();
    formData.append('file', file);
    return this.httpClient.post<Observable<HttpEvent<object>>>(`/invoiceGroup/file/uploadInvoiceImage`,
      formData, {reportProgress: true, observe: 'events'});
  }


//c层httpEvent.type === HttpEventType.Response
if (httpEvent.type === HttpEventType.Response)
from(this.invoiceImgs).pipe(
        concatMap(invoiceImg => this.invoiceGroupService.uploadInvoiceImage(invoiceImg)),
        last(),
      ).subscribe((httpEvent: HttpEvent<object>) => {
        if (httpEvent.type === HttpEventType.Response) {
          this.invoiceGroupService.initAndPublishTasks(this.parentPath).subscribe(invoiceGroup => {
            this.invoiceGroupService.getInvoiceGroupById(invoiceGroup.id);
          });
        }
      });

image.png

小结:

HttpEventTyp的几个类型
HttpEventType.Sent:表示 HTTP 请求已成功构建并发送到服务器
HttpEventType.UploadProgress:提供有关上传进度的信息,包括已上传的字节和正在上传的文件的总大小
HttpEventType.ResponseHeaders:标记着从服务器接收响应头
HttpEventType.Response: 事件用于指示 HTTP 请求已经成功完成,并且服务器已发送响应数据


zZ_jie
436 声望9 粉丝

虚心接受问题,砥砺前行。