我有一个带有 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 对象吗?
非常感谢。
您的方向是正确的,但是将数组中的多个 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`
}