Bagian pertamaBagian kedua7 Verifikasi dan pesan kesalahan
Sebagian besar formulir kami harus menampilkan pesan validasi untuk memberi tahu pengguna tentang kesalahan yang telah ia buat.
Thymeleaf menawarkan beberapa alat untuk ini: beberapa fungsi di objek
#fields ,
th: error dan
th: errorclass atribut .
7.1 Kesalahan bidang
Mari kita lihat bagaimana kita bisa mengatur kelas CSS spesifik untuk bidang jika berisi kesalahan:
<input type="text" th:field="*{datePlanted}" th:class="${#fields.hasErrors('datePlanted')}? fieldError" />
Seperti yang Anda lihat, fungsi
# fields.hasErrors (...) menerima ekspresi bidang sebagai parameter (
datePlanted ) dan mengembalikan nilai Boolean yang menunjukkan apakah ada kesalahan validasi untuk bidang ini.
Kami juga bisa mendapatkan semua kesalahan untuk bidang ini dan mengulanginya:
<ul> <li th:each="err : ${#fields.errors('datePlanted')}" th:text="${err}" /> </ul>
Alih-alih mengulangi, kita juga bisa menggunakan
th: error , atribut khusus yang membuat daftar dengan semua kesalahan untuk pemilih yang ditentukan, dipisahkan oleh <br />:
<input type="text" th:field="*{datePlanted}" /> <p th:if="${#fields.hasErrors('datePlanted')}" th:errors="*{datePlanted}">Incorrect date</p>
Gaya CSS berbasis kesalahan:
th: errorclassContoh yang kami lihat di atas, mengatur kelas CSS untuk formulir input, jika ada kesalahan dalam bidang ini, sangat umum sehingga Thymeleaf menawarkan atribut khusus untuk eksekusi yang akurat:
th: errorclass .
Diterapkan ke tag bidang formulir (input, pilih, textarea ...), itu akan membaca nama bidang yang akan diperiksa dari
nama yang ada atau atribut
th: bidang dalam tag yang sama, dan kemudian menambahkan kelas CSS yang ditentukan ke tag, jika bidang seperti itu memiliki kesalahan terkait:
<input type="text" th:field="*{datePlanted}" class="small" th:errorclass="fieldError" />
Jika ada kesalahan dalam
datePlanted , itu akan terlihat seperti ini:
<input type="text" id="datePlanted" name="datePlanted" value="2013-01-01" class="small fieldError" />
7.2 Semua kesalahan
Tetapi bagaimana jika kita ingin menunjukkan semua kesalahan dalam formulir? Kita hanya perlu meminta metode
# fields.hasErrors (...) dan
# fields.errors (...) dengan konstanta '
* ' atau '
semua ' (yang setara):
<ul th:if="${#fields.hasErrors('*')}"> <li th:each="err : ${#fields.errors('*')}" th:text="${err}">Input is incorrect</li> </ul>
Seperti dalam contoh di atas, kita bisa mendapatkan semua kesalahan dan mengulanginya ...
<ul> <li th:each="err : ${#fields.errors('*')}" th:text="${err}" /> </ul>
... dan juga buat daftar bersama <br />:
<p th:if="${#fields.hasErrors('all')}" th:errors="*{all}">Incorrect date</p>
Terakhir, perhatikan bahwa
# fields.hasErrors ('*') setara dengan
# fields.hasAnyErrors () , dan
# fields.errors ('*') setara dengan
# fields.allErrors () . Gunakan sintaks yang Anda sukai:
<div th:if="${#fields.hasAnyErrors()}"> <p th:each="err : ${#fields.allErrors()}" th:text="${err}">...</p> </div>
7.3 Kesalahan global
Ada jenis kesalahan ketiga dalam bentuk Spring: kesalahan global. Ini adalah kesalahan yang tidak terkait dengan bidang spesifik apa pun di formulir, tetapi masih ada.
Thymeleaf menawarkan konstanta
global untuk mengakses kesalahan ini:
<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 serta metode pembantu yang setara
# fields.hasGlobalErrors () dan
# fields.globalErrors () :
7.4 Menampilkan kesalahan di luar formulir
Kesalahan validasi formulir juga bisa ditampilkan di luar formulir menggunakan variabel (
$ {...} ) alih-alih ekspresi pilih (
* {...} ) dan awalan untuk nama komponen yang mendukung formulir:
<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 Objek Kesalahan Kaya
Thymeleaf menawarkan kemungkinan mendapatkan informasi tentang kesalahan formulir dalam bentuk komponen bean (bukan string sederhana) dengan atribut
fieldNama (String),
pesan (String) dan
global (boolean).
Kesalahan ini dapat diperoleh dengan menggunakan metode utilitas
# fields.detailedErrors () :
<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 Ini masih prototipe!
Aplikasi kita sudah siap. Tapi mari kita lihat lagi halaman .html yang kami buat ...
Salah satu konsekuensi paling menyenangkan dari bekerja dengan Thymeleaf adalah bahwa setelah semua fungsi ini telah kami tambahkan ke HTML kami, kami masih dapat menggunakan HTML ini sebagai prototipe (kami mengatakan bahwa ini adalah
Template Alami ). Mari kita buka
seedstartermng.html langsung di browser kita tanpa meluncurkan aplikasi kita:

Ini dia! Ini bukan aplikasi yang berfungsi, ini bukan data nyata ... tetapi ini adalah prototipe yang sepenuhnya benar yang terdiri dari kode HTML yang ditampilkan dengan sempurna.
9 Layanan Konversi
9.1 Konfigurasi
Seperti yang dijelaskan sebelumnya, Thymeleaf dapat menggunakan Layanan Transformasi yang terdaftar dalam konteks aplikasi. Kelas konfigurasi aplikasi kami, memperluas
penolong asli Spring
WebMvcConfigurerAdapter , akan secara otomatis mendaftarkan layanan konversi yang dapat kami konfigurasi dengan menambahkan alat pemformatan yang diperlukan. Mari kita lihat tampilannya lagi:
@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 Sintaks braket ganda
Layanan konversi dapat dengan mudah diterapkan untuk mengkonversi / memformat objek apa pun menjadi string. Ini dilakukan dengan menggunakan sintaks ekspresi kurung ganda:
- Untuk ekspresi variabel: $ {{...}}
- Untuk mengekspresikan pilihan: * {{...}}
Jadi, misalnya, diberikan konverter Integer-to-String, yang menambahkan koma sebagai pemisah ribuan, ini adalah:
<p th:text="${val}">...</p> <p th:text="${{val}}">...</p>
... harus menghasilkan:
<p>1234567890</p> <p>1,234,567,890</p>
9.3 Penggunaan dalam formulir
Kami melihat sebelumnya bahwa setiap atribut
field th: akan selalu menerapkan layanan transformasi, jadi ini:
<input type="text" th:field="*{datePlanted}" />
... sebenarnya setara dengan:
<input type="text" th:field="*{{datePlanted}}" />
Perhatikan bahwa sesuai persyaratan Spring, ini adalah satu-satunya skenario di mana layanan transformasi diterapkan pada ekspresi menggunakan sintaks braket tunggal.
9.4 # konversi objek konversi
Objek utilitas konversi #conversions memungkinkan Anda untuk memulai layanan konversi secara manual jika diperlukan:
<p th:text="${'Val: ' + #conversions.convert(val,'String')}">...</p>
Sintaks untuk objek layanan ini adalah:
- # Conversions.convert (Object, Class) : mengonversi objek ke kelas yang ditentukan
- # Conversions.convert (Object, String) : sama seperti di atas, tetapi dengan kelas target sebagai String (perhatikan bahwa paket java.lang. mungkin dihilangkan)
10 Rendering fragmen templat Templat templat (AJAX dll)
Thymeleaf menawarkan kemampuan untuk membuat hanya sebagian dari templat sebagai hasil dari pelaksanaannya:
fragmen .
Ini bisa menjadi alat komponenisasi yang berguna. Misalnya, ini dapat digunakan pada pengontrol yang menjalankan panggilan
AJAX , yang dapat mengembalikan fragmen tata letak halaman yang sudah dimuat ke browser (untuk memperbarui pilihan, mengaktifkan / menonaktifkan tombol ...).
Render terfragmentasi dapat dicapai menggunakan spesifikasi snippet Thymeleaf: objek yang mengimplementasikan antarmuka
org.thymeleaf.fragment.IFragmentSpec .
Implementasi yang paling umum adalah
org.thymeleaf.standard.fragment.StandardDOMSelectorFragmentSpec , yang memungkinkan Anda untuk menentukan fragmen menggunakan pemilih DOM, sama seperti yang digunakan di
: termasuk atau
ke: ganti .
10.1 Mendefinisikan Fragmen dalam View Bean
Kacang tampilan adalah kacang-kacangan dari kelas
org.thymeleaf.spring4.view.ThymeleafView yang dideklarasikan dalam konteks aplikasi (penjelasan
kacang jika Anda menggunakan konfigurasi Java). Mereka memungkinkan Anda menentukan fragmen sebagai berikut:
@Bean(name="content-part") @Scope("prototype") public ThymeleafView someViewBean() { ThymeleafView view = new ThymeleafView("index");
Mengingat definisi kacang di atas, jika controller kami mengembalikan
bagian-konten (nama kacang di atas) ...
@RequestMapping("/showContentPart") public String showContentPart() { ... return "content-part"; }
... Thymeleaf hanya akan mengembalikan fragmen
konten dari templat indeks - lokasi yang mungkin kira-kira sama dengan
/WEB-INF/templates/index.html , setelah menerapkan awalan dan akhiran. Dengan demikian, hasilnya akan sepenuhnya sama dengan menentukan
indeks :: konten :
<!DOCTYPE html> <html> ... <body> ... <div th:fragment="content"> Only this div will be rendered! </div> ... </body> </html>
Perhatikan juga bahwa berkat penyeleksi tata letak Thymeleaf yang kuat, kita dapat memilih sebuah fragmen dalam templat tanpa atribut
fragmen th . Mari kita gunakan atribut
id , misalnya:
@Bean(name="content-part") @Scope("prototype") public ThymeleafView someViewBean() { ThymeleafView view = new ThymeleafView("index");
10.2 Mendefinisikan fragmen dalam nilai pengembalian controller
Alih-alih mendeklarasikan
tampilan kacang , fragmen dapat didefinisikan dari controller menggunakan sintaks
ekspresi fragmen . Sama seperti di
th: masukkan atau
th: ganti atribut.
@RequestMapping("/showContentPart") public String showContentPart() { ... return "index :: content"; }
Tentu saja, kekuatan penuh penyeleksi DOM tersedia lagi, sehingga kami dapat memilih fragmen kami berdasarkan atribut HTML standar, seperti
id = "konten" :
@RequestMapping("/showContentPart") public String showContentPart() { ... return "index :: #content"; }
Dan kita juga bisa menggunakan parameter seperti:
@RequestMapping("/showContentPart") public String showContentPart() { ... return "index :: #content ('myvalue')"; }
11 Fitur Integrasi Tingkat Lanjut
11.1 Integrasi dengan RequestDataValueProcessor
Thymeleaf terintegrasi dengan mulus dengan antarmuka Spring
RequestDataValueProcessor . Antarmuka ini memungkinkan Anda untuk mencegat URL tautan, URL formulir, dan nilai kolom formulir sebelum menuliskannya ke hasil markup, serta secara transparan menambahkan bidang formulir tersembunyi yang menyertakan fitur keamanan, seperti: perlindungan terhadap CSRF (pemalsuan permintaan lintas situs) .
Implementasi
RequestDataValueProcessor dapat dengan mudah dikonfigurasikan dalam konteks aplikasi. Seharusnya mengimplementasikan
org.springframework.web.servlet.support.RequestDataValueProcessor antarmuka dan memiliki
requestDataValueProcessor sebagai nama bean:
@Bean public RequestDataValueProcessor requestDataValueProcessor() { return new MyRequestDataValueProcessor(); }
... dan Thymeleaf akan menggunakannya sebagai berikut:
- th: href dan th: src call RequestDataValueProcessor.processUrl (...) sebelum merender URL
- th: action call RequestDataValueProcessor.processAction (...) sebelum merender atribut action dari form, dan juga mendeteksi ketika atribut ini diterapkan pada tag <form>, yang dalam hal apa pun harus menjadi satu-satunya tempat, dan dalam hal ini memanggil RequestDataValueProcessor.getExtraHiddenFields (... ) dan menambahkan bidang tersembunyi yang dikembalikan tepat sebelum tag penutup </form>
- th: nilai panggilan RequestDataValueProcessor.processFormFieldValue (...) untuk menggambar nilai yang dimaksud, kecuali bidang th: berada di tag yang sama (dalam hal ini bidang th: bidang akan berhati-hati)
- th: bidang memanggil RequestDataValueProcessor.processFormFieldValue (...) untuk menggambar nilai bidang yang berlaku (atau badan tag jika itu adalah <textarea>)
Perhatikan bahwa ada beberapa skenario di mana Anda perlu mengimplementasikan secara eksplisit RequestDataValueProcessor dalam aplikasi Anda. Dalam kebanyakan kasus, ini akan secara otomatis digunakan oleh perpustakaan keamanan yang Anda gunakan secara transparan, misalnya, CSRF Spring Security.11.1 Membangun URI menjadi Pengontrol
Dimulai dengan versi 4.1,
Spring menyediakan kemampuan untuk membuat tautan ke pengontrol beranotasi langsung dari tampilan, tanpa perlu mengetahui URI yang dipetakan pengontrolnya.
Di Thymeleaf, ini dapat dicapai menggunakan ekspresi
# mvc.url (...) , yang memungkinkan Anda untuk mengatur metode pengontrol dalam huruf kapital dari kelas pengontrol di mana mereka berada, diikuti oleh nama metode. Ini sama dengan fungsi
pegas kustom
: mvcUrlx (...) di JSP.
Misalnya, untuk:
public class ExampleController { @RequestMapping("/data") public String getData(Model model) { ... return "template" } @RequestMapping("/data") public String getDataParam(@RequestParam String type) { ... return "template" } }
Kode berikut akan membuat referensi metode:
<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>
Anda dapat membaca tentang mekanisme ini di
http://docs.spring.io/spring-framework/docs/4.1.2.RELEASE/spring-framework-reference/html/mvc.html#mvc-links-to-controllers- dari-dilihat12 Spring WebFlow integrasi
Paket integrasi Thymeleaf + Spring mencakup integrasi dengan Spring WebFlow (2.3+).
WebFlow menyertakan beberapa fitur AJAX untuk merender fragmen halaman yang ditampilkan ketika peristiwa tertentu (transisi) dipicu, dan agar Thymeleaf dapat melacak permintaan AJAX ini, kita perlu menggunakan implementasi ViewResolver lain yang dikonfigurasi sebagai berikut:
<bean id="thymeleafViewResolver" class="org.thymeleaf.spring4.view.AjaxThymeleafViewResolver"> <property name="viewClass" value="org.thymeleaf.spring4.view.FlowAjaxThymeleafView" /> <property name="templateEngine" ref="templateEngine" /> </bean>
... dan kemudian
ViewResolver ini dapat dikonfigurasi di
WebFlow ViewFactoryCreator sebagai:
<bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator"> <property name="viewResolvers" ref="thymeleafViewResolver"/> </bean>
Dari sini Anda dapat menentukan templat Thymeleaf di negara-tampilan Anda:
<view-state id="detail" view="bookingDetail"> ... </view-state>
Dalam contoh di atas,
bookingDetail adalah templat Thymeleaf yang ditentukan dengan cara biasa, dapat dipahami oleh sembarang penyelesai templat yang dikonfigurasi dalam TemplateEngine.
12.2 Cuplikan AJAX di Spring WebFlow
Perhatikan bahwa ini hanya menjelaskan cara membuat fragmen AJAX untuk digunakan dengan Spring WebFlow. Jika Anda tidak menggunakan WebFlow, membuat pengontrol Spring MVC yang menanggapi permintaan AJAX dan mengembalikan sepotong HTML semudah membuat pengontrol lain yang mengembalikan templat, dengan satu-satunya pengecualian bahwa Anda cenderung mengembalikan sebuah fragmen seperti " main :: admin "dari metode pengontrol Anda.WebFlow memungkinkan Anda menentukan rendering melalui AJAX dengan tag <render>, misalnya seperti ini:
<view-state id="detail" view="bookingDetail"> <transition on="updateData"> <render fragments="hoteldata"/> </transition> </view-state>
Fragmen-fragmen ini (dalam hal ini
hoteldata ) dapat berupa daftar fragmen yang dipisahkan koma yang ditunjukkan dalam markup dengan
th: fragmen :
<div id="data" th:fragment="hoteldata"> This is a content to be changed </div>
Selalu ingat bahwa cuplikan ini harus memiliki atribut
id sehingga pustaka Spring JavaScript yang berjalan di browser dapat menggantikan markup.
Anda juga dapat menentukan tag <render> menggunakan pemilih DOM:
<view-state id = "detail" view = "bookingDetail">
/>
</view-state>
... dan itu berarti tidak perlu untuk
th: fragmen :
<div id="data"> This is a content to be changed </div>
Adapun kode yang memicu transisi data
pembaruan , sepertinya ini:
<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>