Velocity Template
Engine |
Avagy miért ne írjunk saját template engine-t
Java nyelven? Bizonyára
sokunk került már szembe azzal a problémával, hogy adott egy szöveges
formátumú sablon (továbbiakban template), melyet ki kell tölteni az üzleti
rétegből nyert szöveges adatokkal. Valószínűleg erre sokunk válasza
az volt, hogy írjuk meg magunk. Ezen próbálkozások általában átláthatatlan
kódot, speciális feladatot megoldó template engine-t, és az egyre több igény
kielégítésére egy saját template nyelv kialakítását eredményezték. Tipikus példa
erre webes alkalmazások fejlesztésekor a statikus HTML tartalom kitöltése
dinamikusan generált, vagy adatbázisból nyert adatokkal. Másik példa levelek
küldésekor egy általános szöveges tartalom feltöltése konkrét
megszólításokkal, értékekkel. Harmadik példaként megemlíthető XML fájlok
generálása, ahol a template tartalmazhatja a tag-eket, attribútumok neveit,
és az attribútumok értékeit vagy a tag-ek közti részeket kell tartalommal
feltölteni. Eredményesebb
megoldás lehet egy konkrét megvalósítás beépítése az alkalmazásunkba.
Ezekből rengeteg található az Interneten, mind szabad forráskódú, mind
kereskedelmi termékként. Én
elsősorban az ingyenes termékek között kutakodtam, bemutatásra a Jakarta
Project keretein belül fejlesztett Velocity Template Engine-t választottam,
hiszen az Apache Software Foundation név már bizonyított a szabad szoftverek
világában, a Jakarta Project-es termékeket megbízhatóság, megfelelő
komplexitás, kidolgozottság, dinamikus fejlesztés jellemzi. Szerencsére a
Velocity is az Apache Software License v1.1 hatálya alá tartozik, mely kevés
megszorítást tartalmaz, így azon kívül, hogy alkalmazásunk dokumentációjában
megemlítünk egy mondatot ezzel kapcsolatban, és mellékeljük a licence fájlt,
semmit nem kell tennünk a felhasználásához és tovább terjesztéséhez. E cikk nem csak ezen termék megismeréséhez
lehet hasznos, hanem bemutatja az alapfogalmakat és megoldásokat,
körvonalazódhat, hogy milyen elvárásaink lehetnek egy hasonló alkalmazással
szemben. A cikk írásakor
az aktuális verzió a 1.3.1-rc2 volt, tehát az implementációs részek ezen
verzió meglétét igénylik, bár az általam említett példákban nem mutatkoznának
a verziók közti különbségek. A Velocity
tehát egy Java nyelven írt, szabad forráskódú szoftvercsomag, mely template
engine funkciókat lát el, rendelkezik egy jól használható API-val, illetve
egy átgondolt, jól dokumentált, minden vezérlési struktúrával rendelkező
template nyelvvel (Velocity Template Language - VTL). A cikk egyikben sem
mélyül el, hanem konkrét példán keresztül mindkettő alapjait
párhuzamosan bemutatja. A Velocity
legjelentősebb felhasználási területe a webes alkalmazások készítése,
ezen belül is a szervlet technológia kiegészítőjeként terjedt el. Előnye,
hogy alkalmazásával külön válaszható a HTML és a Java kód, ami nagyobb
rendszerek fejlesztésekor különösen fontos, hiszen sem a webdesigner nem akar
megtanulni Javaban programozni, sem a programozó nem akar órákat tölteni a
megálmodott oldal beillesztésével. A Velocity válasza a problémára, hogy
mindketten tanuljanak meg egy egyszerűsített, de mégis sok funkcióval
rendelkező köztes nyelvet, mely összeköti a template-tet és a kóddal
előállított adatokat. (Tapasztalatom szerint a gyakorlatban a programozó
írja meg a köztes kódot is, és a designer hamarabb megérti, kevésbé rontja
el.) A Velocity
beleillik az objektumorientált szemléletbe is, hiszen a template-ben
kulcsokat deklarálhatunk, melyekhez kódból objektum példányokat rendelhetünk,
azaz változóként hivatkoznak egy objektumra. Az objektumok metódusait is
meghívhatjuk, akár paraméterezve is, ha Vector, Hashtable vagy Array, akkor végigiterálhatunk az elemein, vagy
egyszerűen kiírhatjuk az objektumot, vagy a metódus visszatérési értékét
(ekkor a toString metódus,
primitív típus esetén a hozzá tartozó osztály toString metódusát hívja meg a Velocity). És végre
elérkeztünk a kódhoz, lássuk, hogy is néz ki mindez a gyakorlatban. Példánk
legyen egy webes CD katalógus, melyben listázni, lekérni, felvinni lehet a
lemezeket. A lista XML-ben is elérhető legyen, és egy lemez felvitelekor
generáljunk egy szöveges levelet. A példa így bemutatja, hogyan használható a
Velocity HTML, XML és általános szöveges stream vagy fájl generálására. A Velocity
installálása nagyon egyszerű, használatba vételéhez csupán a JAR fájlt
kell a szervlet konténer számára elérhetővé tenni. Általánosan
használt objektum a Disc,
forráskódja (Disc.java): public
class Disc { private
String myArtist; private
String myTitle; private
String myInfo; Disc(String artist; String title; String
info) { myArtist = artist; myTitle = title; myInfo = info; } public
String getArtist() { return
myArtist; } public
String getTitle() { return
myTitle; } public
String getInfo() { return
myInfo; } } Az első példa
írja ki egy album adatait. Ehhez szükségünk vagy egy template-re, disc.vm: <html> <body> <h1>$disc.artist -
$disc.title</h1> <p>$disc.info</p> </body> </html> Látható, hogy a
változók előtt $
karaktert kell használnunk, a tulajdonságok minősítésére pontot. Az ehhez
tartozó szervlet, mely a disc
kulcshoz hozzárendeli az objektumot (InfoServlet.java): public class InfoServlet extends
VelocityServlet { public
Template handleRequest(HttpServletRequest request, HttpServletResponse response, Context context ) { Disc disc = new Disc("Jewel", "This
way", "Blahblah."); context.put("disc",
disc); Template template = null; try { template = getTemplate("discinfo.vm"); } catch( ResourceNotFoundException
rnfe ) { // nem
találja a template fájlt } catch(
ParseErrorException pee ) { // a
template szintaktikai hibás } catch(
Exception e ) { // egyéb
hiba } return
template; } } A szervlet
ősosztálya a VelocityServlet lesz, melynek handleRequest metódusa szolgálja ki a http kéréseket. Visszatérési értéke a Template osztály egy objektuma, mely a nyers
template-et tartalmazza. A visszaadott
HTML pedig a következő lesz (Disc.html): <html> <body> <h1> Jewel - This way </h1> <p>Blahblah.</p> </body> </html> A példában
láthatjuk, hogy az artist és title tulajdonságot a
Velocity feloldja getArtist és getTitle
metódushívásokra. Most lássuk a
Velocity ennél bonyolultabb szolgáltatását, méghozzá az iterációt. A lemezek
listázásához a következő template fájl szükséges (disclist.vm): <html> <body> <table> <tr> <td>Előadó</td> <td>Cím</td> </tr> #foreach ($disc in $discs) <tr> <td>$disc.artist</td> <td>$disc.title</td> </tr> #end </table> </body> </html> Látható, hogy a
vezérlési szerkezeteket #
karakterrel kell jelölni. A szervletben
ekkor a handleRequest metódus
első két sorát a következőre kell kicserélnünk: Vector discs =
new Vector(); Disc disc; disc = new Disc("Jewel",
"This way", "Blahblah."); discs.add(disc); disc = new Disc("Jewel",
"Spirit", "Blahblah."); discs.add(disc); context.put("disc", discs); Ekkor a
szervlet a következő HTML fájlt fogja visszaadni (Discs.html): <html> <body> <table> <tr> <td>Előadó</td> <td>Cím</td> </tr> <tr> <td>Jewel</td> <td>This way</td> </tr> <tr> <td>Jewel</td> <td>Spirit</td> </tr> </table> </body> </html> Ha XML-ben
szeretnénk viszontlátni kedvenc adatainkat, használjuk ugyanezen kódot más
template tel: <?xml
version="1.0"?> <discs> #foreach ($disc in $discs) <disc> <artist>$disc.artist</artist> <title>$disc.title</title> </disc> #end </discs> Látható, hogy
ugyanazt az üzleti logikát alkalmazva különböző formátumú kimeneteket
gyárthatunk, csupán más template használatával. Az adat és a formátum így
teljesen szétválik. Abban az
esetben, ha a Velocity-t nem szervletből, hanem külön alkalmazásból,
vagy más beállításra lenne szükségünk, és a feldolgozás eredményét String-be
szeretnénk látni, akkor használjuk a következőféleképpen. Először a
template: Örömmel
jelentjük, hogy az adatbázisunkba bekerült $disc.artist előadótól a $disc.title című album. Majd a forrás: VelocityEngine
ve = new VelocityEngine(); ve.init(); Disc disc = new Disc("Jewel",
"This way", "Blahblah."); VelocityContext
context = new VelocityContext(); context.put("disc", disc); Template t =
ve.getTemplate("discinfomail.vm"); StringWriter
writer = new StringWriter(); t.merge(context, writer); Ez a forrás
mutatja azon alapvető lépéseket, melyek egy részét a VelocityServlet osztály elrejt. Először
inicializálni kell az VelocityEngine-t, majd létrehozni egy Context objektumot, melybe a kulcs és objektum párokat kell beletenni, végül ki
kell választani a template-et, és az adatokat behelyettesíteni. Persze a
Velocity VCL ennél sokkal bonyolultabb, lehetőség van megjegyzések
beszúrására, egyszerűbb kifejezések kiértékelésére, metódusok
paraméterezésére, feltételek, ciklusok definiálására, template-tek másik
template-be illesztésére (akár feldolgozva, akár feldolgozatlanul), makrók
definiálására. Lehetőség
van Context objektumok
összefűzésére is, ilyenkor a később létrehozott Context konstruktorában kell megadni az
előző Context-et. A Velocity-t a
fentiekben két módon használtuk. Az első esetben a szervleteknél a
JVM-ben egy példány helyezkedett el (Singleton Model), ami lehetővé teszi a szervletek számára a naplózó mechanizmus és
a template-ek megosztását. Ha ezt nem szervleteknél használjuk, akkor a Velocity osztály statikus metódusait kell
hívnunk az inicializáláshoz, szolgáltatásai eléréséhez. A második esetben egy
VelocityEngine-t példányosítottunk (Separate Instance), ami lehetővé teszi, hogy más
konfigurációval használjuk a template engine-t ugyanazon alkalmazásban. A Velocity-t
konfigurálhatjuk kódból Properties osztály használatával, vagy megadhatjuk közvetlenül a konfigurációs
állomány útvonalát, szervleteknél a WEB.XML fájlban helyezzük el a következő
részletet: <context-param>
<param-name>properties</param-name>
<param-value>/velocity.properties</param-value> </context-param> A konfigurációval
megadhatjuk a naplózó rendszert (pl. használható a szintén Jakarta Project-es Log4J), karakterkódolást, template fájlok
helyét. Magyar
nyelvű alkalmazások készítőinél gyakran komoly probléma a
template-ben szereplő magyar ékezetes karakterek helyes megjelenítése. A
Velocity-nél ez a következő konfigurációs név és érték párokkal
egyszerűen megoldható: input.encoding=ISO-8859-2 output.encoding=ISO-8859-2 VelocityServlet osztály
használatakor használjuk a default.contentType=”text/html;encoding=ISO-8859-2 értékpárt, míg
Velocity osztály használatakor a mergeTemplate metódusok közül azt használjuk, melynél második
paraméterként meg kell adni a kódolást. A Velocity jó
alternatíva lehet azon Java programozóknak, akik statikus szövegbe
szeretnének dinamikus adatokat illeszteni futásidőben, illetve webes
alkalmazások esetén, akiknek valamilyen okból nem megfelelő a JSP
technológia, és a Java kódot külön akarják választani a statikus
szövegtől. Természetesen a
Velocity csupán alapvető template
engine funkciókat lát el, viszont ennek ismerete is szükséges lehet,
egy bonyolultabb, modern, valamilyen template engine-re épülő,
Model-View-Controller felépítésű framework használatakor (ld. Jakarta
Project-es Turbine, Jetspeed), esetleg egy hasonló fejlesztésekor. A címben
felvetett kérdésre tehát az a válasz, hogy minek írjunk, hiszen van egy
egyszerűen használható, jól átgondolt, szabad forrású megoldás, mely
szinte minden igényt kielégít, de ha nekünk több kell, akár tovább is
fejleszthetjük. |
Viczián István |