A Work in Progress - demo project exploring the application of Thymeleaf to a JEE/Spring application generated by Spring Roo.
A Working Example of this application is maintained on Cloud Foundry.
The Source Code is maintained on GitHub
This project began with a desire to meet the following objectives in a single web application.
-
A light-weight UI consisting of:
- Semantic HTML5
- JavaScript consisting of:
- CSS3
-
An easily customizable, highly usable, visually attractive web page.
-
Usable on any web-enabled device.
-
Supported by a reliable, high-performance Java server back-end consisting of:
- Layered JEE/Spring architecture
- Domain layer - handles data access and persistence for a variety data structures:
- Service layer - handles custom business logic
- Web layer - uses Spring MVC and Thymeleaf to produce valid HTML5 mark up.
- Layered JEE/Spring architecture
-
Able to securely handle enormous data volume and thousands of simultaneous users.
The goal of this project can be summed up in two general objectives not commonly associated in modern (2012) web applications.
-
Rich, light-weight HTML that can be viewed on any web enabled device.
-
High performance, reliable, able to scale to meet any traffic demand.
The power of Spring/JEE applications on the server-side is undisputed, but the corresponding view layer consisting of such technologies as JSP, JSF or FLEX, etc., is complex and unsatisfying from a web development perspective.
JSP was designed to address the perception that the Java programming environment didn't provide developers with enough support for the Web. -Wikipedia. In 2012, JSP still does not provide adequate support for the HTML5 web, or the need for rapid development and maintenance.
JSF is a request-driven MVC web framework for constructing user interfaces using components. As a display technology, JSF 2 uses Facelets... -Wikipedia. Any component-driven UI technology presents a high degree of abstraction and complexity that is not compatible with the goals of rapid development and maintenance.
Adobe Flex is a software development kit (SDK) released by Adobe Systems for the development and deployment of cross-platform rich Internet applications based on the Adobe Flash platform. -Wikipedia. Being dependent on the Flash platform in addition to being a component-driven architecture make Flex completely at odds with the stated Project Goals.
Thymeleaf is an HTML5 oriented template engine for Java applications.
A compelling discussion comparing JSP and Thymeleaf makes the point very well. Spring MVC view layer: Thymeleaf vs. JSP but perhaps still better is a code sample.
This is the Thymeleaf template, list.html which generates the Contact Submissions List page for this project.
For the most part it's just HTML5 markup - it's even viewable in a browser straight from the file system, without a server, which is very handy when styling a page with CSS.
WEB-INF/templates/messageforms/list.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<title>HTML5 Spring Roo Thymeleaf Demo</title>
<meta name="description" content="HTML5 Spring Roo Thymeleaf Demo Contact Form" />
<meta name="author" content="see humans.txt"/>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" href="../../../css/style.css"
th:href="@{/css/style.css}"/>
<script src="../../../js/libs/modernizr-2.0.6.min.js"
th:src="@{/js/libs/modernizr-2.0.6.min.js}"></script>
</head>
<body>
<div id="container">
<header>
<h1>HTML5 Spring Roo Thymeleaf Demo</h1>
<hr />
</header>
<h1>Contact Submissions List</h1>
<table id="display-data">
<thead>
<tr>
<th th:text="#{message_list.theader.count}">
ID</th>
<th th:text="#{message_list.theader.name}">
Name</th>
<th th:text="#{message_list.theader.email}">
E-Mail</th>
<th th:text="#{message_list.theader.phone}">
Phone</th>
<th th:text="#{message_list.theader.website}">
Website</th>
<th th:text="#{message_list.theader.message}">
Message</th>
<th th:text="#{message_list.theader.action}" colspan="2">
Action</th>
</tr>
</thead>
<tbody th:if="${#objects.nullSafe(messageforms, false)}">
<tr th:each="row, rowStat : ${messageforms}">
<td th:text="${rowStat.Count}">1</td>
<td th:text="${row.name}">My Name</td>
<td th:text="${row.email}">my@email.com</td>
<td th:text="${row.phone}">999 555 1212</td>
<td th:text="${row.website}">http://mysite.com</td>
<td th:text="${row.message}">My Message...</td>
<td> <!-- Edit item button -->
<a class="btnIcon" href="update.html"
th:href="@{'/messageforms/' + ${row.id} + '?form'}">
<img id="editBtn" name="editBtn"
src="../../../img/update.png"
title="edit" alt="edit" class="btnIcon"
th:src="@{/img/update.png}"
th:title="#{message_list.button.edit}"
th:alt="#{message_list.button.edit}"/></a>
</td>
<td> <!-- Delete item button -->
<form action="list.html"
th:action="@{'/messageforms/' + ${row.id}}"
method="post">
<input type="hidden" name="_method"
value="DELETE" />
<input type="hidden" name="page" value="1" />
<input type="hidden" name="size" value="10" />
<input type="image" id="deleteBtn"
name="deleteBtn" src="../../../img/delete.png"
title="Delete" alt="Delete" class="btnIcon"
th:src="@{/img/delete.png}"
th:title="#{message_list.button.delete}"
th:alt="#{message_list.button.delete}"/>
</form>
</td>
</tr>
</tbody>
</table>
<!-- Page buttons -->
<a class="button btnSmall" href="../index.html"
th:href="@{/}"
th:text="#{message_list.button.home}">
Home</a>
<a class="button btnSmall" href="create.html"
th:href="@{'/messageforms?form'}"
th:text="#{message_list.button.new}">
New</a>
<a class="button btnSmall" href="list.html"
th:href="@{'/messageforms?page=1&size=10'}"
th:text="#{message_list.button.list}">
List</a>
<footer>
<hr />
<h2>Footer</h2>
</footer>
</div>
<!-- end of #container -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js">
</script>
<script>
/*<![CDATA[*/
window.jQuery ||
document.write(
'<script src="../../../js/libs/jquery-1.6.2.min.js
th:src="@{/js/libs/jquery-1.6.2.min.js}"><\/script>')
/*]]>*/
</script>
</body>
</html>