How to send a multipartFile to an api using react and spring - reactjs

Hi I am trying to connect a react-app with an api that i did with react. The problem is that I can not send a multipartFile to the api side. If I do the request with postman, work correctly. But if i do the request in my react-app do not work.
#Spring
Spring code
#PostMapping("/save")
public ResponseEntity<?> save(#RequestParam(required = false) String folderId, #RequestParam MultipartFile multipartFile) throws IOException{
//folder exist??
int id = Integer.parseInt(folderId);
Optional<Folder> folderOpt = folderService.get(id);
if(folderOpt.isEmpty()){
return new ResponseEntity<>("The folder does not exist", HttpStatus.NOT_FOUND);
}
Folder folder = folderOpt.get();
//connect with cloudinary
BufferedImage bi = ImageIO.read(multipartFile.getInputStream());
if (bi == null){ //is it an image??
return new ResponseEntity("Image does not valid", HttpStatus.BAD_REQUEST);
}
Map result = cloudinaryService.upload(multipartFile);
//save in the bd
Image img = new Image(
(String)result.get("original_filename"),
(String)result.get("url"),
(String)result.get("public_id"));
img.setFolder(folder);
imageService.save(img);
return new ResponseEntity<>(HttpStatus.OK);
}
#Postman
Postman request
#React
React code
const [imageSelected,setImageSelected] = useState("")
const uploadImage = (files) =>{
const formData = new FormData();
formData.append("file", files[0]);
console.log(formData)
ImagenServices.postImage(formData,id)
}
return(
<div className={Styles.container}>
<div>
<input type="file" id="myFileField" onChange={(event) => {setImageSelected(event.target.files)}}/>
<button onClick={() => uploadImage(imageSelected)}>Upload image</button>
</div>
</div>
)
#PostImage service
Service code
async postImage(file,idFolder){
let request = await fetch(REST_API_URL + "/save",{
method: "POST",
body:{
'folderId': idFolder,
'multipartFile': file
},
headers:{
'Accept': 'application/json, text/plain, */*',
'Content-Type': false
}},
)
}
}
#Error
console error
ERROR 95787 --- [io-8080-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Current request is not a multipart request] with root cause
org.springframework.web.multipart.MultipartException: Current request is not a multipart request
at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValueInternal(RequestParamMethodArgumentResolver.java:210) ~[spring-web-5.3.22.jar:5.3.22]

Related

"Required request part 'image' is not present in" error in springboot with reactjs

When i try to upload a image in react, and send it to a spring boot api to save the file in a database, I get the following errors in spring boot:
2022-12-04 03:25:28.610 WARN 15080 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'image' is not present]
2022-12-04 03:25:28.631 WARN 15080 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.util.LinkedHashMap<java.lang.String,java.util.List<java.lang.String>>` from Array value (token `JsonToken.START_ARRAY`); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.util.LinkedHashMap<java.lang.String,java.util.List<java.lang.String>>` from Array value (token `JsonToken.START_ARRAY`)<EOL> at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 1]]
Idk how to solve this. I've tried searching around, but havent found any answer. Im also unsure if the problem is in my react code or in my springboot code.
I think my error is in reactjs, because ive seen in other posts for people have somewhat the same problem, that their problem has been their react code. But I havent figured out what exactly might be wrong with my react code. Im also posting my spring boot code in case you may want to look at it,
My react code:
const FileUpload = () => {
const link = "http://localhost:8080/uploadimage?key"
var formData = new FormData()
const [fileName, setFilename] = useState("")
const [tags, setTags] = useState([])
{/* THIS IS CODE FOR SELECTING A FILE TO UPLOAD*/}
{/* IM TRYING TO DEFINE IMAGE BY PUTTING IT IN QUOTES IN FROMDATA.APPEND */}
const handleFile = (e) => {
setFilename(e.target.files[0].name)
console.log("handle file")
console.log(e.target.files[0])
formData.append("image", e.target.files[0])
}
const uploadFile = (e) => {
{/* THIS IS CODE FOR FILE UPLOADING*/}
console.log("sending...")
console.log(formData)
axios.post(
link,
formData, {
header: {
'Content-Type': 'multipart/form-data'
}
})
.then(res => {
console.log(res.data)
})
.catch(error => {
console.log(error)
})
{/* THIS IS CODE FOR SOMETHING ELSE; SOME TAGHANDLING */}
setTimeout(3000)
const taglink = "http://localhost:8080/givetags/" + fileName;
axios.post(taglink, tags)
.then(res => (
console.log(res.data)
))
}
{/* THIS IS CODE IS ALSO FOR SOMETHING ELSE*/}
function updateTags(e) {
const log = {...tags}
log[e.target.id] = e.target.value.split(" ")
setTags(log)
}
return (
<div>
<Container>
<Card.Title className='text-center mb-3'>Upload File</Card.Title>
<Form.Group controlId='file' className='mb-3'>
<Form.Control type='file' onChange={(e) => handleFile(e)}></Form.Control>
</Form.Group>
<Form.Group controlId='tags' className='mb-3'>
<Form.Control onChange={(e) => updateTags(e)} type="text" placeholder='Write tags'></Form.Control>
</Form.Group>
<Button onClick={(e) => uploadFile(e)}>Upload File</Button>
</Container>
<TagsConvention></TagsConvention>
</div>
)
}
export default FileUpload
This is my springboot code:
Controller:
#RestController
public class FileController {
#Autowired
private ImageServiceImpl service;
//==========================For uploading a file======================================
#CrossOrigin(origins = "http://localhost:3000")
#PostMapping("/uploadimage")
public ResponseEntity<?> uploadImage(#RequestParam("image") MultipartFile file) throws IOException {
String uploadImage = service.uploadImage(file);
return ResponseEntity.status(HttpStatus.OK)
.body(uploadImage);
}
#CrossOrigin(origins = "http://localhost:3000")
#GetMapping("/getimage/{fileName}")
public ResponseEntity<?> downloadImage(#PathVariable String fileName){
byte[] file=service.downloadImage(fileName);
System.out.println(file);
return ResponseEntity.status(HttpStatus.OK)
.contentType(MediaType.valueOf(service.getType(fileName)))
.body(file);
}
#CrossOrigin(origins = "http://localhost:3000")
#PostMapping("/givetags/{fileName}")
public ImageData giveImagetags(#PathVariable String fileName, #RequestBody Map<String, List<String>> tags) {
//return service.giveImageTags(fileName, tags);
//return service.giveImageTags(fileName, tags);
System.out.println(tags);
List<String> tagList = tags.get("tags");
return service.giveImageTags(fileName, tagList);
}
#CrossOrigin(origins = "http://localhost:3000")
#GetMapping("/getallimages")
public List<String> getAllImages() {
return service.getAllImages();
}
}
My model for the image:
#Entity
#Table(name = "ImageData")
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class ImageData implements Image{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long imageDataId;
private String name;
private String type;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name="file_has_tag",
joinColumns = {#JoinColumn(name="image_data_id")},
inverseJoinColumns = {#JoinColumn(name = "tag_id")})
#JsonIgnoreProperties("image_data")
private Set<Tag> tags;
#Lob
#Column(name = "image_data",length = 1000)
private byte[] data;
#Override
public String toString() {
return "ImageData{" +
"imageDataId=" + imageDataId +
", name='" + name + '\'' +
", type='" + type + '\'' +
", tags=" + tags +
'}';
}
}
Service function for uploading a file:
public String uploadImage(MultipartFile file) throws IOException {
ImageData imageData = imageDataRepository.save(ImageData.builder()
.name(file.getOriginalFilename())
.type(file.getContentType())
.data(ImageUtils.compressImage(file.getBytes())).build()); //"data" is from the model class
System.out.println(imageData.toString());
if (imageData != null) {
return "file uploaded successfully : " + file.getOriginalFilename();
}
return null;
}
functions in utils class for compressing image
public static byte[] compressImage(byte[] data) {
Deflater deflater = new Deflater();
deflater.setLevel(Deflater.BEST_COMPRESSION);
deflater.setInput(data);
deflater.finish();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
byte[] tmp = new byte[4*1024];
while (!deflater.finished()) {
int size = deflater.deflate(tmp);
outputStream.write(tmp, 0, size);
}
try {
outputStream.close();
} catch (Exception ignored) {
}
return outputStream.toByteArray();
}
Ive tried to change the value of formdata, and the key in "image" in fromdata.append, but I havent figured it out. Ive also tried to search up the problem, but people have had different syntax problems from me, so idk what might be the problem.
There are two questions:
(1)Required request part 'image' is not present, the problem should be the parameter name problem, The #RequestParam("image") prefix must be "image". You can check if some parameter names are image.
(2)JSON parse error: In my opinion, the main cause of the problem is the API: givetags, #RequestBody Map<String, List> tags, which is not translated properly when receiving the react parameter. You can try using List to receive arguments.

getting google oauth to work with flask, react, postgresql. keep getting internal server error and cors errors

I'm trying to get google oauth to work with flask and react. When I run the server and try to log in, the google sign-in window pops up and immediately closes down and I get an internal server error. in my flask terminal I get this error:
raise MissingCodeError("Missing code parameter in response.")
oauthlib.oauth2.rfc6749.errors.MissingCodeError: (missing_code) Missing code parameter in response.
Any thoughts?
app.py
#app.route('/login', methods=['POST'])
#cross_origin()
def login():
google_provider = get_google_provider()
auth_endpoint = google_provider["authorization_endpoint"]
request_uri = client.prepare_request_uri(
authorization_endpoint,
redirect_uri=request.base_url + "/callback",
scope=["openid", "email", "profile"]
)
return redirect(request_uri)
#app.route('/login/callback', methods=['GET', 'POST'])
#cross_origin()
def login_callback():
code = request.json.get("access token")
print("**************")
# print(list(request.args.keys()))
print(request.json)
print("**************")
token, headers, body = client.prepare_token_request(
token_endpoint,
code=code,
authorization_response=request.url,
redirect_url=request.base_url
)
token_response = requests.post(
token_url,
headers=headers,
data=body,
auth=(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET)
)
client.parse_request_body_response(json.dumps(token_response.json()))
userinfo_endpoint = google_provider["userinfo_endpoint"]
uri, headers, body = client.add_token(userinfo_endpoint)
userinfo_response = request.get(uri, headers=headers, data=body)
if userinfo_response.json().get("email_verified"):
unique_id = userinfo_response.json()["sub"]
user_email = userinfo_response.json()["email"]
user_picture = userinfo_response.json()["picture"]
user_name = userinfo_response.json()["given_name"]
user_member_since = datetime.today().strftime('%Y-%m-%d')
else:
print("User email not available or not verified by Google")
user = User(id=unique_id, name=user_name, email=user_email, picture=user_picture, member_since=user_member_since)
if not User.get(unique_id):
User.create(unique_id, user_name, user_email, user_picture, user_member_since)
login_user(user)
redirect(url_for("/new-user-form"))
app.js
googleResponse = (response) => {
const tokenBlob = new Blob([JSON.stringify({access_token: response.accessToken}, null, 2)], {type: 'application/json'});
const options = {
method: 'POST',
body: tokenBlob,
mode: 'cors',
cache: 'default'
}
fetch(`${BASE_URL}/login/callback`, options).then(r => {
if (r.headers.get('Content-Type') === 'text/html; charset=utf-8') {
console.log('error')
return
}
const token = r.headers.get('x-auth-token')
r.json().then(user => {
if (token) {
this.setState({isAuthenticated: true, user, token, message: `${user.name}`})
console.log(token)
}
});
})
}
onFailure = (error) => {
alert(error.data)
}
<Route path='/login'>
<GoogleLogin
clientId={config.GOOGLE_CLIENT_ID}
buttonText="Login"
onSuccess={this.googleResponse}
onFailure={this.onFailure}
/>

How to upload file along with json meta data using rest api

I have requirement to upload xlsx file on server along with some json data(both has to be done in one request). I was able to upload just file using multipart/form-data, but when I tried add JSON data to the same request, request is failing with org.apache.commons.fileupload.FileUploadBase$InvalidContentTypeException: the request doesn't contain a multipart/form-data or multipart/mixed stream
exception. Below is my code.
Client side code
var method = 'POST';
$.ajax({
type: method,
url : "rest/file/upload",
transformRequest: function () {
var formData = new FormData();
formData.append("model", JSON.stringify(jsonData));
formData.append("file",document.getElementById("fileForm"));
return formData;
},
enctype : 'multipart/form-data',
processData : false,
contentType : false,
success: function (data) {},
error: function (data) {}
});
model is the JSON data & file is xlsx file which is to be uploaded.
Server Side Code
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.TEXT_PLAIN)
public Response uploadResumableISOFile(#Context HttpServletRequest request, #Context UriInfo uri,
#Context HttpHeaders headers, #Context HttpServletResponse response) throws IOException {
ServletFileUpload uploader = null;
try {
DiskFileItemFactory fileFactory = new DiskFileItemFactory();
uploader = new ServletFileUpload(fileFactory);
List<FileItem> fileItemsList = uploader.parseRequest(request);
Iterator<FileItem> fileItemsIterator = fileItemsList.iterator();
while (fileItemsIterator.hasNext()) {
FileItem fileItem = fileItemsIterator.next();
File file = File.createTempFile("TEMP_", ".xlsx");
fileItem.write(file);
System.out.print("File " + fileItem.getName() + " uploaded successfully.");
}
System.out.println("File uploaded to successfully...");
return Response.status(Response.Status.OK).build();
} catch (Exception e) {
System.out.println(e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Failed to upload file.").build();
}
}
Please let me know if something is missing.

How to open Rest API Post response in New window using Angular Js

I am making a rest API call using Angular. My Rest API look like as below:
#RequestMapping(value = "/getPDF/{projectId}", method = RequestMethod.POST)
public ResponseEntity<byte[]> generateReport(#PathVariable("projectId") long projectId, #RequestBody Object vo, final HttpServletRequest request) {
vo.setProjectId(projectId);
byte[] pdf = blueprintService.generateBluePrint(vo);
LOG.debug(new StringBuilder("Generating Blueprint for VO: ").append(vo).toString());
String fileName = null;
try {
ProjectDetailsVO pdvo = projectSetupService.getProjectDetails(vo.getProjectId());
fileName = new StringBuilder(pdvo.getClientName()).append("_")
.append(pdvo.getProjectName()).append("_")
.append(System.currentTimeMillis()).append(".pdf")
.toString();
} catch (Exception e) {
}
if (fileName == null || fileName.trim().isEmpty())
fileName = new StringBuilder("Project_")
.append(vo.getProjectId()).append("_")
.append(System.currentTimeMillis())
.append(".pdf").toString();
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/pdf");
String userAgent = request.getHeader("User-Agent");
if (userAgent != null && !(userAgent.contains("Firefox") && userAgent.contains("Mac"))) {
LOG.debug("Inline BP Content");
headers.add("Content-Disposition", new StringBuilder("inline; filename=\"").append(fileName).append("\"").toString());
} else {
LOG.debug("Attached BP Content");
headers.add("Content-Disposition", new StringBuilder("attachment; filename=\"").append(fileName).append("\"").toString());
}
if (pdf != null)
headers.setContentLength(pdf.length);
return new ResponseEntity<byte[]>(pdf, headers, HttpStatus.OK);
}
}
So server is setting file name for the PDF which I want to be the name of the generated PDF.
I tried below angular code:
success: function (data, status, headers, config) {
$modalInstance.close();
var file = new Blob([data], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
}
It works fine but it open the pdf of it's own name. Which I think, since Angular is converting the response into PDF. Hence Headers are getting excluded.
Is there any way to make a post request so it will open a PDF in new browser tab some code like as below:
$http.post{
url: myRestURL,
data: postbodyData,
taget: _blank
}
which will open my rest URL in new tab and show the PDF in browser.
Thank you.

How can I send a file from the server to client using REST (JAX-RS Jersey)?

I want to send a file from my server side (EJB) using REST Jersey (JAX-RS).
I am trying with the following code,
Public Response getFiles() {
File file = new File(fileName);
FileOutputStream dest = new FileOutputStream(file);
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));
out.putNextEntry(new ZipEntry(fileName));
final ResponseBuilder response = Response.ok(out);
response.header("Content-Type", "*/*");
response.header("Content-Disposition", "attachment; filename=" + file.getName() + ".zip");
return response.build();
}
But I am getting the exception message
type class java.util.zip.ZipOutputStream, and MIME media type */* was not found
SEVERE: The registered message body writers compatible with the MIME media type are:
Also tried with "Content-Type" , "application/octet-stream", "application/x-www-form-urlencoded" and multipart/form-data
But none of them is working.
Use application/zip.
#GET
#Produces("application/zip")
public Response getZip() {
final File f = new File("/tmp/foo.zip");
ResponseBuilder response = Response.ok((Object) f);
response.header("Content-Disposition", "attachment; filename=" + f.getName());
return response.build();
}
application/octet-stream + gzip
#GET
#Path("/getFiles")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFiles() {
StreamingOutput stream = new StreamingOutput() {
#Override
public void write(OutputStream output) throws IOException, WebApplicationException {
String filePath = "/yourFile.pdf";
java.nio.file.Path path = Paths.get(filePath);
byte[] data = Files.readAllBytes(path);
output.write(data);
output.flush();
}
};
return Response.ok(stream).build();
}
and a jersey filter added to web.xml
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.GZIPContentEncodingFilter</param-value>
</init-param>
when making the request:
send a header of "Accept" with value of "application/octet-stream"
and a header of "Accept-Encoding" with value of "gzip"

Resources