Saiba como usar filas de tarefas e a App Engine Image API para redimensionar as imagens.
As filas de tarefas executam o código fora da interação direta do usuário, permitindo que as tarefas sejam realizadas em segundo plano. Este guia usa uma fila de tarefas para executar tarefas após adicionar uma imagem ao Cloud Storage. As tarefas a serem realizadas na fila de tarefas são estas:
- Recupere o arquivo de imagem que acabou de ser enviado para o Cloud Storage.
- Redimensione-o para uma imagem em miniatura usando a Image API.
- Armazene a miniatura resultante no Cloud Storage.
O ambiente de execução Java 8 do App Engine também é compatível com classes de manipulação de imagens nativas do Java, como AWT e Java2D (ambos em inglês).
Antes de começar
Configure o ambiente de desenvolvimento e crie o projeto do App Engine.
Este guia usa a biblioteca de IOUtils Apache Commons. Para incluir a biblioteca de IOUtils no projeto do App Engine:
Adicione ao seu
pom.xml
:<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version> </dependency>
Como importar bibliotecas
O código de amostra fornecido com este guia usa as seguintes importações:
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;
Como criar uma fila de tarefas
O App Engine fornece uma fila de tarefas default
, mas é possível criar filas de tarefas diferentes para tipos de trabalho distintos. Por exemplo, é possível criar
uma fila de tarefas para redimensionar imagens e outra para atualizar o banco de dados do aplicativo.
Para adicionar filas, crie o arquivo queue.xml
no diretório WEB-INF
do projeto do App Engine. Uma fila de tarefas precisa especificar um nome e uma
taxa de execução:
<?xml version="1.0" encoding="UTF-8"?>
<queue-entries>
<queue>
<name>resize-image</name>
<rate>60/h</rate>
</queue>
</queue-entries>
Essa fila de exemplo, chamada resize-image
, define uma taxa de execução de 60 vezes por hora, ou uma vez por minuto. Para ver as opções da fila de listagem completa, consulte a referência queue.xml
.
Uma fila de tarefas tem dois componentes: o solicitante e um gerenciador. O solicitante adiciona uma tarefa à fila e a envia para o gerenciador de tarefas.
Como adicionar tarefas a uma fila
Para adicionar uma tarefa a uma fila:
Crie um objeto de fila de tarefas usando
QueueFactory.getQueue()
. Especifique o nome da fila definido emqueue.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. } }
Adicione tarefas ao objeto
Queue
. Conforme o exemplo de código,imageResizeQueue.add()
adiciona uma tarefa ao objetoimageResizeQueue
:try { // Add a queued task to create a thumbnail of the uploaded image imageResizeQueue.add( TaskOptions.Builder.withUrl("/tasks/imageresize").param("filename", filename)); }
Especifique o URI do gerenciador de tarefas usando
TaskOptions.Builder.withUrl()
com os parâmetros enviados ao gerenciador.Neste exemplo, o URI é
/tasks/imageresize
e o parâmetro é uma variável chamadafilename
que contém o nome do arquivo da imagem a ser processada.
Como criar um gerenciador de tarefas
Depois que você tiver adicionado uma tarefa à fila, o gerenciador de tarefas mapeado para o URI
/tasks/imageresize
será executado. Gerenciador de tarefas é um Servlet Java que tenta executar a tarefa até ser bem-sucedido.
Neste exemplo, o gerenciador faz três tarefas:
Recuperar a imagem especificada pelo autor da chamada do Cloud Storage.
Transformar a imagem usando a App Engine Image API. Neste exemplo, uma imagem em miniatura.
Armazenar a imagem transformada (miniatura) no Cloud Storage.
Para criar o gerenciador de tarefas:
Adicione uma anotação que mapeie o gerenciador para o URI
/tasks/imageresize
:@WebServlet(name = "imageResize", description = "Task queue handler", urlPatterns = "/tasks/imageresize") public class imageResize extends HttpServlet { // Task handler functionality }
Configure uma conexão com o Cloud Storage conforme documentado no guia Como usar o Cloud Storage e recupere a imagem do Cloud Storage:
public void init() throws ServletException { // initiate GcsService GcsService gcsService = GcsServiceFactory.createGcsService( new RetryParams.Builder() .initialRetryDelayMillis(10) .retryMaxAttempts(10) .totalRetryPeriodMillis(15000) .build()); }
Processe a solicitação da fila de tarefas de entrada usando o nome do arquivo fornecido para recuperar a imagem do 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
Use o objeto
ImagesService
para fazer o redimensionamento da imagem:// 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()));
O snippet acima usa o método
makeResize()
da API Image para redimensionar a imagem para uma miniatura. Para fazer isso, ele lê a imagem do Cloud Storage em umInputChannel
e a converte em um ByteArray usandoIOUtils.toByteArray()
.Depois de aplicar a transformação, a nova imagem tem a string
thumbnail_
anexada ao nome de arquivo, permissão definida para ser publicamente legível e gravada no Cloud Storage.
Como proteger URLs do gerenciador de tarefas
Proteja tarefas que realizem operações confidenciais, como modificar dados. Dessa forma, usuários externos não podem chamá-los diretamente. Você pode fazer isso restringindo o acesso à tarefa a administradores do App Engine, o que evita que usuários acessem URLs de tarefa. Essa restrição não se aplica a solicitações de tarefas provenientes do aplicativo do App Engine.
No exemplo atual, os gerenciadores de tarefas têm URLs na pasta /tasks/
.
Para restringir o acesso à pasta /tasks/
aos administradores do App Engine, adicione o
seguinte ao web.xml
do projeto.
<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>
Como remover uma única tarefa de uma fila
Para remover uma única tarefa de uma fila, use deleteTask()
:
private void removeTask(Queue queue, String taskName) {
queue.deleteTask(taskName); // remove a task from a queue
}
Como remover todas as tarefas de uma fila
Para remover todas as tarefas de uma fila, use purge()
. A limpeza pode demorar até um minuto para remover todas as tarefas na fila.
private void purgeQueue(Queue queue) {
queue.purge(); // remove all tasks from a queue
}
Pode demorar um minuto para remover todas as tarefas de uma fila. Dessa forma, você precisa esperar alguns segundos até adicionar novas tarefas à fila.
Como excluir uma fila de tarefas
Para excluir uma fila de tarefas, remova a entrada do arquivo queue.xml
do projeto e
reimplante.
Como implantar no App Engine
Implante o app no App Engine usando o Maven.
Acesse o diretório raiz do projeto e digite:
mvn package appengine:deploy -Dapp.deploy.projectId=PROJECT_ID
Substitua PROJECT_ID pelo ID do projeto do Google Cloud. Se
o arquivo pom.xml
já
especificar o
ID do projeto, não será necessário incluir a propriedade -Dapp.deploy.projectId
no
comando executado.
Depois que o Maven implantar o aplicativo, digite o comando a seguir para abrir uma guia do navegador da Web automaticamente em seu novo aplicativo:
gcloud app browse
Próximas etapas
Este guia mostra como usar uma fila de tarefas para criar uma miniatura de imagem e armazená-la no Cloud Storage. Ele pode ser usado com outros serviços de armazenamento, como Cloud Datastore ou Cloud SQL.