Velocity, Freemarker, Jade4J – Alternativen zu JSPs

Webanwendungen auf Java-Basis werden heutzutage größtenteils mit Hilfe eines umfangreichen Webframeworks (wie Java Server Faces, Google Web Toolkit oder Wicket) realisiert. Viele dieser Technologien bringen ihre eigene Templatesprache mit, die HTML um eigene Elemente erweitern. Falls man allerdings die Web-Basistechnologien Servlets/JSPs nutzt oder das Webframework neben JSPs auch andere Templatesprachen unterstützt (wie Spring MVC), wird der Einsatz einer alternativen Templatesprache vielleicht mit höherer Produktivität und mehr Spaß belohnt.

Solange man nur auf eine Templatesprache wie JSP beschränkt ist, braucht man sich auch keine Gedanken um die Effizienz der eingesetzten Sprache zu machen. Aber in diesem Artikel möchte ich dazu animieren, andere Templatesprachen mal auszuprobieren. Deren produktiven Einsatz sollte man sich natürlich zuvor gut überlegen – einige Aspekte sind beispielsweise:

  • Sprache: Einfachheit und Klarheit versus Ausdrucksstärke und Komplexität
  • Erweiterungen: Erstellung und Einbindung von Bibliotheken (z.B.: Tag-Libraries für JSPs)
  • Werkzeuge: Unterstützung innerhalb von Editoren/IDEs (z.B.: Syntax-Highlighting)
  • Mitarbeiter: Know-How im Team und Bereitschaft neue Sprachen zu lernen

In der folgenden kleinen Beispielanwendung werden die Temlatesprachen JSP, Velocity, FreeMarker und Jade4J parallel genutzt. Als Basis setze ich Spring MVC ein, das sehr schön von der eingesetzten Templatesprache abstrahiert. Somit können wir den MVC-Controller und das MVC-Modell für die MVC-View unabhängig von der tatsächlich eingesetzten Templatesprache nutzen.

Das Grundgerüst – Maven, Servlet, Spring MVC

Das folgende Beispiel ist bei Github verfügbar: example-spring-template. Wenn man Maven installiert hat, lässt sich das Projekt ganz einfach mit 'mvn install' bauen. Die erzeugte Webanwendung im target-Verzeichnis ‚example-spring-template.war‘ ist dann beispielsweise in einem Tomcat- oder Jetty-Server ausführbar.

In der Maven-Konfiguration pom.xml wird Spring-MVC und die jeweilige Template-Bibliothek eingebunden. Dann definieren wir im Deployment Descriptor der Webanwendung web.xml, dass das Spring-Dispatcherservlet mit dem Namen ‚template‘ alle URLs mit der Endung ‚.html‘ entgegennehmen soll. Dieses Spring-Servlet konfigurieren wir in der Datei ‚template-servlet.xml‘. Sie enthält die Information, wo nach den Controllern gesucht werden soll und welche ViewResolvers verwendet werden sollen.

Für jede Templatesprache benötigen wir einen eigenen ViewResolver und eventuell noch eine zusätzliche Konfiguration. Im Spring-Controller TemplateController haben wir für jede Templatesprache eine Dispatcher-Methode, die auf das jeweilige Template verweist. Hier folgen die jeweiligen Konfigurationsdateien und anschließend die Template-Dateien in der jeweiligen Sprache.

Maven-Konfiguration: pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>de.bruns.example.spring</groupId>
	<artifactId>template</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>war</packaging>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>3.0.7.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>org.freemarker</groupId>
			<artifactId>freemarker</artifactId>
			<version>2.3.16</version>
		</dependency>

		<dependency>
			<groupId>org.apache.velocity</groupId>
			<artifactId>velocity</artifactId>
			<version>1.7</version>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<dependency>
			<groupId>de.neuland</groupId>
			<artifactId>spring-jade4j</artifactId>
			<version>0.2.3</version>
		</dependency>

		<dependency>
			<groupId>de.neuland</groupId>
			<artifactId>jade4j</artifactId>
			<version>0.2.14</version>
		</dependency>
	</dependencies>

	<repositories>
		<repository>
			<id>spring-jade4j-releases</id>
			<url>https://github.com/neuland/spring-jade4j/raw/master/releases</url>
		</repository>
		<repository>
			<id>jade4j-releases</id>
			<url>https://github.com/neuland/jade4j/raw/master/releases</url>
		</repository>
	</repositories>

	<build>
		<finalName>example-spring-template</finalName>
	</build>
</project>

Deployment Descriptor der Webanwendung: web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<display-name>Spring Template Example</display-name>

	<servlet>
		<servlet-name>template</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>template</servlet-name>
		<url-pattern>*.html</url-pattern>
	</servlet-mapping>

	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

Spring-Konfiguration: template-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-2.5.xsd
       ">

	<context:component-scan base-package="de.bruns.example.spring.template" />

    <!-- Velocity -->
    <bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
        <property name="resourceLoaderPath" value="/WEB-INF/views/" />
    </bean>

    <bean id="velocityViewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
        <property name="order" value="1" />
        <property name="cache" value="true" />
        <property name="prefix" value="" />
        <property name="suffix" value=".vm" />
    </bean>

	<!-- Freemarker -->
	<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
		<property name="templateLoaderPath" value="/WEB-INF/views/" />
	</bean>

	<bean id="freemarkerViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
		<property name="order" value="2" />
		<property name="cache" value="false" />
		<property name="prefix" value="" />
		<property name="suffix" value=".ftl" />
	</bean>

	<!-- Jade4J -->
	<bean id="templateLoader" class="de.neuland.jade4j.spring.template.SpringTemplateLoader">
		<property name="basePath" value="/WEB-INF/views/" />
	</bean>

	<bean id="jadeConfiguration" class="de.neuland.jade4j.JadeConfiguration">
		<property name="prettyPrint" value="false" />
		<property name="caching" value="false" />
		<property name="templateLoader" ref="templateLoader" />
	</bean>

	<bean id="jadeViewResolver" class="de.neuland.jade4j.spring.view.JadeViewResolver">
		<property name="order" value="3" />
		<property name="configuration" ref="jadeConfiguration" />
		<property name="renderExceptions" value="true" />
	</bean>

	<!-- JSP -->
	<bean id="jspViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
		<property name="order" value="4" />
		<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
		<property name="prefix" value="/WEB-INF/views/" />
		<property name="suffix" value=".jsp" />
	</bean>
</beans>

Spring-Controller: TemplateController.java

package de.bruns.example.spring.template;

import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class TemplateController {

   @RequestMapping("/jsp")
   public ModelAndView jsp() {
      Map<String, String> variables = new HashMap<String, String>();
      variables.put("version", "2.0");
      return new ModelAndView("jsp", variables);
   }

   @RequestMapping("/velocity")
   public ModelAndView velocity() {
      Map<String, String> variables = new HashMap<String, String>();
      variables.put("version", "1.7");
      return new ModelAndView("velocity", variables);
   }

   @RequestMapping("/freemarker")
   public ModelAndView freemarker() {
      Map<String, String> variables = new HashMap<String, String>();
      variables.put("version", "2.3.16");
      return new ModelAndView("freemarker", variables);
   }

   @RequestMapping("/jade")
   public ModelAndView jade() {
      Map<String, String> variables = new HashMap<String, String>();
      variables.put("version", "0.2.14");
      return new ModelAndView("jade", variables);
   }

}
Übersicht - hier geht es los

Übersicht – hier geht es los

Templatesprache JSP

  • bewährte Standard-Templatesprache, die vielen Java-Entwicklern bekannt ist
  • viele Erweiterungen anderer Anbieter (Taglibs)
  • Java-Code kann innerhalb des Templates genutzt werden
  • die vielen Möglichkeiten können Entwickler zu komplexen Views verleiten
<html>
<body>
JSP Version ('jsp.jsp'): <%= request.getAttribute("version") %>
</body>
</html>
Von einer JSP gerenderte Webseite

Von einer JSP gerenderte Webseite

Templatesprache Apache Velocity

  • Velocity ist eine bewährte Technologie (>10 Jahre) der Apache Software Foundation
  • findet Verwendung in vielen Produkten: z.B. Jira
  • strikte Trennung zwischen Anwendungslogik und View
  • Generierung anderer Dateiformate möglich: XML, CSV, SQL
<html>
<body>
Velocity Version ('velocity.vm'): $version
</body>
</html>
Von Velocity gerenderte Webseite

Von Velocity gerenderte Webseite

Templatesprache FreeMarker

  • FreeMarker ist eine bewährte Technologie (>10 Jahre)
  • findet Verwendung in vielen Produkten: z.B. Hibernate
  • strikte Trennung zwischen Anwendungslogik und View
  • Generierung anderer Dateiformate möglich: XML, CSV, SQL
<html>
<body>
Freemarker Version ('freemarker.ftl'): ${version}
</body>
</html>
Von Freemarker gerenderte Webseite

Von Freemarker gerenderte Webseite

Templatesprache Jade4J

  • sehr junge Technologie hosted auf Github
  • Nutzung von Jade-Templates (JavaScript/Node), ähnelt HAML-Templates (Ruby)
  • strikte Trennung zwischen Anwendungslogik und View
  • keine schließenden HTML-Tags
  • klare und einfache Strukturen
  • nette interaktive Jade-Dokumentation: hier
  • Templating mit Jade und entsprechendem Editor (wie Colorer) macht Spaß 😉
html
body
  | Version ('jade.jade'):
  = version
Von Jade4J gerenderte Webseite

Von Jade4J gerenderte Webseite

Qual der Wahl

Welche der Templatesprachen würde ich jetzt für ein Projekt nutzen? Die vier Sprachen sind meiner Meinung in drei Kategorien einzuteilen:

  • JSP: komplexe, sehr stark verbreitete, bewährte Technologie
  • Velocity/FreeMarker: Trennung von Anwendungslogik und View, stark verbreitete und bewährte Technologie
  • Jade4J: sehr einfache Struktur, Trennung von Anwendungslogik und View, momentan wenig verbreitet, junge Technologie

Die geringere Komplexität durch eine klare Trennung von Anwendungslogik und View lohnt sich mittel- und langfristig immer, sodass ich Velocity und FreeMarker den JSPs vorziehen würde. Es gibt einige Vergleiche zwischen Velocity und FreeMarker (Vergleich auf StackOverflow und FreeMarker). Falls ich keine speziellen Anforderungen habe, würde ich mich für FreeMarker entscheiden, weil Hibernate 2006 von Velocity auf FreeMarker wechselte (Fehlerverarbeitung sei beispielsweise besser – Blog-Beitrag). Aber eigentlich habe ich mich schon in die einfache Schreibweise von Jade4j verliebt und glaube, dass sich solch eine einfache Templatesprache auch im Java-Bereich durchsetzen wird.

Advertisements

Eine Antwort zu “Velocity, Freemarker, Jade4J – Alternativen zu JSPs

  1. Pingback: Neue JRebel Lizenz – weiterhin keine Redeployments mehr | Andreas Bruns

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s