Apprenez à utiliser les files d'attente de tâches et l'API Image d'App Engine pour redimensionner les images.
Les files d'attente de tâches exécutent le code sans l'interaction directe de l'utilisateur, permettant ainsi aux tâches d'être effectuées en arrière-plan. Ce guide utilise une file d'attente de tâches pour effectuer des tâches après avoir ajouté une image à Cloud Storage. Les tâches à exécuter, qui se trouvent dans la file d'attente, sont les suivantes :
- Récupérer le fichier image qui vient d'être importé dans Cloud Storage
- Redimensionner cette image sous forme de vignette à l'aide de l'API Image
- Stocker la vignette obtenue dans Cloud Storage
L'environnement d'exécution Java 8 d'App Engine accepte également les classes de manipulation d'images natives de Java, telles que AWT et Java2D.
Avant de commencer
Configurez votre environnement de développement et créez votre projet App Engine.
Ce guide utilise la bibliothèque Apache Commons IOUtils. Pour l'inclure dans votre projet App Engine, procédez comme suit :
Ajoutez ceci au fichier
pom.xml
:<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version> </dependency>
Importer des bibliothèques
L'exemple de code fourni dans ce guide utilise les importations suivantes :
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;
Créer une file d'attente de tâches
Bien qu'App Engine fournisse une file d'attente de tâches default
, vous pouvez créer plusieurs files d'attente pour différents types de tâches. Par exemple, vous pouvez créer une file d'attente de tâches pour redimensionner les images, et une autre pour mettre à jour la base de données de votre application.
Pour ajouter des files d'attente, créez le fichier queue.xml
dans le répertoire WEB-INF
de votre projet App Engine. Une file d'attente doit spécifier un nom et un taux d'exécution :
<?xml version="1.0" encoding="UTF-8"?>
<queue-entries>
<queue>
<name>resize-image</name>
<rate>60/h</rate>
</queue>
</queue-entries>
Dans cet exemple, la file d'attente nommée resize-image
définit un taux d'exécution de 60 tâches par heure, soit une tâche par minute. Pour découvrir la liste complète des options de files d'attente, consultez la documentation de référence sur queue.xml
.
Une file d'attente de tâches comprend deux composants : le demandeur de tâches et un gestionnaire de tâches. Le demandeur ajoute une tâche à la file d'attente et l'envoie au gestionnaire de tâches.
Ajouter des tâches à une file d'attente
Pour ajouter une tâche à une file d'attente, procédez comme suit :
Créez un objet de file d'attente de tâches à l'aide de
QueueFactory.getQueue()
, en veillant à spécifier le nom de la file d'attente défini dans le fichierqueue.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. } }
Ajoutez des tâches à l'objet
Queue
. Comme illustré dans l'exemple de code,imageResizeQueue.add()
ajoute une tâche à l'objetimageResizeQueue
:try { // Add a queued task to create a thumbnail of the uploaded image imageResizeQueue.add( TaskOptions.Builder.withUrl("/tasks/imageresize").param("filename", filename)); }
Spécifiez l'URI du gestionnaire de tâches à l'aide de
TaskOptions.Builder.withUrl()
, ainsi que tous les paramètres envoyés au gestionnaire.Dans cet exemple, l'URI est
/tasks/imageresize
et le paramètre est une variable appeléefilename
qui contient le nom de fichier de l'image à traiter.
Créer un gestionnaire de tâches
Une fois que vous avez ajouté une tâche à la file d'attente, le gestionnaire de tâches mappé avec l'URI /tasks/imageresize
s'exécute. Il s'agit d'un servlet Java qui tente d'exécuter la tâche jusqu'à ce qu'elle aboutisse.
Dans cet exemple, le gestionnaire de tâches exécute trois tâches :
Récupérer l'image spécifiée par le demandeur dans Cloud Storage
Convertir l'image à l'aide de l'API Image d'App Engine, dans cet exemple, en vignette
Stocker l'image convertie (vignette) dans Cloud Storage
Pour créer le gestionnaire de tâches, procédez comme suit :
Ajoutez une annotation qui mappe le gestionnaire avec l'URI
/tasks/imageresize
:@WebServlet(name = "imageResize", description = "Task queue handler", urlPatterns = "/tasks/imageresize") public class imageResize extends HttpServlet { // Task handler functionality }
Configurez une connexion à Cloud Storage comme indiqué dans le guide d'utilisation de Cloud Storage, puis récupérez l'image dans Cloud Storage :
public void init() throws ServletException { // initiate GcsService GcsService gcsService = GcsServiceFactory.createGcsService( new RetryParams.Builder() .initialRetryDelayMillis(10) .retryMaxAttempts(10) .totalRetryPeriodMillis(15000) .build()); }
Traitez la requête entrante de la file de tâches en utilisant le nom de fichier fourni pour récupérer l'image dans 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
Utilisez l'objet
ImagesService
afin de redimensionner l'image :// 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()));
L'extrait ci-dessus se sert de la méthode
makeResize()
de l'API Image pour redimensionner l'image en vignette. Pour ce faire, il lit l'image de Cloud Storage dans unInputChannel
et la convertit en ByteArray à l'aide deIOUtils.toByteArray()
.Après avoir appliqué la transformation, la nouvelle image comporte la chaîne
thumbnail_
ajoutée à son nom de fichier, l'autorisation étant définie pour être lisible et écrite publiquement dans Cloud Storage.
Sécuriser les URL du gestionnaire de tâches
Vous devez sécuriser les tâches qui effectuent des opérations sensibles, telles que la modification des données, afin que les utilisateurs externes ne puissent pas les appeler directement. Pour ce faire, vous pouvez limiter l'accès aux tâches aux administrateurs App Engine, ce qui empêche les utilisateurs d'accéder aux URL de tâches. Notez que cette restriction ne s'applique pas aux requêtes de tâches provenant de votre application App Engine.
Dans cet exemple, les gestionnaires de tâches ont des URL dans le dossier /tasks/
.
Pour restreindre l'accès au dossier /tasks/
aux administrateurs App Engine, ajoutez ce qui suit au fichier web.xml
du projet.
<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>
Supprimer une seule tâche d'une file d'attente
Pour supprimer une seule tâche d'une file d'attente, servez-vous de la méthode deleteTask()
:
private void removeTask(Queue queue, String taskName) {
queue.deleteTask(taskName); // remove a task from a queue
}
Supprimer toutes les tâches d'une file d'attente
Pour supprimer toutes les tâches d'une file d'attente, utilisez purge()
. L'opération peut prendre jusqu'à une minute.
private void purgeQueue(Queue queue) {
queue.purge(); // remove all tasks from a queue
}
Comme la suppression de toutes les tâches d'une file d'attente peut durer une minute, vous devez attendre quelques secondes avant d'ajouter d'autres tâches à la file d'attente.
Supprimer une file d'attente de tâches
Pour supprimer une file d'attente de tâches, supprimez l'entrée du fichier queue.xml
du projet et procédez au redéploiement.
Déployer sur App Engine
Vous pouvez déployer votre application sur App Engine à l'aide de Maven.
Accédez au répertoire racine de votre projet, puis saisissez la commande suivante :
mvn package appengine:deploy -Dapp.deploy.projectId=PROJECT_ID
Remplacez PROJECT_ID par l'ID de votre projet Google Cloud. Si votre ID de projet est déjà inclus dans le fichier pom.xml
, vous n'avez pas besoin d'inclure la propriété -Dapp.deploy.projectId
dans la commande que vous exécutez.
Lorsque Maven a déployé votre application, saisissez la commande ci-dessous pour ouvrir un onglet de navigateur Web automatiquement dans votre nouvelle application :
gcloud app browse
Étape suivante
Ce guide explique comment créer une miniature d'une image à l'aide d'une file d'attente de tâches et la stocker dans Cloud Storage. Ce service peut s'utiliser en complément d'autres services de stockage tels que Cloud Datastore ou Cloud SQL.