Model-View-Controller mit Spring und Thymeleaf
Thymeleaf ist eine moderne Template Engine, um Server-seitig html zu generieren. Hier zeige ich, wie es in einem Spring MVC Projekt eingesetzt wird. Dabei demonstriere ich verschiedene Thymeleaf Ausdrücke (if, loop, usw.), Lesen des Modells und Nutzung von CSS oder JavaScript.
Model-View-Controller mit Spring und Thymeleaf
- Das Modell (Model) wird mit einfachen Java Objekten realisiert (POJO).
- Die Ansicht (View) wird mittels Thymeleaf in html, css und JavaScript implementiert.
- Der Controller wird als Spring Bean vom Typ @Controller umgesetzt.
Thymeleaf ins Java Projekt integrieren
<artifactId>spring-boot-starter-thymeleaf</artifactId>
Spring Controller
- Liste mit allen erstellten Dingen (Items) anzeigen.
- Neues Ding erstellen und der Liste hinzufügen.
- Den klassischen MVC Controller annotieren wir in Spring mit @Controller. Dadurch wird der ItemContoller als Bean im Spring IoC Container bekannt. Eingehende Requests werden vom Dispatcher Servlet entsprechend dem registrierten Handler Mapping an den richtigen Controller geschickt.
- @GetMapping und @PostMapping kennen wir schon aus diesem Artikel rest-json-apis-in-java-leicht-gemacht. Das Spring Handler Mapping basiert auf den hier konfigurierten Pfaden, so dass eingehendet Request entsprechend ihres Typs und URL-Pfades an die jeweilige Methode des Controllers geschickt werden.
Die Methode showItems bearbeitet hier eingehende GET Requests für 2 verschiedene Pfade - generell können beliebig viele Pfade bzw. eine Liste von Pfaden auf eine Methode gemappt werden. - @RequestParam mappt die Daten innerhalb des POST Formulars auf den annotierten Parameter in der Methode createNewItem. Das Formular stelle ich in einem zweiten Artikel zu Thymeleaf html Templates vor.
- Model : Die Methode createNewItem hat den Parameter model, der automatisch eine Instanz des Model Interface bereitstellt. Diese Model Instanz kann dann mit den Daten des Modells befüllt werden und in der View ausgelesen werden (siehe Kapitel weiter unten). Model ist vergleichbar mit einer Map, daher kann eine Model Instanz auch mit der Methode asMap als Map Instanz verarbeitet werden.
- ModelAndView : Die Methode showItems hat den Parameter mav vom Typ ModelAndView. Die ModelAndView Klasse ist ein Kombination aus dem Model und der anzuzeigenden View. Mit mav.addObject werden Objekte dem Modell innerhalb der Klasse ModelAndView hinzugefügt. Mit setView oder setViewName wird die anzuzeigende View definiert. Im Beispiel hier setze ich immer den String viewName, dessen Wert dem Namen der Thymeleaf html-Templates mit oder ohne Dateiendung ".html" entsprechen muss.
- Wenn die Methode einfach nur einen String zurückgibt (siehe showCreateItem), versucht Spring eine passende View zu finden und diese anzuzeigen. Findet Spring keine View, kommt es zu einem "Internal Server Error".
Hier unterscheiden sich @RestController vom @Controller. Der RestController interpretiert den Sting als den Inhalt der Response und nicht als die nächste anzuzeigende View. Gibt man im RestController ein View Objekt zurück, so zeigt auch dieser die View an.
Ihr könnt das einfach testen, indem ihr in unserem Demo Projekt einfach mal die ItemController Annotation ändert.
POJO Modell Klasse
Thymeleaf View
- JSP - JavaServer Pages : https://www.oracle.com/java/technologies/jspt.html
- Groovy Markup Templates : http://groovy-lang.org/templating.html#_the_markuptemplateengine
- JSF - Java Server Faces : https://www.oracle.com/java/technologies/javaserverfaces.html
HTML, CSS und JavaScript Dateien richtig ablegen
- templates ist der Standard Ordner für alle Thymeleaf Templates, die in Form von html Dateien gespeichert werden.
- static wird für statische Dateien, wie JavaScript- und CSS-Dateien verwendet. Es empfiehlt sich mit weiteren Unterverzeichnissen eine Ordnung zu schaffen. Ich habe daher hier die beiden Unterverzeichnisse js für JavaScript-Dateien und css für Cascading Style Sheets angelegt.
https://github.com/elmar-brauch/thymeleaf
Verzeichnis-Struktur Thymeleaf |
Thymeleaf Templates
initial-scale=1, shrink-to-fit=no" />
</div>
Die Thymeleaf Ausdrücke erkennt man hier am Prefix "th:":
- xmlns:th="http://www.thymeleaf.org" ist die Definition des XML Namespaces für Thymeleaf. Das wird benötigt, damit die folgenden Thymeleaf Ausdrücke als solche erkannt werden.
- Mit th:href="@{/css/main.css}" wird hier eine Hyper-Referenz (href) auf die verwendete CSS Datei main.css gemacht. Der Pfad /css/main.css muss sich im Spring resource Folder befinden. Links zu URLs oder Dateien werden immer mit @{...} definiert.
- th:src="@{/js/main.js}" referenziert hier die JavaScript Quellen-Datei (src) "/js/main.js". Es funktioniert analog zur th:href Hyper-Referenz.
- <a th:href="@{/item-create}"> : th:href kann auch für Links (in a-Tags) zu anderen Views genutzt werden, die dann wieder über den Spring Controller ausgespielt werden, siehe ItemController Klasse showCreateItem Methode.
- th:if="${#lists.isEmpty(items)} ist ein Thymeleaf if-Ausdruck zum Ein- oder Ausblenden des zugehörigen Tags. Die Erklärung dieses Ausdrucks findet ihr bereits im ersten Abschnitt dieses Blog-Posts.
Hier möchte ich noch mal darauf eingehen, wo die items Liste her kommt. Schauen wir uns noch mal unseren Controller an. Dort sehen wir, dass eine Liste mit Item Objekten zum Modell per Methode addAttribute hinzugefügt wurde. addAttribute verwendet als Schlüssel den Wert "items", daher können wir in Thymeleaf mit items auf den Wert im Modell, also die List<Item> Instanz zugreifen. - th:unless="${#lists.isEmpty(items)} bzw. th:unless ist die negierte Form vom vorherigen th:if. Es entspricht also exakt diesen Ausdruck:
th:if="${not #lists.isEmpty(items)}. - th:each="item : ${items}" ist eine for-each Schleife, wie wir sie auch aus Java kennen. ${items} greift auf die List<Item> Instanz in unserem Modell zu. Mit th:each iteriert Thymeleaf über alle Element in der Liste. Innerhalb der Tags (im Beispiel <li>) im Schleifen Tag (im Beispiel <ol>) können wir mit ${item} auf die einzelnen Listenelemente zugreifen.
- th:text="${item.name}" wird verwendet um einen Text in einem Tag auszuspielen. Der Text wird aus der Variablen item bzw. deren Attribute name ausgelesen.
Fazit & Ausblick
In diesem Blog-Post haben wir gesehen, wie man mit Spring MVC Web-Applikationen bauen kann. Die html Seiten haben wir mit Thymeleaf Templates erstellt. Variable Elemente wurden vom Controller ins Modell geschrieben und im html-Template mit Thymeleaf Ausdrücken ausgelesen.
Im 2. Teil zu Thymeleaf stelle ich folgende Aspekte vor:
- Schreiben ins Modell bzw. html Formulare
- JavaScript in Thymeleaf Templates
- Iternationalisierung (i18n) bzw. mehrere Sprachen mit Spring
- Wiederverwendung von Thymeleaf Templates - z.B. dasselbe html head-Tag in mehreren Seiten anzeigen
https://github.com/elmar-brauch/thymeleaf
Weiterführende Informationen zu Thymeleaf findet ihr hier:
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html
Kommentare