• SpringBoot 整合Thymeleaf教程及使用


    Thymeleaf 是一款用于渲染 XML/XHTML/HTML5 内容的模板引擎。它与 JSP,Velocity,FreeMaker 等模板引擎类似,也可以轻易地与 Spring MVC 等 Web 框架集成。与其它模板引擎相比,Thymeleaf 最大的特点是,即使不启动 Web 应用,也可以直接在浏览器中打开并正确显示模板页面 。

    目录

    一、整合Thymeleaf

    二、Thymeleaf 使用教程

    三、Thymeleaf 实战应用


    一、整合Thymeleaf

     1、引入Thymeleaf starter依赖

    1. <!-- thymeleaf 相关依赖 -->
    2. <dependency>
    3. <groupId>org.springframework.boot</groupId>
    4. <artifactId>spring-boot-starter-thymeleaf</artifactId>
    5. </dependency>

    2、在 application.properties 添加 Thymeleaf 相关配置

    1. server.port= 8092
    2. #关闭 Thymeleaf 的缓存开发过程中无需重启
    3. spring.thymeleaf.cache = false
    4. #设置thymeleaf页面的编码
    5. spring.thymeleaf.encoding=UTF-8
    6. spring.thymeleaf.mode=HTML5
    7. #设置thymeleaf页面的后缀
    8. spring.thymeleaf.suffix=.html
    9. #设置thymeleaf页面的存储路径
    10. spring.thymeleaf.prefix=classpath:/templates/

    Thymeleaf默认会开启页面缓存,提高页面并发能力。但会导致我们修改页面不会立即被展现,因此我们关闭缓存:spring.thymeleaf.cache=false

    修改完毕页面,需要使用快捷键:Ctrl + Shift + F9来刷新工程。

    3、编写访问 Thymeleaf 页面 Controller

    1. @Controller
    2. @RequestMapping("/hello")
    3. public class ThymeleafHelloWrodController {
    4. @RequestMapping({"/", "/index"})
    5. @ResponseBody
    6. public String index(Model model,String id) {
    7. model.addAttribute("msg", "welcome you!" + id);
    8. Map<String,String> user = new HashMap<>();
    9. user.put("uid","11111");
    10. user.put("umc","testmc");
    11. user.put("etel","13550125501");
    12. model.addAttribute("user", user);
    13. return "index"; //返回的是index.html的页面
    14. }
    15. @RequestMapping("/thymeleaf")
    16. public String helloThymeleaf(Model model){
    17. model.addAttribute("hello","hello Thymeleaf!");
    18. return "hello/index";
    19. }
    20. }

    后台springmvc 使用 Model 传入数据 (包名:org.springframework.ui.Model)

    Thymeleaf的主要作用是把model中的数据渲染到html中,因此其语法主要是如何解析model中的数据。

    3、Controller类编写(@RequestBody注解是必须加上的,将java对象转为json格式的数据。如果出现页面显示不了又没有报错可能就是Controller类没有加@RequestBody)

    返回的是Thymeleaf 模板对应的index.html的页面 

    - public interface Model{}             //是一个接口
    - public class ModelMap extends LinkedhashMap{}            //继承了LinkedHashMap
    - public class ExtendedModelMap extends MOdelMap implements Model{}       //继承了ModelMap又实现了Model接口
      - public class BindingAwareModelMap{}  //这个类对应的子类,就可以去实例化ModelMap也可以实例化Model
        - //因为ModelMap继承了LinkedHashMap所以说,BindingAwareModelMap也可以实例化Map集合
     

    4、Thymeleaf 页面代码如下

    src/main/resources/templates/index.html

    1. <!DOCTYPE html>
    2. <html xmlns="http://www.w3.org/1999/xhtml"
    3. xmlns:th="http://www.thymeleaf.org">
    4. <head>
    5. <meta charset="utf-8">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <meta name="renderer" content="webkit">
    8. <title>首页</title>
    9. <link rel="shortcut icon" th:href="@{/favicon.ico}"/>
    10. <link th:href="@{/static/css/bootstrap.min.css}" rel="stylesheet"/>
    11. <link th:href="@{/static/css/font-awesome.min.css}" rel="stylesheet"/>
    12. </head>
    13. <body class="fixed-sidebar full-height-layout gray-bg" style="overflow:hidden">
    14. <div id="wrapper">
    15. <h1 th:text="${msg}"></h1>
    16. <p data-th-text="${msg}">test p</p>
    17. <p th:inline="text">p:[(${msg})]</p>
    18. </div>
    19. <h2>
    20. <p>Name: <span th:text="${user.uid}">Jack</span>.</p>
    21. <p>Age: <span th:text="${user.umc}">21</span>.</p>
    22. <p>friend: <span th:text="${user.etel}">Rose</span>.</p>
    23. </h2>
    24. <script th:src="@{/static/js/jquery.min.js}"></script>
    25. <script th:src="@{/static/js/bootstrap.min.js}"></script>
    26. <script>
    27. </script>
    28. </body>
    29. </html>

    5、访问页面

    http://localhost:8092/index

    http://localhost:8092/index?id=test

    二、Thymeleaf 使用教程

    Thymeleaf 模板引擎具有以下特点:
    动静结合:Thymeleaf 既可以直接使用浏览器打开,查看页面的静态效果,也可以通过 Web 应用程序进行访问,查看动态页面效果。
    开箱即用:Thymeleaf 提供了 Spring 标准方言以及一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
    多方言支持:它提供了 Thymeleaf 标准和 Spring 标准两种方言,可以直接套用模板实现 JSTL、 OGNL 表达式;必要时,开发人员也可以扩展和创建自定义的方言。
    与 SpringBoot 完美整合:SpringBoot 为 Thymeleaf 提供了的默认配置,并且还为 Thymeleaf 设置了视图解析器,因此 Thymeleaf 可以与 Spring Boot 完美整合。

    1、在页面的 html 标签中声明名称空间

    <html xmlns:th="http://www.thymeleaf.org">

    在 html 标签中声明此名称空间,可避免编辑器出现 html 验证错误,但这一步并非必须进行的,即使我们不声明该命名空间,也不影响 Thymeleaf 的使用。

    把html 的名称空间,改成:xmlns:th="http://www.thymeleaf.org" 会有语法提示

    2、标准表达式语法

    Thymeleaf的主要作用是把model中的数据渲染到html中,因此其语法主要是如何解析model中的数据。通过${}来获取model中的变量,注意这不是el表达式,而是ognl表达式,但是语法非常像。

    Thymeleaf崇尚自然模板,意思就是模板是纯正的html代码,脱离模板引擎,在纯静态环境也可以直接运行。现在如果我们直接在html中编写 ${}这样的表达式,显然在静态环境下就会出错,这不符合Thymeleaf的理念。

    1. <h1>
    2. 欢迎您:<span th:text="${user.name}">请登录</span>
    3. </h1>

    静态情况下,th指令不会被识别,而是显示默认值:请登录 

    但是浏览器也不会报错,把它当做一个普通属性处理。这样span的默认值请登录就会展现在页面
    如果是在Thymeleaf环境下,th指令就会被识别和解析,而th:text的含义就是替换所在标签中的文本内容,于是user.name的值就替代了 span中默认的请登录

    如果不支持这种th:的命名空间写法,那么可以把th:text换成 data-th-text,Thymeleaf也可以兼容。

    th:text指令出于安全考虑,会把表达式读取到的值进行处理,防止html的注入。

    例如,

    你好

    将会被格式化输出为$lt;p$gt;你好$lt;/p$lt;。

    如果想要不进行格式化输出,而是要输出原始内容,则使用th:utext来代替.

     Thymeleaf中所有的表达式都需要写在指令中,指令是HTML5中的自定义属性,在Thymeleaf中所有指令都是以th:开头。因为表达式${user.name}是写在自定义属性中,因此在静态环境下,表达式的内容会被当做是普通字符串,浏览器会自动忽略这些指令,这样就不会报错了!

    1. <h2>
    2. <p>Name: <span th:text="${user.name}">Jack</span>.</p>
    3. <p>Age: <span th:text="${user.age}">21</span>.</p>
    4. <p>friend: <span th:text="${user.friend.name}">Rose</span>.</p>
    5. </h2>

    对象.属性名方式 

    ${user.name} 可以写作${user['name']}

    1. <h2 th:object="${user}">
    2. <p>Name: <span th:text="*{name}">Jack</span>.</p>
    3. <p>Age: <span th:text="*{age}">21</span>.</p>
    4. <p>friend: <span th:text="*{friend.name}">Rose</span>.</p>
    5. </h2>

     当数据量比较多的时候,频繁的写user.就会非常麻烦。

    首先在 h2上 用 th:object="${user}"获取user的值,并且保存
    然后,在h2内部的任意元素上,可以通过 *{属性名}的方式,来获取user中的属性,这样就省去了大量的user.前缀了

    1. <h2 th:object="${user}">
    2. <p>FirstName: <span th:text="*{name.split(' ')[0]}">Jack</span>.</p>
    3. <p>LastName: <span th:text="*{name.split(' ')[1]}">Li</span>.</p>
    4. </h2>

    ognl表达式本身就支持方法调用 

     Thymeleaf中提供了一些内置对象,并且在这些对象中提供了一些方法,方便我们来调用。获取这些对象,需要使用#对象名来引用。

    一些环境相关对象
    对象    作用
    #ctx    获取Thymeleaf自己的Context对象
    #requset    如果是web程序,可以获取HttpServletRequest对象
    #response    如果是web程序,可以获取HttpServletReponse对象
    #session    如果是web程序,可以获取HttpSession对象
    #servletContext    如果是web程序,可以获取HttpServletContext对象
    Thymeleaf提供的全局对象:
    对象    作用
    #dates    处理java.util.date的工具对象
    #calendars    处理java.util.calendar的工具对象
    #numbers    用来对数字格式化的方法
    #strings    用来处理字符串的方法
    #bools    用来判断布尔值的方法
    #arrays    用来护理数组的方法
    #lists    用来处理List集合的方法
    #sets    用来处理set集合的方法
    #maps    用来处理map集合的方法

     java代码:

    1. @GetMapping("show3")
    2. public String show3(Model model){
    3. model.addAttribute("today", new Date());
    4. return "show3";
    5. }

    页面代码: 

    1. <p>
    2. 今天是: <span th:text="${#dates.format(today,'yyyy-MM-dd')}">2018-04-25</span>
    3. </p>
    4. ${#strings.equals('编程帮',name)}
    5. ${#session.getAttribute('map')}
    6. ${session.map}

    字面值:

    基本类型如:字符串、数值、布尔等,并不希望被Thymeleaf解析为变量,这个时候称为字面值

    字符串字面值:th:text="'thymeleaf'" 使用一对'引用的内容

    数字字面值:th:text="2018" 数字不需要任何特殊语法, 写的什么就是什么,而且可以直接进行算术运算

    布尔字面值:th:if="true"

    空字面值:

    1. <p>
    2.   你正在观看 <span th:text="'thymeleaf'">template</span> 的字符串常量值.
    3. </p>

    拼接
    我们经常会用到普通字符串与表达式拼接的情况:

    <span th:text="'欢迎您:' + ${user.name} + '!'"></span>

     字符串字面值需要用'',拼接起来非常麻烦,Thymeleaf对此进行了简化,使用一对|即可:

    <span th:text="|欢迎您:${user.name}|"></span>

    运算

    1. <span th:text="${user.age}"></span>
    2. <span th:text="${user.age}%2 == 0"></span>

    支持的算术运算符:+ - * / %

    支持的比较运算:>, <, >= and <=

    但是>, <不能直接使用,因为xml会解析为标签,要使用别名。

    注意 == and !=不仅可以比较数值,类似于equals的功能。

    可以使用的别名:gt (>), lt (<), ge (>=), le (<=), not (!). Also eq (==), neq/ne (!=).

    三元运算:

    默认值:  ( ?:之间没有空格 )

    ${}内部的是通过OGNL表达式引擎解析的,外部的才是通过Thymeleaf的引擎解析,因此运算符尽量放在${}外进行。 

    设置属性值

    在 Thymeleaf 模板文件中,你可以使用th:*(或者使用th:attr属性)来设置任意的 HTML5 标签属性的值。不仅如此,你还可以th:*-*来同时为多个不同的标签属性设置相同的一个值,甚至你可以使用th:attrappendth:attrprepend来追加新的值到现有的标签属性值中。

    th:attr 这种方式是不被推荐的

    1. <!-- <div item-id="1001">Welcome to BeiJing!</div> -->
    2. <div th:item-id="${user.id}">Welcome to BeiJing!</div>
    3. <img src="logo.png" th:alt-title="LOGO图片">

    th:*  中的*可以是 HTML5 支持的任意属性名称,甚至这些属性名称可以是自定义的

    th:*-* 如果想要同时为标签的多个不同属性设置相同的一个值,可以使用th:*-*的语法:

    th:attrappend & th:attrprepend  可以将表达式的结果分别追加到指定的属性值之后和之前。

    1. <!-- <button class="btn enable">购买</button> -->
    2. <button class="btn" th:attrappend="class=${outOfStock} ? ' enable' : ' disable'">购买</button>
    3. <!-- <button class="enable btn">购买</button> -->
    4. <button class="btn" th:attrprepend="class=${outOfStock} ? 'enable ' : 'disable '">购买</button>

    还有两个常用的具体附加属性th:classappend="..."th:styleappend=""。它们分别用来代替th:attrappend="class=..."th:attrappend="style=..."

    1. <!-- <button class="btn enable">购买</button> -->
    2. <button class="btn" th:classappend="${outOfStock} ? ' enable' : ' disable'">购买</button>

     循环/IF/SWITCH

    1. <tr th:each="user : ${users}">
    2. <td th:text="${user.name}">Onions</td>
    3. <td th:text="${user.age}">2.41</td>
    4. </tr>
    5. <tr th:each="user,stat : ${users}">
    6. <td th:text="${user.name}">Onions</td>
    7. <td th:text="${user.age}">2.41</td>
    8. </tr>

     stat对象包含以下属性:

    index,从0开始的角标
    count,元素的个数,从1开始
    size,总元素个数
    current,当前遍历到的元素
    even/odd,返回是否为奇偶,boolean值
    first/last,返回是否为第一或最后,boolean值

    1. <div th:switch="${user.role}">
    2. <p th:case="'admin'">用户是管理员</p>
    3. <p th:case="'manager'">用户是经理</p>
    4. <p th:case="*">用户是别的玩意</p>
    5. </div>

     JS模板

    1. <script th:inline="javascript">
    2. const user = /*[[${user}]]*/ {};
    3. const age = /*[[${user.age}]]*/ 20;
    4. console.log(user);
    5. console.log(age)
    6. </script>

    在script标签中通过th:inline="javascript"来声明这是要特殊处理的js脚本

    语法结构:

    const user = /*[[Thymeleaf表达式]]*/ "静态环境下的默认值";

    因为Thymeleaf被注释起来,因此即便是静态环境下, js代码也不会报错,而是采用表达式后面跟着的默认值。

    链接表达式 @{}

    @{}是专门用来处理 URL 链接地址的。
    不管是静态资源的引用,还是 form 表单的请求,凡是链接都可以用链接表达式 (@{...})。

    链接表达式的形式结构如下:

    无参请求:@{/xxx}
    有参请求:@{/xxx(k1=v1,k2=v2)}

    绝对地址: 

    1. <p th:text="@{https://fanlychie.github.io}">p>

    页面相对地址示例:

    1. <p th:text="@{commons/base.html}">p>

    上下文相对地址(相对于当前的服务)示例:

    1. <p th:text="@{/css/mian.css}">p>

    服务器相对地址(相对于部署在同一个服务器中的不同服务)示例:

    1. <p th:text="@{~/image/upload}">p>

    参数使用示例:








     

    片段表达式

    ~{}可以用来引用一段公共的 HTML 代码片段。

     在 Thymeleaf 模板文件中,你可以使用th:fragment属性来定义一段公共的代码片段,然后你可以通过使用th:insertth:replace属性来将这些公共的代码片段引入到模板文件中来。

    th:insert是直接将代码片段插入到标签体内

    th:replace则是用代码片段直接替换标签体内容。

    src/main/resources/templates/base.html,通过th:fragment属性定义一段公共的代码片段:

    <div id="footer" th:fragment="footerFragment">&copy; 2017 fanlychie</div>

    src/main/resources/templates/index.html,通过th:insert属性引用一段公共的代码片段:

    <div th:insert="~{base :: footerFragment}"></div>
    
    <div th:replace="~{base :: footerFragment}"></div>

    (1)其中,~{}是可选的,我们可以去掉这层的包裹:

    (2)若 index.html 与 base.html 不在同级目录,如 templates/commons/base.html:

    (3)使用th:fragment属性定义代码片段时,你还可以声明一组参数:
    1. <div th:fragment="crumbs(parent, child)">
    2. <i th:text="${parent}"></i> <i th:text="${child}"></i>
    3. </div>
    4. <!--
    5. <i>用户中心</i>
    6. <i>我的订单</i>
    7. -->
    8. <div th:insert="::crumbs('用户中心', '我的订单')"></div>

    三、Thymeleaf 实战应用

    1、input 、textarea 赋值

    1. //JAVA
    2. @RequestMapping(value = { "formData", "" })
    3. public String list(HttpServletRequest request, ModelMap model) {
    4. Entity entity = xxxService.getEntity();
    5. model.addAttribute("entity", entity);
    6. return "test.html";
    7. }
    1. <!-- HTML -->
    2. <input type="text" th:attr="name=${entity.name},required=${entity.propRequired}" placeholder="请输入"/>
    3. <textarea th:text="${entity.remarks=='null'?'':entity.remarks}" placeholder="请输入"></textarea>

    2.复选框 判断选中

    1. //JAVA
    2. @RequestMapping(value = { "checkboxValue", "" })
    3. public String list(HttpServletRequest request, ModelMap model) {
    4. Entity entity = xxxService.getEntity();
    5. model.addAttribute("entity", entity);
    6. return "test.html";
    7. }
    1. <input type="checkbox" th:checked="${entity.prop1 eq '1'}"> aaa
    2. <input type="checkbox" th:checked="${entity.prop2 eq '1'}"> bbb

    3.下拉框 动态赋值 与 回显

    1. //JAVA
    2. @RequestMapping(value = { "selectList", "" })
    3. public String list(HttpServletRequest request, ModelMap model) {
    4. List<selectData> selectList = xxxService.getSelectList();
    5. int type = xxxService.getType();
    6. model.addAttribute("type", type);
    7. model.addAttribute("selectList", selectList);
    8. return "test.html";
    9. }
    • 下拉框数据填充
    1. <select data-placeholder="请选择" id="selectData" >
    2. <option value=" " selected>请选择</option>
    3. <option th:each="data:${selectList}" th:value="${data.id}" th:text="${data.name}"> </option>
    4. </select>
    • 下拉框数据填充,判断,回显数据
    1. <select>
    2. <option value="" th:selected="${type eq ''}">请选择</option>
    3. <option value="1" th:selected="${type eq 1}">字符型</option>
    4. <option value="2" th:selected="${type eq 2}">整型</option>
    5. <option value="3" th:selected="${type eq 3}">日期</option>
    6. </select>
    • js设置下拉框选中,回显数据
    1. <script type="text/javascript">
    2. $("#selectData").ready(function() {
    3. var value= "[[${type}]]";
    4. $("#selectData option[value= " + value + "]").prop("selected",true);
    5. });
    6. </script>

    4.循环遍历

    1. @RequestMapping(value = { "loopTest", "" })
    2. public String list(HttpServletRequest request, ModelMap model) {
    3. List<Entity> dataList = xxxService.getEntityList();
    4. Map<String,List<Entity>> dataMap = xxxService.getEntityMap();
    5. model.addAttribute("dataList", dataList);
    6. model.addAttribute("dataMap", dataMap);
    7. return "test.html";
    8. }
    • 遍历 list 数据:循环生成表格数据
    1. <table>
    2. <head>
    3. <tr>
    4. <th>ID</th>
    5. <th>名称</th>
    6. <th>类型</th>
    7. <th>时间</th>
    8. <th>是否可用</th>
    9. </head>
    10. <body>
    11. <tr th:each="data : ${dataList}" >
    12. <td th:text="${data.id}"></td>
    13. <td th:text="${data.name}"></td>
    14. <td th:switch="${data.type}">
    15. <span th:case="1">字符型</span>
    16. <span th:case="2">整型</span>
    17. <span th:case="3">日期</span>
    18. </td>
    19. <td th:text="${#dates.format(data.createDate, 'yyyy-MM-dd HH:mm:ss')}"></td>
    20. <td>
    21. <span th:if="${data.usable} eq '1'">
    22. <i class="fa fa-check"></i>
    23. </span>
    24. </td>
    25. </tr>
    26. </body>
    27. </table>
    • 遍历map数据
    1. <div th:each="dataEntry,dataStat: ${dataMap}" >
    2. <div> [[${dataEntry.key}]] </div>
    3. <div th:each="data: ${dataEntry.value}">
    4. <div>
    5. <dt>[[${data.id}]]: </dt>
    6. <dd>[[${data.name}]]</dd>
    7. </div>
    8. </div>
    9. </div>

    5.超链接 url传参

    1. @RequestMapping(value = { "formData", "" })
    2. public String list(HttpServletRequest request, ModelMap model) {
    3. Entity entity = xxxService.getEntity();
    4. model.addAttribute("entity", entity);
    5. return "test.html";
    6. }
    1. <a th:href="@{test/form(id=${entity.id},name=${entity.name})}">超链接1</a>
    2. <a th:href="@{test/form?id='+${entity.id}}+'&name='+${entity.name}">超链接2</a>

    springboot配合thymeleaf,调用接口不跳转页面只显示文本

    问题一:thymeleaf不跳转页面,只显示文本index

    1. @RequestMapping("/excel")
    2. @RestController
    3. public class OperateExcelController {
    4. @GetMapping(value = "")
    5. public String index() {
    6. //使用@RestController不能直接返回return "index",否则不会跳转页面,只会再页面显示index文本而已
    7. return "index";
    8. }

    @RestController注解相当于@ResponseBody和@Controller合在一起的作用。在使用@RestController注解Controller时,Controller中的方法无法返回jsp页面,或者html,配置的视图解析器 InternalResourceViewResolver不起作用,返回的内容就是Return 里的内容。

    包括在Mapping注解使用的同时使用@ResponseBody时也会出现同样的问题。

    解决方案

    解决办法①:去除@ResponseBody或将含有Rest的注解换成对应的原始注解@Controller;

    1. @RequestMapping("/excel")
    2. @Controller
    3. public class OperateExcelController {
    4. @GetMapping(value = "")
    5. public String index() {
    6. return "index";
    7. }

     解决办法②:不通过String返回,通过ModelAndView对象返回,上述例子可将return语句换成下面的句子,在使用ModelAndView对象返回的时候,不需要考虑有没有@ResponseBody类似的注解。

    1. @RequestMapping("/excel")
    2. @RestController
    3. public class OperateExcelController {
    4. @GetMapping(value = "")
    5. public ModelAndView index() {
    6. return new ModelAndView("index");
    7. }

  • 相关阅读:
    STAP旁瓣干扰抑制与干扰对抗仿真
    TPH-yolov5 小目标检测
    Apple macOS 13 Ventura 有意义的操作系统
    .NET 7.0 重磅发布及资源汇总
    常见算法题分类总结之二分算法(Binary-Search):致敬经典,超越经典
    NNZ 2591 是环状甘氨酸脯氨酸 (cGP) 小肽的合成类似物 | MedChemExpress (MCE)
    beamManagement(三)connected mode DL Beam training
    Linux命令之压缩zip
    LeetCode:第302场周赛【总结】
    【js】js中深拷贝与浅拷贝:
  • 原文地址:https://blog.csdn.net/yangyifan0/article/details/128069902