given BlobstoreService served HttpServletResponse, how to fetch the served blob? - java

Here is my Serve.java, which is my Serve servlet.
public class Serve extends HttpServlet {
private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException {
BlobKey blobKey = new BlobKey(req.getParameter("blob-key"));
blobstoreService.serve(blobKey, res);
}
}
When I host my server and access serve servlet via browser, I see my blob (a picture). So I'm assuming the blob, in its picture file format, is stored in HttpServletResponse.
How do I access this blob / file? I actually need the file from an Android app using HttpResponse, but I'll figure that out myself.

You can create a BlobstoreInputStream
to read a blob from the BlobStore programmatically.
If you need the file in an Android app, should serve it the way you already do and just read the response in your app.

Related

Which annotation do i use to upload an image on GAE endpoint?

I have an SPI Google endpoint, I can't find any examples on which annotation to use to accept a for example a MultipartFile file?
#ApiMethod(name = "saveNewBill" ,
httpMethod = ApiMethod.HttpMethod.POST)
public Bill saveBillImage( #Named("content") MultipartContent f ){
Bill bill = new Bill();
return bill;
}
EDIT: I have just noticed, while reading up on some other things Blobstore related, that Google now recommends using Google Cloud Storage INSTEAD of the Blobstore for serving of media.
Since you are using an Endpoint on App Engine, you should use the BlobStore.
It is the preferred way to handle uploading, storage and retrieval of images on App Engine.
The following function in the BlobstoreService will generate an upload URL which you then upload the image to using a standard Multipart Request with the image data being passed in a parameter named file.
BlobstoreServiceFactory.getBlobstoreService().createUploadUrl("/[servlet name goes here]");
You will need to provide the name of a Servlet to which the request will be redirected after the upload has completed. This Servlet can access the newly created Blobstore item and do something meaningful with it - such as get the serving URL of the image and return it to the client.
Here is a snippet of a Servlet that does just that:
public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
List<BlobKey> blobs = blobstoreService.getUploads(req).get("file");
BlobKey blobKey = blobs.get(0);
ImagesService imagesService = ImagesServiceFactory.getImagesService();
ServingUrlOptions servingOptions = ServingUrlOptions.Builder.withBlobKey(blobKey);
servingOptions.secureUrl(true);
String servingUrl = imagesService.getServingUrl(servingOptions);
res.setStatus(HttpServletResponse.SC_OK);
res.setContentType("text/plain");
PrintWriter out = res.getWriter();
out.print(servingUrl);
out.flush();
out.close();
}
You can also add some querystring parameters of your own to the upload URL which can be read in the Servlet. This can be useful for things like attaching the BlobKey to a specific entity etc.
For a more in-depth look at the Blobstore, I recommend the following article from Romin Irani's App Engine Tutorial: https://rominirani.com/episode-13-using-the-blobstore-java-api-56423cf6a1b#.6t95vziul

What is the correct way to serve image file from Blob in Spring MVC controller?

I wrote a simple SpringMVC app and host on a Paas. I have created a table in Mysql and a column is the Blob. I can upload files through the Mysql admin. Right now, my server can serve html file or javascript files correctly in browser. However, when I serve a jpg file in http://myserver.com/File/ad.jpg, my browser showed a small icon and if I save it, the Windows Image software shows that the image is damaged.
Here are some of the code:
#RequestMapping(value="/File/**", //{name:.+}",
method = RequestMethod.GET)
public #ResponseBody void getContent(
// #PathVariable("name") String name,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
String name = request.getPathInfo();
....
IOUtils.copy(blob.getBinaryStream(), out);
I found that getServletContext() returns null, so I wasn't able to get contentType, so I saved contentType in Mysql as image/jpeg for the ad.jpg. I set the disposition to be inline. What else should I do to serve a jpg?
I finally found that the original code has nothing wrong. The original Mysql admin web page uploaded the blob incorrectly. After I found the Paas has a secret new admin page and that can upload a correct blob with an binary option. I still appreciate all the replies in comments.

Saving blobs with Google Endpoint

I have an app that allows users to save blobs in the blobstore. I have a schema that does so presently, but I am interested in something simpler and less twisted. For context, imagine my app allows users to upload the picture of an animal with a paragraph describing what the animal is doing.
Present schema
User calls my endpoint api to save the paragraph and name of the animal in entity Animal. Note: The Animal entity actually has 4 fields ( name, paragraph, BlobKey, and blobServingUrl as String). But the endpoint api only allows saving of the two mentioned.
Within the endpoint method, on app-engine side, after saving name and paragraph I make the following call to generate a blob serving url, which my endpoint method returns to the caller
#ApiMethod(name = "saveAnimalData", httpMethod = HttpMethod.POST)
public String saveAnimalData(AnimalData request) throws Exception {
...
BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
String url = blobstoreService.createUploadUrl("/upload");
return url;
}
On the android side, I use a normal http call to send the byte[] of the image to the blobstore. I use apache DefaultHttpClient(). Note: the blobstore, after saving the image, calls my app-engine server with the blob key and serving url
I read the response from the blobstore (blobstore called my callback url) using a normal java servlet, i.e. public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException. From the servlet, I put the BlobKey and blobServingUrl into the Animal entity for the associated animal. (I had passed some meta data to the blobstore, which I use as markers to identify the associated animal entity).
Desired Schema
This is where your response comes in. Essential, I would like to eliminate the java servlet and have my entire api restricted to google cloud endpoint. So my question is: how would I use my endpoint to execute steps 3 and 4?
So the idea would be to send the image bytes to the endpoint method saveAnimalData at the same time that I am sending the paragraph and name data. And then within the endpoint method, send the image to the blobstore and then persist the BlobKey and blobServingUrl in my entity Animal.
Your response must be in java. Thanks.
I see two questions in one here :
Can Google Cloud Endpoints handle multipart files ? -> I don't know about this TBH
Is there a simpler process to store blobs than using the BlobStoreService?
It depends on the size of your image. If you limit your users to < 1MB files, you could just store your image as a Blob property of your Animal entity. It would allow you to bypass the BlobStoreService plumbering. See : https://developers.google.com/appengine/docs/java/datastore/entities?hl=FR
This solution still depends on how the Cloud Endpoint would handle the multipart file as a raw byte[]...
We encountered the same issue with GWT + Google App Engine in 2009, and it was before the BlobStoreService was made available.
GWT RPC and Cloud Endpoints interfaces share some similarities, and for us it was not possible. We had to create a plain HTTP Servlet, and use a Streaming Multipart file resolver beacause the one from Apache's HTTP Commons used the file system.

How to make a servlet interact with the API of a website and also store the XML response?

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String text = "some text";
response.setContentType("text/plain"); // Set content type of the response so that jQuery knows what it can expect.
response.setCharacterEncoding("UTF-8"); // You want world domination, huh?
response.getWriter().write(text); // Write response body.
}
If I use this servlet , where request variable will have the url of the API of the website . Then how do I capture the response ? I would want to know what is the code to do that , and is this the right way to go about it when trying to build a JSP page that deals with interacting with an API of a website and showing data ?
You're confusing things. The HttpServletRequest is the HTTP request which the client (the webbrowser) has made to reach the servlet. The HttpServletResponse is the response which you should use to send back the result to the client (the webbrowser).
If you want to fire a HTTP request programmatically, you should use java.net.URLConnection.
URLConnection connection = new URL("http://example.com").openConnection();
InputStream input = connection.getInputStream(); // This contains the response. You need to convert this to String or some bean and then display in JSP.
See also:
How to use java.net.URLConnection to fire and handle HTTP requests

How to send byte[] as pdf to browser in java web application?

In action method (JSF) i have something like below:
public String getFile() {
byte[] pdfData = ...
// how to return byte[] as file to web browser user ?
}
How to send byte[] as pdf to browser ?
In the action method you can obtain the HTTP servlet response from under the JSF hoods by ExternalContext#getResponse(). Then you need to set at least the HTTP Content-Type header to application/pdf and the HTTP Content-Disposition header to attachment (when you want to pop a Save As dialogue) or to inline (when you want to let the webbrowser handle the display itself). Finally, you need to ensure that you call FacesContext#responseComplete() afterwards to avoid IllegalStateExceptions flying around.
Kickoff example:
public void download() throws IOException {
// Prepare.
byte[] pdfData = getItSomehow();
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
// Initialize response.
response.reset(); // Some JSF component library or some Filter might have set some headers in the buffer beforehand. We want to get rid of them, else it may collide.
response.setContentType("application/pdf"); // Check http://www.iana.org/assignments/media-types for all types. Use if necessary ServletContext#getMimeType() for auto-detection based on filename.
response.setHeader("Content-disposition", "attachment; filename=\"name.pdf\""); // The Save As popup magic is done here. You can give it any filename you want, this only won't work in MSIE, it will use current request URL as filename instead.
// Write file to response.
OutputStream output = response.getOutputStream();
output.write(pdfData);
output.close();
// Inform JSF to not take the response in hands.
facesContext.responseComplete(); // Important! Else JSF will attempt to render the response which obviously will fail since it's already written with a file and closed.
}
That said, if you have the possibility to get the PDF content as an InputStream rather than a byte[], I would recommend to use that instead to save the webapp from memory hogs. You then just write it in the well-known InputStream-OutputStream loop the usual Java IO way.
You just have to set the mime type to application/x-pdf into your response. You can use the setContentType(String contentType) method to do this in the servlet case.
In JSF/JSP you could use this, before writing your response:
<%# page contentType="application/x-pdf" %>
and response.write(yourPDFDataAsBytes()); to write your data.
But I really advise you to use servlets in this case. JSF is used to render HTML views, not PDF or binary files.
With servlets you can use this :
public MyPdfServlet extends HttpServlet {
protected doGet(HttpServletRequest req, HttpServletResponse resp){
OutputStream os = resp.getOutputStream();
resp.setContentType("Application/x-pdf");
os.write(yourMethodToGetPdfAsByteArray());
}
}
Resources :
mimeapplication.net - pdf
Javadoc - ServletResponse
Javadoc - HttpServlet
When sending raw data to the browser using JSF, you need to extract the HttpServletResponse from the FacesContext.
Using the HttpServletResponse, you can send raw data to the browser using the standard IO API.
Here is a code sample:
public String getFile() {
byte[] pdfData = ...
FacesContext context = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
OutputStream out = response.getOutputStream();
// Send data to out (ie, out.write(pdfData)).
}
Also, here are some other things you might want to consider:
Set the content type in the HttpServletResponse to inform the browser you're sending PDF data:
response.setContentType("application/pdf");
Inform the FacesContext that you sent data directly to the user, using the context.responseComplete() method. This prevents JSF from performing additional processing that is unnecessary.

Categories

Resources