Aprende a usar las listas de tareas en cola y la API de imágenes de App Engine para cambiar el tamaño de las imágenes.
Las listas de tareas en cola ejecutan el código fuera de la interacción directa del usuario, lo cual permite que se realicen tareas en segundo plano. En esta guía se utiliza una lista de tareas en cola para realizar tareas después de agregar una imagen a Cloud Storage. Las tareas que se tienen que realizar en la lista de tareas en cola son las siguientes:
- Recupera el archivo de imagen que acabas de subir a Cloud Storage.
- Cambia el tamaño a una imagen en miniatura con la API de imágenes.
- Almacena la miniatura en Cloud Storage.
El entorno de ejecución de Java 8 en App Engine también admite las clases de manipulación de imágenes nativas de Java, como AWT y Java2D.
Antes de comenzar
Configura tu entorno de desarrollo y crea tu proyecto de App Engine.
En esta guía se usa la biblioteca Apache Commons IOUtils. Para incluir la biblioteca IOUtils en tu proyecto de App Engine, sigue estos pasos:
Agrega a
pom.xml
:<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version> </dependency>
Importa bibliotecas
En el código de muestra proporcionado con esta guía, se usan las siguientes importaciones:
import com.google.appengine.api.images.Image;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ImagesServiceFactory;
import com.google.appengine.api.images.Transform;
import org.apache.commons.io.IOUtils;
Crea una lista de tareas en cola
Si bien App Engine proporciona una lista de tareas en cola default
, puedes crear diferentes listas de tareas en cola para los distintos tipos de trabajo. Por ejemplo, puedes crear una lista de tareas en cola con el fin de cambiar el tamaño de las imágenes y otra para actualizar la base de datos de la app.
Para agregar colas, crea el archivo queue.xml
en el directorio WEB-INF
del proyecto de App Engine. Una taskqueue debe especificar un nombre y una frecuencia de ejecución:
<?xml version="1.0" encoding="UTF-8"?>
<queue-entries>
<queue>
<name>resize-image</name>
<rate>60/h</rate>
</queue>
</queue-entries>
Esta cola de ejemplo con el nombre resize-image
define una frecuencia de ejecución de 60 veces por hora o una vez por minuto. Para ver las opciones de fila de lista completa, consulta la referencia queue.xml
.
Una lista de tareas en cola tiene dos componentes: el solicitante de tareas y el controlador de tareas. El solicitante agrega una tarea a la cola y la envía al controlador de tareas.
Agrega tareas a una cola
Para agregar una tarea a una cola, haz lo siguiente:
Crea un objeto de lista de tareas en cola mediante
QueueFactory.getQueue()
y asegúrate de especificar el nombre de la cola definido enqueue.xml
:Queue imageResizeQueue; // Taskqueue queue @Override public void init() throws ServletException { // Setup Cloud Storage service gcsService = GcsServiceFactory.createGcsService( new RetryParams.Builder() .initialRetryDelayMillis(10) .retryMaxAttempts(10) .totalRetryPeriodMillis(15000) .build()); // Initialize the queue object with the specific queue imageResizeQueue = QueueFactory.getQueue([QUEUE-NAME]); // Cloud SQL connection setup try { final String url = System.getProperty("cloudsql"); // Cloud SQL server URI try { conn = DriverManager.getConnection(url); // Connect to the database Statement createTable; // SQL statement // Batch SQL table creation commands createTable.addBatch(createContentTableSql); createTable.addBatch(createUserTableSql); createTable.addBatch(createImageTableSql); createTable.addBatch(createBlogPostImageTableSql); conn.createTable.executeBatch(); // Execute batch } catch (SQLException e) { throw new ServletException("Unable to connect to Cloud SQL", e); } } finally { // Nothing really to do here. } }
Agrega tareas al objeto
Queue
. Como se observa en la muestra de código,imageResizeQueue.add()
agrega una tarea al objetoimageResizeQueue
:try { // Add a queued task to create a thumbnail of the uploaded image imageResizeQueue.add( TaskOptions.Builder.withUrl("/tasks/imageresize").param("filename", filename)); }
Especifica el URI del controlador de tareas mediante
TaskOptions.Builder.withUrl()
, junto con cualquier parámetro enviado al controlador.En este ejemplo, el URI es
/tasks/imageresize
y el parámetro es una variable llamadafilename
que contiene el nombre del archivo de la imagen que se procesará.
Crea un controlador de tareas
Una vez que agregaste una tarea a la cola, el controlador de tareas asignado al URI /tasks/imageresize
se ejecutará. Un controlador de tareas es un servlet de Java que intenta realizar la tarea hasta lograrlo.
En este ejemplo, el controlador de tareas realiza tres tareas:
Recupera la imagen especificada por el emisor desde Cloud Storage.
Transforma la imagen en este ejemplo en una imagen en miniatura con la API de App Engine Image.
Almacena la imagen transformada (imagen en miniatura) en Cloud Storage.
Para crear el controlador de tareas:
Agrega una anotación que mapee el controlador al URI
/tasks/imageresize
:@WebServlet(name = "imageResize", description = "Task queue handler", urlPatterns = "/tasks/imageresize") public class imageResize extends HttpServlet { // Task handler functionality }
Configura una conexión a Cloud Storage como se documenta en la guía Usa Cloud Storage y recupera la imagen desde Cloud Storage:
public void init() throws ServletException { // initiate GcsService GcsService gcsService = GcsServiceFactory.createGcsService( new RetryParams.Builder() .initialRetryDelayMillis(10) .retryMaxAttempts(10) .totalRetryPeriodMillis(15000) .build()); }
Controla la solicitud entrante de la lista de tareas en cola con el nombre de archivo proporcionado para recuperar la imagen desde Cloud Storage:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String filename = req.getParameter("filename"); // Get the filename passed from the task requestor GcsFilename gcsFile = new GcsFilename(bucket, filename); // Create a valid Cloud Storage filename GcsInputChannel readChannel = gcsService.openPrefetchingReadChannel(gcsFile, 0, BUFFER_SIZE); // Read the file from Cloud Storage
Usa el objeto
ImagesService
para cambiar el tamaño de la imagen:// Get an instance of the ImagesService we can use to transform images. ImagesService imagesService = ImagesServiceFactory.getImagesService(); // Make an image directly from a byte array, and transform it. Image image = ImagesServiceFactory.makeImage(IOUtils.toByteArray(Channels.newInputStream(readChannel))); Transform resize = ImagesServiceFactory.makeResize(100, 50); // resize image to 100x50 Image resizedImage = imagesService.applyTransform(resize, image); // Write the transformed image back to a Cloud Storage object. gcsService.createOrReplace( new GcsFilename(bucket, "thumbnail_" + filename), new GcsFileOptions.Builder().acl("public-read").build(), ByteBuffer.wrap(resizedImage.getImageData()));
El fragmento anterior usa el método
makeResize()
de la API de imágenes para cambiar el tamaño de la imagen a una miniatura. Para ello, lee la imagen desde Cloud Storage enInputChannel
y la convierte en ByteArray medianteIOUtils.toByteArray()
.Después de aplicar la transformación, la imagen nueva tiene la string
thumbnail_
anexada a su nombre de archivo, escrita en Cloud Storage y con permiso de lectura pública.
Protege las URL del controlador de tareas
Debes proteger las tareas que realizan operaciones sensibles, como modificar datos, para que usuarios externos no puedan emitirlas de manera directa. Para ello, restringe el acceso a las tareas a los administradores de App Engine, lo cual no permite que los usuarios accedan a las URL de tareas. Ten en cuenta que esta restricción no aplica a las solicitudes de tareas que provienen de la app de App Engine.
En el ejemplo actual, los controladores de tareas tienen URL en la carpeta /tasks/
.
Para restringir el acceso a la carpeta /tasks/
a los administradores de App Engine, agrega lo siguiente al web.xml
del proyecto.
<security-constraint>
<web-resource-collection>
<web-resource-name>tasks</web-resource-name>
<url-pattern>/tasks/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
Quita una sola tarea de una cola
Para quitar una sola tarea de una cola, usa deleteTask()
:
private void removeTask(Queue queue, String taskName) {
queue.deleteTask(taskName); // remove a task from a queue
}
Quita todas las tareas de una cola
Para quitar todas las tareas de una cola, usa purge()
. La eliminación definitiva de las todas las tareas en la cola puede demorar hasta un minuto.
private void purgeQueue(Queue queue) {
queue.purge(); // remove all tasks from a queue
}
La eliminación definitiva de todas las tareas de una cola puede demorar hasta un minuto, por lo que deberías esperar unos segundos antes de agregar nuevas tareas a la cola.
Borra una lista de tareas en cola
Para borrar una lista de tareas en cola, quita la entrada del archivo queue.xml
del proyecto y vuelve a implementarla.
Implementa en App Engine
Puedes implementar tu aplicación en App Engine con Maven.
Ve al directorio raíz de tu proyecto y escribe lo siguiente:
mvn package appengine:deploy -Dapp.deploy.projectId=PROJECT_ID
Reemplaza PROJECT_ID por el ID del proyecto de Google Cloud. Si tu archivo pom.xml
ya especifica tu ID del proyecto, no necesitas incluir la propiedad -Dapp.deploy.projectId
en el comando que ejecutas.
Luego de que Maven implemente tu aplicación, escribe lo siguiente para abrir una pestaña del navegador web de forma automática en tu nueva aplicación:
gcloud app browse
Pasos siguientes
En esta guía se muestra cómo usar una lista de tareas en cola para crear una imagen en miniatura y almacenarla en Cloud Storage. Puede usarse con otros servicios de almacenamiento, como Cloud Datastore o Cloud SQL.