I built my API using spring boot.
#RequestMapping(value = "/v1/users/profile-picture/update", method = RequestMethod.POST)
public Object updateProfilePicture(Principal principal, #ModelAttribute UpdateProfilePictureDTO profile_picture){
Long user_id = accessTokenHandler.getIdByPrincipal(principal);
if(user_id == null)
return new DefaultResponseDTO(201,ResponseStatus.INVALID_USER,"No such user.");
if(profile_picture.getProfile_picture() == null)
return new DefaultResponseDTO(201,ResponseStatus.MISSING_INPUTS,"Profile Picture is missing.");
return userService.updateProfilePicture(user_id, profile_picture.getProfile_picture());
}
I want to send an image file to this controller. I tried with react.js. First I build formData and append the image into form data.
let formData = new FormData()
formData.append(
'profile_picture',
newFileList[0],
)
React API end point,
export async function profilePictureUpdate(formData) {
//image must be send as formdata
const response = await http.post(
apiEndPoint + '/profile-picture/update',
formData,
{
headers: {
Authorization: `Bearer ${getJwt()}`,
"Content-type": "multipart/form-data",
}
});
console.log("response of profile picuter", response);
return response
}
But when submit an image file, get a 400 bad request. How can I solve this?
Spring Boot (2.4.x): replace #ModelAttribute UpdateProfilePictureDTO profile_picture with #RequestParam(value = "profile_picture") MultipartFile file and then process the file. Make sure MultipartAutoConfiguration enabled (docs). If you registered a servlet via ServletRegistrationBean add multipart config to it:
servletRegistrationBean.setMultipartConfig(new MultipartConfigElement("/tmp",
multipartProperties.getMaxFileSize(),
multipartProperties.getMaxRequestSize(),
multipartProperties.getFileSizeThreshold()));
Related
I'm trying to consume a Spring-Boot API using React.
It worked fine on the server side and lately I had to add #CurrentUser UserPrincipal userPrincipal as a parameter and it's still working fine.
The problem is when trying to send Http requests it starts giving me a NullPointerException and I expected that because I didn't add anything inside the react function.
What must I add in the frontend?
Backend:
#CrossOrigin(origins = "*", maxAge = 3600)
#PostMapping("/FileUpload")
public void fileUpload(#RequestParam("file") MultipartFile file, #CurrentUser UserPrincipal userPrincipal,
Patient patient, Observation observation) {
String result = hl7v22cs.fileParser(file);
if (result.contains("|2.2")) {
hl7v22cs.fileParser(file);
hl7v22cs.textParser(file);
hl7v22cs.extractPatientSegment(userPrincipal, patient, file);
hl7v22cs.extractObservationSegment(observation, file);
}
}
Frontend:
class ConverterService {
convert(file) {
let formData = new FormData();
formData.append("file", file);
return axios.post("http://localhost:8080/api/FileUpload", formData, {
headers: {
"Content-Type": "multipart/form-data",
}
});
}
}
I have a very annoying issue. I have this Javascript code inside a React component:
let entityJson = JSON.stringify(entityObject);
fetch("http://localhost:8080/add", {
method: "POST",
mode: "no-cors",
headers: { "Content-Type" : "application/json charset=UTF-8"},
body: entityJson
}).then(data => console.log(data));
This is sending a request to the follow function in an Spring Boot Rest controller:
#PostMapping(produces = "application/json")
public AddEntityResponse newEntity(#RequestBody String person, HttpServletResponse response) {
AddEntityResponse respons = new AddEntityResponse(0,0);
Gson jsonReader = new Gson();
try{
Person newPerson = jsonReader.fromJson(person, Person.class);
personStore.addPerson(newPerson);
respons.setStatus(1);
respons.setId(newPerson.getId());
}catch(Exception e){
System.out.println(e.toString());
}
return respons;
}
But regardless of what I add, this is the request I am getting an empty response, so I guess the issue is in the Java code. I am learning this stuff now, started today so sorry if this seem a bit stupd.
I am trying to send an API request through my React frontend to Spring backend. When I send the request I get this error:
Could not resolve parameter [0] in private org.springframework.http.ResponseEntity com.example.bottlecap.controllers.BottlecapController.entryForm(com.example.bottlecap.domian.Bottlecap,org.springframework.web.multipart.MultipartFile): Content type 'application/octet-stream' not supported
However, when I set up the request using Postman it goes through fine. I presume there may be an issue with how I am setting up my FormData on the React end. However, I have had little luck figuring it out.
My API is supposed to recieve an object that holds data about my submission as well as an image that goes with the submission. In my Postman request, I am creating a form data that holds a JSON file that holds all the object data and a random image just for testing. As I said, the requets goes through fine with this. However, in the frontend code, I am parsing through the object data as Json and adding it to a FormData as well as adding the image to the FormData.
Here is my Spring Controller:
#RequestMapping(path ="/bottlecap/entry", method = RequestMethod.POST, consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_OCTET_STREAM_VALUE})
private ResponseEntity entryForm(#RequestPart("cap") Bottlecap cap, #RequestPart("file") MultipartFile image){
System.out.println(cap);
cap.toString();
System.out.println("Test");
return ResponseEntity.ok().build();
}
Here is my react Frontend form submission handler:
handleSubmit = event =>{
console.log(this.state.page);
console.log(this.state.page);
event.preventDefault();
const cap ={
"name":this.state.name,
"brand":this.state.brand,
"yearMade":parseInt(this.state.yearMade),
"country": this.state.country,
"description":this.state.description,
"yearFound":parseInt(this.state.yearFound),
"isAlcoholic":"true"
};
const stringCap = JSON.stringify({cap});
console.log(cap);
var formData = new FormData();
formData.append('cap', JSON.parse(stringCap));
formData.append('file',this.state.imageFile)
axios.post('http://localhost:8080/bottlecap/entry', formData, {headers:{'Content-Type':'multipart/form-data'}})
.then(res=>{
console.log(res);
console.log(res.data);
//window.location = "/success"
this.setState({pageDone:true})
this.setState({pageLoading:true})
})
}
Here is a screenshot of my Postman request if it may help.
Also here is the contents of the json file I am sending through on Postman, if it may help as well.
{"name":"post-test",
"brand":"post-test",
"yearMade":1000,
"country":"post-test",
"description":"post-test",
"yearFound":1000,
"isAlcoholic":"true"}
The last change I did was adding a header to the axios API request, but still no luck.
In postman, for parameter named cap, you're sending a .json file. But in your reactjs code, you're doing
formData.append('cap', JSON.parse(stringCap));
JSON.parse will create a javascript object which is not what your backend is expecting. You need to send it as a JSON file.
Not tested, but this might give you the idea.
const json = JSON.stringify(cap);
const blob = new Blob([json], {
type: 'application/json'
});
var formData = new FormData();
formData.append('cap', blob);
formData.append('file', this.state.imageFile)
axios.post('http://localhost:8080/bottlecap/entry', formData, {headers:{'Content-Type':'multipart/form-data'}})
.then(res=>{
console.log(res.data);
}
This is my fetch sample in Vue3, and it works thanks to you. Thanks!
let formData = new FormData();
formData.append('productJsonData', new Blob([JSON.stringify(productJsonObject)], {type: 'application/json'}));
formData.append('file', image); // This image comes from an <v-file-input> TAG
const response = await fetch(
`http://.../addProduct`,
{
headers: { 'Accept': 'application/json' },
method: 'POST',
body: formData
}
);
const responseData = await response.json();
if (!response.ok) {
console.log('REST error: [' + responseData.error + ']')
throw error;
}
I'm using AngularJS to make my front end and Java with Spring Boot to make my back end. I'm trying to import/upload a xlsx, xls, or ods file from the Angular to my Java, but whatever I do, the request doesn't send my file!
Java endpoint:
#PostMapping(value = "/upload/{type}")
#ResponseBody
private ResponseEntity<List<Rota>> importFile(#PathVariable("type") String type,
#RequestParam(required = false, value = "file") MultipartFile fileParam,
#RequestBody MultipartFile file) {
System.out.println("File: " + file.getName());
if(type.toUpperCase().equals("XLSX")){
System.out.println("XLSX!");
}else if(type.toUpperCase().equals("XLS")){
System.out.println("XLS!");
}else if(type.toUpperCase().equals("ODS")){
System.out.println("ODS!");
}else{
System.out.println("OPS!");
return new ResponseEntity<>(new ArrayList<>(), HttpStatus.UNSUPPORTED_MEDIA_TYPE);
}
return new ResponseEntity<>(new ArrayList<>(), HttpStatus.OK);
}
My request-id made using an Angular class prepared to only make requests. I'll post here the code that we use normally in the project and the code that actually worked but I can't use it.
DataFactory:
DataFactory.POST = function (url, entity, config = null) {
if (url && entity) {
return $http
.post(url, entity, config)
.then(res => $q.resolve(res.data), error => $q.reject(error));
}
};
The code that actually worked:
var xhr = new XMLHttpRequest;
xhr.open('POST', `${URL.CTM_ODS()}/rotas/upload/${type}`, true);
xhr.send(formData);
When I use Postman, sending the file through the body, the back end receives null, but when I use form-data from Postman, works fine!
Using the DataFactory I got the following stack on my back end:
WARN 16796 --- [p1002886236-126] org.eclipse.jetty.http.HttpParser : badMessage: java.lang.IllegalStateException: too much data after closed for HttpChannelOverHttp#78fd8670{r=2,c=false,a=IDLE,uri=}
Found the answer in this video: https://www.youtube.com/watch?v=vLHgpOG1cW4
My problem was that the AngularJS deserialize the file! So, what I've made was just put a config object saying to not do that:
DataFactory.POST(`${URL.CTM_ODS()}/rotas/upload/${type}`, formData, { transformRequest: angular.indentity, headers: { 'Content-Type': undefined } }).then(response => {
delete vm.importacao.arquivoCsv;
console.log('Response: ', response);
LoadingManager.hide();
});
As you can see, the difference is on the header object, can you see that we pass the content type as undefined and transformRequest: angular.indentity? That worked for me! If anyone has other way to do so, feel free to comment! Thanks and have a nice day!
I have to put the API Key in the request header as:
Authorization: Bearer "YOUR API KEY"
This is my code (I'm not sure where to put the header and how)
Future<Stream<Book>> getBooks() async {
var url = ‘example_url’
var client = http.Client();
var streamedResponse = await client.send(
http.Request(‘get’, Uri.parse(url))
);
return streamedResponse.stream
.transform(utf.decoder)
.transform(json.decoder)
.expand(jsonBody) => (jsonBody as Map)[‘results’] )
.map((jsonBook) = Book.fromJson(jsonBook));
}
The Flutter docs https://flutter.io/cookbook/networking/authenticated-requests/ says to use this format for authenticated requests but this is not for streams, this returns a future of an object (Book)
Future<Book> fetchPost() async {
final response = await http.get(
'https://jsonplaceholder.typicode.com/posts/1',
headers: {HttpHeaders.authorizationHeader: "Place your_api_token_here"},
);
final responseJson = json.decode(response.body);
return Book.fromJson(responseJson);
}
You can add custom headers after you created the Request
final request = http.Request('GET'), url)
..headers.addAll(myHeaders);
I have made a custom header using http.Request as follow bellow :
final url =
'https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-10.6.0-amd64-xfce-CD-1.iso';
final request = Request('GET', Uri.parse(url));
request.headers.clear();
request.headers.addAll({"content-type":"application/json"});