Store image to Blobstore from android client and retrieve blobkey and upload url to store in Datastore. - GAE

后端 未结 3 949
一个人的身影
一个人的身影 2020-12-09 12:08

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.

相关标签:
3条回答
  • 2020-12-09 12:40

    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();
            }
    
        }
    
    0 讨论(0)
  • 2020-12-09 12:46

    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>
    
    0 讨论(0)
  • 2020-12-09 12:47

    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.

    0 讨论(0)
提交回复
热议问题