Send/Receive images via REST - java

I am using grizzly for java rest service and consuming these web services in an android app.
Its working fine as far as "text" data is concerned.
Now I want to load the images(from server) in my android application, using this rest service and also allow the users to update image from the device.
I have tried this code
#GET
#Path("/img3")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFile()
{
File file = new File("img/3.jpg");
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM).header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"") // optional
.build();
}
The code above allow me to download the file, but is it possible to display result in broswer? like this
http://docs.oracle.com/javase/tutorial/images/oracle-java-logo.png

Solution of Part 1:
I have made the changes in my code as suggested by Shadow
#GET
#Path("/img3")
#Produces("image/jpg")
public Response getFile(#PathParam("id") String id) throws SQLException
{
File file = new File("img/3.jpg");
return Response.ok(file, "image/jpg").header("Inline", "filename=\"" + file.getName() + "\"")
.build();
}
Requested image will be displayed in browser
Part 2:
The code used to convert back Base64 encoded image
#POST
#Path("/upload/{primaryKey}")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces("image/jpg")
public String uploadImage(#FormParam("image") String image, #PathParam("primaryKey") String primaryKey) throws SQLException, FileNotFoundException
{
String result = "false";
FileOutputStream fos;
fos = new FileOutputStream("img/" + primaryKey + ".jpg");
// decode Base64 String to image
try
{
byte byteArray[] = Base64.getMimeDecoder().decode(image);
fos.write(byteArray);
result = "true";
fos.close();
}
catch (Exception e)
{
e.printStackTrace();
}
return result;
}

Related

Image upload/download using aws lambda

I am trying to create a lambda function which accepts an image as multipart object, then does some processing and uploads it to s3 bucket and provides some response back to the user.
I have found some examples how to proceed however, i do not understand do i have to create two lambda functions and upload separate jars or it can be done differently.
So far i have service that parses multipart and uploads to s3 , my question is how to approach using aws lambdas, thank you guys
public String uploadFile(MultipartFile multipartFile) {
String fileUrl = "";
try {
File file = convertMultiPartToFile(multipartFile);
String fileName = generateFileName(multipartFile);
fileUrl = endpointUrl + "/" + bucketName + "/" + fileName;
uploadFileTos3bucket(fileName, file);
} catch (Exception e) {
throw new RuntimeException(e);
}
return fileUrl;
}
private File convertMultiPartToFile(MultipartFile file){
File convFile = new File(file.getOriginalFilename());
try {
FileOutputStream fos = new FileOutputStream(convFile);
fos.write(file.getBytes());
fos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
return convFile;
}
private String generateFileName(MultipartFile multiPart) {
return new Date().getTime() + "-" + multiPart.getOriginalFilename().replace(" ", "_");
}
private void uploadFileTos3bucket(String fileName, File file) {
s3client.putObject(new PutObjectRequest(bucketName, fileName, file)
.withCannedAcl(CannedAccessControlList.PublicRead));
}
I'd suggest you can simply use one lambda function, which should be integrated with an api gateway endpoint. So the user can invoke the endpoint (post) with the file that needs to be uploaded into S3 and then from the lambda function you can do the rest ( processing + uploading to s3) and then return some response back to the user.
This could be a starting point.
to get the s3 URL of your uploaded file:
s3Client.getUrl("your_bucket_name", "your_file_key").toExternalForm();
Here is another example to resize the images in S3 using Lambda. It's JS code though and uses only one Lambda function.

FTP downloaded image is not displayed correctly

I save user uploaded images in FTP.
FTP service is running on server Server-A. The actual problem is when I want to see the uploaded image from the web application running in my local host everything works, but when I deploy the local application to Tomcat running on the same server Server-A, images are not displayed correctly.
The picture when I run the web application in local Tomcat:
The same picture when I run the web application in the remote Tomcat:
You can see that the second image is not displayed correctly. Also want to mention that the FTP is the same one.
I am using Spring with Apache FtpClient library for image upload/download functionality.
Controller source code:
#RequestMapping(value = "/{id:\\d+}/image", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)
protected byte[] getUserImage(BaseForm form,
#PathVariable("id") int userId) {
try {
User user = checkToken(form.getToken());
log.info("/users/{id}/image [GET]. User: " + user + ", form: " + form + ", User id: " + userId);
FileWrapper image = service.getUserImage(userId);
if(image != null) {
return ftpService.downloadFtpFile(image.getName());
}
}
catch(Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
FtpService source code:
public byte[] downloadFtpFile(String filePath) throws IOException {
FTPClient client = new FTPClient();
try {
client.connect(host, port);
if(!client.login(username, password)) {
throw new AdminException("Invalid ftp username/password");
}
client.enterLocalPassiveMode();
try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
client.retrieveFile(filePath, outputStream);
return outputStream.toByteArray();
}
}
catch(Exception e) {
log.error(e.getMessage(), e);
}
finally {
if(client.isConnected()) {
client.logout();
client.disconnect();
}
}
return null;
}
Thanks in advance!
If you've not set the FTP transfer to be binary (as opposed to ASCII) it will "convert the line endings" (or what it thinks are line endings) which will corrupt the picture.

Jersey client to download and save file

I Am new to jersey/JAX-RS implementation.
Please find below my jersey client code to download file:
Client client = Client.create();
WebResource wr = client.resource("http://localhost:7070/upload-0.0.1-SNAPSHOT/rest/files/download");
Builder wb=wr.accept("application/json,application/pdf,text/plain,image/jpeg,application/xml,application/vnd.ms-excel");
ClientResponse clientResponse= wr.get(ClientResponse.class);
System.out.println(clientResponse.getStatus());
File res= clientResponse.getEntity(File.class);
File downloadfile = new File("C://Data/test/downloaded/testnew.pdf");
res.renameTo(downloadfile);
FileWriter fr = new FileWriter(res);
fr.flush();
My Server side code is :
#Path("/download")
#GET
#Produces({"application/pdf","text/plain","image/jpeg","application/xml","application/vnd.ms-excel"})
public Response getFile()
{
File download = new File("C://Data/Test/downloaded/empty.pdf");
ResponseBuilder response = Response.ok((Object)download);
response.header("Content-Disposition", "attachment; filename=empty.pdf");
return response.build();
}
In my client code i am getting response as 200 OK,but i am unable to save my file on hard disk
In the below line i am mentioning the path and location where the files need to be saved.
Not sure whats going wrong here,any help would be appreciated.Thanks in advance!!
File downloadfile = new File("C://Data/test/downloaded/testnew.pdf");
For folks still looking for a solution, here is the complete code on how to save jaxrs response to a File.
public void downloadClient(){
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:7070/upload-0.0.1-SNAPSHOT/rest/files/download");
Response resp = target
.request("application/pdf,image/jpeg,application/xml,application/vnd.ms-excel")
.get();
if(resp.getStatus() == Response.Status.OK.getStatusCode())
{
InputStream is = resp.readEntity(InputStream.class);
fetchFeed(is);
//fetchFeedAnotherWay(is) //use for Java 7
IOUtils.closeQuietly(is);
System.out.println("the file details after call:"+downloadfile.getAbsolutePath()+", size is "+downloadfile.length());
}
else{
throw new WebApplicationException("Http Call failed. response code is"+resp.getStatus()+". Error reported is"+resp.getStatusInfo());
}
}
/**
* Store contents of file from response to local disk using java 7
* java.nio.file.Files
*/
private void fetchFeed(InputStream is){
File downloadfile = new File("C://Data/test/downloaded/testnew.pdf");
byte[] byteArray = IOUtils.toByteArray(is);
FileOutputStream fos = new FileOutputStream(downloadfile);
fos.write(byteArray);
fos.flush();
fos.close();
}
/**
* Alternate way to Store contents of file from response to local disk using
* java 7, java.nio.file.Files
*/
private void fetchFeedAnotherWay(InputStream is){
File downloadfile = new File("C://Data/test/downloaded/testnew.pdf");
Files.copy(is, downloadfile.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
I don't know if Jersey let's you simply respond with a file like you have here:
File download = new File("C://Data/Test/downloaded/empty.pdf");
ResponseBuilder response = Response.ok((Object)download);
You can certainly use a StreamingOutput response to send the file from the server, like this:
StreamingOutput stream = new StreamingOutput() {
#Override
public void write(OutputStream os) throws IOException,
WebApplicationException {
Writer writer = new BufferedWriter(new OutputStreamWriter(os));
//#TODO read the file here and write to the writer
writer.flush();
}
};
return Response.ok(stream).build();
and your client would expect to read a stream and put it in a file:
InputStream in = response.getEntityInputStream();
if (in != null) {
File f = new File("C://Data/test/downloaded/testnew.pdf");
//#TODO copy the in stream to the file f
System.out.println("Result size:" + f.length() + " written to " + f.getPath());
}
This sample code below may help you.
https://stackoverflow.com/a/32253028/15789
This is a JAX RS rest service, and test client. It reads bytes from a file and uploads the bytes to the REST service. The REST service zips the bytes and sends it back as bytes to the client. The client reads the bytes and saves the zipped file.
I had posted this as a response to another thread.
Here's another way of doing it using Files.copy().
private long downloadReport(String url){
long bytesCopied = 0;
Path out = Paths.get(this.fileInfo.getLocalPath());
try {
WebTarget webTarget = restClient.getClient().target(url);
Invocation.Builder invocationBuilder = webTarget.request(MediaType.TEXT_PLAIN_TYPE);
Response response = invocationBuilder.get();
if (response.getStatus() != 200) {
System.out.println("HTTP status " response.getStatus());
return bytesCopied;
}
InputStream in = response.readEntity( InputStream.class );
bytesCopied = Files.copy(in, out, REPLACE_EXISTING);
in.close();
} catch( IOException e ){
System.out.println(e.getMessage());
}
return bytesCopied;
}

How to make a pdf appear as a download option rather than rendering on the browser?

I am using Jasper Reports in my project for producing the reports in multiple formats. Although all the code examples run fine, I have ran into a conceptual issue.
I wrote this trivial code which produces a PDF at the browser as a download option:
#GET
#Path("/basicdbreport")
#Produces("application/pdf")
public Response basicDbReport(#Context ServletContext context,
#Context HttpServletResponse response) throws JRException,
IOException {
Connection connection = null;
byte[] reportBytes = null;
String reportName = "firstsqlexample";
File file = new File(path + reportName + JASPER_EXTENSION);
// check if compiled report exists
if (!file.exists()) {
compileReport(context.getRealPath(path + reportName + JRXML_EXTENSTION));
}
// input stream for filling the compiled report
InputStream compiledReportStream = context.getResourceAsStream(path
+ reportName + JASPER_EXTENSION);
try {
connection = dataSource.getConnection();
reportBytes = JasperRunManager.runReportToPdf(compiledReportStream,
new HashMap<String, Object>(), connection);
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (reportBytes != null) {
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(reportBytes);
}
ResponseBuilder restResponse = Response.ok();
restResponse.header("Content-Disposition",
"attachment; filename=firstSQLReport.pdf");
return restResponse.build();
}
The code runs fine and I get a download prompt at the browser. However, when I dug deeper into the Jasper API I found a method runReportToPdfStream() method which would handle the output stream for me.
The new code looks something like this:
#GET
#Path("/basicdbreport")
#Produces("application/pdf")
public Response basicDbReport(#Context ServletContext context,
#Context HttpServletResponse response) throws JRException,
IOException {
ServletOutputStream outputStream = response.getOutputStream();
Connection connection = null;
String reportName = "firstsqlexample";
File file = new File(path + reportName + JASPER_EXTENSION);
// check if compiled report exists
if (!file.exists()) {
compileReport(context.getRealPath(path + reportName + JRXML_EXTENSTION));
}
// input steam to fill complied report
InputStream compiledReportStream = context.getResourceAsStream(path
+ reportName + JASPER_EXTENSION);
try {
connection = dataSource.getConnection();
JasperRunManager.runReportToPdfStream(compiledReportStream, outputStream, new HashMap<String, Object>(), connection);
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
ResponseBuilder restResponse = Response.ok();
restResponse.header("Content-Disposition",
"attachment; filename=firstSQLReport.pdf");
return restResponse.build();
}
The code runs fine but I do not get any download prompt, the pdf gets rendered on the browser instead. The response headers are as follows (on the browser):
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
Date: Wed, 21 Aug 2013 05:51:42 GMT
What's the reason that the code now fails to provide a download prompt? I am not an ace with HTTP but I guess this:
restResponse.header("Content-Disposition",
"attachment; filename=firstSQLReport.pdf");
is responsible for the download option. Its nowhere in the response although I did include it in the code. Please advice.
yes, you are right, Content-Disposition is the response header that you need to set to trigger the download action on the client browser.
i think you need to set the response headers first before writing to the response output stream.

Pictures uploaded with valums ajax upload and OctetStreamReader dosn't work in IE - Java/JSP

I'm having a problem with picture uploading in Internet Explorer 7, 8 and 9 (haven't tested other versions). It works fine in FF and Chrome, but for some reason the picture is uploaded wrong when i try to upload in any versions of IE.
What i mean by that is that the file gets uploaded in the right directory with the right name, but i cant open it in any picture editing programs.
Furthermore when i open the picutre in Notepad++ i see that the picture got some meta data displaying like:
-----------------------------7db1f6c907fe
Content-Disposition: form-data; name="qqfile"; filename="jingjang.jpg"
Content-Type: image/jpeg
(hashcode here)
-----------------------------7db1f6c907fe--
If i remove the code the picture works fine! So can anyone tell me what is generating the code and how do i stop it? :)
I use Valums Ajax Upload on my JSP page:
var imageFolder = "images/upload/<%=user.getUsername()%>/temp/";
new qq.FileUploader({
element: document.getElementById('TempUploadButton'),
action: 'OctetStreamReader',
debug: false,
multiple: false,
params: {"type" : "user"},
onComplete: function(id, fileName) {
var d = new Date();
$("#UserPageAvatarPic a img").attr("src", imageFolder+"<%=user.getUsername()%>.jpg?cache="+d.getTime() );
},
onSubmit : function(id, fileName) {
// hide all prev elements
$('#TempUploadButton ul.qq-upload-list li').each(function() {
$(this).hide();
});
}
});
And OctetStreamReader as my servlet
public class OctetStreamReader extends HttpServlet {
private static final long serialVersionUID = 6748857432950840322L;
private static final String DESTINATION_DIR_PATH = "files";
private static String realPath;
UserService userService = UserService.getService();
/**
* {#inheritDoc}
* #param config
* #throws ServletException
*/
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
realPath = getServletContext().getRealPath(DESTINATION_DIR_PATH) + "/";
}
/**
* Handles the HTTP <code>POST</code> method.
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException {
User user = userService.getUser(((Integer) request.getSession().getAttribute("user")).intValue());
String type = request.getParameter("type");
String username = user.getUsername();
PrintWriter writer = null;
InputStream is = null;
FileOutputStream fos = null;
type = "user";
try {
writer = response.getWriter();
} catch (IOException ex) {
log(OctetStreamReader.class.getName() + "has thrown an exception: " + ex.getMessage());
}
try {
String filename = "";
if (type.equals("user")) {
realPath = getServletContext().getRealPath("/images/upload/" + username + "/temp/");
is = request.getInputStream();
String strDirectoy = getServletContext().getRealPath("/images/upload/" + username + "/temp/" );
boolean success = (new File(strDirectoy)).mkdir();
File f1 = new File(strDirectoy);
File[] children = f1.listFiles();
filename = username + ".jpg";
}
if (type.equals("post")) {
realPath = getServletContext().getRealPath("/images/upload/" + username + "/post/");
is = request.getInputStream();
String strDirectoy = getServletContext().getRealPath("/images/upload/" + username + "/post/" );
boolean success = (new File(strDirectoy)).mkdir();
File f1 = new File(strDirectoy);
File[] children = f1.listFiles();
filename = Calendar.getInstance().getTimeInMillis()+".jpg";
}
if (type.equals("editpost")) {
realPath = getServletContext().getRealPath("/images/upload/" + username + "/editpost/");
is = request.getInputStream();
String strDirectoy = getServletContext().getRealPath("/images/upload/" + username + "/editpost/" );
boolean success = (new File(strDirectoy)).mkdir();
File f1 = new File(strDirectoy);
File[] children = f1.listFiles();
filename = Calendar.getInstance().getTimeInMillis() + ".jpg";
}
fos = new FileOutputStream(new File(realPath + "/" + filename), false);
IOUtils.copy(is, fos);
response.setStatus(response.SC_OK);
writer.print("{success: true, filename: \"" + filename + "\"}");
} catch (FileNotFoundException ex) {
response.setStatus(response.SC_INTERNAL_SERVER_ERROR);
writer.print("{success: false}");
log(OctetStreamReader.class.getName() + "has thrown an exception: " + ex.getMessage());
} catch (IOException ex) {
response.setStatus(response.SC_INTERNAL_SERVER_ERROR);
writer.print("{success: false}");
log(OctetStreamReader.class.getName() + "has thrown an exception: " + ex.getMessage());
} finally {
try {
fos.close();
is.close();
} catch (IOException ignored) {
}
}
writer.flush();
writer.close();
}
}
Also in fileuploader.js i tried to change the Content Type from application/octet-stream to multipart/form-data
/**
* Sends the file identified by id and additional query params to the server
* #param {Object} params name-value string pairs
*/
_upload: function(id, params){
var file = this._files[id],
name = this.getName(id),
size = this.getSize(id);
this._loaded[id] = 0;
var xhr = this._xhrs[id] = new XMLHttpRequest();
var self = this;
xhr.upload.onprogress = function(e){
if (e.lengthComputable){
self._loaded[id] = e.loaded;
self._options.onProgress(id, name, e.loaded, e.total);
}
};
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
self._onComplete(id, xhr);
}
};
// build query string
params = params || {};
params['qqfile'] = name;
var queryString = qq.obj2url(params, this._options.action);
xhr.open("POST", queryString, true);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.setRequestHeader("X-File-Name", encodeURIComponent(name));
xhr.setRequestHeader("Content-Type", "multipart/form-data");
xhr.send(file);
},
HTML file uploads use by default the multipart/form-data request encoding (this is in order to be able to upload multiple files and/or to mix normal input field values in one request). You're however not parsing and extracting the individual form data parts from the request body, instead you're reading and writing the entire request body plain unmodified to a file.
is = request.getInputStream();
fos = new FileOutputStream(new File(realPath + "/" + filename), false);
IOUtils.copy(is, fos);
This is indeed not ever going to work. That you said that it works in FF/Chrome is beyond me. Perhaps you're misinterpreting the results or do not have tested it in those browsers with binary files at all.
You need to use Apache Commons FileUpload to extract the parts from a multipart/form-data request. Or, when you're already on Servlet 3.0, you could also use the Servlet API provided HttpServletRequest#getParts() method.
See also:
How to upload files to server using JSP/Servlet?
HTML5 File Upload to Java Servlet
Unrelated to the concrete problem, you've another problem with the code posted so far. You're storing uploaded files in the web content of the expanded WAR. This is far from a solid permanent storage location. Everytime when you redeploy a new WAR, all those files will get lost. You'd need to backup them everytime which is plain clumsy and error prone. Rather store them in a fixed location outside the expanded WAR folder.
See also:
Java EE - Best way to get real path to uploaded files?
Use this:
InputStream is = null;
// Check that we have a file upload request
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
// Create a factory for disk-based file items
if (isMultipart) {
FileItemFactory factory = new DiskFileItemFactory();
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
try {
// Parse the request
ArrayList<DiskFileItem> files = (ArrayList<DiskFileItem>) upload.parseRequest(request);
if (!files.isEmpty()) {
is = files.get(0).getInputStream();
}
} catch (FileUploadException ex) {
Logger.getLogger(OctetStreamReader.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
is = request.getInputStream();
}

Categories

Resources