是否可以在 httpClient.post 中发送 FormData 对象数组?

问题描述 投票:0回答:1

我有一个带有 Java 后端的 Angular 前端应用程序,用户可以在其中选择一个文档,然后保存它。

为此,我一直将 FormData 对象从前端发送到后端,没有出现任何问题。

这是我目前在前端的一个片段,用于将单个文件的内容发送到后端:

public postSaveDocument(entityType: DocumentEntityType, id: number, body: DocumentInputDto): Observable<Upload<UploadWithLockResultsDto>> {

    const url = `${DocumentationService.baseUrl}/${getUrlSegment(entityType)}/${id}/documents`;

     //Create a FormData object and set the values of the document
     const formData = new FormData();
     formData.append('documentId', this.documentId.toString());
     formData.append('title', this.title);
     formData.append('content', this.content, this.content.name);
    


    return this.httpClient.post(url, formData,
      {...DocumentationService.options, reportProgress: true, observe: 'events', responseType: 'json'})
      .pipe(upload<UploadWithLockResultsDto>());



}

这是我在后端所做的用于保存该文件的操作:

@PostMapping("/{documentEntityType}/{entityId}/documents")
    public ResponseEntity<UploadWithLockResultsDto> saveDocument(
           @PathVariable("documentEntityType") DocumentEntityType documentEntityType,
           @PathVariable("entityId") Integer entityId,
           DocumentInputDto documentInputDto,
                                   ) throws AuthException, IOException {

           //Save the updates to the database
           var uploadWithLockResultsDto = documentService.documentUpdate(documentInputDto, authentication.getName(), authentication.getPrincipal());
           return handleUploadWithLockResults(uploadWithLockResultsDto);
   
}

这对于保存单个文档来说效果很好。

现在我想做的是允许用户一次选择多个文档,并在将它们发送到后端时一次性保存。

到目前为止还没有运气。

我尝试将数据放入前端的 FormData 对象数组中

public postSaveDocuments(entityType: DocumentEntityType, id: number, body: DocumentInputDto[]): Observable<Upload<UploadWithLockResultsDto>> {

    const formDataArray: any[] = [];
    body.forEach(documentInputDto => {

      const formData = new FormData();
      formData.append('documentId', this.documentId.toString());
      formData.append('title', this.title);
      formData.append('content', this.content, this.content.name);
      formDataArray.push(formData);
    });

    return this.httpClient.post(url, formDataArray,
      {...DocumentationService.options, reportProgress: true, observe: 'events', responseType: 'json'})
      .pipe(upload<UploadWithLockResultsDto>());
}

然后我尝试在后端将其作为数组收集起来

@PostMapping("/{documentEntityType}/{entityId}/documents")
    public ResponseEntity<UploadWithLockResultsDto> saveDocument(
           @PathVariable("documentEntityType") DocumentEntityType documentEntityType,
           @PathVariable("entityId") Integer entityId,
           DocumentInputDto[] documentInputDtos,
                                   ) throws AuthException, IOException {

           //Save the docs to the database
           var uploadWithLockResultsDto = documentService.updateDocuments(documentInputDtos, authentication.getName(), authentication.getPrincipal());
           return handleUploadWithLockResults(uploadWithLockResultsDto);
   
}

毫不奇怪,这行不通。 它甚至永远不会到达后端。 我意识到 FormData 对象数组可能并不意味着从前端发送到后端。

任何人都可以为我指出正确的方向,即如何修改调用,以便从前到后发送多个 FormData 对象吗?

非常感谢。

angular typescript form-data
1个回答
0
投票

您的方向是正确的,但是将数组中的多个 FormData 对象直接从前端发送到后端是行不通的,因为 FormData 对象应该作为单个实体发送。相反,您应该使用多部分表单请求将文档作为单个 FormData 对象中的各个部分发送。

第 1 步:前端 - 修改 FormData 对象以处理多个文件 要发送多个文件,您可以将每个文档的数据附加到同一个 FormData 对象,并为每个文档使用唯一的键。这将允许您在一个 HTTP 请求中发送多个文档。

更新了前端代码:

public postSaveDocuments(entityType: DocumentEntityType, id: number, body: DocumentInputDto[]): Observable<Upload<UploadWithLockResultsDto>> {

    const url = `${DocumentationService.baseUrl}/${getUrlSegment(entityType)}/${id}/documents`;

    // Create a single FormData object for all documents
    const formData = new FormData();

    // Loop through the document DTOs and append each one
    body.forEach((documentInputDto, index) => {
      formData.append(`documents[${index}].documentId`, this.documentId.toString());
      formData.append(`documents[${index}].title`, this.title);
      formData.append(`documents[${index}].content`, this.content, this.content.name);
    });

    return this.httpClient.post(url, formData, {
      ...DocumentationService.options,
      reportProgress: true,
      observe: 'events',
      responseType: 'json'
    }).pipe(upload<UploadWithLockResultsDto>());
}

第2步:后端-处理多部分表单数据 在后端,您需要处理多个文件及其关联的元数据。您可以通过接受 MultipartFile 数组或自定义 DTO 形式的数据来完成此操作,具体取决于您希望如何构建请求。由于您要发送元数据和文件,因此可以使用@RequestParam和@ModelAttribute注释的组合来绑定表单数据和文件内容。

更新后端代码:

@PostMapping("/{documentEntityType}/{entityId}/documents")
public ResponseEntity<UploadWithLockResultsDto> saveDocuments(
    @PathVariable("documentEntityType") DocumentEntityType documentEntityType,
    @PathVariable("entityId") Integer entityId,
    @RequestParam("documents") List<MultipartFile> documents,
    @RequestParam Map<String, String> documentMetadata) throws AuthException, IOException {

    // Parse metadata and files
    List<DocumentInputDto> documentInputDtos = new ArrayList<>();
    for (int i = 0; i < documents.size(); i++) {
        MultipartFile file = documents.get(i);
        String documentId = documentMetadata.get("documents[" + i + "].documentId");
        String title = documentMetadata.get("documents[" + i + "].title");

        DocumentInputDto documentInputDto = new DocumentInputDto();
        documentInputDto.setDocumentId(Long.parseLong(documentId));
        documentInputDto.setTitle(title);
        documentInputDto.setContent(file); // Assuming the DocumentInputDto has a 'content' field for the file

        documentInputDtos.add(documentInputDto);
    }

    // Save the documents to the database
    var uploadWithLockResultsDto = documentService.updateDocuments(documentInputDtos, authentication.getName(), authentication.getPrincipal());
    return handleUploadWithLockResults(uploadWithLockResultsDto);
}

第 3 步:更新您的 DocumentInputDto

public class DocumentInputDto {
    private Long documentId;
    private String title;
    private MultipartFile content; // The file being uploaded
    
    // Getters and setters...`enter code here`
}
© www.soinside.com 2019 - 2024. All rights reserved.