How to share image between Spring-Boot and React - reactjs

I am developing full stack internet-market and i need to send image to my Spring Rest Controller and save it to db. How to do that? I tryed something like that:
setFile(e.target.files && e.target.files[0])
This file is file from <input type="file"/>
After that i send this file to my put method
DishesService.addDish(dish, file)
static async addDish(dish: IDish, file: any) {
try {
await axios.post<IDish>('http://localhost:8080/dishes', dish)
.then(response => {
this.updateDishImage(response.data.id, file)
})
} catch (e) {
console.log('произошла ошибка при добавлении блюда')
}
}
static async updateDishImage(id: number | undefined, image: any) {
try {
await axios.put('http://localhost:8080/dishes/' + id, {}, {
params: {
file: image
}
})
} catch (e) {
console.log('Произошла ошибка при добавлении картинки к блюду')
}
}
And my Spring Boot Put method:
#PutMapping("{dishId}")
public ResponseEntity<DishEntity> updateDishImage(#PathVariable Long dishId, #RequestParam("file") MultipartFile file) {
DishEntity updateDish = dishService.updateDishImage(file, dishId);
return ResponseEntity.ok(updateDish);
}
I get exception:
org.springframework.web.multipart.MultipartException: Current request is not a multipart request

You are missing the headers:
headers: {
"Content-Type": "multipart/form-data",
}
in your axios call

Try this :
#RequestMapping(path = "{dishId}", method = PUT, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
public ResponseEntity<DishEntity> updateDishImage(#PathVariable Long dishId, #RequestPart("file") MultipartFile file) {
// your logic
}
You can also encode you images into base64, then send them to the server-side as string.

Related

SOLVED - How to open Streamable File as pdf in React client

I got this data from backend when try to get a pdf file:
`%PDF-1.7 %���� 5 0 obj <</Filter/FlateDecode/Length 823>>stream x���MS�0���{l���)&���#CCK'!%�ӿߕmb���;�y�Ҿ��K��H�����aN��q��%�Iz&#�i�T
<......>
1950
%EOF\`
How can REACT read and open this as pdf file in a new tab?
NOTE: I'm able to see the PDF file content in postman when call backend endpoint.
I tried this:
Backend controller (Nestjs):
#Get('/getPDF/:uuid')
async getFile(
#Param('uuid') uuid: string,
#Response({ passthrough: true }) res,
): Promise<StreamableFile> {
const resp = await this.service.downloadPDF(uuid);
if (!resp) {
return null;
}
res.header('Content-Type', `application/pdf`);
res.header('Content-Disposition', `attachment; filename="${resp.fileName}`);
return new StreamableFile(resp.buffer); // resp.buffer === Uint8Array
}
Frontend (REACT):
This will call backend api to get pdf file:
getPDF(uuid: string): Promise<AxiosResponse<Blob>> {
return this.httpClient.get(`${this.apiUrlPath}/getPDF/${uuid}`, {
responseType: 'blob',
});
}
This was supposed to render the pdf file
const response = await api.getPDF(uuid);
window.open(URL.createObjectURL(response.data));
I got this error:
TypeError: Failed to execute 'createObjectURL' on 'URL': Overload resolution failed.
UPDATED
Change AxiosResponse type from Blob to ArrayBuffer and create a new Blob from that buffer, solves the issue
This works:
getPDF(uuid: string): Promise<AxiosResponse<ArrayBuffer>> {
return this.httpClient.get(`${this.apiUrlPath}/getPDF/${uuid}`, {
responseType: 'arraybuffer',
});
}
const response = await api.getPDF(uuid);
const blob = new Blob([response.data], { type: "application/pdf" });
window.open(URL.createObjectURL(blob));
Thanks amir sarfar
Try passing a blob to createObjectURL:
const response = await api.getPDF(uuid);
const blob = new Blob([response.data], { type: "application/pdf" });
window.open(URL.createObjectURL(blob));

ReactJS API request failing

I am developing a react app using Spring Boot backend.
I am not very friendly with Java or Spring Boot and now I am stuck with an issue.
Bellow is backend method code which is handling the request
#RestController
#RequestMapping("/toys")
public class ToysController {
#Autowired
private ToysService toysService;
#CrossOrigin(origins = "*")
#PostMapping("/addtoy")
public ResponseEntity<Toys> addToy(#RequestParam("file") MultipartFile file,
#RequestParam("toyName") String toyName,
#RequestParam("toyDescription") String toyDescription,
#RequestParam("toyPrice") Long toyPrice,
#RequestParam("quantity") int quantity,
#RequestParam("availability") Boolean availability,
#RequestParam("sellerId") Long sellerId) throws IOException{
Toys toy = new Toys();
toy.setToyName(toyName);
toy.setToyDescription(toyDescription);
toy.setQuantity(quantity);
toy.setToyPrice(toyPrice);
toy.setAvailability(availability);
toy.setSellerId(sellerId);
toy.setToyImage(ImageEncoderDecoder.compressBytes(file.getBytes()));
toy.setImageName(file.getOriginalFilename());
Toys toyRes = toysService.addToy(toy);
if(toyRes!=null) {
toyRes.setToyImage(ImageEncoderDecoder.decompressBytes(toyRes.getToyImage()));
return new ResponseEntity<Toys>(toyRes,HttpStatus.OK);
}
else {
return new ResponseEntity<Toys>(HttpStatus.NO_CONTENT);
}
}
}
Below are the request details I am supposed to use
API: http://localhost:8081/toys/addtoy
Method: POST
Body:
[{"key":"toyName","value":"Car","type":"text","enabled":true},
{"key":"toyDescription","value":"small car 6 month old","type":"text","enabled":true},
{"key":"toyPrice","value":"600","type":"text","enabled":true},
{"key":"quantity","value":"2","type":"text","enabled":true},
{"key":"availability","value":"true","type":"text","enabled":true},
{"key":"file","type":"file","enabled":true,"value":[]},
{"key":"sellerId","value":"1","type":"text","enabled":true}]
Response: Status code 200
Following is how I am trying to hit the API
export const addToy = toy => {
const requestOptions = {
mode: 'cors',
method: 'POST',
headers: {
"Content-Type": "multipart/form-data; boundary=%%",
'Access-Control-Allow-Origin' : '*'
},
body: toy
};
fetch(`${API}/toys/addtoy`, requestOptions) // API = 'http://localhost:8081'
.then(response => {
if(response.status === 200)
console.log('Toy Inserted');
console.log('Resopose : ', response);
})
.catch(err => {
console.log('Error while inserting toy : ', err);
})
}
Calling the above method
const handleSubmit = e => {
e.preventDefault()
let formData = new FormData()
formData.append('toyName', toyName)
formData.append('toyDescription', toyDesc)
formData.append('toyPrice', parseInt(toyPrice))
formData.append('quantity', parseInt(toyQty))
formData.append('availability', parseInt(toyQty) > 0)
formData.append('file', image)
formData.append('sellerId', parseInt(loggedIn.loggedInUser.userId))
addToy(formData)
}
The response I am getting back
body: ReadableStream
locked: false
bodyUsed: false
headers: Headers {}
ok: false
redirected: false
status: 400
statusText: ""
type: "cors"
url: "http://localhost:8081/toys/addtoy"

View pdf from spring get request via react/axios

I have a spring endpoint that serves a pdf as a byte[] and a React ui that is getting a 406 when I try to call the endpoint.
spring endpoint:
#GetMapping(value = "report/{report_id}", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<InputStreamResource> generateReviewTaskReport(
HttpServletResponse response,
#PathVariable("report_id") String reportId,
#RequestAttribute(USER_ID) String loginId) {
byte[] report = reportService.generateReport(reportId, loginId);
ByteArrayInputStream inputStream = new ByteArrayInputStream(report);
HttpHeaders headers = new HttpHeaders();
headers.setContentLength(report.length);
headers.add("Content-Disposition", "inline;filename=" + reportId + "_report.pdf");
return ResponseEntity
.ok()
.headers(headers)
.contentType(MediaType.APPLICATION_PDF)
.body(new InputStreamResource(inputStream));
}
I've tried:
headers.add("Content-Disposition", "attachment;filename=" + reportId + "_report.pdf");
same result.
react request:
export const getReport = (reportId = '') => (dispatch) => {
const report = `${apiConfig.reportUrl}${reportId}`
const promise = axios.get(report,
{
responseType: 'blob',
headers: {
'Accept': 'application/pdf'
}
})
return dispatch({
type: GET_REPORT,
payload: promise,
})
}
case GET_REPORT:
if (payload.data) {
const report = new Blob([payload.data])
reportUrl = URL.createObjectURL(report)
window.open(reportUrl, "_blank")
}
I've tried responseType: 'bufferArray', returning a plain byte[] from my spring endpoint, always get a 406. I'm guessing it's because I have the wrong mime type in my 'Accept' header. I've tried 'application/pdf' and '*/*', same result. What headers do I need to accept an InputStreamResource or byte[]?
With postman I can download the file just fine.
my config:
#Component
public class WebConfiguration extends WebMvcConfigurationSupport {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(byteArrayHttpMessageConverter());
converters.add(new ResourceHttpMessageConverter());
}
#Bean
public HttpMessageConverter byteArrayHttpMessageConverter() {
ByteArrayHttpMessageConverter arrayHttpMessageConverter =
new ByteArrayHttpMessageConverter();
arrayHttpMessageConverter.setSupportedMediaTypes(getSupportedMediaTypes());
return arrayHttpMessageConverter;
}
private List<MediaType> getSupportedMediaTypes() {
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.APPLICATION_PDF);
mediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
return mediaTypes;
}
}
A general solution, but i think in you'r case it should works fine ;)
axios({
url: 'http://api.dev/file-download', //your url
method: 'GET',
responseType: 'blob', // important
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.pdf'); //or any other extension
document.body.appendChild(link);
link.click();
});
gist: https://gist.github.com/javilobo8/097c30a233786be52070986d8cdb1743
Full credits to: https://gist.github.com/javilobo8

ionic 3 acces to json key

i can't access to a key of a json response from a restful web service.
{"_body":"{\"values\": {\"user_id\":\"1\",\"name\":\"fred test\",\"email\":\"fred#test.test\",\"username\":\"fredtest\",\"token\":\"d5f66a06ec809d70d0c52842df8dc0011d7d1ad0f2d56f50d3123da17a2489fe\"}}","status":200,"ok":true,"statusText":"OK","headers":{"pragma":["no-cache"],"content-type":["text/html;charset=UTF-8"],"cache-control":["no-store"," no-cache"," must-revalidate"],"expires":["Thu"," 19 Nov 1981 08:52:00 GMT"]},"type":2,"url":"http://localhost/PHP-Slim-Restful/api/login"}
I would like to acces to 'values' in this function: (this.responseData.values)
login(){
console.log('login'+ this.userData);
// Your app login API web service call triggers
this.authService.postData(this.userData,'login').then((result) => {
this.responseData = result;
console.log('userdata : '+ temp);
if(this.responseData.values){
console.log('response: ' + this.responseData);
localStorage.setItem('userData', JSON.stringify(this.responseData));
this.navCtrl.push(TabsPage);
}
else{
this.showToastWithCloseButton()
}
}, (err) => {
console.log('erreur : '+err);
});
}
I have an error undifined!
Can you help me?
I have used Observable to return json data and using the subscribe function in my method and using response.json() to convert the JSON reponse from RESTful webservices.
My component method,
import {Http, Headers, Response, RequestOptions} from '#angular/http';
import {Observable} from 'rxjs/Rx';
var response = this.service.post('deleteUserDetails/'+this.selectedUserId, null);
response.subscribe((res) => {
var response = res.json();
});
Service Post method,
post(url: string, data : any): Observable<any> {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
let options = new RequestOptions({ headers: headers});
return this.http.post(url, data,{headers: headers});
}
I think this might be helpful for your query.
You can make a for in your JSON and access the return values of your post. Something like that.
"this.responseData = result.json();" -> Return JSON. Make a for.
Example:
public postData(data, url: string) {
this.http.post(url, data).toPromise().then(res => {
let responseData = res.json();
if (responseData) {
for (var item of responseData) {
//Implments
}
}
}, (err) => {
});
}

File upload returns 200 but file not uploaded (express to spring)

I am trying to upload a file from my local uploads folder to an external web server (Java Spring) but I can't seem to get it to work. I am getting a 200 Ok status return but when I check, the file has not been uploaded.
Here is my code for reference:
var form = new FormData();
form.append('my_field', 'my value');
form.append('my_buffer', new Buffer(10));
form.append('my_logo', request('http://localhost:8080/' + req.files.file.path));
request({
url: someDomain + '/proj/new/deliveryAttachment',
method: "POST",
headers: {
'Accept' : 'application/json, text/plain, */*',
'Content-Type': 'multipart/form-data'
},
jar: getJar(),
qs: {
pid: req.query.id
},
formData: {
deliveryAttachment: form
}
}, function (error, response, body) {
res.send(body);
});
And here is the Java Spring controller:
#RequestMapping(value = "proj/new/deliveryAttachment", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
public String insertDeliveryAttachment(#RequestParam("pid") long pid,
#RequestParam("deliveryAttachment") MultipartFile file) {
try {
DeliveryAttachment a = new DeliveryAttachment(file.getOriginalFilename(), pid);
ps.insertDeliveryAttachment(a, file.getBytes());
return String.valueOf(a.id);
} catch (IOException e) {
return "-1";
}
}
Any help would be appreciated!
EDIT
I have screencapped the console log and it seems that it can only pass through the middleware API then to the part where it gets the file from the uploads folder. It doesn't proceed to the request.post though.
To retrieve file please process like this :
#RequestMapping(value = "proj/new/deliveryAttachment", method =RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
public String insertDeliveryAttachment(#RequestParam("pid") long pid,
#RequestPart("deliveryAttachment") MultipartFile file) // This is the key annotation to use
{
//Your code here
}

Resources