四时宝库

程序员的知识宝库

架构实战篇(四):Spring Boot整合 Thymeleaf

前言

Thymeleaf 是一种模板语言。那模板语言或模板引擎是什么?常见的模板语言都包含以下几个概念:数据(Data)、模板(Template)、模板引擎(Template Engine)和结果文档(Result Documents)。

Spring boot 支持多种模板语言(Thymeleaf 、Freemarker、Mustache、Groovy Templates)

Thymeleaf 跟大部分的模板语言类似,上手容易,使用简单

项目结构图

最终运行结果

下面开始一步一步的编写代码了

增加Spring boot的maven 依赖

在原有基础的pom结构中追加Swagger2的依赖

<?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>
 <parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>1.5.10.RELEASE</version>
 </parent>
 <groupId>com.example</groupId>
 <artifactId>spring-boot-web-thymeleaf</artifactId>
 <version>1.0-SNAPSHOT</version>
 <properties>
 <java.version>1.8</java.version>
 </properties>
 <dependencies>
 <!-- Compile -->
 <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>

增加一个消息类

package sample.web.ui;import java.util.Calendar;import org.hibernate.validator.constraints.NotEmpty;public class Message { private Long id; // 编写不能为空的提示语
 @NotEmpty(message = "Message is required.") private String text; // 编写不能为空的提示语
 @NotEmpty(message = "Summary is required.") private String summary; private Calendar created = Calendar.getInstance(); // get set }

保存消息的接口

package sample.web.ui;public interface MessageRepository { Iterable<Message> findAll(); Message save(Message message); Message findMessage(Long id); void deleteMessage(Long id); }

使用内存保存消息

package sample.web.ui;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ConcurrentMap;import java.util.concurrent.atomic.AtomicLong;public class InMemoryMessageRepository implements MessageRepository { // 用来模拟主键自增
 private static AtomicLong counter = new AtomicLong(); // 用来存储消息
 private final ConcurrentMap<Long, Message> messages = new Concur rentHashMap<Long, Message>(); @Override
 public Iterable<Message> findAll() { return this.messages.values();
 } @Override
 public Message save(Message message) {
 Long id = message.getId(); if (id == null) { // 生成一个ID
 id = counter.incrementAndGet();
 message.setId(id);
 } // 保存消息
 this.messages.put(id, message); return message;
 } @Override
 public Message findMessage(Long id) { return this.messages.get(id);
 } @Override
 public void deleteMessage(Long id) { this.messages.remove(id); } }

编写控制层代码

package sample.web.ui.mvc;import org.springframework.stereotype.Controller;import org.springframework.validation.BindingResult;import org.springframework.web.bind.annotation.*;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.mvc.support.RedirectAttributes;import sample.web.ui.Message;import sample.web.ui.MessageRepository;import javax.validation.Valid;@Controller@RequestMapping("/messages")public class MessageController { private final MessageRepository messageRepository; public MessageController(MessageRepository messageRepository) { this.messageRepository = messageRepository;
 } // 进入消息列表页面
 @GetMapping
 public ModelAndView list() {
 Iterable<Message> messages = this.messageRepository.findAll(); return new ModelAndView("messages/list", "messages", messages);
 } // 查看消息详情
 @GetMapping("{id}") public ModelAndView view(@PathVariable("id") Message message) { return new ModelAndView("messages/view", "message", message);
 } // 进入创建消息页面
 @GetMapping(params = "form") public String createForm(@ModelAttribute Message message) { return "messages/form";
 } // 创建消息
 @PostMapping
 public ModelAndView create(@Valid Message message, BindingResult result,
 RedirectAttributes redirect) { // 内容验证
 if (result.hasErrors()) { return new ModelAndView("messages/form", "formErrors", result.getAllErrors());
 } // 保存消息
 message = this.messageRepository.save(message); // 重定向增加一个消息
 redirect.addFlashAttribute("globalMessage", "Successfully created a new message"); return new ModelAndView("redirect:/messages/{message.id}", "message.id", message.getId());
 } // 删除消息
 @GetMapping(value = "delete/{id}") public ModelAndView delete(@PathVariable("id") Long id) { this.messageRepository.deleteMessage(id);
 Iterable<Message> messages = this.messageRepository.findAll(); return new ModelAndView("messages/list", "messages", messages);
 } // 进入修改消息页面
 @GetMapping(value = "modify/{id}") public ModelAndView modifyForm(@PathVariable("id") Message message) { return new ModelAndView("messages/form", "message", message); } }

程序入口main

package sample.web.ui.mvc;import org.springframework.stereotype.Controller;import org.springframework.validation.BindingResult;import org.springframework.web.bind.annotation.*;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.mvc.support.RedirectAttributes;import sample.web.ui.Message;import sample.web.ui.MessageRepository;import javax.validation.Valid;@Controller@RequestMapping("/messages")public class MessageController { private final MessageRepository messageRepository; public MessageController(MessageRepository messageRepository) { this.messageRepository = messageRepository;
 } // 进入消息列表页面
 @GetMapping
 public ModelAndView list() {
 Iterable<Message> messages = this.messageRepository.findAll(); return new ModelAndView("messages/list", "messages", messages);
 } // 查看消息详情
 @GetMapping("{id}") public ModelAndView view(@PathVariable("id") Message message) { return new ModelAndView("messages/view", "message", message);
 } // 进入创建消息页面
 @GetMapping(params = "form") public String createForm(@ModelAttribute Message message) { return "messages/form";
 } // 创建消息
 @PostMapping
 public ModelAndView create(@Valid Message message, BindingResult result,RedirectAttributes redirect) { // 内容验证
 if (result.hasErrors()) { return new ModelAndView("messages/form", "formErrors", result.getAllErrors());
 } // 保存消息
 message = this.messageRepository.save(message); // 重定向增加一个消息
 redirect.addFlashAttribute("globalMessage", "Successfully created a new message"); return new ModelAndView("redirect:/messages/{message.id}", "message.id", message.getId());
 } // 删除消息
 @GetMapping(value = "delete/{id}") public ModelAndView delete(@PathVariable("id") Long id) { this.messageRepository.deleteMessage(id);
 Iterable<Message> messages = this.messageRepository.findAll(); return new ModelAndView("messages/list", "messages", messages);
 } // 进入修改消息页面
 @GetMapping(value = "modify/{id}") public ModelAndView modifyForm(@PathVariable("id") Message message) { return new ModelAndView("messages/form", "message", message); } } 

编写布局页面

<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"
 xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"><head><title>Layout</title><link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"
 href="../../css/bootstrap.min.css" />
 <link rel="icon" th:href="@{/favicon.jpg}" href="favicon.jpg" /></head><body>
 <div class="container">
 <div class="navbar">
 <div class="navbar-inner">
 <a class="brand" th:href="@{/messages}" href="#">Thymeleaf - Layout</a>
 <ul class="nav">
 <li><a th:href="@{/messages}" href="messages.html"> Messages </a></li>
 </ul>
 </div>
 </div>
 <h1 layout:fragment="header">Layout</h1>
 <div layout:fragment="content">Fake content</div>
 </div> </body> </html>

编写列表页面

<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"
 xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
 layout:decorator="layout"><head><title>Messages : View all</title></head><body>
 <h1 layout:fragment="header">Messages : View all</h1>
 <div layout:fragment="content" class="container">
 <div class="pull-right">
 <a href="form.html" th:href="@{/messages/(form)}">Create Message</a>
 </div>
 <table class="table table-bordered table-striped">
 <!-- 使用下面注解类解决IntelliJ提示问题 -->
 <!--/*@thymesVar id="messages" type="java.util.List"*/-->
 <!--/*@thymesVar id="message" type="sample.web.ui.Message"*/-->
 <thead>
 <tr>
 <td>ID</td>
 <td>Created</td>
 <td>Summary</td>
 </tr>
 </thead>
 <tbody>
 <tr th:if="${messages.isEmpty()}">
 <td colspan="3">No messages</td>
 </tr>
 <tr th:each="message : ${messages}">
 <td th:text="${message.id}">1</td>
 <td th:text="${#calendars.format(message.created)}">July 11,
 2012 2:17:16 PM CDT</td>
 <td><a href="view.html" th:href="@{'/messages/' + ${message.id}}"
 th:text="${message.summary}"> The summary </a></td>
 </tr>
 </tbody>
 </table>
 </div></body></html>

编写增加页面

<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"
 xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
 layout:decorator="layout"><head><title>Messages : Create</title></head><body>
 <h1 layout:fragment="header">Messages : Create</h1>
 <div layout:fragment="content" class="container">
 <!-- 使用下面注解类解决IntelliJ提示问题 -->
 <!--/*@thymesVar id="message" type="sample.web.ui.Message"*/-->
 <form id="messageForm" th:action="@{/messages/(form)}" th:object="${message}"
 action="#" method="post">
 <div th:if="${#fields.hasErrors('*')}" class="alert alert-error">
 <p th:each="error : ${#fields.errors('*')}" th:text="${error}">
 Validation error</p>
 </div>
 <div class="pull-right">
 <a th:href="@{/messages}" href="messages.html"> Messages </a>
 </div>
 <input type="hidden" th:field="*{id}"
 th:class="${#fields.hasErrors('id')} ? 'field-error'" /> <label
 for="summary">Summary</label> <input type="text"
 th:field="*{summary}"
 th:class="${#fields.hasErrors('summary')} ? 'field-error'" /> <label
 for="text">Message</label>
 <textarea th:field="*{text}"
 th:class="${#fields.hasErrors('text')} ? 'field-error'"></textarea>
 <div class="form-actions">
 <input type="submit" value="Save" />
 </div>
 </form>
 </div></body></html>

编写详情页面

<html xmlns:th="http://www.thymeleaf.org"
 xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
 layout:decorator="layout"><head><title>Messages : View</title></head><body><!-- 使用下面注解类解决IntelliJ提示问题 --><!--/*@thymesVar id="message" type="sample.web.ui.Message"*/-->
 <h1 layout:fragment="header">Messages : Create</h1>
 <div layout:fragment="content" class="container">
 <!--/*@thymesVar id="globalMessage" type=""*/-->
 <div class="alert alert-success" th:if="${globalMessage}"
 th:text="${globalMessage}">Some Success message</div>
 <div class="pull-right">
 <a th:href="@{/messages}" href="list.html"> Messages </a>
 </div>
 <dl>
 <dt>ID</dt>
 <dd id="id" th:text="${message.id}">123</dd>
 <dt>Date</dt>
 <dd id="created" th:text="${#calendars.format(message.created)}">
 July 11, 2012 2:17:16 PM CDT</dd>
 <dt>Summary</dt>
 <dd id="summary" th:text="${message.summary}">A short summary... </dd>
 <dt>Message</dt>
 <dd id="text" th:text="${message.text}">A detailed message that
 is longer than the summary.</dd>
 </dl>
 <div class="pull-left">
 <a href="messages" th:href="@{'/messages/delete/' + ${message.id}}">
 delete </a> | <a href="form.html"
 th:href="@{'/messages/modify/' + ${message.id}}"> modify </a>
 </div>
 </div></body></html>

Spring 设置 application.properties

spring.thymeleaf.cache=falseserver.tomcat.basedir=target/tomcat
server.tomcat.accesslog.enabled=true

编写日志文件 logback.xml

<?xml version="1.0" encoding="UTF-8"?><configuration>
 <include resource="org/springframework/boot/logging/logback/base.xml"/></configuration>

bootstrap v2.0 请到官网下载

到这里所有的类都编写完了,让我们来用用看吧

让我们打开浏览器地址栏访问

http://localhost:8080/

演示

你的运行结果对了吗?

关注我们

想要了解更多内容请关注“IT实战联盟”,也可以留言和作者互动 获取源码哦!!!

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接