Храните изображение в Blobstore от клиента android и извлекайте blobkey и загружайте URL-адрес для хранения в хранилище данных. - GAE

В моем приложении для Android я хочу загрузить изображение в Blobstore, а затем загрузить URL-адрес Upload и изображение Blobkey, чтобы я мог сохранить Blobkey в DataStore.

Я пробовал этот код, но мое изображение не загружается:

Сервлет (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);
    }

Код: клиент 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;
                }

Это вернет URL-адрес загрузки в форме /_ah/upload/akjdhjahdjaudshgaajsdhjsdh, который я могу использовать для хранения изображения.

Этот код использует url для хранения изображения:

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

Здесь, если я проверяю значение String s, он показывает null. Это означает, что он возвращает нулевой ответ. Я не знаю, в чем проблема с этим кодом. Пожалуйста, помогите мне решить эту проблему.

Ответ 1

После многих попыток я решил эту проблему. Чтобы сохранить изображение в blobstore, первому android нужно сделать запрос сервлету, который будет генерировать URL-адрес загрузки:

Клиент Android: он запросит генерировать URL-адрес и получит URL-адрес из сервлета

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 - сервлет для генерации URL-адреса и отправки ответа клиенту

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

В клиенте android напишите ниже код, загружающий изображение, чтобы возвратить ответ от сервлета.

//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, который возвращает Uploadurl и Blobkey изображения

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

    }

Ответ 2

Благодаря zanky мне удалось это понять, и я хочу добавить свой код, потому что некоторый код устарел в его ответе, а также некоторый код нуждается в дополнительном объяснении, таком как переопределение и асинтеза. Кстати, код может не работать на локальном сервере из-за путаницы localhost и IP. Попытайтесь использовать движок приложения, когда будете готовы.

Servlet-1 BlobUrlGet. Это пойдет на сторону приложения. Этот сервлет создает URL-адрес загрузки для метода post в клиентском коде.

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 Этот код будет автоматически вызываться, когда сообщение будет сделано для blobstore. В результате это даст нам blobkey и сервисный url для загрузки изображения позже.

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. Эта асинтеза вызовет сервлеты и отправит сообщение в blobstore с информацией, которую он получает.

    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;

    }
    }

В конце концов, нам нужно обновить web.xml, чтобы иметь возможность выполнять сервлеты.

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

Ответ 3

Я работаю с конечными точками в Android Studio, благодаря SAVANTE, я могу закончить свой код, но мне пришлось внести небольшие корректировки.

в Servlet 1: Я использовал Endpoints, с этим я могу очень легко обрабатывать OAuth2 в моем методе:

@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 в конечных точках Android Studio, не позволяйте мне использовать JSONObject для этого rason Я создаю свой собственный Json: в Servlet 2:

String myJson = "{'servingUrl': '" + servingUrl +
                        "', 'blobKey': '" + blobKey.getKeyString() + "'}";

            PrintWriter out = resp.getWriter();
            out.print(myJson);
            out.flush();
            out.close();

Я надеюсь работать для кого-то еще, я потратил 48 часов, пытаясь понять и управлять Blobstore.

Изменить:

Чтобы сделать аутентифицированный звонок от клиента, это способ использования учетных данных 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);

При создании вашей конечной точки введите свои учетные данные:

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

Для получения имени учетной записи клиента используйте Plus API

accountName = Plus.AccountApi.getAccountName(mGoogleApiClient);

Прочитайте ссылки в комментариях, с документацией Google, чтобы это понять.