Image, Pdf download not working in Java Rest Api - java

Im trying to download the image and pdf with the below code
File createdFile = new File("logs/decryptedDocs"+filename);
Path path = Paths.get(createdFile.getAbsolutePath());
logger.info("Path is..{}",path.toUri());
Resource resource = new UrlResource(path.toUri());
headers.add("Content-Disposition", "attachment;filename="+resource.getFilename());
// Try to determine file's content type
String contentType = null;
try {
contentType = httpServletRequest.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
} catch (IOException ex) {
logger.info("Could not determine file type.");
}
// Fallback to the default content type if type could not be determined
if(contentType == null) {
contentType = "application/octet-stream";
}
logger.info("ContentType is..{}",contentType);
return ResponseEntity.ok()
.headers(headers)
.contentLength(createdFile.length())
.contentType(MediaType.parseMediaType(contentType))
.body(resource);
In my local it is working and in postman when I checked image was visible but couldn't download directly in postman also but when I try to hit the API from front end, the image is visible in the preview section but getting some error in the response like json parser exception. front end technology used is AngularJs.
please help me on this.

Related

S3 generate download link

I'm having trouble generating a download link for an html file i'm uploading to aws s3 server. I am able to generate the link and access the file. But what I want to happen is that when I click the link is for the file to be downloaded instead of opening it.
Here is and example of the url:
https://wassap_app.s3.us-east-1.amazonaws.com/report/test.html
Below is the code for the method that does the upload:
public boolean uploadFile(String name) {
try {
this.client.putObject(new PutObjectRequest(bucketName, "report/" + name, this.file)
.withCannedAcl(CannedAccessControlList.PublicRead));
String url = client.getUrl(bucketName, "report/" + name).toExternalForm();
System.out.println("################ Download File URL ################");
System.out.println(url);
System.out.println("###################################################");
return true;
} catch (AmazonServiceException ase) {
return false;
} catch (AmazonClientException ace) {
return false;
}
}
You can use the response-content-disposition query parameter as documented here. Your URL will then look like:
https://wassap_app.s3.us-east-1.amazonaws.com/report/test.html?response-content-disposition=attachment%3B%20filename%3D%22report.html%22
But the documentation also states:
You must sign the request, either using an Authorization header or a
pre-signed URL, when using these parameters. They cannot be used with
an unsigned (anonymous) request.
To sign the request for the user you can use a presigned URL. I don't have a Java environment to test right now, but something like the following should work.
GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, "report/" + name);
ResponseHeaderOverrides overrides = new ResponseHeaderOverrides();
overrides.setContentDisposition("attachment; filename=\"report.html\"");
req.setResponseHeaders(overrides);
URL url = this.client.generatePresignedUrl(req);
System.out.println(url);
Call this method:
String url = client.getResourceUrl(bucketName, "report/" + name);
Hope this helps!

Multipart File Upload via REST API corrupts file and increases file size

Am uploading a file (any format doc, docx, pdf, text, etc) as multipart form/data to a REST API from Postman or application UI. The text file uploads fine. All other non-text formats get corrupted. I cant open those files.
The size of the uploaded file increases drastically. Check the following server log:
File size just before call to request.getRequestDispatcher().forward(): 27583
Controller, first line in method:39439
The size of the uploaded file is 27.3Kb
I am guessing the files gets corrupted because of the other data appended to the file.
Controller method is
#RequestMapping(value="/entity/{entity}/{entityId}/type/{type}/{derive}",method = RequestMethod.POST)
#ResponseBody
public String uploadFile(#RequestParam("file") MultipartFile multipartFile,#PathVariable("entity")String entity,#PathVariable("type")String type,#PathVariable("entityId")Long entityId,#PathVariable("derive") boolean derive) throws Exception
Since text file is saving correctly and other files also get written correctly, don't think the code to write the file is incorrect.
Code to get inputStream
public String storeFile(MultipartFile multipartFile, String entity, Long id, String uploadType, boolean isDerive,String customName)
throws Exception
{
try
{
System.out.println(multipartFile.getSize());
String fileName = "";
String contentType = "";
if (multipartFile != null)
{
fileName = multipartFile.getOriginalFilename();
contentType = multipartFile.getContentType();
if (contentType == null)
{
contentType = "application/msword";
}
}
InputStream is = multipartFile.getInputStream();
String filePath = getFileName(entity, uploadType, id, fileName, isDerive,customName);
Helper.storeFile(is, filePath);
precedingPath = precedingPath.length() > 0 ? precedingPath + "/":"";
return precedingPath + filePath;
}
catch (WebException e)
{
e.printStackTrace();
throw e;
}
catch (Exception e)
{
e.printStackTrace();
throw new WebException(e.getMessage(), IHttpConstants.INTERNAL_SERVER_ERROR, e);
}
}
Helper.storeFile
public static File storeFile(InputStream is, String filePath) throws IOException {
try {
String staticRepoPath = null;
if (MasterData.getInstance().getSettingsMap().containsKey(Settings.REPO_LOCATION.toString())) {
staticRepoPath = MasterData.getInstance().getSettingsMap().get(Settings.REPO_LOCATION.toString());
} else {
throw new WebException("Invalid Settings");
}
byte[] buffer = new byte[is.available()];
is.read(buffer);
File targetFile = new File(staticRepoPath + File.separator + filePath);
#SuppressWarnings("resource")
OutputStream outStream = new FileOutputStream(targetFile);
outStream.write(buffer);
return targetFile;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
My Ajax request is as follows
var fd = new FormData();
//Take the first selected file
fd.append("file", document.actualFile);
//Generic AJAX call
CandidateService.ajax_uploadDocumentWithDocType($scope.candidate.id, fd, document.docType, function (error, json)
Content type while uploading:
var config = {headers:{'X-Auth-Token':authToken, 'Content-Type': undefined}, transformRequest: angular.identity};
Would anyone know how I can fix this and upload the file successfully?
Q1) Why does the file size change between the request dispatcher and the controller that handles the file data.
Q2) Could this change of file size be the cause of file corruption? Libre Office cause General Input/Output Error.
I figured the problem with the file upload. I had a spring filter in between that was changing the request to a wrappedRequest. This was adding additional data to the multipart data and causing the file to be corrupted.
Well in my case I had this exact same problem when accesing the API through Amazon API Gateway. Turned out I forgot to allow multipart ContentType on API Gateway.
Kind of weird the requests still made it to my server and text files worked fine.

Receiving customized response and file from REST web services

I'm trying to create some REST web services with Java in order to send data, do calculations on the server, and return the result. In a first stage I send and receive information as an excel file (in the future I prefer to use XML or JSON).
Well, after a lots of hours trying it, and reading lots of posts, it seems I'm very close to achieve it, but I don't know how to obtain the final response of the server.
I have a service like this:
#GET
#Path("/test")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFile(#QueryParam("IDfile") String IDfile) {
if(IDfile.trim().length() == 0 || IDfile == null) {
return Response.status(Response.Status.BAD_REQUEST).entity("IDfile cannot be blank").build();
}
String uploadedFileLocation = "C:\\FilesWebservice\\" + IDfile;
Boolean sortida = false;
try {
prova prueba = new prova();
sortida = prueba.prova(uploadedFileLocation); //this creates an xls file as response
} catch (Exception ex) {
System.out.println("error" + ex.toString());
Logger.getLogger(ServiceResource.class.getName()).log(Level.SEVERE, null, ex);
}
if (sortida) {
File file = new File("C:\\FilesWebservice\\out\\prediction.xls"); // the File path you want to serve.
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional
.build();
} else
return Response.status(500).entity("It was unable to calculate (Ask God for the reason)").build();
}
It works OK, if I send a GET through the browser I receive the file in my downloads folder, but I need to consume the service with another application. Thus, I'm developing a client with Netbeans, and then, NB created automatic code according to my web service. In this case I have:
public <T> T getFile(Class<T> responseType, String IDfile) throws ClientErrorException {
WebTarget resource = webTarget;
if (IDfile != null) {
resource = resource.queryParam("IDfile", IDfile);
}
resource = resource.path("test");
Builder builder = resource.request(MediaType.APPLICATION_OCTET_STREAM_TYPE);
Invocation invocation = builder.buildGet();
return resource.request(MediaType.APPLICATION_OCTET_STREAM_TYPE).get(responseType);
}
Maybe I added some lines, I can't remember now. Anyway, the service returns a status code, a customised message and the file as attachment. I want to read at least the status code and obviously save the file, but I don't know how can I do it.
I tried to do:
MyJerseyClientAlgA client = new MyJerseyClientAlgA("192.168.1.30");
Object response = client.getFile(Response.class, "3cphkhfu.xls");
but it was unsuccessful to extract the information I need from 'response'.
Any help or ideas would be appreciated.
Many thanks in advance
EDIT:
Thanks #LutzHorn for your reply. I'm not sure if I understand well your proposal, I'll do some tests and if I find a solution I'll post under my question. Anyway, I generated again the automatic code for consuming the REST service, that is:
public <T> T getFile(Class<T> responseType, String IDfile) throws ClientErrorException {
WebTarget resource = webTarget;
if (IDfile != null) {
resource = resource.queryParam("IDfile", IDfile);
}
resource = resource.path("test");
return resource.get(responseType);
}
but I have an error in the last line, it indicates:
cannot find symbol
symbol: method get(Class)
so I changed this line for
return resource.request(MediaType.APPLICATION_OCTET_STREAM_TYPE).get(responseType);
but I'm not sure if this is right.
Well, after some hours searching and testing, this piece of code works. I don't know if it is the best solution, but it does exactly what I want: extract the status and save the file returned by the web service.
public void getFile(String IDfile) throws ClientErrorException {
WebTarget resource = webTarget;
if (IDfile != null) {
resource = resource.queryParam("IDfile", IDfile);
}
resource = resource.path("test");
Invocation inv = resource.request(MediaType.APPLICATION_OCTET_STREAM_TYPE).buildGet();
Response rp = inv.invoke();
InputStream attachment = null;
try {
if (rp.getStatus() == 200) {
attachment = rp.readEntity(InputStream.class); //This method can be invoked only once unless you buffer the response...
ReadableByteChannel rbc = Channels.newChannel(attachment); //website.openStream()
FileOutputStream fos = new FileOutputStream("C://FilesWebservice/solution.xls");
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
} else {
System.out.println(rp.getStatus());
}
} catch ( Exception ex) {
ex.printStackTrace();
} finally {
rp.close();
}
}

Issue while Upload file using Multipart Request in Codename One

I tried to upload a image to the server, it throws me the Error 405 : Method not found, but from that same Url i can able to Download any files.. following is the code i tried.
private void uploadFileToServer(ActionEvent event) throws IOException
{
try{
InfiniteProgress ip = new InfiniteProgress();
Dialog dlg = ip.showInifiniteBlocking();
dlg.show();
MultipartRequest request = new MultipartRequest();
FileSystemStorage fs = FileSystemStorage.getInstance();
String fileUri = fs.getAppHomePath() + "654319032015150536IR.png";
request.setUrl("http://192.XX.XX.58:XX/HttpFolder/");
request.setPost(true);
InputStream is = FileSystemStorage.getInstance().openInputStream(fileUri);
request.addData("file", is, FileSystemStorage.getInstance().getLength(fileUri), "image/png");
request.setFilename("file", fileUri);
request.setPriority(ConnectionRequest.PRIORITY_CRITICAL);
NetworkManager.getInstance().addToQueue(request);
dlg.dispose();
if (event instanceof NetworkEvent) {
NetworkEvent ne = (NetworkEvent)event;
Dialog.show("Result:", ne.getMetaData().toString(), "","");
}
}
catch(Exception e){
Dialog.show("ERROR", e.getMessage(), "OK",null);
}
}
You can't upload to an arbitrary URL, you need to have a servlet that handles multipart on the POST http method.
We have a demo that includes the server side code here: http://codenameone.com/blog/build-mobile-ios-apps-in-java-using-codename-one-on-youtube.html
Notice that you also did some other "problematic" things in the code such as using PRIORITY_CRITICAL and using the InputStream API rather than just giving the file URL (which is more efficient).

How to download file in Spring mvc and mongodb

Hi have written controller class like below. I am trying to get file from mongo db and try to download it.
organizationFileAttachmentService.setUser(getUser());
GridFSDBFile file = organizationFileAttachmentService.getGridFSDBFileById(new ObjectId(id), "File");
if (file != null) {
byte[] content = organizationFileAttachmentService.findByIdAndBucket(new ObjectId(id), "File");
try {
int size = content.length;
InputStream is = null;
byte[] b = new byte[size];
try {
is = new ByteArrayInputStream(content);
is.read(b);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null)
is.close();
} catch (Exception ex) {
}
}
response.setContentType(file.getContentType());
// String attachment =
// "attachment; filename=\""+file.getFilename()+"\"";
String attachment = "attachment; filename=" + file.getFilename();
// response.setContentLength(new
// Long(file.getLength()).intValue());
response.setCharacterEncoding(file.getMD5());
response.setHeader("content-Disposition", attachment);// "attachment;filename=test.xls"
// copy it to response's OutputStream
// FileCopyUtils.copy(is, response.getOutputStream());
IOUtils.copy(is, response.getOutputStream());
response.flushBuffer();
is.close();
} catch (IOException ex) {
_logger.info("Error writing file to output stream. Filename was '" + id + "'");
throw new RuntimeException("IOError writing file to output stream");
}
but i am not able to down load file. can any one help me.
In case you missed it, Spring provides various built in resource handlers.
http://docs.spring.io/spring/docs/3.2.5.RELEASE/spring-framework-reference/html/resources.html#resources-implementations
If your method returns one of those (perhaps the ByteArrayResource in your case), then you just need a couple of annotations on the interface like so:
#RequestMapping(value = "/foo/bar/{fileId}",
method = RequestMethod.GET,
produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE })
#ResponseBody FileSystemResource downloadFile(Long fileId);
No fiddling with encodings and headers for you that way. I'd recommend trying that before rolling your own.
Edit: The above worked fine in Spring 3.1.4. It no longer works for 3.2.x or 4.x. Whereas previously, the produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE } would cause Spring to add the appropriate headers, it now treats that as a restriction. If accessing the URL with a standard web browser, an accept header of "application/octet-stream" will not be sent. Spring will therefore return a 406 error. To get it working again, such a method needs to be re-written without the "produces" attribute. Instead, add HttpServletResponse to the method arguments and add the header inside the method. i.e.:
#RequestMapping(value = "/foo/bar/{fileId}",
method = RequestMethod.GET)
#ResponseBody FileSystemResource downloadFile(
Long fileId, HttpServletResponse response) {
...
response.setHeader( "Content-Disposition", "attachment;filename=" + fileName );
...
}
Edit redux:
Now using Spring 4.0.7 via Spring Boot 1.1.8. It would appear that setting the produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE } instruction is now working again. Just having that instruction seems to be enough for all the browsers I have tried. Note however, that I have also found that it does not set the Content-Disposition, which is left as application/json. Although this doesn't seem to be an issue for browsers, I have come across bugs in PHP client applications, which seem to behave only based on the Content-Disposition. So it seems that the current solution is to do both of the above!
I have changed my request as GET and added request in anchor tag in html. Aslo changed my code as
#RequestMapping(value = "/getFileById/{id}", method = RequestMethod.GET)
public #ResponseBody
void download(#PathVariable String id, HttpServletRequest request, HttpServletResponse response) throws IOException {
organizationFileAttachmentService.setUser(getUser());
GridFSDBFile file = organizationFileAttachmentService.getGridFSDBFileById(new ObjectId(id), "File");
if (file != null) {
try {
response.setContentType(file.getContentType());
response.setContentLength((new Long(file.getLength()).intValue()));
response.setHeader("content-Disposition", "attachment; filename=" + file.getFilename());// "attachment;filename=test.xls"
// copy it to response's OutputStream
IOUtils.copyLarge(file.getInputStream(), response.getOutputStream());
} catch (IOException ex) {
_logger.info("Error writing file to output stream. Filename was '" + id + "'");
throw new RuntimeException("IOError writing file to output stream");
}
}
}
Now it is working fine for me.

Categories

Resources