Starten Sie die Velocity Template Engine

Mit der Velocity Template Engine können Sie Daten aus Anwendungen und Servlets rendern. Velocity wird hauptsächlich zur Entwicklung dynamischer, servletbasierter Websites verwendet und eignet sich aufgrund der sauberen Trennung von Vorlage und Java-Code ideal für die MVC-Webentwicklung. Als allgemeine Vorlagen-Engine eignet sich Velocity für viele andere Zwecke, z. B. zur Codegenerierung, XML-Generierung und -Transformation sowie zur Verarbeitung von Textströmen. Dieser Artikel stellt die Velocity Template Language (VTL) vor und enthält Beispiele für die Verwendung der Velocity Engine, einschließlich der Generierung von Webinhalten in einer Java-Servlet-Umgebung.

Velocity ist ein Open-Source-Template-Tool, das von einer internationalen Freiwilligengemeinschaft entwickelt und vom Jakarta-Projekt der Apache Software Foundation gehostet wird. Auf der Jakarta Velocity Project-Website, auf der Sie den frei verfügbaren Quellcode herunterladen können, steht eine florierende und wachsende Benutzergemeinschaft bereit, Fragen zu beantworten und Lösungen für häufig auftretende Vorlagenprobleme anzubieten. Velocity wurde von dem wegweisenden WebMacro-Projekt inspiriert, für das wir in der Velocity-Community dankbar sind.

In diesem Artikel stelle ich eine kurze Einführung in die Velocity Template Engine und ihre Vorlagensprache Velocity Template Language (VTL) vor. Ich zeige auch anhand mehrerer Beispiele, wie Velocity verwendet wird.

Hallo Welt natürlich

Ohne ein Hello World-Beispiel wäre keine Erklärung eines programmierbezogenen Themas vollständig. Jede Anwendung mit Velocity erfordert zwei Teile. Die erste ist die Vorlage, in diesem Beispiel eine Datei mit dem Namen helloworld.vm:

Hallo $ name! Willkommen bei Velocity!

Das zweite ist ein entsprechendes Java-Programm namens HelloWorld.java:

import java.io.StringWriter; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; öffentliche Klasse HelloWorld {public static void main (String [] args) löst zuerst die Ausnahme {/ * aus, ruft eine Engine ab und initialisiert sie * / VelocityEngine ve = new VelocityEngine (); ve.init (); / * Als nächstes holen Sie sich die Vorlage * / Template t = ve.getTemplate ("helloworld.vm"); / * Erstelle einen Kontext und füge Daten hinzu * / VelocityContext context = new VelocityContext (); context.put ("name", "World"); / * rendere jetzt die Vorlage in einen StringWriter * / StringWriter writer = new StringWriter (); t.merge (Kontext, Autor); / * zeige die Welt * / System.out.println (writer.toString ()); }}

Wenn Sie dieses Programm kompilieren und ausführen, sehen Sie die Ausgabe:

Hallo Welt! Willkommen bei Velocity!

Dies ist ein triviales Beispiel, aber es enthält die entscheidenden Teile, um Ihnen eine Vorstellung davon zu geben, worum es beim Velocity-Templating geht.

Warum sollte ich es benutzen?

Velocity wurde als benutzerfreundliches allgemeines Vorlagenwerkzeug entwickelt und ist in allen Java-Anwendungsbereichen nützlich, in denen Daten formatiert und präsentiert werden müssen. Sie sollten Velocity aus folgenden Gründen verwenden:

  • Es passt sich vielen Anwendungsbereichen an
  • Es bietet eine einfache, klare Syntax für den Vorlagen-Designer
  • Es bietet ein einfaches Programmiermodell für den Entwickler
  • Da Vorlagen und Code getrennt sind, können Sie sie unabhängig voneinander entwickeln und verwalten
  • Die Velocity-Engine lässt sich problemlos in jede Java-Anwendungsumgebung integrieren, insbesondere in Servlets
  • Mit Velocity können Vorlagen auf alle öffentlichen Methoden von Datenobjekten im Kontext zugreifen

Der letzte Punkt ist wichtig - es bedeutet, dass Sie Ihre vorhandenen Klassen wiederverwenden können. Objekte, die Sie in Ihren Vorlagen verwenden möchten, müssen also nicht wie JavaBeans strukturiert sein oder spezielle E / A- oder Lebenszyklusmodi wie JSP-Taglibs (JavaServer Pages) implementieren. Die einzige Voraussetzung ist, dass die Methoden öffentlich sind. Sie werden mehr davon sehen, wenn wir die Vorlagensprache ausführlich behandeln.

Eine der Stärken von Velocity besteht darin, dass eine Trennung der funktionalen Verantwortung innerhalb der Anwendung nachdrücklich erzwungen wird. Dazu wird der Vorlagenzugriff auf Objekte beschränkt, die der Anwendungscode speziell zur Verfügung stellt. Dies bedeutet, dass sich Designer ausschließlich auf die Datenpräsentation (die Ansicht) konzentrieren können und der Anwendungsprogrammierer sich auf die Anwendungssteuerung (den Controller) und die Geschäftslogik und das Datenmanagement (das Modell) in Model-View-Controller (MVC) konzentrieren kann. Entwicklung. MVC ist ein anerkanntes Entwicklungsmuster, das sowohl die Entwicklung als auch die laufende Wartung anspruchsvoller Anwendungen vereinfacht.

Wo benutze ich es?

Geschwindigkeit wird erfolgreich eingesetzt in:

  • Servlet-basierte Webanwendungen
  • Java- und SQL-Codegenerierung
  • XML-Verarbeitung und -Transformation
  • Textverarbeitung, z. B. Generierung von RTF-Dateien

Velocity wird am häufigsten als Rendering-Engine für die Entwicklung von Java-Servlet-basierten Webanwendungen anstelle von oder in Verbindung mit JSPs und anderen Rendering-Technologien verwendet. Neben der einfachen, wartbaren Vorlagensyntax wird Velocity in der Webentwicklung verwendet, da die Vorlagensprache die Daten bearbeiten und darstellen kann, nicht Daten erstellen kann. Dies entmutigt die Programmierung innerhalb der Vorlagen. Das ist eine gute Sache; Dadurch bleibt die Geschäfts- und Anwendungslogik Ihres Java-Codes dort, wo sie hingehört.

Velocity eignet sich gut für die J2EE-Webentwicklung (Java 2 Platform, Enterprise Edition), da die Plattform andere Ausgabetechnologien als JSP unterstützt. Während JSP in der J2EE-Spezifikation enthalten ist, muss J2EE nicht verwendet werden.

Wie funktioniert es?

Sie verwenden denselben allgemeinen Prozess zum Erstellen einer Velocity-basierten Anwendung wie jede andere Anwendung. Betrachten wir ein interessanteres Beispiel als die obige Hello World-Anwendung. Angenommen, Sie betreiben eine Zoohandlung und möchten eine E-Mail-Explosion generieren, um einen Verkauf anzukündigen. Zuerst müssen Sie die E-Mail entwerfen und dann die Vorlage und den Code basierend auf diesem Entwurf entwickeln.

Überlegungen zur Entwurfszeit

Sie müssen drei Elemente für Ihr Design berücksichtigen:

  • Welche Daten sollen in die E-Mail aufgenommen werden?
  • Was bildet die Datenelemente nehmen sollen (zum Beispiel wie List, Map, oder String)
  • Wie nennt man diese Datenelemente?

Nehmen wir für dieses Beispiel an, Sie entscheiden sich für drei zum Verkauf stehende Haustiere mit jeweils unterschiedlichen Werbepreisen. Sie beschließen, jedem Kosenamen und seinem Preis eine Karte zuzuordnen und dann alle drei Karten in einer Liste zu speichern. Sie nennen diese Liste petList, den Kosenamen nameund den Preis wie priceauf der Karte. Nachdem Sie die relevanten Daten, ihre Darstellung und die Benennungskriterien identifiziert haben, können Sie den Code und das Design der Vorlage schreiben.

Schreiben Sie den Code und das Vorlagendesign

Sobald Sie sich auf Datenspezifikationen geeinigt haben, können Sie mit Velocity den Code schreiben und die Vorlage parallel entwerfen. Der Designer integriert die Daten in den Inhalt der Nichtdatenpräsentation (wie Bilder, Text usw.) in der Vorlage. In diesem Fall schreiben wir einfach in den E-Mail-Text:

$ petList.size () Haustiere im Angebot! Wir sind stolz darauf, diese feinen Haustiere zu diesen erstaunlichen Preisen anbieten zu können. Wählen Sie nur diesen Monat aus: #foreach ($ pet in $ petList) $ pet.name für nur $ pet.price #end Call Today!

Als Programmierer müssen Sie:

  • Rufen Sie alle Daten aus den Datenquellen ab - eine Datenbank über JDBC (Java Database Connectivity), eine Datei oder nur etwas Berechnetes
  • Stellen Sie diese Daten unter Verwendung der vereinbarten Namen in den Kontext
  • Rendern Sie die Vorlage mit dem Kontext, um eine Ausgabe zu erstellen

Sie können sich aus dem Hello World-Beispiel daran erinnern, dass ich die Klasse VelocityContextals Kontext bezeichnet habe . Nach dem Vorbild von a java.util.Mapist der Kontext ein Objekt, das Daten enthält, die von der Anwendung oder dem Servlet bereitgestellt werden, auf die die Vorlage zugreift.

For this example, we get all the data from our data sources (in this case, we hardwire it into the code), organize it, and add it to the context:

 /* create our list of maps */ ArrayList list = new ArrayList(); Map map = new HashMap(); map.put("name", "horse"); map.put("price", "00.00"); list.add( map ); map = new HashMap(); map.put("name", "dog"); map.put("price", "9.99"); list.add( map ); map = new HashMap(); map.put("name", "bear"); map.put("price", ".99"); list.add( map ); /* add that list to a VelocityContext */ VelocityContext context = new VelocityContext(); context.put("petList", list); 

It appears we really want to get rid of those bears!

Now, with the data organized and placed in the context and the template ready, we can render the template against the context. Here is the code:

import java.io.StringWriter; import java.util.List; import java.util.ArrayList; import java.util.Map; import java.util.HashMap; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; public class PetStoreEmail { public static void main( String[] args ) throws Exception { /* first, get and initialize an engine */ VelocityEngine ve = new VelocityEngine(); ve.init(); /* organize our data */ ArrayList list = new ArrayList(); Map map = new HashMap(); map.put("name", "horse"); map.put("price", "00.00"); list.add( map ); map = new HashMap(); map.put("name", "dog"); map.put("price", "9.99"); list.add( map ); map = new HashMap(); map.put("name", "bear"); map.put("price", ".99"); list.add( map ); /* add that list to a VelocityContext */ VelocityContext context = new VelocityContext(); context.put("petList", list); /* get the Template */ Template t = ve.getTemplate( "petstoreemail.vm" ); /* now render the template into a Writer */ StringWriter writer = new StringWriter(); t.merge( context, writer ); /* use the output in your email body */ sendEmail( writer.toString() ); } } 

This complete program generates your email body. Because Velocity renders templates into a Writer, you can easily manage the output. In this case, the rendered output went into a String via the StringWriter, but it could easily have gone to a file, a browser, or a BLOB (binary large object) in a database. This is one reason why Velocity integrates so easily into Java applications.

The program output (your email body) looks like this:

 3 Pets on Sale! We are proud to offer these fine pets at these amazing prices. This month only, choose from: horse for only 00.00 dog for only 9.99 bear for only .99 Call Today! 

Velocity Template Language

I've shown Velocity templates for two different examples, but in neither case have I explained what the special markup did (although you could probably guess).

The Velocity Template Language (VTL) is a simple syntax providing two parts: references, a formalism for accessing objects in the context; and directives, a set of statements used for control and action. Described as "a language definition with a feature set that fits comfortably on a standard business card" (see Jim Jagielski's "Getting Up to Speed with Velocity") VTL has been intentionally kept simple and small by the community.

References

References in the template access data. They freely mix with the template's non-VTL content. Formally defined, a reference is anything in a template that starts with the '$' character and refers to something in the context. If no corresponding data object exists in the context, the template simply treats the reference as text and renders it as-is into the output stream.

Here is a short template containing a simple reference mixed with non-VTL content:

 Hello $name! Welcome to Velocity! 

Here, the reference is $name. As in the Hello World example, Velocity replaces $name in the template with the toString() return value of what is placed in the context under the key name:

 Hello World! Welcome to Velocity! 

The Velocity reference allows access to any object's public method, and the template's syntax is the same as it would be in Java code. Here are a few examples:

 There are $myBean.getSize() elements. $myObject.anotherMethod( 1, "more data ") $foo.getBar().barMethod("hello", $moredata ) $foo.myMethod( $bar.callThis() ) 

You may recall from the Pet Store email example that we stored the name and price information in a java.util.Map, and accessed the data using two tokens name and price, which don't exist as methods in the java.util.Map class:

 $pet.name for only $pet.price 

This works because Velocity incorporates a JavaBean-like introspection mechanism that lets you express method accesses in references using a property notation. In the Pet Store example template, Velocity's introspection facility finds and invokes the Map's public Object get(String) method with the keys name and price. We could access the same data in a different way by invoking the get(String) method directly in the template:

 $pet.get('name') for only $pet.get('price') 

Dies würde die gleiche Ausgabe erzeugen und besser darstellen, was tatsächlich passiert. Die andere Art der Verwendung der Eigenschaftsnotation ist jedoch einfacher zu lesen und bindet Ihre Vorlage nicht an die spezifische Implementierung der Datenklasse. Beispielsweise können Sie das in Mapin Listdurch eine Klasse mit öffentlichen Methoden getName()und ersetzen getPrice(), und die ursprüngliche Beispielvorlage, die Folgendes enthält, funktioniert weiterhin:

 $ pet.name für nur $ pet.price