I have Spring boot 2 backend REST post API as follows:-
@RequestMapping(value = "/profile", method = RequestMethod.POST)
public Profile saveOrUpdateProfile(@RequestParam("file") MultipartFile file, @RequestBody Profile profile, String path) {
logger.info("file name:" + file.getOriginalFilename());
if (file != null) {
profile.setFileDownloadUri(profileService.storeFile(file, path));
return profileService.saveOrUpdateProfile(profile);
} else {
return null;
}
}
I am trying to call this from Reactjs as follows:-
static postProfile(selectedFile, profile, replacePhotoPath) {
if (selectedFile) {
let serverResponse;
let formData = new FormData();
formData.append("porofile", profile);
formData.append("file", selectedFile);
formData.append("path", replacePhotoPath);
axios.post('http://localhost:8080/profile', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(res => {
console.log('res:' + res)
serverResponse = res.data;
})
.catch((error) => {
// handle this error
console.log('error: ' + error);
//setMessageFromServer(error.data)
POST http://localhost:8080/profile 400 serverResponse = error.data;
})
return serverResponse;
}
}
I got an error as:
xhr.js:178 POST http://localhost:8080/profile 415
You may understand that, I am trying to post a profile with photo file. I am new in Reactjs and trying to learn by coding. I don't know how to make this axios post call to this API. If it is possible to do it by using another API than axios, it is fine for me. Thanks in advance!
Updated questions 1:- Endpoint:-
@RequestMapping(value = "/profile2", method = RequestMethod.POST, consumes = MULTIPART_FORM_DATA)
public ResponseEntity<?> saveProfile(@RequestParam("file") MultipartFile file, @RequestParam("path") String path, @RequestParam("profile") Profile profile) {
logger.info("file name:" + file.getOriginalFilename());
return null;
}
Reactjs:-
static postProfile(selectedFile, replacePhotoPath, profile) {
if (selectedFile) {
let serverResponse;
let formData = new FormData();
formData.append("file", selectedFile);
formData.append("path", replacePhotoPath);
formData.append("profile", profile)
axios.post('http://localhost:8080/profile', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(res => {
console.log('res:' + res)
serverResponse = res.data;
})
.catch((error) => {
// handle this error
console.log('error: ' + error);
//setMessageFromServer(error.data)
serverResponse = error.data;
})
return serverResponse;
}
}
I got diffrent error:-
POST http://localhost:8080/profile 400
Updated question 2:-
@PostMapping("/profile2")
public void saveProfile(@ModelAttribute ProfileWrapper model) {
logger.info("image: " + model.getImage());
logger.info("profile: " + model.getProfile());
}
Reactjs:-
static postData(selectedFile, replacePhotoPath, profile) {
if (selectedFile) {
let serverResponse;
let formData = new FormData();
formData.append("porofile", profile);
formData.append("file", selectedFile);
formData.append("path", replacePhotoPath);
axios.post('http://localhost:8080/profile', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(res => {
console.log('res:' + res)
serverResponse = res.data;
//this.postProfile(data, selectedCity, history);
})
.catch((error) => {
// handle this error
console.log('error: ' + error);
//setMessageFromServer(error.data)
serverResponse = error.data;
})
return serverResponse;
}
}
This time where was no error, it could reach the endpoint. But the ProfileWrapper model members are null. So the log printed:-
: image: null : profile: null
Then I updated Reactjs as:-
static postData(selectedFile, replacePhotoPath, profile, selectedCity, history) {
if (selectedFile) {
let serverResponse;
let wrappe = {
"profile": profile,
"image" : selectedFile,
"path": replacePhotoPath
}
// let formData = new FormData();
// formData.append("porofile", profile);
// formData.append("file", selectedFile);
// formData.append("path", replacePhotoPath);
axios.post('http://localhost:8080/profile', wrappe, {
// headers: {
// 'Content-Type': 'multipart/form-data'
// }
})
.then(res => {
console.log('res:' + res)
serverResponse = res.data;
//this.postProfile(data, selectedCity, history);
})
.catch((error) => {
// handle this error
console.log('error: ' + error);
//setMessageFromServer(error.data)
serverResponse = error.data;
})
return serverResponse;
}
}
It is the same again no error, but it arrives at the endpoint with the model's member null. To make sure, I debug the frontend code to check that I am filling correct data and it is not null. All looks fine.
Update 3:-
Btw, I removed the String path member from both back and front.
public class ProfileWrapper {
private MultipartFile image;
private Profile profile;
public ProfileWrapper() {
}
public ProfileWrapper( MultipartFile image, Profile profile) {
this.image = image;
this.profile = profile;
}
public Profile getProfile() {
return profile;
}
public void setProfile(Profile profile) {
this.profile = profile;
}
public MultipartFile getImage() {
return image;
}
public void setImage(MultipartFile image) {
this.image = image;
}
}
Btw I updated the endpoint to @RequestBody. Then I got this error:-
[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.springframework.web.multipart.MultipartFile]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of org.springframework.web.multipart.MultipartFile
(no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: (PushbackInputStream); line: 1, column: 269] (through reference chain: com.profile.wrapper.ProfileWrapper["image"])] with root cause
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of org.springframework.web.multipart.MultipartFile
(no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: (PushbackInputStream); line: 1, column: 269] (through reference chain: com.profile.wrapper.ProfileWrapper["image"])