32

eclipse プラグインを使用して、アプリエンジンに接続された Android プロジェクトを開発しています。アプリの 1 つの側面は、ユーザー Alpha がユーザー Bravo に写真を送信できるようにすることです。そのために、次のセットアップを行います。

ユーザー アルファ投稿:

  • エンドポイントを介してアプリ エンジン サーバーに画像を送信する
  • サーバーはイメージをブロブ ストアに保存します
  • サーバーはブロブキーをデータストアに保存します

ユーザー Bravo 取得:

  • サーバーはデータストアから blobkey を取得します
  • サーバーは blob キーを使用して画像を取得します
  • サーバーはエンドポイントを使用して Android アプリに画像を送信します

この設定には、私の Android アプリが画像を送信してから、ブロブの痛みで画像が見えるようになるまで 2 分以上かかります。言うまでもなく、これはまったく受け入れられません。

私のサーバーは、次のコードを使用して、プログラムで画像を処理しています。

public static BlobKey toBlobstore(Blob imageData) throws FileNotFoundException, FinalizationException, LockException, IOException {
        if (null == imageData)
            return null;

        // Get a file service
        FileService fileService = FileServiceFactory.getFileService();

        // Create a new Blob file with mime-type "image/png"
        AppEngineFile file = fileService.createNewBlobFile("image/jpeg");// png

        // Open a channel to write to it
        boolean lock = true;
        FileWriteChannel writeChannel = fileService.openWriteChannel(file, lock);

        // This time we write to the channel directly
        writeChannel.write(ByteBuffer.wrap
            (imageData.getBytes()));

        // Now finalize
        writeChannel.closeFinally();
        return fileService.getBlobKey(file);
    }

エンドポイントを使用するように公式の例を適応させる方法(アプリ エンジン インスタンスを使用する必要がある場合) またはgetServingUrl(インスタンスをバイパスして) ブロブを保存して提供する方法を知っている人はいますか?
言葉の代わりにコードを含めてください。ありがとう。

4

3 に答える 3

32

私がこれをどのように行っているかを共有します。私は google-cloud-endpoints を使用していませんが、独自の REST ベースの API を使用していますが、いずれにしても同じ考えである必要があります。

コードを使用して段階的にレイアウトします。うまくいけば、明確になります。この例のように一般的な方法を使用するのではなく、エンドポイントを使用するようにリクエストを送信する方法を変更するだけです。定型文をいくつか含めていますが、簡潔にするためにtry/catch、エラーチェックなどは除外しています。

ステップ 1 (クライアント)

最初のクライアントがサーバーからのアップロード URL を要求します。

HttpClient httpclient = new DefaultHttpClient();    
HttpConnectionParams.setConnectionTimeout(httpclient.getParams(), 10000); //Timeout Limit

HttpGet httpGet = new HttpGet("http://example.com/blob/getuploadurl");
response = httpclient.execute(httpGet);

ステップ 2 (サーバー)

サーバー側では、アップロード リクエスト サーブレットは次のようになります。

String blobUploadUrl = blobstoreService.createUploadUrl("/blob/upload");

res.setStatus(HttpServletResponse.SC_OK);
res.setContentType("text/plain");

PrintWriter out = res.getWriter();
out.print(blobUploadUrl);
out.flush();
out.close();

createUploadUrl の引数に注意してください。これは、実際のアップロードが完了すると、クライアントがリダイレクトされる場所です。ここで、blobkey および/または提供 URL を保存し、それをクライアントに返します。ステップ4を処理するサーブレットをそのURLにマップする必要があります

ステップ 3 (クライアント) 再度クライアントに戻り、ステップ 2 で返された URL を使用して実際のファイルをアップロード URL に送信します。

HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(uploadUrlReturnedFromStep2);

FileBody fileBody  = new FileBody(thumbnailFile);
MultipartEntity reqEntity = new MultipartEntity();

reqEntity.addPart("file", fileBody);

httppost.setEntity(reqEntity);
HttpResponse response = httpclient.execute(httppost)

createUploadUrl()このリクエストが手順 2 でサーブレットに送信されると、前の手順で指定したサーブレットにリダイレクトされます。

ステップ 4 (サーバー)

サーバー側に戻ります。これは、 にマップされた URL を処理するサーブレットblob/uploadです。ここでは、blobkey とサービス URL を json オブジェクトでクライアントに返します。

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

res.setStatus(HttpServletResponse.SC_OK);
res.setContentType("application/json");

JSONObject json = new JSONObject();
json.put("servingUrl", servingUrl);
json.put("blobKey", blobKey.getKeyString());

PrintWriter out = res.getWriter();
out.print(json.toString());
out.flush();
out.close();

ステップ 5 (クライアント)

json から blobkey とサービス URL を取得し、それをユーザー ID などと一緒に送信してデータストア エンティティに保存します。

JSONObject resultJson = new JSONObject(resultJsonString);

String blobKey = resultJson.getString("blobKey");
String servingUrl = resultJson.getString("servingUrl");

List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);

nameValuePairs.add(new BasicNameValuePair("userId", userId));
nameValuePairs.add(new BasicNameValuePair("blobKey",blobKey));
nameValuePairs.add(new BasicNameValuePair("servingUrl",servingUrl));

HttpClient httpclient = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(httpclient.getParams(), 10000);

HttpPost httppost = new HttpPost(url);
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);

// Continue to store the (immediately available) serving url in local storage f.ex

ステップ 6 (サーバー) データストアにすべてを実際に格納 (この例では objectify を使用)

final String userId   = req.getParameter("userId");
final String blobKey  = req.getParameter("blobKey");
final String servingUrl = req.getParameter("servingUrl");

ExampleEntity entity = new ExampleEntity();
entity.setUserId(userId);
entity.setBlobKey(blobKey);
entity.setServingUrl(servingUrl);

ofy().save().entity(entity);

これで物事がより明確になることを願っています。このより一般的な例の代わりにクラウド エンドポイントを使用するように回答を編集したい場合は、お気軽に :)

配信URLについて

サービング URL は、その場で画像を動的にスケーリングできるため、画像をクライアントに提供する優れた方法です。たとえば=sXXX、サービング URL の末尾に追加するだけで、小さな画像を LDPI ユーザーに送信できます。XXX は、画像の最大寸法のピクセル サイズです。インスタンスを完全に避けて帯域幅のみを支払い、ユーザーは必要なものだけをダウンロードします。

PS!

ステップ 4 で停止し、ステップ 3 で userId f.ex を渡すことにより、そこに直接保存することができるはずです。すべてのパラメーターはステップ 4 に送信されるはずですが、うまくいきませんでした。現時点でのやり方なので、うまくいくことがわかっているので、この方法で共有しています。

于 2013-06-02T21:08:05.527 に答える
2

エンドポイントの API でコールバック サービスを実行する方法をいろいろ試したので、そのアプローチを中止します。ただし、APIエンドポイントに並列サーブレットを作成することでその問題を解決できました。クラスサーバーを定義してweb.xml構成を追加するだけで済みます。ここで私の解決策:

1 アップロード用の URL を取得するための Enpoint サービス: 次に、サービスを clientId で保護することができます

@ApiMethod(name = "getUploadURL",  httpMethod = HttpMethod.GET)
    public Debug getUploadURL() { 
        String blobUploadUrl =  blobstoreService.createUploadUrl("/update");
        Debug debug = new Debug(); 
        debug.setData(blobUploadUrl);
        return debug; 
    }

2. これで、クライアントはアップロード URL を取得するためにエンドポイントを呼び出すことができます:
おそらく次のようなものです (Android の場合、クライアント ライブラリのエンポイントも使用します):

gapi.client.debugendpoint.getUploadURL().execute(); 

3. 次のステップは、最後のステップでキャッチした URL への投稿 です。Android の httpClient を使用してこれを行うことができます。私の場合は、Web からアップロードする必要があり、フォームを使用し、onChangeFile() イベント コールバックを使用します。 (ステップ3を使用して)uploadurlを取得し、フォームパラメータ「action」と「codeId」を変更する応答があった場合、誰かが送信ボタンをクリックすることを決定します。

<form id="submitForm"  action="put_here_uploadUrl" method="post" enctype="multipart/form-data">
<input type="file" name="image" onchange="onChangeFile()">
<input type="text" name="codeId" value='put_here_some_dataId'>
<input type="submit" value="Submit"></form>

4 最後に、並列サーブレット クラス:

@SuppressWarnings("serial")
public class Update  extends HttpServlet{

    public void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {    

        String userId   = req.getParameter("codeId");

        List<BlobKey> blobs = BSF.getService().getUploads(req).get("image");
        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();
        try {
            json.put("imageUrl", servingUrl);
            json.put("codeId", "picture_of_"+userId);
            json.put("blobKey",  blobKey.getKeyString());
        } catch (JSONException e){

            e.printStackTrace();            
        }

        PrintWriter out = resp.getWriter();
        out.print(json.toString());
        out.flush();
        out.close();
    }
}

com.apppack が更新クラスのパッケージである web.xml に追加します。

<servlet>
<servlet-name>update</servlet-name>
<servlet-class>com.apppack.Update</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>update</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
于 2015-02-27T19:50:59.307 に答える