Usa las API de App Engine para Cloud Storage

En este documento, se describe cómo almacenar y recuperar datos mediante la biblioteca cliente de App Engine para Cloud Storage. También se supone que sabes cómo compilar una aplicación de App Engine, como se describe en la Guía de inicio rápido del entorno estándar de App Engine en Java 8. También se supone que comprende los conceptos básicos para usar Cloud Storage en App Engine.

Descarga la biblioteca cliente de App Engine para Cloud Storage

Puedes descargar la biblioteca con herramientas populares como Apache Maven, Apache Ivy o Git, o bien puedes descargar la biblioteca de forma manual desde el repositorio de Maven. Elige tu método preferido.

Git

Si tienes Git instalado, puedes clonar el repositorio de GitHub de la biblioteca cliente de Google Cloud Storage de la siguiente manera:

git clone https://github.com/GoogleCloudPlatform/appengine-gcs-client.git

Maven

Los usuarios de Maven deben incluir lo siguiente en el archivo pom.xml de su aplicación:

<dependency>
    <groupId>com.google.appengine.tools</groupId>
    <artifactId>appengine-gcs-client</artifactId>
    <version>0.7</version>
</dependency>

Ivy

Los usuarios de Ivy deben incluir lo siguiente en el archivo ivy.xml de su aplicación:

<dependency org="com.google.appengine.tools"
            name="appengine-gcs-client"
            rev="latest.integration" />

Descarga manual

Visita el repositorio Maven de la biblioteca y descarga los últimos archivos JAR de clase, fuente y JavaDoc:

Además, deberás descargar las siguientes dependencias y, luego, incluirlas en tu aplicación:

Las LCA y la biblioteca cliente de App Engine

Una aplicación que usa la biblioteca cliente no puede cambiar la LCA del depósito, pero puede especificar una LCA que controle el acceso a los objetos que cree. La configuración de LCA disponible se describe en la documentación sobre la clase FcsFileOptions.

Cloud Storage y subdirectorios

La biblioteca cliente de App Engine para Cloud Storage permite suministrar delimitadores de subdirectorios cuando creas un objeto, aunque no hay subdirectorios verdaderos en Cloud Storage. En Cloud Storage, un subdirectorio es una parte del nombre de archivo del objeto.

Por ejemplo, podrías suponer que si creas un objeto somewhere/over/the/rainbow.mp3, se almacenaría el archivo rainbow.mp3 en el subdirectorio somewhere/over/the/. En realidad, el nombre que recibe el objeto es somewhere/over/the/rainbow.mp3.

Usa la biblioteca cliente de App Engine con el servidor de desarrollo para aplicaciones

Puedes utilizar la biblioteca cliente con el servidor de desarrollo. Sin embargo, dado que no existe una emulación local de Cloud Storage, todas las solicitudes de lectura y escritura de archivos deben enviarse a través de Internet a un depósito de Cloud Storage real.

A fin de usar la biblioteca cliente con el servidor de desarrollo para aplicaciones, ejecuta dev_appserver.py con la marca --default_gcs_bucket_name [BUCKET_NAME], y reemplaza [BUCKET_NAME] con el nombre del depósito de Cloud Storage que utilizas.

Esta marca controla el depósito que se mostrará cuando la aplicación llame a file.DefaultBucketName(ctx).

Lee y escribe en Google Cloud Storage

Importaciones necesarias

En el siguiente fragmento se muestran las importaciones que necesitas para el acceso a Cloud Storage a través de la biblioteca cliente:

import com.google.appengine.tools.cloudstorage.GcsFileOptions;
import com.google.appengine.tools.cloudstorage.GcsFilename;
import com.google.appengine.tools.cloudstorage.GcsInputChannel;
import com.google.appengine.tools.cloudstorage.GcsOutputChannel;
import com.google.appengine.tools.cloudstorage.GcsService;
import com.google.appengine.tools.cloudstorage.GcsServiceFactory;
import com.google.appengine.tools.cloudstorage.RetryParams;

Cómo especificar el depósito de Cloud Storage

En el siguiente fragmento se muestra una forma para permitir que el usuario especifique un nombre del depósito cuando escribe un archivo en un depósito:

function uploadFile() {
  var bucket = document.forms["putFile"]["bucket"].value;
  var filename = document.forms["putFile"]["fileName"].value;
  if (bucket == null || bucket == "" || filename == null || filename == "") {
    alert("Both Bucket and FileName are required");
    return false;
  } else {
    var postData = document.forms["putFile"]["content"].value;
    document.getElementById("content").value = null;

    var request = new XMLHttpRequest();
    request.open("POST", "/gcs/" + bucket + "/" + filename, false);
    request.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
    request.send(postData);
  }
}

El fragmento antecede al /gcs/ requerido para el depósito y nombre del archivo que proporcionó el usuario.

Cómo escribir en Cloud Storage

Para escribir un archivo en Cloud Storage:

@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
  GcsFileOptions instance = GcsFileOptions.getDefaultInstance();
  GcsFilename fileName = getFileName(req);
  GcsOutputChannel outputChannel;
  outputChannel = gcsService.createOrReplace(fileName, instance);
  copy(req.getInputStream(), Channels.newOutputStream(outputChannel));
}

En este ejemplo se escribe un archivo nuevo en Cloud Storage o, si ya existe un archivo con el mismo nombre, se lo reemplaza. Esto resulta útil porque una vez que escribes un archivo en Cloud Storage, no puedes modificarlo. Para cambiar el archivo, debes realizar las modificaciones en una copia del archivo y, luego, reemplazar el archivo anterior.

Cómo leer desde Cloud Storage

Para leer un archivo desde Cloud Storage:

@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
  GcsFilename fileName = getFileName(req);
  if (SERVE_USING_BLOBSTORE_API) {
    BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
    BlobKey blobKey = blobstoreService.createGsBlobKey(
        "/gs/" + fileName.getBucketName() + "/" + fileName.getObjectName());
    blobstoreService.serve(blobKey, resp);
  } else {
    GcsInputChannel readChannel = gcsService.openPrefetchingReadChannel(fileName, 0, BUFFER_SIZE);
    copy(Channels.newInputStream(readChannel), resp.getOutputStream());
  }
}

En la línea que contiene gcsService.openPrefetchingReadChannel, ten en cuenta el uso de recuperación previa. Esto almacena los datos en la memoria y los recupera antes de que se requieran para evitar el bloqueo de la llamada de lectura.

Modifica objetos en Cloud Storage

Para modificar un objeto existente en Cloud Storage, escribe el objeto modificado con el mismo nombre de archivo que el original.

Cómo borrar objetos de Cloud Storage

El siguiente procedimiento muestra cómo borrar objetos en una aplicación que almacena el nombre completo del objeto de Cloud Storage (nombre de archivo) en una base de datos de Cloud SQL:

final String bucket = "CLOUD-STORAGE-BUCKET"; // Cloud Storage bucket name
Map<String, String[]> userData = req.getParameterMap();

String[] image = userData.get("id"); // Grab the encoded image ID
String decodedId = new String(Base64.getUrlDecoder().decode(image[0])); // decode the image ID
int imageId = Integer.parseInt(decodedId);

// Grab the filename and build out a Cloud Storage filepath in preparation for deletion
try (PreparedStatement statementDeletePost = conn.prepareStatement(imageFilenameSql)) {
  statementDeletePost.setInt(1, imageId); // cast String to Int
  ResultSet rs = statementDeletePost.executeQuery(); // remove image record
  rs.next(); // move the cursor

  GcsFilename filename = new GcsFilename(bucket, rs.getString("filename"));
  if (gcsService.delete(filename)) {

    // Remove all records of image use in the blog
    // Use of foreign keys with cascading deletes will cause removal from blogpostImages table
    PreparedStatement statementDeleteImageRecord = conn.prepareStatement(deleteSql);
    statementDeleteImageRecord.setInt(1, imageId);
    statementDeleteImageRecord.executeUpdate();

    final String confirmation =
        "Image ID "
            + imageId
            + " has been deleted and record of its use in blog posts have been removed.";

    req.setAttribute("confirmation", confirmation);
    req.getRequestDispatcher("/confirm.jsp").forward(req, resp);
  } else {
    final String confirmation = "File marked for deletion does not exist.";

    req.setAttribute("confirmation", confirmation);
    req.getRequestDispatcher("/confirm.jsp").forward(req, resp);
  }
} catch (SQLException e) {
  throw new ServletException("SQL error", e);
}

El código anterior decodifica el ID de imagen codificada de Base64 y recupera el nombre de archivo de una imagen identificada por su image_id desde la tabla images. El nombre de archivo se convierte en un nombre de archivo válido para Cloud Storage con GcsFilename.

El archivo se borra del depósito mediante gcsService.delete. Finalmente, quita el registro de su uso en la tabla blogpostImage.

Pasos siguientes

¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...

Entorno estándar de App Engine para Java 8