Issue
I am trying to upload Angular form data to Spring Boot server.
Simply, in Spring Boot I accept:
data class Photo(
val id: Long = 0L,
val file: MultipartFile
)
data class PostRequest(
@field:Size(min = 1, max = 100)
val title: String,
val photos: List<Photo> = mutableListOf()
)
via Controller:
fun createPost(@Valid @ModelAttribute postRequest: PostRequest)
In Angular I created this form:
this.postForm = this.fb.group({
title: ["", [Validators.required, Validators.minLength(1)]],
photos: this.fb.array([]),
});
When user uploads a photo I call these lines:
const photosArray = this.postForm.get("photos") as FormArray;
const newPhotoGroup = this.fb.group({
id: "",
file: event.target.result,
});
photosArray.push(newPhotoGroup);
Finally, I construct a form data object:
const formData = new FormData();
formData.append("title", this.postForm.get("title")?.value);
formData.append("photos", this.postForm.get("photos")?.value);
I use this function to post this form to API:
postRequest<T>(url: string, body: any): Observable<HttpResponse<T>> {
const headers = new HttpHeaders({
"Content-Type": "multipart/form-data",
});
return this.http.post<T>(url, body, {
headers,
observe: "response",
withCredentials: true,
});
}
In developer tools I see this request:
Spring Boot complains:
org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
Someone, enlighten me. Thank you.
Solution
photos form control is an array of objects, which is sent like that (as [object Object]) in the request, hence the error.
You need to loop the array and append each file:
const formData = new FormData();
formData.append("title", this.postForm.get("title")?.value);
// loop files and append them
this.postForm.get("photos")?.value.forEach((obj:any, i:number)=>{
formData.append("photos", obj.file); // user property which has file:File
});
Also, when adding file to the array, make sure it has File type (event.target.result seems to be a string now, if so, use event.target.file or add a new property, for example 'uploadFile', and add that to formData later):
const newPhotoGroup = this.fb.group({
id: "",
file: event.target.result, // this should be File from event.target.file
});
if you want to include id, i.e. custom file data, along with the file, it cannot go along with the file in the same formData key
You could use id instead of filename:
formData.append("photos", obj.file, obj.id)
or adapt the upload process something like this: sending JSON object along with file using FormData in ajax call and accessing the json object in PHP
Finally, make the reqeuest without content-type headers, the FormData will handle it:
return this.http.post<T>(url, body, {
observe: "response",
withCredentials: true,
});
Answered By - traynor

0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.