Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Spring I/O 2016: Bringing new life to the view layer of Spring web apps with Thymeleaf

Spring I/O 2016: Bringing new life to the view layer of Spring web apps with Thymeleaf

The view layer of Java web applications has undergone a profound transformation along the last years, with the advent of so many client-side frameworks and the move of significant parts of the user interface responsibilities to the browser side. But this has never meant the complete dismissal of the server side as an important factor in the building of web user interfaces, and newer architectures are increasingly stressing the need for good server-side template technologies that work together with the client side in order to create the best and most efficient possible UIs.

At the same time, the growing mismatch between web design and software development has not helped reducing the overlap and the conflict between the teams and tools that bring data to the view layer and those in charge of representing such data in the most useful and visually appealing way.

Thymeleaf recently appeared in this scenario as a modern Java template engine for the server side aimed at offering the most satisfactory developer experience possible, at the same time as providing a good integration for client-side frameworks during the development process. And it is currently doing so with some degree of success, having become the view layer of choice for many teams, especially in the Spring MVC and Spring Boot ecosystems.

This talk will cover the core Thymeleaf concepts as well as its usage in Spring web applications, and also show the new exciting features included in Thymeleaf 3.0.

Daniel Fernández

May 19, 2016

More Decks by Daniel Fernández

Other Decks in Technology


  1. Bringing new life to the view layer of Spring web

    apps with Thymeleaf Daniel Fernández @danfenz
  2. Spring I/O 2016 #springio16 #thymeleaf | @danfenz What is Thymeleaf?

    • A server-side template engine for Java ‣ Open Source — Apache 2.0 License ‣ First version 2011 — Currently 3.0.0 May 2016! ‣ 75,000+ downloads (core) April 2016 • Processes HTML, XML, JavaScript, CSS, text • View layer in Spring MVC apps ‣ Also MVC 1.0, vert.x, ratpack, Spring Reactive
  3. Spring I/O 2016 #springio16 #thymeleaf | @danfenz What does it

    look like? <table> <thead> <tr> <th th:text="#{msgs.headers.name}">Name</th> <th th:text="#{msgs.headers.price}">Price</th> </tr> </thead> <tbody> <tr th:each="prod : ${allProducts}"> <td th:text="${prod.name}">Oranges</td> <td th:text="${#numbers.formatDecimal(prod.price,1,2)}">0.99</td> </tr> </tbody> </table>
  4. Spring I/O 2016 #springio16 #thymeleaf | @danfenz “My HTML is

    not HTML anymore, but that's OK because the UI design phase is already finished.” err… nope :)
  5. Spring I/O 2016 #springio16 #thymeleaf | @danfenz So what about

    style changes? • Most times developers will do those… …restarting the application for each shade of blue ‣ Yes, JRebel exists… but a running server still needed ‣ More importantly: working Java code still needed • There must be a better way
  6. Spring I/O 2016 #springio16 #thymeleaf | @danfenz “Natural Templates: templates

    can be documents as valid as the final result, the engine syntax doesn't break the document structure.” “Comparison of web template engines” [Wikipedia]
  7. Spring I/O 2016 #springio16 #thymeleaf | @danfenz The trick •

    Use non-standard attributes • Browsers ignore them • And they don't have influence on the DOM! <ul> <li th:each="f : ${fruits}" th:text="${f.name}">Apricot</li> </ul>
  8. Spring I/O 2016 #springio16 #thymeleaf | @danfenz HTML5 allows custom

    attributes <ul> <li data-th-each="f : ${fruits}" data-th-text="${f.name}">Apricot</li> </ul> <ul> <li>Apricot</li> </ul> browser display equivalent
  9. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Now we can

    prototype! <img src="../resources/images/logo.png" th:src="@{/images/logo.png}"/> <img src="../resources/images/logo.png"/> <img src="/myapp/images/logo.png"/> browser display equivalent output of running webapp
  10. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Yet prototyping is

    very optional • No need for double attributes, just a tool: src + th:src, href + th:href... • Virtue is in the middle (usually) ‣ Natural templates for some design-representative pages ‣ Most compact possible code for the rest of them <tr> <td><img th:src="@{/images/logo.png}"/></td> <td>Welcome to our e-shop, [[${session.user.name}]].</td> </tr>
  11. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Page composition /

    layout <div th:insert="footer :: copy">...</div> ... <div th:fragment="copy"> © 2015 The Great Great Web Developers </div> ... somewhere in our footer.html also th:replace
  12. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Markup selectors <div

    th:replace="http://bannerserv.example.net/ :: div.banner">...</div> ... <div class="banner"> ... <img src="//somevendor/onegreatadd.png" width="168" height="80"/> ... </div> ... our banner server returns plain HTML (no th:fragment)
  13. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Fragments with parameters

    <div th:fragment="joiner (onevar, twovar)"> <p th:text="|${onevar} - ${twovar}|">...</p> </div> ... <div th:replace="::joiner (${user.name},${user.surname})">...</div> ... fragment can take parameters call fragment as if it were a function
  14. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Extending Thymeleaf •

    Dialects: add attributes, resolvers, utilities… • Not even the Standard Dialect (th:*) required • Can be a template engine framework <div> <blogfarm:entry-content blogfarm:summary="true"/> </div>
  15. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Testing the view

    layer • Fully automated — tests are mere text files %TEMPLATE_MODE HTML # --------------------------------------------------------- %CONTEXT myvar = 'Thymeleaf' # --------------------------------------------------------- %INPUT <div> <span th:text="|Hello, ${myvar}!|">Goodbye Hassle!</span> </div> # --------------------------------------------------------- %OUTPUT <div> <span>Hello, Thymeleaf!</span> </div>
  16. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Thymeleaf 3.0 in

    space and time • Dev of the 3.0 branch started July 2014 • Almost complete rewrite of the engine • 63K+ lines of code 85% new • 77K+ lines of test 40% new • 220 litres of coffee 100% arabica
  17. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Improved performance •

    Rendering time — Memory footprint — Latency 2.1.4 3.0.0
  18. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Full HTML5 support

    • New parsing system • No longer XML-based • Created from scratch with Thymeleaf in mind <div ng-app><p th:text=${mytext}>Whatever valid template!
  19. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Improved inlining •

    Output values without a supporting tag ‣ Already existed th:inline="text" Thymeleaf 2.1 • Now a 1st-class citizen, no th:inline needed ‣ In fact, better remove them <p>This product is called [[${product.name}]] and it's great!</p>
  20. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Text processing. And

    JS. And CSS Dear [(${customer.name})], This is the list of our products: [# th:each="prod : ${products}"] - [(${prod.name})]. Price: [(${prod.price})] EUR/kg [/] Thanks, The Thymeleaf Shop
  21. Spring I/O 2016 #springio16 #thymeleaf | @danfenz JavaScript natural templates

    var greeter = function() { var username = /*[[${session.user.name}]]*/ 'John Apricot'; alert('Hello ' + username); }; var greeter = function() { var username = 'Martin Grapefruit'; alert('Hello ' + username); }; both <script> and .js files processing result
  22. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Fragment expressions •

    Generalised syntax of th:insert, th:replace • Can be used elsewhere… even as parameters! <div th:replace="common :: header">...</div> <div th:replace="~{common :: header}">...</div> <head th:replace="base :: common_header(~{::title},~{::link})"> <title>Awesome - Main</title> <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"> <link rel="stylesheet" th:href="@{/themes/smoothness/jquery-ui.css}"> </head>
  23. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Decoupled templates <table

    id="detail"> <tr> <td>Green Plum</td> <td>Round-oval shape and smooth-textured, pale green flesh</td> </tr> </table> <thlogic> <attr sel="#detail/tr" th:each="f : ${fruits}"> <attr sel="/td[0]" th:text="${f.name}"/> <attr sel="/td[1]" th:text="${f.description}"/> </attr> </thlogic> fruits.html fruits.th.xml
  24. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Reactive friendliness •

    Server-side rendering in reactive frameworks ‣ Usually unoptimised: Memory, Latency, Scalability • Hybrid rendering starting to be a thing ‣ Rendering being (partially?) pushed back to the server • Thymeleaf 3.0 ‣ Full independence from the Servlet API for web apps ‣ Three reactive-friendly operation modes
  25. Spring I/O 2016 #springio16 #thymeleaf | @danfenz Reactive-friendly operation modes

    Publisher<Data> Data Iterable<Data> CONTEXT "<!DOCTYPE>\n<html>\n<body>..." String Publisher<Output> OUTPUT CHANNEL Publisher<Data> Data Iterable<Data> CONTEXT Publisher<Output> OUTPUT CHANNEL Publisher<Data> CONTEXT Publisher<Output> OUTPUT CHANNEL 1 DATA-DRIVEN BUFFERED NORMAL