Almacena la imagen en Blobstore desde el cliente android y recupera blobkey y sube url para almacenarla en Datastore. GAE

En mi aplicación de Android, quiero cargar la imagen en Blobstore, luego recuperar una URL de carga y la Blobkey de la imagen, para poder almacenar la Blobkey en el DataStore.

He intentado este código, pero mi imagen no está subiendo:

Servlet (URL de carga de devolución)

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); } 

Código: cliente de Android

 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; } 

Esto devolverá url de carga en forma de /_ah/upload/akjdhjahdjaudshgaajsdhjsdh que puedo usar para almacenar la imagen.

Este código utiliza la url para almacenar la imagen:

 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); } 

Aquí, si compruebo el valor de la cadena s , se muestra null . Eso significa que está devolviendo una respuesta nula. No sé cuál es el problema con este código. Por favor, me guía para resolver este problema.

Después de muchos intentos solucioné este problema. Para almacenar la imagen en blobstore, el primer android necesita hacer una solicitud a servlet que generará url de carga:

Cliente Android: Pedirá para generar url y obtiene url de 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 para generar url y envía respuesta al cliente

 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); } 

En el cliente android, escriba debajo de la imagen de subida de código a la respuesta devuelta desde arriba del 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 que devuelve Uploadurl y Blobkey de imagen

 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(); } } 

Gracias a zanky me las arreglé para entenderlo y quiero añadir mi código porque algún código es obsoleto en su respuesta y también algún código necesita más explicación como overriding y asynctask. Por cierto, el código no funciona en el servidor local debido a la confusión localhost y IP. Pruebe el motor de aplicaciones cuando esté listo.

Servlet-1 BlobUrlGet. Esto irá al lado del appengine. Este servlet produce url de carga para el método post en el código del cliente.

 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 Este código se llamará automáticamente cuando se publique la publicación en blobstore. Como resultado, nos dará blobkey y servidor URL para descargar la imagen más tarde.

 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(); } } } 

Código de cliente de Android. Este asynctask llamará a los servlets y hará el post a blobstore con la información que recibe.

  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; } } 

Después de todo necesitamos actualizar web.xml para poder ejecutar 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> 

Estoy trabajando con terminales en Android Studio, gracias a SAVANTE, puedo terminar mi código, pero tuve que hacer pequeños ajustes.

En Servlet 1: Utilicé Endpoints, con esto puedo manejar muy fácil el OAuth2 en mi método:

 @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; } 

Mi Backend en los puntos finales Android Studio, no me deje usar JSONObject para este rason Hago mi propio Json: in Servlet 2:

 String myJson = "{'servingUrl': '" + servingUrl + "', 'blobKey': '" + blobKey.getKeyString() + "'}"; PrintWriter out = resp.getWriter(); out.print(myJson); out.flush(); out.close(); 

Espero que trabaje para otra persona, pasé 48 horas tratando de entender y operar Blobstore.

Editar:

Para realizar una llamada autenticada desde el cliente, esta es la forma de utilizar las credenciales de Google:

 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); 

Cuando construya su Endpoint, coloque su credencial:

 PostEndpoint.Builder builder = new PostEndpoint.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), credential) .setRootUrl(getActivity().getString(R.string.backend_url_connection)); myApiService = builder.build(); 

Para Obtener el nombre de cuenta del cliente, utilice Plus API

 accountName = Plus.AccountApi.getAccountName(mGoogleApiClient); 

Lea los enlaces en los comentarios, con la documentación de Google para entender bien esto.

  • GCM y App Engine para aplicaciones de chat
  • GCM duplicó mensajes
  • Convertir una cadena en número de coma flotante en java
  • Google OAuth2 - token de acceso y token de actualización -> invalid_grant / Code ya se redimió
  • Notificación Push mediante Firebase y Google Cloud Messaging
  • "No se pudo inicializar el SDK de App Engine en (ruta de acceso)" en eclipse 4.2.2 con Mac OSX León de montaña
  • Cambio de token de autenticación de Facebook
  • ¿Cómo enviar datos desde dispositivos móviles Android al almacén de datos de Google App Engine?
  • Cómo implementar un GCM Hello World para Android con Android Studio
  • Objectify OfyService NoClassDefFoundError para el punto final del motor de la aplicación
  • No se ha establecido la raíz SDK de App Engine. Asegúrese de establecer la variable de entorno 'APPENGINE_HOME' propiedad del sistema 'appengine.sdk.root'!
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.