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

懂点代码的大叔 2018-03-15 14:32:51 ⋅ 619 阅读

前言

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实战联盟”微信公众号!也可以留言和作者交流 获取源码哦!!!



全部评论: 0

    我有话说:

    架构实战(十七):Spring Boot Assembly 整合 thymeleaf

    如何让服务器上的 sprig boot 项目升级变的方便快捷

    架构实战(三)-Spring Boot架构搭建RESTful API案例

    之前分享了Spring Boot 整合Swagger 让API可视化和前后端分离架构 受到了大家一致好评 ,本节就接着上节的代码做了详细的查询代码的补充和完善并搭建RESTful API架构案例。

    架构实战(七):Spring Boot Data JPA 快速入门

    Spring Data JPA 是Spring Data 的一个子项目,它通过提供基于JPA的Repository极大了减少了操作JPA的代码。

    架构实战(六):Spring Boot RestTemplate的使用

    RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。

    架构实战(十):Spring Boot 多缓存实战

    多场景下的不同缓存策略解决方案

    架构实战(一)-Spring Boot+MyBatis基础架构搭建

    Spring的追求一定是简单点简单点,让java的开发变得更加简单、容易。瞧瞧的告诉你们直接copy就能用哦~~~

    架构实战(十五):Spring Boot 解耦之事件驱动

    通过使用spring 事件来解决业务代码的耦合

    微服务架构实战(六):Spring boot2.x 集成阿里大鱼短信接口详解与Demo

    Spring boot2.x 集成阿里大鱼短信接口,发送短信验证码及短信接口详解。

    架构实战(十二):Spring Boot 分布式Session共享Redis

    分布式Web网站一般都会碰到集群session共享问题,小编整理了一套解决方案,内附GitHub 源码地址哦~~~

    架构实战(十一):Spring Boot 集成企业级搜索引擎 SolrCloud

    Solr是以Lucene为基础实现的文本检索应用服务。Solr部署方式有单机方式、多机Master-Slaver方式、Cloud方式。

    架构实战(二)-Spring Boot整合Swagger,让你的API可视化

    你还在跟前端对接上花费很多的时间而没有效果吗?你还在为写接口文档而烦恼吗?今天就教大家一个接口对接神器...

    码云推荐:一个优秀的分布式spring boot/Spring Cloud API限流框架,特别适合微服务架构

    一个优秀的分布式spring boot/Spring Cloud API限流框架,特别适合微服务架构.

    架构实战(九):Spring Boot 集成 RocketMQ

    快速集成阿里开源消息队列 RocketMQ

    微服务架构学习笔记:gRPC Spring Boot Starter 2.2.0 发布,及使用步骤

    gRPC Spring Boot Starter 项目是一个 gRPC 的 Spring Boot 模块。内嵌一个 gRPC Server 对外提供服务,并支持 Spring Cloud 的服务发现

    架构实战(十):Spring Boot 集成 Dubbo

    Dubbo是阿里巴巴SOA服务化治理方案的核心框架,一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案。

    架构实战(十三):Spring Boot Logback 邮件通知

    日志对于应用程序来说是非常重要的,当你的程序报错了,而你又不知道是多么可怕的一件事情,本文使用logback把程序报错信息邮件到开发者

    SpringBoot+zk+dubbo架构实践(二):SpringBoot 集成 zookeeper

    不啰嗦,本完成两件事:1、搭建SpringBoot 框架;2、基于spring boot框架访问zookeeper。