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:
- Google Endpoints Android con Python Backend
- Alcance de acceso utilizando el nombre de tipo en Google Cloud / Android Mobile Backend Starter
- Puntos finales de la nube de Google App Engine Marcador Pr @ blem -> Generar error del motor de aplicaciones en el proyecto limpio de Android
- Google Cloud Datastore / Mobile Backend Starter - Error de permisos en la actualización / actualizaciónTodas las llamadas
- Pruebas locales para la aplicación de Android que utilizan puntos finales de Cloud para Google App Engine
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.
- ¿Tengo que usar CollectionResponse como un tipo de retorno en GAE Endpoints API o puedo usar colecciones java de entidades?
- Google Cloud Endpoint continúa lanzando una excepción de "final inesperado"
- Credenciales de la cuenta de servicio de Firebase Permiso de lectura de Json leído
- Endpoints de Google App Engine Cloud userId es nulo
- Problemas al ejecutar aplicaciones desplegadas en Google AppEngine
- Nodos de la nube de Appengine generación de cliente que no genera el archivo jar de origen
- No se puede comunicar Google Datastore con la aplicación Android en Android Studio
- Error de la aplicación GAE Python (servicios de usuario) en Android Chrome con varias cuentas de Google asociadas
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.
- Retrofit2 + SimpleXML en Kotlin: MethodException: La anotación debe marcar un método set o get
- Path.approximate () no es compatible con android studio 0.8.14 beta