Spring Boot (5) Thymeleaf
This section describes how to use spring boot + Thymeleaf to setup a web page demo system, spring boot supports FreeMarker, Groovy, Thymeleaf, Velocity and Mustache template engine, but the default template engine is Thymeleaf.
1. Creating the POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.my.study.springboot</groupId>
<artifactId>web</artifactId>
<version>0.0.1-RELEASE</version>
<properties>
<!-- Generic properties -->
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Need to specify thymeleaf version, otherwise, cannot redirect html file -->
<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.1.1</thymeleaf-layout-dialect.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.14.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. Java Code, Model, Controller, Main, etc
package com.my.study.springboot.web.entity;
/**
* Entity Object
*/
public class Employee {
private int id;
private String name;
private int age;
private String desc;
public Employee() {
}
public Employee(int id, String name, int age, String desc) {
this.id = id;
this.name = name;
this.age = age;
this.desc = desc;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
package com.my.study.springboot.web.mockdb;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.my.study.springboot.web.entity.Employee;
/**
* Employee mock DB
*/
public class EmployeeDB {
private static final List<Employee> EMPLOYEES = new ArrayList<>();
static {
for (int i = 0; i < 3; i++) {
EMPLOYEES.add(new Employee(i, "user" + i, 20 + i, "desc " + i + "."));
}
}
public static Employee findEmployee(int id) {
for (Employee e : EMPLOYEES) {
if (e.getId() == id) {
return e;
}
}
return null;
}
public static List<Employee> findAllEmployees() {
return EMPLOYEES;
}
public static synchronized void addEmployee(Employee employee) {
EMPLOYEES.add(employee);
}
public static void updateEmployee(Employee employee) {
for (Employee e : EMPLOYEES) {
if (e.getId() == employee.getId()) {
e.setName(employee.getName());
e.setAge(employee.getAge());
e.setDesc(employee.getDesc());
return;
}
}
}
public static void deleteEmployee(int id) {
Iterator<Employee> it = EMPLOYEES.iterator();
while (it.hasNext()) {
Employee e = it.next();
if (e.getId() == id) {
it.remove();
return;
}
}
}
public static void deleteAll() {
EMPLOYEES.clear();
}
}
package com.my.study.springboot.web.controller;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.my.study.springboot.web.entity.Employee;
import com.my.study.springboot.web.mockdb.EmployeeDB;
@Controller
public class EmployeeController {
@RequestMapping("/list")
public String listEmployees(Model model) {
List<Employee> employees = EmployeeDB.findAllEmployees();
model.addAttribute("employees", employees);
return "employee/list_employees";
}
}
package com.my.study.springboot.web;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
3. list_employees.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>Insert title here</title>
</head>
<link rel="stylesheet" th:href="@{/css/main.css}"/>
<script type="text/javascript" th:src="@{/js/main.js}"></script>
<body>
<h2>Employee List</h2>
<div>
<table border="1">
<tr>
<td>ID</td>
<td>Name</td>
<td>Age</td>
<td>Delete</td>
</tr>
<tr th:each="employee:${employees}">
<td><span th:text="${employee.id}"></td>
<td><span th:text="${employee.name}"></td>
<td><span th:text="${employee.age}"></td>
<td><input type="button" value="Delete" th:onclick="'delete_employee(\'' + ${employee.id} + '\');'"/></td>
</tr>
</table>
</div>
</body>
</html>
4. JS, CSS
table {
width: 400px;
}
function delete_employee(id) {
alert("Delete employee id:" + id);
}
5. Code structure
6. Testing
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.14.RELEASE)
2018-07-09 16:57:48.253 INFO 17932 --- [ main] com.my.study.springboot.web.Main : Starting Main on CNENWANGS56L1C with PID 17932 (C:\D\work\projects\sts\springboot-web\target\classes started by ...
2018-07-09 16:57:48.260 INFO 17932 --- [ main] com.my.study.springboot.web.Main : No active profile set, falling back to default profiles: default
2018-07-09 16:57:48.841 INFO 17932 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@130f889: startup date [Mon Jul 09 16:57:48 CST 2018]; root of context hierarchy
2018-07-09 16:57:51.067 INFO 17932 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2018-07-09 16:57:51.114 INFO 17932 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2018-07-09 16:57:51.114 INFO 17932 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.31
2018-07-09 16:57:51.345 INFO 17932 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2018-07-09 16:57:51.345 INFO 17932 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2509 ms
......
2018-07-09 16:57:53.306 INFO 17932 --- [ main] com.my.study.springboot.web.Main : Started Main in 5.512 seconds (JVM running for 6.101)
Enter:
http://localhost:8080/list