Erster TeilZweiter Teil7 Überprüfungs- und Fehlermeldungen
Die meisten unserer Formulare sollten Validierungsmeldungen anzeigen, um den Benutzer über von ihm gemachte Fehler zu informieren.
Thymeleaf bietet hierfür mehrere Tools an: verschiedene Funktionen im
# fields- Objekt,
th: error- und
th: errorclass-Attribute .
7.1 Feldfehler
Mal sehen, wie wir eine bestimmte CSS-Klasse für ein Feld festlegen können, wenn es einen Fehler enthält:
<input type="text" th:field="*{datePlanted}" th:class="${#fields.hasErrors('datePlanted')}? fieldError" />
Wie Sie sehen können, empfängt die Funktion
# fields.hasErrors (...) einen
Feldausdruck als Parameter (
datePlanted ) und gibt einen booleschen Wert zurück, der angibt, ob für dieses Feld Validierungsfehler
vorliegen .
Wir können auch alle Fehler für dieses Feld abrufen und wiederholen:
<ul> <li th:each="err : ${#fields.errors('datePlanted')}" th:text="${err}" /> </ul>
Anstatt zu iterieren, könnten wir auch
th: Errors verwenden , ein spezielles Attribut, das eine Liste mit allen Fehlern für den angegebenen Selektor erstellt, getrennt durch <br />:
<input type="text" th:field="*{datePlanted}" /> <p th:if="${#fields.hasErrors('datePlanted')}" th:errors="*{datePlanted}">Incorrect date</p>
Fehlerbasiertes CSS-Styling:
th: errorclassDas obige Beispiel, in dem die CSS-Klasse für das Eingabeformular festgelegt wurde, wenn in diesem Feld Fehler auftreten, ist so häufig, dass Thymeleaf ein spezielles Attribut für die genaue Ausführung bietet:
th: errorclass .
Wird auf das Formularfeld-Tag (Eingabe, Auswahl, Textbereich ...) angewendet, liest es den Namen des zu überprüfenden Felds aus einem vorhandenen
Namen oder den Attributen
th: field im selben Tag und fügt dem Tag die angegebene CSS-Klasse hinzu, falls es sich um ein solches Feld handelt hat verwandte Fehler:
<input type="text" th:field="*{datePlanted}" class="small" th:errorclass="fieldError" />
Wenn
datePlanted Fehler
enthält , sieht es folgendermaßen aus:
<input type="text" id="datePlanted" name="datePlanted" value="2013-01-01" class="small fieldError" />
7.2 Alle Fehler
Aber was ist, wenn wir alle Fehler im Formular anzeigen möchten? Wir müssen nur die Methoden
# fields.hasErrors (...) und
# fields.errors (...) mit den Konstanten '
* ' oder '
all ' (die äquivalent sind)
anfordern :
<ul th:if="${#fields.hasErrors('*')}"> <li th:each="err : ${#fields.errors('*')}" th:text="${err}">Input is incorrect</li> </ul>
Wie in den obigen Beispielen könnten wir alle Fehler erhalten und sie durchlaufen ...
<ul> <li th:each="err : ${#fields.errors('*')}" th:text="${err}" /> </ul>
... und erstellen Sie auch eine gemeinsame Liste <br />:
<p th:if="${#fields.hasErrors('all')}" th:errors="*{all}">Incorrect date</p>
Beachten Sie schließlich, dass
# fields.hasErrors ('*') # fields.hasAnyErrors () und
# fields.errors ('*') # fields.allErrors () entspricht . Verwenden Sie die von Ihnen bevorzugte Syntax:
<div th:if="${#fields.hasAnyErrors()}"> <p th:each="err : ${#fields.allErrors()}" th:text="${err}">...</p> </div>
7.3 Globale Fehler
In der Spring-Form gibt es einen dritten Fehlertyp: globale Fehler. Hierbei handelt es sich um Fehler, die keinem bestimmten Feld im Formular zugeordnet sind, aber dennoch vorhanden sind.
Thymeleaf bietet eine
globale Konstante für den Zugriff auf diese Fehler:
<ul th:if="${#fields.hasErrors('global')}"> <li th:each="err : ${#fields.errors('global')}" th:text="${err}">Input is incorrect</li> </ul>
<p th:if="${#fields.hasErrors('global')}" th:errors="*{global}">Incorrect date</p>
... a sowie die entsprechenden
Hilfsmethoden # fields.hasGlobalErrors () und
# fields.globalErrors () :
7.4 Fehler außerhalb von Formularen anzeigen
Fehler bei der Formularüberprüfung können auch außerhalb von Formularen mithilfe von Variablen (
$ {...} ) anstelle von ausgewählten Ausdrücken (
* {...} ) und einem Präfix für den Namen der Komponente angezeigt werden, die das Formular unterstützt:
<div th:errors="${myForm}">...</div> <div th:errors="${myForm.date}">...</div> <div th:errors="${myForm.*}">...</div> <div th:if="${#fields.hasErrors('${myForm}')}">...</div> <div th:if="${#fields.hasErrors('${myForm.date}')}">...</div> <div th:if="${#fields.hasErrors('${myForm.*}')}">...</div> <form th:object="${myForm}"> ... </form>
7.5 Rich-Error-Objekte
Thymeleaf bietet die Möglichkeit, Informationen über Formularfehler in Form von Bean-Komponenten (anstelle von einfachen Zeichenfolgen) mit den Attributen
fieldName (String),
message (String) und
global (boolean)
abzurufen .
Diese Fehler können mit der
Dienstprogrammmethode # fields.detailedErrors () behoben werden:
<ul> <li th:each="e : ${#fields.detailedErrors()}" th:class="${e.global}? globalerr : fielderr"> <span th:text="${e.global}? '*' : ${e.fieldName}">The field name</span> | <span th:text="${e.message}">The error message</span> </li> </ul>
8 Dies ist immer noch ein Prototyp!
Unsere Bewerbung ist fertig. Aber schauen wir uns noch einmal die von uns erstellte HTML-Seite an ...
Eine der erfreulichsten Konsequenzen der Arbeit mit Thymeleaf ist, dass wir nach all diesen Funktionen, die wir unserem HTML hinzugefügt haben, diesen HTML-Code weiterhin als Prototyp verwenden können (wir sagen, dass dies eine
natürliche Vorlage ist ). Lassen Sie uns
seedstartermng.html direkt in unserem Browser öffnen, ohne unsere Anwendung zu starten:

Hier ist es! Dies ist keine funktionierende Anwendung, es sind keine echten Daten ... aber es ist ein völlig korrekter Prototyp, der aus perfekt angezeigtem HTML-Code besteht.
9 Der Konvertierungsdienst
9.1 Konfiguration
Wie bereits erläutert, kann Thymeleaf den im Anwendungskontext registrierten Transformationsdienst verwenden. Unsere Anwendungskonfigurationsklasse, die den nativen Spring
WebMvcConfigurerAdapter-Helfer erweitert , registriert automatisch einen Konvertierungsdienst, den wir durch Hinzufügen der erforderlichen Formatierungswerkzeuge konfigurieren können. Mal sehen, wie es wieder aussieht:
@Override public void addFormatters(final FormatterRegistry registry) { super.addFormatters(registry); registry.addFormatter(varietyFormatter()); registry.addFormatter(dateFormatter()); } @Bean public VarietyFormatter varietyFormatter() { return new VarietyFormatter(); } @Bean public DateFormatter dateFormatter() { return new DateFormatter(); }
9.2 Syntax in doppelten Klammern
Der Konvertierungsdienst kann einfach angewendet werden, um ein Objekt in eine Zeichenfolge zu konvertieren / zu formatieren. Dies erfolgt mithilfe der Ausdruckssyntax in doppelten Klammern:
- Für variable Ausdrücke: $ {{...}}
- So drücken Sie eine Auswahl aus: * {{...}}
Angesichts des Integer-to-String-Konverters, der Kommas als Tausendertrennzeichen hinzufügt, lautet dies beispielsweise:
<p th:text="${val}">...</p> <p th:text="${{val}}">...</p>
... sollte führen zu:
<p>1234567890</p> <p>1,234,567,890</p>
9.3 Verwendung in Formularen
Wir haben bereits gesehen, dass jedes
th: field- Attribut immer einen Transformationsdienst anwendet.
<input type="text" th:field="*{datePlanted}" />
... eigentlich gleichbedeutend mit:
<input type="text" th:field="*{{datePlanted}}" />
Beachten Sie, dass dies gemäß der Spring-Anforderung das einzige Szenario ist, in dem der Transformationsdienst auf Ausdrücke mit einklammeriger Syntax angewendet wird.
9.4 Konvertierungsobjekt #conversions
Mit dem Konvertierungsdienstprogramm #conversions können Sie den Konvertierungsdienst bei Bedarf manuell starten:
<p th:text="${'Val: ' + #conversions.convert(val,'String')}">...</p>
Die Syntax für dieses Serviceobjekt lautet:
- # convertions.convert (Object, Class) : Konvertiert das Objekt in die angegebene Klasse
- # convertions.convert (Object, String) : wie oben, jedoch mit der Zielklasse als String (beachten Sie, dass das Paket java.lang. möglicherweise weggelassen wird)
10 Rendern von Fragmenten der Vorlage Vorlagenfragmente (AJAX usw.)
Thymeleaf bietet die Möglichkeit, nur einen Teil der Vorlage als Ergebnis ihrer Ausführung zu rendern:
Fragment .
Dies kann ein nützliches Komponentenwerkzeug sein. Beispielsweise kann es auf Controllern verwendet werden, die bei
AJAX- Aufrufen ausgeführt werden und Fragmente des Layouts einer Seite zurückgeben können, die bereits in den Browser geladen wurde (um die Auswahl zu aktualisieren, schalten Sie die Schaltflächen ein / aus ...).
Fragmentiertes Rendern kann mithilfe von Thymeleaf-Snippet-Spezifikationen erreicht werden: Objekte, die die Schnittstelle
org.thymeleaf.fragment.IFragmentSpec implementieren.
Die häufigste dieser Implementierungen ist
org.thymeleaf.standard.fragment.StandardDOMSelectorFragmentSpec , mit der Sie ein Fragment mithilfe des DOM-Selektors angeben können, genau wie in
th: include oder
th: replace .
10.1 Fragmente in einer View Bean definieren
View Beans sind Beans der Klasse
org.thymeleaf.spring4.view.ThymeleafView , die im Anwendungskontext deklariert sind (
Bean- Annotation, wenn Sie die Java-Konfiguration verwenden). Mit ihnen können Sie Fragmente wie folgt angeben:
@Bean(name="content-part") @Scope("prototype") public ThymeleafView someViewBean() { ThymeleafView view = new ThymeleafView("index");
In Anbetracht der obigen Definition einer Bean, wenn unser Controller einen
Inhaltsteil (den Namen der obigen Bean) zurückgibt ...
@RequestMapping("/showContentPart") public String showContentPart() { ... return "content-part"; }
... Thymeleaf gibt nach dem Anwenden des Präfixes und des Suffixes nur ein Fragment des
Inhalts der Indexvorlage zurück , dessen Speicherort wahrscheinlich ungefähr mit
/WEB-INF/templates/index.html übereinstimmt . Somit entspricht das Ergebnis vollständig der Angabe von
index :: content :
<!DOCTYPE html> <html> ... <body> ... <div th:fragment="content"> Only this div will be rendered! </div> ... </body> </html>
Beachten Sie auch, dass wir dank der leistungsstarken Thymeleaf-Layout-Selektoren ein Fragment in einer Vorlage ohne
th: fragment- Attribute auswählen können. Verwenden wir zum Beispiel das Attribut
id :
@Bean(name="content-part") @Scope("prototype") public ThymeleafView someViewBean() { ThymeleafView view = new ThymeleafView("index");
10.2 Fragmente im Rückgabewert der Steuerung definieren
Anstatt
View Beans zu deklarieren, können Fragmente vom Controller mithilfe der Syntax für Fragmentausdrücke definiert werden. Genau wie in den Attributen
th: insert oder
th: replace .
@RequestMapping("/showContentPart") public String showContentPart() { ... return "index :: content"; }
Natürlich ist die volle Leistung der DOM-Selektoren wieder verfügbar, sodass wir unser Fragment basierend auf Standard-HTML-Attributen wie
id = "content" auswählen können:
@RequestMapping("/showContentPart") public String showContentPart() { ... return "index :: #content"; }
Und wir können auch Parameter verwenden wie:
@RequestMapping("/showContentPart") public String showContentPart() { ... return "index :: #content ('myvalue')"; }
11 Erweiterte Integrationsfunktionen
11.1 Integration mit RequestDataValueProcessor
Thymeleaf lässt sich nahtlos in die Spring
RequestDataValueProcessor- Schnittstelle integrieren. Über diese Schnittstelle können Sie Link-URLs, Formular-URLs und Formularfeldwerte abfangen, bevor Sie sie in das Markup-Ergebnis schreiben. Außerdem können Sie versteckte Formularfelder mit Sicherheitsfunktionen transparent hinzufügen, z. B.: Schutz vor CSRF (Cross-Site Request Forgery) .
Die Implementierung von
RequestDataValueProcessor kann einfach im Anwendungskontext konfiguriert werden. Es sollte die Schnittstelle
org.springframework.web.servlet.support.RequestDataValueProcessor implementieren und
requestDataValueProcessor als Bean-Namen haben:
@Bean public RequestDataValueProcessor requestDataValueProcessor() { return new MyRequestDataValueProcessor(); }
... und Thymeleaf wird es wie folgt verwenden:
- th: href und th: src rufen RequestDataValueProcessor.processUrl (...) auf, bevor die URL gerendert wird
- th: action ruft RequestDataValueProcessor.processAction (...) auf, bevor das Aktionsattribut des Formulars gerendert wird, und erkennt außerdem, wann dieses Attribut auf das <form> -Tag angewendet wird, das in jedem Fall der einzige Ort sein sollte, und ruft in diesem Fall RequestDataValueProcessor.getExtraHiddenFields (...) auf ) und fügt die zurückgegebenen ausgeblendeten Felder unmittelbar vor dem schließenden </ form> -Tag hinzu
- th: value ruft RequestDataValueProcessor.processFormFieldValue (...) auf, um den Wert zu zeichnen, auf den es verweist, es sei denn, th: field befindet sich im selben Tag (in diesem Fall kümmert sich th: field darum).
- th: field ruft RequestDataValueProcessor.processFormFieldValue (...) auf, um den Wert des Feldes zu zeichnen, auf das es angewendet wird ( oder den Hauptteil des Tags, wenn es <textarea> ist).
Beachten Sie, dass es nur sehr wenige Szenarien gibt, in denen Sie RequestDataValueProcessor explizit in Ihrer Anwendung implementieren müssten . In den meisten Fällen wird es automatisch von Sicherheitsbibliotheken verwendet, die Sie transparent verwenden, z. B. CSRF von Spring Security.11.1 URIs für Controller erstellen
Ab Version 4.1 bietet
Spring die Möglichkeit, Links zu mit Anmerkungen versehenen Controllern direkt aus Ansichten zu erstellen, ohne die URIs zu kennen, denen diese Controller zugeordnet sind.
In Thymeleaf kann dies mit dem Ausdruck
# mvc.url (...) erreicht werden , mit dem Sie Controller-Methoden in Großbuchstaben der Controller-Klasse festlegen können, in der sie sich befinden, gefolgt vom Methodennamen. Dies entspricht der benutzerdefinierten Funktion
spring: mvcUrlx (...) in JSP.
Zum Beispiel für:
public class ExampleController { @RequestMapping("/data") public String getData(Model model) { ... return "template" } @RequestMapping("/data") public String getDataParam(@RequestParam String type) { ... return "template" } }
Der folgende Code erstellt Methodenreferenzen:
<a th:href="${(#mvc.url('EC#getData')).build()}">Get Data Param</a> <a th:href="${(#mvc.url('EC#getDataParam').arg(0,'internal')).build()}">Get Data Param</a>
Weitere Informationen zu diesem Mechanismus finden Sie unter
http://docs.spring.io/spring-framework/docs/4.1.2.RELEASE/spring-framework-reference/html/mvc.html#mvc-links-to-controllers- von Ansichten12 Spring WebFlow-Integration
Thymeleaf + Spring-Integrationspakete beinhalten die Integration mit Spring WebFlow (2.3+).
WebFlow enthält einige AJAX-Funktionen zum Rendern von Fragmenten der angezeigten Seite, wenn bestimmte Ereignisse (Übergänge) ausgelöst werden. Damit Thymeleaf diese AJAX-Anforderungen verfolgen kann, muss eine andere ViewResolver-Implementierung verwendet werden, die wie folgt konfiguriert ist:
<bean id="thymeleafViewResolver" class="org.thymeleaf.spring4.view.AjaxThymeleafViewResolver"> <property name="viewClass" value="org.thymeleaf.spring4.view.FlowAjaxThymeleafView" /> <property name="templateEngine" ref="templateEngine" /> </bean>
... und dann kann dieser
ViewResolver in
WebFlow ViewFactoryCreator wie
folgt konfiguriert werden:
<bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator"> <property name="viewResolvers" ref="thymeleafViewResolver"/> </bean>
Von hier aus können Sie Thymeleaf-Vorlagen in Ihrem Ansichtsstatus definieren:
<view-state id="detail" view="bookingDetail"> ... </view-state>
Im obigen Beispiel ist
bookingDetail eine Thymeleaf-Vorlage, die auf die übliche Weise angegeben wird und für jeden der in TemplateEngine konfigurierten Vorlagen-Resolver verständlich ist.
12.2 AJAX-Snippets in Spring WebFlow
Beachten Sie, dass hier nur erläutert wird, wie AJAX-Fragmente zur Verwendung mit Spring WebFlow erstellt werden. Wenn Sie WebFlow nicht verwenden, ist das Erstellen eines Spring MVC-Controllers, der auf eine AJAX-Anforderung reagiert und ein Stück HTML zurückgibt, so einfach wie das Erstellen eines anderen Controllers, der eine Vorlage zurückgibt, mit der einzigen Ausnahme, dass Sie wahrscheinlich ein Fragment wie " main " zurückgeben :: admin "von Ihrer Controller-Methode.Mit WebFlow können Sie das Rendern über AJAX mit <render> -Tags definieren, beispielsweise wie folgt:
<view-state id="detail" view="bookingDetail"> <transition on="updateData"> <render fragments="hoteldata"/> </transition> </view-state>
Diese Fragmente (in diesem Fall
Hoteldata ) können eine durch Kommas getrennte Liste von Fragmenten sein, die im Markup mit
th: fragment : angegeben sind.
<div id="data" th:fragment="hoteldata"> This is a content to be changed </div>
Denken Sie immer daran, dass diese Snippets ein
ID- Attribut haben müssen, damit im Browser ausgeführte Spring JavaScript-Bibliotheken das Markup ersetzen können.
Sie können <render> -Tags auch mit DOM-Selektoren angeben:
<view-state id = "detail" view = "bookingDetail">
/>
</ view-state>
... und das heißt, es besteht keine Notwendigkeit für
th: fragment :
<div id="data"> This is a content to be changed </div>
Der Code, der den
updateData- Übergang auslöst, sieht folgendermaßen aus:
<script type="text/javascript" th:src="@{/resources/dojo/dojo.js}"></script> <script type="text/javascript" th:src="@{/resources/spring/Spring.js}"></script> <script type="text/javascript" th:src="@{/resources/spring/Spring-Dojo.js}"></script> ... <form id="triggerform" method="post" action=""> <input type="submit" id="doUpdate" name="_eventId_updateData" value="Update now!" /> </form> <script type="text/javascript"> Spring.addDecoration( new Spring.AjaxEventDecoration({formId:'triggerform',elementId:'doUpdate',event:'onclick'})); </script>