I have angular2 front-end and Dropwizard back-end. I'm trying to upload a picture from front-end to back-end.
My html code:
<input type="file" name="file" (change)="fileChange($event)">
My component:
fileChange(event) {
let fileList: FileList = event.target.files;
if (fileList.length > 0) {
let file: File = fileList[0];
let formData:FormData = new FormData();
formData.append('file', file);
this.siteDescriptionService.sendPhoto(formData).subscribe(value => {
console.log("value", value);
});
}
}
My service:
sendPhoto(data): Observable<any> {
return this.http.postPhoto('api/site/savePhoto', data, null).map(res => res);
}
My http interceptor:
postPhoto(url: string, params?: any, options?: RequestOptionsArgs): Observable<any> {
this.beforeRequest();
let headers = new Headers();
headers.append('Content-Type', 'multipart/form-data');
let reqOptions = new RequestOptions({ headers: headers });
return super.post(this.getFullUrl(url), params, reqOptions)
.catch(this.onCatch)
.do((res: Response) => {
this.onSuccess(res);
}, (error: any) => {
this.onError(error);
})
.finally(() => {
this.onFinally();
});
}
The request is being send with such payload:
------WebKitFormBoundaryAz4AnN4lFPWKUvmH
Content-Disposition: form-data; name="file"; filename="logo.png"
Content-Type: image/png
------WebKitFormBoundaryAz4AnN4lFPWKUvmH--
And on my server I have:
#POST
#Timed
#Path("savePhoto")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
public Response uploadFile(InputStream uploadedInputStream) throws IOException {
String uploadedFileLocation = "/tmp/photo1.png";
FormDataMultiPart part = new FormDataMultiPart().field("file", uploadedInputStream, MediaType.TEXT_PLAIN_TYPE);
FormDataBodyPart p = part.getField("file");
InputStream i = (InputStream) p.getEntity();
writeToFile( i, uploadedFileLocation);
String output = "File uploaded to : " + uploadedFileLocation;
return Response.ok(output).build();
}
private void writeToFile(InputStream uploadedInputStream, String uploadedFileLocation)
throws IOException {
int read;
final int BUFFER_LENGTH = 1024;
final byte[] buffer = new byte[BUFFER_LENGTH];
OutputStream out = new FileOutputStream(new File(uploadedFileLocation));
while ((read = uploadedInputStream.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
out.flush();
out.close();
}
Everything is fine, file is being saved, but it's saved with the whole request payload, including Content-Disposition, Content-Type headers, etc., and therefore the file becomes "broken".
How can I remove the Content-Disposition header from file?
When you use an InputStream parameter, you're saying you want to whole request body. If you just want a single part, you need to annotate it with #FormDataParam with the name of the part
public Response uploadFile(#FormDataParam("file") InputStream file,
#FormDataParam("file") FormDataContentDisposition fdcd) {
String filename = fcdc.getFileName();
// You don't need to create the FormDataMultiPart
// just save the InputStream parameter
}
In order for this to work, you also need to to register the MutliPartFeature
env.jersey().register(MultiPartFeature.class);
Related
I could see many related topics, but I have a specific problem. I am using spring boot controller to download a zip file. I am able to download the file when it is http verb get, but as I have to pass a big json payload I changed to post. Since then instead of downloading it as file it is responding the contents of the file with some ascii characters. Below is the method in controller for downloading the file.
#ApiResponses(value = { #ApiResponse(code = 404, message = "file could not be found"),
#ApiResponse(code = 200, message = "File was created sucessfully") })
#PostMapping(path="/download-file/1.0", produces="application/zip")
public ResponseEntity<InputStreamResource> downloadFile(
#ApiParam(value = "File creation contents", required = true) #RequestBody InputDetailsVO inputDetailsVO) {
File file = null;
InputStreamResource resource = null;
HttpHeaders headers = new HttpHeaders();
try {
//Creating InputStreamResource out of zip file
resource = new InputStreamResource(new FileInputStream(file));
String contentType = "application/zip";
if (!StringUtils.isEmpty(contentType)) {
headers.setContentType(MediaType.parseMediaType(contentType));
}
headers.add("Content-Disposition","attachment; filename=\""+file.getName()+"\"");
} catch (Exception e) {
log.error("Issue with file creation",e);
}
return ResponseEntity.ok()
.contentLength(file.length())
.contentType(MediaType
.parseMediaType(MediaType.APPLICATION_OCTET_STREAM_VALUE))
.headers(headers).body(resource);
}
Below is the response I am getting instead of file download
PK;��N <?xml version="1.0" encoding="UTF-8"?>
<employeeDetails>
<name>Harry</name>
<age>30</30>
<email>test#test.com</test>
</employeeDetails>PK�qB�#Y;YPK;��N�qB�#Y;Yemployee details.xmlPKL�Y
Try like this, you can download any type of file. I assume that InputDetailsVO contains the name of the file or you can have your own logic to pick the file name. On the top of this method, you can provide swagger related annotations.
#PostMapping(value = "/download-file/1.0", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<?> downloadFile(#RequestBody InputDetailsVO inputDetailsVO) {
String dirPath = "your-location-path";
byte[] fileBytes = null;
try {
String fileName = inputDetailsVO.getFileName();
fileBytes = Files.readAllBytes(Paths.get(dirPath + fileName));
} catch (IOException e) {
e.printStackTrace();
}
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
.body(fileBytes);
}
I also had a similar use case. I am sharing the code which had solved the issue.
#RequestMapping(value="/download",method=RequestMethod.GET,produces="application/zip" )
public ResponseEntity<?> download(HttpServletResponse response) throws IOException
{
//Some Code...
File file = new File("F:\\Folder\\Folder\\Folder\\"+filename);
InputStreamResource resource2 = new InputStreamResource(new FileInputStream(file));
response.setContentType("application/zip");
response.setHeader("Content-Disposition", String.format("inline; filename=\"" + filename + "\""));
response.setHeader("responseType", "arraybuffer");
response.setHeader("Content-Length", ""+file.length());
return new ResponseEntity<InputStreamResource>(resource2,HttpStatus.ACCEPTED);
}
I'm trying to download any file calling my rest webservices. I'm using spring + jersey for the web services and Angular 2 for the front.
So when I clink on the front, the webservices get my file but the window to download it is not shown.
My rest API :
#POST
#Path("/download")
#ApiOperation(value = "Download")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response downloadFile(#ApiParam(value = "File", required = true) String filePath) {
File file = new File("/webapps/pdf/upload/msg/1/gest.PNG");
Response.ResponseBuilder response = Response.ok((Object) file);
try {
String contentType = Files.probeContentType(file.toPath());
response.header("Content-Disposition", "attachment; filename="+file.getName());
response.header("Content-Type", contentType);
return response.build();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
My Angular service :
downloadFile(path) {
const headers = new Headers({'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*'});
const options = new RequestOptions({headers: headers});
options.responseType = ResponseContentType.Blob;
return this.http.post(apiUrl + "msg/download", path, options)
.catch(this.handleError);
}
My Angular component :
downloadFile(documentPath) {
this.msgService.downloadFile(documentPath).subscribe(response => {
var contentType = response.headers('Content-Type');
let url = window.URL.createObjectURL(new Blob([response._body], {type: contentType}));
window.open(url);
});
}
Html :
<figure class="ui-g-12 " *ngFor="let document of msg.documents_path" (click)="downloadFile(document)">
<img [src]="selectImageByExtension(document.split('.').pop().toLowerCase())" />
<figcaption>{{document.split('/').pop().toLowerCase()}}</figcaption>
</figure>
When I click on my figure I can see that the file is well gotten:
But nothing pops up.
What did I miss ?
So the only solution working for me was to use GET request instead of POST passing the filepath as a pathparam.
Rest API :
#GET
#Path("/download/{filePath}")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getdownloadFile(#PathParam("filePath") String filePath) {
String path = null;
byte [] barr = Base64.getDecoder().decode(filePath);
path = new String(barr);
File file = new File(path);
try {
String contentType = Files.probeContentType(file.toPath());
Response.ResponseBuilder response = Response.ok((Object) file);
response.header("Content-Disposition", "attachment; filename="+file.getName());
response.header("Content-Type", contentType);
response.header("Content-Length", file.length());
return response.build();
} catch (IOException e) {
e.printStackTrace();
return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
}
}
Angular service :
downloadFile(path) {
const headers = new Headers({'Content-Type': 'text/plain', 'Accept': '*'});
const options = new RequestOptions({headers: headers});
options.responseType = ResponseContentType.Blob;
return this.http.get(apiUrl + "msg/download/"+btoa(path), options)
.map(res => res)
.catch(this.handleError);
}
Angular component :
downloadFile(documentPath) {
this.msgService.downloadFile(documentPath).subscribe(response => {
let params = documentPath.split('/' );
var blob = new Blob([response._body]);
FileSaver.saveAs(blob, params[params.length-1]);
});
}
I'm trying to implement an ajax download. This is my code for the ajax request:
$('#download').click(function(){
$.ajax({
url: '${downloadPath}',
type: 'GET',
data: {${_csrf.parameterName}:'${_csrf.token}'},
success: function (res) {
}
});
});
And this is my controller's method:
#Secured("IS_AUTHENTICATED")
#RequestMapping(value="download/{id}", method=RequestMethod.GET, produces="application/pdf")
#ResponseBody
public void download(#PathVariable(value="id") final Long id, HttpServletResponse response) throws IOException {
CheckList checkList = checkListService.findById(id);
// byte[] byteItem = checkListService.getFileByIdDocument(id);
File f = new File(VariabiliGlobali.PATH_CHECKLIST+checkList.getPratica().getId()+"/"+id);
ServletOutputStream out = response.getOutputStream();
response.setContentType("application/pdf");
response.setContentLength((int)f.length());
response.setHeader("Content-Disposition", "attachment; filename=\"" + f.getName() + "\"");
FileInputStream in = new FileInputStream(f);
byte[] buffer = new byte[4096];
int length;
while( (length = in.read(buffer) ) > 0) {
out.write(buffer, 0, length);
}
in.close();
out.flush();
}
I can see the pdf inside the response:
But my browser (Chrome) doens't do anything.
Where am I wrong? How can I dowload it?
You don't need ajax and you are using as content type application/octet-stream as we can see in your code here:
response.setContentType("application/octet-stream");
If you want to display the pdf inside the browser (if the browser has the proper plugin to read pdf) you should use:
the right pdf content type
set the proper header
In my code i did the following:
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "inline; filename=pdfFileName.pdf;");
In any case I'd suggest to yuo to use the "spring" way like this:
#Secured("IS_AUTHENTICATED")
#RequestMapping(value="download/{id}", method=RequestMethod.GET)
public ResponseEntity<InputStreamResource> download(#PathVariable(value="id") final Long id) throws IOException {
HttpHeaders respHeaders = new HttpHeaders();
MediaType mediaType = new MediaType("application","pdf");
respHeaders.setContentType(mediaType);
respHeaders.setContentDispositionFormData("inline", "pdfFileName.pdf");
//Here you have to take the InputStream of the file you want to download
InputStreamResource isr = new InputStreamResource(new FileInputStream(file));
return new ResponseEntity<InputStreamResource>(isr, respHeaders, HttpStatus.OK);
}
I hope it's useful
Angelo
Set your content type in header. So browsers handles the pdf.
headers.setContentType(MediaType.parseMediaType("application/pdf"));
Below is the sample code.
#Secured("IS_AUTHENTICATED")
#RequestMapping(value="download/{id}", method=RequestMethod.GET, produces="application/pdf")
public ResponseEntity<?> download(#PathVariable(value="id") final Long id, HttpServletResponse response) throws IOException {
List<SampleDto> reportData = new ArrayList<SampleDto>();
HttpHeaders headers = new HttpHeaders();
if (null == reportData || reportData.size() == 0) {
return new ResponseEntity<byte[]>(null, headers, HttpStatus.NO_CONTENT);
}
byte[] contents = writePdfContentToBytes();//Here you should your code to get content in bytes.
headers.setContentType(MediaType.parseMediaType("application/pdf"));
headers.setContentDispositionFormData("inline", "Report.pdf");
return new ResponseEntity<byte[]>(contents, headers, HttpStatus.OK);
}
I am getting this error:
the request was rejected because no multipart boundary was found
when I upload an image through postman like this: I have saveImage as url, in header I have content/type and multipart/form-data and choossed raw and uploaded an image.
This is my controller:
#RequestMapping(value = "/saveImage",
method = RequestMethod.POST,
consumes = "application/json", produces = "application/json;charset=UTF-8")
public #ResponseBody ResponseEntity<GenericResponseVO<? extends IServiceVO>> getImage(
#RequestBody(required = false) GenericRequestVO<ImageCriteriaVO> imageCriteriaVO,HttpServletRequest request, HttpServletResponse response ) {
return requestHandlerInvoker.callHandler(
HandlerName.SAVE_IMAGE_HANDLER,request,response,imageCriteriaVO);
}
This my handler:
public GenericResponseVO<? extends IServiceVO> handleRequest(
UserContext userCtx, HttpServletRequest httpRequest,
HttpServletResponse httpResponse,
GenericRequestVO<? extends IServiceVO> requestVO)
throws O2Exception {
GenericResponseVO<ImageResultVO> imageVO = new GenericResponseVO<ImageResultVO>();
ImageResultVO imageResultVO = (ImageResultVO) serviceInvoker
.callService(ServiceName.IMAGE_SERVICE, userCtx,requestVO.getBody());
imageVO.setBody(imageResultVO);
imageVO.getHeader().setStatus(new Status(Status.SUCCESS, "Token"));
return imageVO;
This my service:
public IServiceVO service(UserContext userCtx, IServiceVO inputVO)
throws O2Exception {
LOG.info(LoggingEvent.Image_INPROGRESS,"Inside get list of treasure hunt for corporate service");
ImageCriteriaVO imageCriteriaVO = (ImageCriteriaVO) inputVO;
System.out.println(imageCriteriaVO.getFile());
ImageResultVO imageResultVO = new ImageResultVO();
CommonsMultipartFile file = null;
String fileName = null;
if (!file.isEmpty()) {
try {
fileName = file.getOriginalFilename();
byte[] bytes = file.getBytes();
BufferedOutputStream buffStream =
new BufferedOutputStream(new FileOutputStream(new File("F:/" + fileName)));
buffStream.write(bytes);
buffStream.close();
}catch (Exception e) {
}
}
return imageResultVO;
}
This my criteria class:
public class ImageCriteriaVO implements IServiceVO{
private byte[] file;
public byte[] getFile() {
return file;
}
public void setFile(byte[] file) {
this.file = file;
}
}
I hope this answer may help
Remove Content-Type from header when you are trying to upload, Postman will do it automatically.
if you set Content-Type: undefined, Postman will automatically sets Content-Type to multipart/form-data and depending upon the media it will set boundary.
Mail user agents ignore content-disposition headers in the messages.
File name should be mentioned in filename parameter. Otherwise should be mentioned in both filename and the name parameters5
multipart/form-data with Angular JS
I'm trying to implement a Service that automatically starts a download with the requested file.
This is my AJAX call:
function downloadFile(fileName) {
$.ajax({
url : SERVICE_URI + "files/" + fileName,
contentType : 'application/json',
type : 'GET',
success : function (data)
{
alert("done!");
},
error: function (error) {
console.log(error);
}
});
}
and this is my Spring Service method GET:
#RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET)
public void getFile(#PathVariable("file_name") String fileName,
HttpServletResponse response) {
try {
// get your file as InputStream
FileInputStream fis = new FileInputStream( fileName + ".csv" );
InputStream is = fis;
// copy it to response's OutputStream
ByteStreams.copy(is, response.getOutputStream());
response.setContentType("text/csv");
response.flushBuffer();
} catch (IOException ex) {
throw new RuntimeException("IOError writing file to output stream");
}
}
When my client requests the existing file from the server, the AJAX success() method is executed but the file is not even downloading. Am I doing anything wrong?
Don't use ajax, just set window.location.href to the url of the file and set the http content disposition header in your server script to force the browser to save the file.
function downloadFile(fileName) {
window.location.href = SERVICE_URI + "files/" + fileName;
}