In my Android application, I want to upload image to the Blobstore, then retrieve an Upload url and the image's Blobkey, so I can store the Blobkey in the DataStore.
I've tried this code, but my image isn't uploading:
Servlet (Return upload url)
BlobstoreService blobstoreService = BlobstoreServiceFactory
.getBlobstoreService();
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
UploadOptions uploadOptions = UploadOptions.Builder
.withGoogleStorageBucketName("photobucket11")
.maxUploadSizeBytes(1048576);
String blobUploadUrl = blobstoreService.createUploadUrl("/upload",
uploadOptions);
// String blobUploadUrl = blobstoreService.createUploadUrl("/uploaded");
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("text/plain");
PrintWriter out = resp.getWriter();
out.print(blobUploadUrl);
}
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
doGet(req, resp);
}
Code : Android client
Bitmap bmp = BitmapFactory.decodeFile(imagePath);
ByteArrayOutputStream out = new ByteArrayOutputStream();
bmp.compress(CompressFormat.JPEG, 75, out);
byte[] imgByte = out.toByteArray();
String encodedImage = Base64.encodeToString(imgByte,
Base64.DEFAULT);
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(
"app-url/ImgUpload");
HttpResponse response = httpClient.execute(httpGet);
HttpEntity urlEntity = response.getEntity();
InputStream in = urlEntity.getContent();
String str = "";
while (true) {
int ch = in.read();
if (ch == -1)
break;
str += (char) ch;
}
This will return upload url in form of /_ah/upload/akjdhjahdjaudshgaajsdhjsdh
which I can use to store the image.
This code uses the url to store the image:
httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost(str);
ByteArrayBody bab = new ByteArrayBody(imgByte, "forest.jpg");
MultipartEntity reqEntity = new MultipartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE);
reqEntity.addPart("uploaded", bab);
reqEntity.addPart("photoCaption", new StringBody("sfsdfsdf"));
postRequest.setEntity(reqEntity);
response = httpClient.execute(postRequest);
BufferedReader reader = new BufferedReader(
new InputStreamReader(
response.getEntity().getContent(), "UTF-8"));
String sResponse;
StringBuilder s = new StringBuilder();
while ((sResponse = reader.readLine()) != null) {
s = s.append(sResponse);
}
Here, if I check value of the String s
, it shows null
. That means it is returning a null response. I don't know what the problem is with this code. Please guide me to solve this problem.
After many tries i solved this problem. To store image in blobstore, first android needs to make request to servlet which will generate upload url :
Android client : It will request to generate url and gets url from servlet
HttpClient httpClient = new DefaultHttpClient();
//This will invoke "ImgUpload servlet
HttpGet httpGet = new HttpGet("my-app-url/ImgUpload");
HttpResponse response = httpClient.execute(httpGet);
HttpEntity urlEntity = response.getEntity();
InputStream in = urlEntity.getContent();
String str = "";
while (true) {
int ch = in.read();
if (ch == -1)
break;
str += (char) ch;
}
ImgUpload.java - Servlet to generate url and sends response to client
BlobstoreService blobstoreService = BlobstoreServiceFactory
.getBlobstoreService();
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
//"uploaded" is another servlet which will send UploadUrl and blobkey to android client
String blobUploadUrl = blobstoreService.createUploadUrl("/uploaded");
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("text/plain");
PrintWriter out = resp.getWriter();
out.print(blobUploadUrl);
}
In android client,write below code upload image to returned response from above servlet.
//Save image to generated url
HttpPost httppost = new HttpPost(str);
File f = new File(imagePath);
FileBody fileBody = new FileBody(f);
MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("file", fileBody);
httppost.setEntity(reqEntity);
response = httpClient.execute(httppost); //Here "uploaded" servlet is automatically invoked
urlEntity = response.getEntity(); //Response will be returned by "uploaded" servlet in JSON format
in = urlEntity.getContent();
str = "";
while (true) {
int ch = in.read();
if (ch == -1)
break;
str += (char) ch;
}
JSONObject resultJson = new JSONObject(str);
String blobKey = resultJson.getString("blobKey");
String servingUrl = resultJson.getString("servingUrl");
uploaded.java- servlet which returns Uploadurl and Blobkey of image
BlobstoreService blobstoreService = BlobstoreServiceFactory
.getBlobstoreService();
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
try {
List<BlobKey> blobs = blobstoreService.getUploads(req).get("file");
BlobKey blobKey = blobs.get(0);
ImagesService imagesService = ImagesServiceFactory
.getImagesService();
ServingUrlOptions servingOptions = ServingUrlOptions.Builder
.withBlobKey(blobKey);
String servingUrl = imagesService.getServingUrl(servingOptions);
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("application/json");
JSONObject json = new JSONObject();
json.put("servingUrl", servingUrl);
json.put("blobKey", blobKey.getKeyString());
PrintWriter out = resp.getWriter();
out.print(json.toString());
out.flush();
out.close();
} catch (JSONException e) {
e.printStackTrace();
}
}
Thanks to zanky I managed to understand it and I want to add my code because some code is deprecated in his answer and also some code need more explanation like overriding and asynctask. By the way the code may not work on local server because of the localhost and IP confusion. Try on the app engine when you are ready.
Servlet-1 BlobUrlGet. This will go to appengine side. This servlet produces upload url for the post method in the client code.
public class BlobUrlGet extends HttpServlet{
BlobstoreService blServ = BlobstoreServiceFactory.getBlobstoreService();
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
String blobUploadUrl = blServ.createUploadUrl("/blobupload");
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("text/plain");
PrintWriter out = resp.getWriter();
out.print(blobUploadUrl);
}
}
Servlet-2 BlobUpload This code will be automatically called when the post is done to blobstore. As a result it will give us blobkey and serving url to download the image later.
public class BlobUpload extends HttpServlet {
BlobstoreService blobstoreService = BlobstoreServiceFactory
.getBlobstoreService();
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
try {
List<BlobKey> blobs = blobstoreService.getUploads(req).get("photo");
BlobKey blobKey = blobs.get(0);
ImagesService imagesService = ImagesServiceFactory.getImagesService();
ServingUrlOptions servingOptions = ServingUrlOptions.Builder.withBlobKey(blobKey);
String servingUrl = imagesService.getServingUrl(servingOptions);
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("application/json");
JSONObject json = new JSONObject();
json.put("servingUrl", servingUrl);
json.put("blobKey", blobKey.getKeyString());
PrintWriter out = resp.getWriter();
out.print(json.toString());
out.flush();
out.close();
} catch (JSONException e) {
e.printStackTrace();
}
}
}
Android Client side code. This asynctask will call the servlets and do the post to blobstore with the info it gets.
private class GetBlobUrlTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... arg0){
HttpClient httpClient = new DefaultHttpClient();
//This will invoke "ImgUpload servlet
HttpGet httpGet = new HttpGet("http://PUT_YOUR_URL_HERE/bloburlget");
HttpResponse response;
try {
response = httpClient.execute(httpGet);
HttpEntity urlEntity = response.getEntity();
InputStream in = urlEntity.getContent();
String str = "";
StringWriter writer = new StringWriter();
String encoding = "UTF-8";
IOUtils.copy(in, writer, encoding);
str = writer.toString();
HttpPost httppost = new HttpPost(str);
File f = new File(picturePath);
MultipartEntityBuilder reqEntity = MultipartEntityBuilder.create();
reqEntity.addBinaryBody("photo", f, ContentType.create("image/jpeg"), "foto2.jpg");
httppost.setEntity(reqEntity.build());
response = httpClient.execute(httppost); //Here "uploaded" servlet is automatically invoked
str = EntityUtils.toString(response.getEntity());
JSONObject resultJson = new JSONObject(str);
blobKey = resultJson.getString("blobKey");
servingUrl = resultJson.getString("servingUrl");
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
After all we need to update web.xml to be able to execute servlets.
<servlet>
<servlet-name>BlobUrlGet</servlet-name>
<servlet-class>PUT_YOUR_PACKAGE_NAME.BlobUrlGet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>BlobUrlGet</servlet-name>
<url-pattern>/bloburlget</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>BlobUpload</servlet-name>
<servlet-class>PUT_YOUR_PACKAGE_NAME.BlobUpload</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>BlobUpload</servlet-name>
<url-pattern>/blobupload</url-pattern>
</servlet-mapping>
I am working with endpoints in Android Studio, thanks to SAVANTE, I can finish my code but I had to make small adjustments.
in Servlet 1: I used Endpoints, with this I can handle very easy the OAuth2 in my method:
@ApiMethod(name = "getBlobURL", scopes = {Constants.EMAIL_SCOPE},
clientIds = {Constants.WEB_CLIENT_ID,
Constants.ANDROID_CLIENT_ID,
com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID},
audiences = {Constants.ANDROID_AUDIENCE})
public BlobAttributes getBlobURL(User user) throws UnauthorizedException,
ConflictException{
//If if is not null, then check if it exists. If yes, throw an Exception
//that it is already present
if (user == null){
throw new UnauthorizedException("User is Not Valid");
}
BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
String blobUploadUrl = blobstoreService.createUploadUrl("/blobupload");
//BlobAttributes is a class
BlobAttributes ba= new BlobAttributes();
ba.setBlobURL(blobUploadUrl);
return ba;
}
My Backend in endpoints Android Studio, do not let me use JSONObject for this rason I make my own Json: in Servlet 2:
String myJson = "{'servingUrl': '" + servingUrl +
"', 'blobKey': '" + blobKey.getKeyString() + "'}";
PrintWriter out = resp.getWriter();
out.print(myJson);
out.flush();
out.close();
I hope works for somebody else, I spent 48 hours trying to understand and operate Blobstore.
Edit:
For make a authenticated call from client this is the way using Google credentials:
accountName = settings.getString(start.KEY_ACCOUNT_NAME, null); //Email account that you before save it
credential = GoogleAccountCredential.usingAudience(getActivity(),
start.WEB_CLIENT_ID); //WEB_CLIENT_ID is your WEB ID in Google Console
credential.setSelectedAccountName(accountName);
When build your Endpoint put your credential:
PostEndpoint.Builder builder = new PostEndpoint.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), credential)
.setRootUrl(getActivity().getString(R.string.backend_url_connection));
myApiService = builder.build();
For Get the Account Name of the client, use Plus API
accountName = Plus.AccountApi.getAccountName(mGoogleApiClient);
Read the links down in the comments, with Google documentation for good understand this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With