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

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.

Related

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

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]

Angularjs : call to REST API to get a docx document from server

I am trying to call a service from angularjs that produces a docx document.
Angularjs is supposed to display the save prompt of the web browser, and then save the document.
When I open the saved document, what I get in the docx file is :
Undefined
Api rest :
#RequestMapping(value = "/create-avenant",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public void getAvenant(#RequestBody AvenantDTO avenant, HttpServletResponse response) {
contratService.createAvenant(response, avenant);
}
service produces a XWPFDocument and send to browser :
private void sendDocToBrowser(HttpServletResponse response, XWPFDocument doc) throws IOException {
try
{
byte[] buffer = new byte[8192];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
doc.write(baos);
response.setHeader("Content-Disposition", "attachment;filename=myDoc.docx");
response.setContentType("application/docx");
ServletOutputStream outputStream = response.getOutputStream();
baos.writeTo(outputStream);
outputStream.flush();
}
finally
{
outputStream.close();
}
}
Angularjs :
Avenant.create(avenant,function(result){
var blob = new Blob([result.body], { type: 'application/docx' });
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'file.docx';
link.click();
})

HTTP 204 error when sending File in response REST

This is my write to excel method which returns javax.ws.rs.core.Response
public Response writeToExcel(UserDeatilsVOWrapper listBook) {
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet spreadsheet = workbook.createSheet("Resource Information");
int rowCount = 0;
createHeaderRow(spreadsheet);
for (UserDetailsVO detailsVO : listBook.getUserDetailsList()) {
Row row = spreadsheet.createRow(++rowCount);
writeBook(detailsVO, row);
}
Response response = null;
try (FileOutputStream outputStream = new FileOutputStream(new File("ResourceInformation.xlsx"))) {
workbook.write(outputStream);
// header required to enable download pop-up and set file name
Response.ok().header("Content-Disposition", "attachment; filename=" + "ResourceInformation.xlsx").build();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return response;
}
This is my web service:
#POST
#Path(WebServiceConstants.DOWNLOAD_EXCEL)
#Consumes(MediaType.APPLICATION_JSON)
public Response getFile(UserDeatilsVOWrapper wrapper) {
Response respose=new ExportToExcel().writeToExcel(wrapper);
return respose;}
I get a HTTP204 error. I'm using postman. I know, I'm doing a big mistake in write to excel method and when trying to send file along with response.
Also is there any possible way to write a file object on REST response without saving file on server? I'm doing terrible in here. any help is appreciated.
I do not see where you set your file to the response. Normally you would do something like this
File file = new File("ResourceInformation.xlsx"))
// Do your excel-writing here...
ResponseBuilder response = Response.ok((Object) file);
response.header("Content-Disposition", "attachment; filename=" + "ResourceInformation.xlsx");
return response.build();

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