我可以一次性将图片保存到 Blobstore 并将数据保存到 Datastore 吗?

Can I save images to Blobstore and save data to Datastore in one trip?

这个论点已经在很多场合提出并得到解决:Blobstore 在存储图像方面比 DataStore 更好。现在假设我有一个类似于 Instagram 或 Facebook 或 Yelp 或任何图像密集型应用程序的应用程序。在我的特殊情况下,理想模型是

public class IdealPostModel{

  Integer userId;
  String synopsys;
  Blob image;
  ...//more data/fields about the post

}

但由于我必须使用 BlobStore,我的模型没有 blob,而是 URL 或 BlobKey。重要的是要发送一个 post(即保存一个 post 到服务器)应用程序必须——按照这个顺序——

  1. 将所有非 blob 数据发送到服务器。
  2. 等待服务器响应 BlobstoreUtils.generateServingUrl(null) 数据
  3. 将图像发送到 BlobStore
  4. 让 BlobStore 使用图像的 BlobKey 或 url 向我的服务器发送响应
  5. 将 BlobKey/url 存储在我的 DataStore 实体中

握手次数太多了!!!

有没有办法将第一步中的所有数据发送到服务器:字符串和图像。然后让服务器从那里做其他一切?当然,我在这里希望减少工作量。我想 App Engine 现在应该已经很成熟了,一定有比我的架构更简单的方法。

现在我当然会在这里,因为我遇到了数据已保存但 BlobKey 或 URL 未保存到实体的情况。大约有 10% 的时间会发生这种情况。或者可能更少,但确实感觉像是 10%。它让我的用户发疯,这意味着它让我更加发疯,因为我不想失去我的用户。

理想情况下

  1. 应用一次调用即可将所有内容发送到服务器:图像和元数据,例如 userId 和 synopsys
  2. 服务器以某种方式从 Blobstore 获取 blob 密钥
  3. 服务器将图像发送到 blobstore,存储在提供的 blob 键中,服务器将其他数据发送到 DataStore,还包括数据存储中的 blob 键。

更新

    public static String generateServingUrl(String path) {
        BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
        return blobstoreService.createUploadUrl(null == path ? "/upload" : path);
    }

这是我服务器上的一个片段。

工作流程不同。举个例子:

  1. 新post的表单下有"Post"按钮和"Attach an image"按钮。

  2. 当用户点击“附加”按钮时,您要求用户 select 一个文件并将其保存到 BlobStore(或 Google 云存储)。无需调用 BlobstoreUtils.generateServingUrl(null) - 您需要上传 URL。当调用 returns 键时,您将其存储在 Post 对象中。

  3. 当用户点击 Post 按钮时,您会保存 Post - 包括数据存储中的图像密钥。因此,整个工作流只需要两次调用。

  4. 如果用户点击“取消”按钮 - 请记住删除上传的图像(如果有),否则它们将被孤立。棘手的部分是,如果用户只是离开了您的应用程序或失去了连接,就删除这些图像。

如果需要,您可以反向操作 - 先保存 post,然后让用户附加图像。这不是大多数用户所期望的,但它解决了孤立图像的问题。

您实际上可以在一个请求中发送所有内容。

请记住,当您使用通过调用 blobstoreService.createUploadUrl("/yourservingurl") 获得的 URL 发送 blob 时,GAE 实际上会向不同的 URL 发出第一个请求,存储 blob,然后调用 /yourservingurl 将 blobkeys 传递给您,您可以通过以下方式检索这些密钥:

Map<String, List<BlobKey>> blobs = blobstoreService.getUploads(req);
List<BlobKey> blobKeys = blobs.get("myFile");

所以实际上所有其他表单值都将在第一次请求后丢失,但是 如果您可以动态构建 URL 例如

blobstoreService.createUploadUrl("/yourservingurl?param1=a&param2=b")

然后您可以在 Servlet 上取回这些参数并立即保存所有内容(包括已存储的 blob 的 blobkey),从而减少对数据存储的调用。

更新: 步骤是

1) 在客户端收集所有参数并使用这些参数创建上传 URL 例如:blobstoreService.createUploadUrl("/yourservingurl?userId=989787")。 GAE 将为该特定请求生成唯一的 URL。

当您提交表单时,GAE 将保留 blob 并调用 /yourservingurl

2) 在服务于 /yourservingurl 的 Servlet 上,您将获得您上传的所有 blobkeys 表单文件:blobstoreService.getUploads(request) AND你可以得到你包含在标准中的参数request.getParameter("userId")

3) 现在在您的 servlet 中,您拥有发送的所有参数(例如 userId)以及 blobkey,您可以在一次调用中保留您的 Post 对象。