Nachfolgend werden Aufgabenwarteschlangen beschrieben und es wird gezeigt, wie Sie die App Engine Image API zur Größenänderung von Bildern verwenden.
Aufgabenwarteschlangen führen Code außerhalb direkter Nutzerinteraktionen aus, also im Hintergrund. In diesem Leitfaden wird eine Aufgabenwarteschlange verwendet, um Aufgaben auszuführen, nachdem ein Bild zu Cloud Storage hinzugefügt wurde. Diese sind:
- Das soeben in Cloud Storage gespeicherte Bild wird abgerufen.
- Das Bild wird mithilfe der Image API in eine Miniaturansicht umgewandelt.
- Die Miniaturansicht wird in Cloud Storage gespeichert.
Die App Engine Java 8-Laufzeit unterstützt auch native Java-Bildmanipulierungsklassen wie AWT und Java2D.
Vorbereitung
Konfigurieren Sie Ihre Entwicklungsumgebung und erstellen Sie Ihr App Engine-Projekt.
In dieser Anleitung wird die Apache Commons IOUtils-Bibliothek verwendet. So fügen Sie Ihrem App Engine-Projekt die IOUtils-Bibliothek hinzu:
Zum
pom.xml
hinzufügen:<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version> </dependency>
Bibliotheken importieren
Im Beispielcode werden die folgenden Importe verwendet:
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;
Eine Aufgabenwarteschlange erstellen
App Engine stellt eine default
-Aufgabenwarteschlange bereit. Sie können verschiedene Aufgabenwarteschlangen für unterschiedliche Aufgabentypen erstellen. Sie können beispielsweise eine Aufgabenwarteschlange erstellen, um die Größe von Bildern zu ändern, und eine weitere, um die Datenbank Ihrer Anwendung zu aktualisieren.
Erstellen Sie zum Hinzufügen von Warteschlangen die Datei queue.xml
im Verzeichnis WEB-INF
Ihres App Engine-Projekts. Für eine Aufgabenwarteschlange müssen ein Name und eine Ausführungsrate angegeben werden:
<?xml version="1.0" encoding="UTF-8"?>
<queue-entries>
<queue>
<name>resize-image</name>
<rate>60/h</rate>
</queue>
</queue-entries>
Diese Beispielwarteschlange mit dem Namen resize-image
definiert eine Ausführungsrate von 60-mal pro Stunde oder einmal pro Minute. Die vollständigen Optionen für die Listenwarteschlange finden Sie in der Referenz queue.xml
.
Eine Aufgabenwarteschlange hat zwei Komponenten: einen Aufgaben-Requester und einen Aufgaben-Handler. Der Requestor fügt eine Aufgabe zur Warteschlange hinzu und sendet sie an den Aufgaben-Handler.
Aufgaben zu einer Warteschlange hinzufügen
So fügen Sie einer Warteschlange eine Aufgabe hinzu:
Erstellen Sie mithilfe von
QueueFactory.getQueue()
ein Aufgabenwarteschlangenobjekt und stellen Sie dabei sicher, dass Sie den inqueue.xml
definierten Warteschlangennamen angeben: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. } }
Fügen Sie dem Objekt
Queue
Aufgaben hinzu. Wie im Codebeispiel gezeigt, fügtimageResizeQueue.add()
demimageResizeQueue
- Objekt eine Aufgabe hinzu:try { // Add a queued task to create a thumbnail of the uploaded image imageResizeQueue.add( TaskOptions.Builder.withUrl("/tasks/imageresize").param("filename", filename)); }
Geben Sie den URI des Aufgaben-Handlers zusammen mit und allen an den Handler gesendeten Parametern mit
TaskOptions.Builder.withUrl()
an.In diesem Beispiel lautet der URI
/tasks/imageresize
und der Parameter eine Variable namensfilename
, die den Dateinamen des zu verarbeitenden Bilds enthält.
Einen Aufgaben-Handler erstellen
Sobald Sie der Warteschlange eine Aufgabe hinzugefügt haben, wird der Aufgaben-Handler ausgeführt, der dem URI /tasks/imageresize
zugeordnet ist. Ein Aufgaben-Handler ist ein Java-Servlet, das eine Aufgabe so lange ausführt, bis diese erfolgreich abgeschlossen wurde.
In diesem Beispiel hat der Handler drei Aufgaben:
das vom Aufrufer angegebene Bild aus Cloud Storage abrufen,
das Bild mithilfe der App Engine Image API umwandeln, in diesem Fall in eine Miniaturansicht und
das neue Bild (Miniaturansicht) in Cloud Storage speichern.
So erstellen Sie den Aufgaben-Handler:
Fügen Sie eine Anmerkung hinzu, die den Handler dem URI
/tasks/imageresize
zuordnet:@WebServlet(name = "imageResize", description = "Task queue handler", urlPatterns = "/tasks/imageresize") public class imageResize extends HttpServlet { // Task handler functionality }
Richten Sie eine Verbindung zu Cloud Storage ein. Informationen dazu entnehmen Sie der Cloud Storage-Anleitung. Rufen Sie das Bild von Cloud Storage ab:
public void init() throws ServletException { // initiate GcsService GcsService gcsService = GcsServiceFactory.createGcsService( new RetryParams.Builder() .initialRetryDelayMillis(10) .retryMaxAttempts(10) .totalRetryPeriodMillis(15000) .build()); }
Verarbeiten Sie den eingehenden Aufgabenwarteschlangen-Request und verwenden Sie den angegebenen Dateinamen, um das Bild von Cloud Storage zu laden:
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
Verwenden Sie das Objekt
ImagesService
, um die Bildgröße anzupassen:// 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()));
Im obigen Snippet wird die Image API-Methode
makeResize()
verwendet, um die Größe des Bildes in eine Miniaturansicht zu ändern. Dazu liest er das Bild aus Cloud Storage in einInputChannel
und konvertiert es mitIOUtils.toByteArray()
in ein ByteArray.Nach dem Anwenden der Transformation wird das neue Bild mit dem String
thumbnail_
an seinen Dateinamen angehängt. Die Berechtigung ist öffentlich lesbar und wird in Cloud Storage geschrieben.
URLs von Aufgaben-Handlern absichern
Aufgaben, die vertrauliche Operationen vornehmen, wie zum Beispiel Daten ändern, sollten Sie so absichern, dass sie von externen Nutzern nicht direkt aufgerufen werden können. Beschränken Sie dazu die Berechtigung zum Aufgabenzugriff auf App Engine-Administratoren. Normale Nutzer können dann nicht auf die Aufgaben-URLs zugreifen. Beachten Sie, dass diese Einschränkung nicht für Aufgaben-Requests gilt, die von Ihrer App Engine-App stammen.
Im aktuellen Beispiel haben die Aufgaben-Handler URLs im Ordner /tasks/
.
Um den Zugriff auf den Ordner /tasks/
auf App Engine-Administratoren zu beschränken, fügen Sie dem web.xml
des Projekts Folgendes hinzu:
<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>
Eine einzelne Aufgabe aus einer Warteschlange entfernen
Verwenden Sie deleteTask()
, um eine einzelne Aufgabe aus einer Warteschlange zu entfernen:
private void removeTask(Queue queue, String taskName) {
queue.deleteTask(taskName); // remove a task from a queue
}
Alle Aufgaben aus einer Warteschlange entfernen
Wenn Sie alle Aufgaben aus einer Warteschlange entfernen möchten, verwenden Sie purge()
. Es kann bis zu eine Minute dauern, bis alle Aufgaben einer Warteschlange gelöscht sind.
private void purgeQueue(Queue queue) {
queue.purge(); // remove all tasks from a queue
}
Der Löschvorgang dauert eine Weile. Warten Sie daher einige Sekunden, bevor Sie neue Aufgaben zur Warteschlange hinzufügen.
Eine Aufgabenwarteschlange löschen
Wenn Sie eine Aufgabenwarteschlange löschen möchten, entfernen Sie den Eintrag aus der Datei queue.xml
des Projekts und stellen Sie die Datei noch einmal bereit.
In App Engine bereitstellen
Sie können Ihre Anwendung mithilfe von Maven in App Engine bereitstellen.
Wechseln Sie zum Stammverzeichnis Ihres Projekts und geben Sie Folgendes ein:
mvn package appengine:deploy -Dapp.deploy.projectId=PROJECT_ID
Ersetzen Sie PROJECT_ID durch die ID Ihres Google Cloud-Projekts. Wenn in der Datei pom.xml
bereits Ihre Projekt-ID angegeben ist, müssen Sie das Attribut -Dapp.deploy.projectId
nicht in dem von Ihnen ausgeführten Befehl einfügen.
Nachdem Ihre Anwendung von Maven bereitgestellt wurde, sollte automatisch ein Webbrowser-Tab in Ihrer neuen Anwendung geöffnet werden. Geben Sie dazu Folgendes ein:
gcloud app browse
Weitere Informationen
In dieser Anleitung wird beschrieben, wie eine Aufgabenwarteschlange verwendet wird, um von einem Bild eine Miniaturansicht zu erstellen und in Cloud Storage zu speichern. Dieselbe Vorgehensweise gilt auch für andere Speicherdienste wie Cloud Datastore oder Cloud SQL.