Thymeleaf
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>Good Thymes Virtual Grocery</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" media="all"
href="../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
</head>
<body>
<p th:text="#{home.welcome}">Welcome to our grocery store!</p>
</body>
</html>
Spring integration
Gradle dependency
compile 'org.thymeleaf:thymeleaf-spring4:3.0.1.RELEASE'
springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="controllers"/>
<bean id="templateResolver"
class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/"/>
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="cacheable" value="false" />
</bean>
<bean id="templateEngine"
class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver"/>
</bean>
<bean id="viewResolver" class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
<property name="order" value="1" />
<property name="viewNames" value="*" />
<property name="cache" value="false" />
</bean>
<mvc:annotation-driven ignore-default-model-on-redirect="true" />
<mvc:resources mapping="/static/**" location="/static/" />
</beans>
Java config
@Configuration
@EnableWebMvc
@ComponentScan(basePackageClasses = {DemoController.class})
public class WebConfig extends WebMvcConfigurerAdapter {
private static final Charset UTF8 = Charset.forName("UTF-8");
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
super.configureMessageConverters(converters);
//StringHttpMessageConverter shmc = new StringHttpMessageConverter(UTF8);
//converters.add(shmc);
}
@Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
viewResolver.setViewNames(new String[]{"*"});
viewResolver.setCache(false);
viewResolver.setCharacterEncoding(UTF8.toString());
return viewResolver;
}
private SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
return engine;
}
@Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML");
resolver.setCacheable(false);
resolver.setCharacterEncoding(UTF8.toString());
return resolver;
}
}
Template
Layout
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head th:fragment="head">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Bootstrap 101 Template</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="/static/css/styles.css" th:href="@{/static/css/styles.css}" />
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container" th:fragment="navbar">
<nav class="navbar navbar-inverse">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">SPRING DEMO</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="" th:href="@{/}">Home</a></li>
<li><a href="" th:href="@{/vehiculos}">Vehiculos</a></li>
</ul>
</div>
<!--/.nav-collapse -->
</nav>
</div>
<div class="container content">
</div>
<th:block th:fragment="beforeBodyClose">
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
</th:block>
</body>
</html>
View
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head lang="en" th:replace="layout :: head">
</head>
<body role="document">
<div class="container" th:replace="layout :: navbar">
</div>
<div class="container" role="main">
<div class="page-header">
<h1>Vehículo <small th:text="${vehiculo.id} ? 'Modificación' : 'Creación'">Creación</small></h1>
</div>
<form class="form-horizontal" th:action="@{/vehiculos/form}" th:object="${vehiculo}" method="post">
<div class="form-group">
<label th:for="${#ids.next('clasesVehiculo')}" class="col-sm-2 control-label">Clase</label>
<div class="col-sm-10">
<select class="form-control" th:field="*{claseVehiculo}">
<option th:each="clase : ${clasesVehiculo}"
th:value="${clase}"
th:text="${clase}">--</option>
</select>
</div>
</div>
<div class="form-group" th:class="${#fields.hasErrors('placa')}? 'has-error form-group' : 'form-group'">
<label th:for="${#ids.next('placa')}" class="col-sm-2 control-label">Placa</label>
<div class="col-sm-10">
<input type="text" class="form-control" th:field="*{placa}" placeholder="Placa">
</div>
<span class="col-md-offset-2 col-sm-10 help-block" th:if="${#fields.hasErrors('placa')}" th:errors="*{placa}"></span>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary">GUARDAR</button>
<a class="btn btn-default" href="#" th:href="@{/vehiculos}" role="button">CANCELAR</a>
</div>
</div>
<input type="hidden" th:field="*{id}" />
</form>
</div>
<!-- Before body close -->
<th:block th:include="layout :: beforeBodyClose"/>
</body>
</html>