背景

  • 视图解析:Spring Boot默认不支持 JSP,但确实可以通过额外配置用上JSP。
  • 不过强行用JSP已经脱离了Spring Boot易配置、快速开发的初衷。如果可能,应避免使用 JSP。所以需要引入第三方模板引擎技术实现页面渲染。
  • Spring Boot支持FreeMarker、Groovy、Thymeleaf和Mustache四种模板解析引擎,并对以上模板引擎做了自动配置支持。
  • Spring Boot 中推荐使用 Thymeleaf 作为模板引擎,因为 Thymeleaf 提供了完美的 Spring MVC 支持。
  • SpringBoot 为 Thymeleaf 提供自动配置,因此 Thymeleaf 可以与 Spring Boot 完美整合

Thymeleaf

简介

  • Thymeleaf 的主要目标是为您的开发工作流程带来优雅的自然模板:HTML可以在浏览器中正确显示,也可以作为静态原型工作,从而加强开发团队的协作。
  • Thymeleaf 是一个流行的模板引擎,该模板引擎采用 Java 语言开发
    模板引擎是一个技术名词,是跨领域跨平台的概念,在 Java 语言体系下有模板引擎,在C#、PHP 语言体系下也有模板引擎,甚至在 JavaScript 中也会用到模板引擎技术,Java 生态下的模板引擎有 Thymeleaf 、Freemaker、Velocity、Beetl(国产) 等。
  • Thymeleaf 对网络环境不存在严格的要求,既能用于 Web 环境下,也能用于非 Web 环境下。在非 Web 环境下,他能直接显示模板上的静态数据;在 Web 环境下,它能像 Jsp 一样从后台接收数据并替换掉模板上的静态数据。它是基于 HTML 的,以 HTML 标签为载体,
  • Thymeleaf 要寄托在 HTML 标签下实现。
  • Spring Boot 集成了 Thymeleaf 模板技术,并且 Spring Boot 官方也推荐使用 Thymeleaf 来替代 JSP 技术,Thymeleaf 是另外的一种模板技术,它本身并不属于 Spring Boot,Spring Boot只是很好地集成这种模板技术,作为前端页面的数据展示,在过去的 Java Web 开发中,我们往往会选择使用 Jsp 去完成页面的动态渲染,但是 jsp 需要翻译编译运行,效率低
  • Thymeleaf官网:https://www.thymeleaf.org/
  • Thymeleaf 官方手册:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html

在这里插入图片描述

Thymeleaf的特征

  1. 动静结合: Thymeleaf可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。浏览器解释HTML时会忽略未定义的标签属性,所以 Thymeleaf的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。
  2. 开箱即用: 它提供标准和Spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果。
  3. 国际化的支持: Thymeleaf 提供Spring标准方言和一个与 SpringMVC 完美集成的可选模块,快速实现表单绑定、属性编辑器、国际化等功能。
  4. 与SpringBoot完美整合: SpringBoot提供了Thymeleaf的自动配置,设置了视图解析器,可以像以前操作jsp一样来操作Thymeleaf。代码几乎没有任何区别,就是在模板语法上有区别。

模板引擎是什么

  • 模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。
  • 模板引擎不属于特定技术领域,它是跨领域跨平台的概念。在asp下有模板引擎,在PHP下也有模板引擎,在C#下也有,甚至JavaScript、WinForm开发都会用到模板引擎技术。
  • 常见的模板引擎都包含以下几个概念:数据(Data)、模板(Template)、模板引擎(Template Engine)和结果文档(Result Documents)。
    在这里插入图片描述

代码示例

1.引入依赖

主要是spring-boot-starter-thymeleaf依赖

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter-test</artifactId>
            <version>2.2.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

2.修改配置文件,添加Thymeleaf的配置信息

开发阶段关闭缓存

server:
  port: 9999
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/smbms?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
  thymeleaf:
    cache: false # 关闭缓存,方便调试
    suffix: .html
    prefix: classpath:/templates/
    mode: HTML

mybatis:
  mapper-locations: classpath:mapper/*.xml

在这里插入图片描述

3.编写HTML模板文件

  • Spring Boot默认的模板文件存放的位置为“classpath:/templates/”,
  • Spring Boot默认的静态文件路径为”classpath:/static/”,可以存放CSS、JS文件等模板公用的静态文件。
  • 添加index.html,并导入Thymeleaf的名称空间<html lang="en" xmlns:th="http://www.thymeleaf.org">,才能使用Thymeleaf的语法和模板功能
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>首页</h1>
<hr>
    <h1>Hello,<span th:text="${who}"></span></h1>
<hr>
</body>
</html>

4.编写控制器,返回ModelAndView,进行视图渲染

package cn.smbms.controller;
import cn.smbms.pojo.User;
import cn.smbms.service.UserService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

/**
 * @author: zjl
 * @datetime: 2024/5/6
 * @desc: 
 */
@Controller
public class IndexController {
    @Resource
    private UserService userService;
    @RequestMapping("/index")
    public String index(Model model){
        model.addAttribute("who","周杰伦");
        return "index";
    }
}

Thymeleaf语法

1.常用标签/属性

大部分属性和 html 的一样,只不过前面加了一个 th 前缀。 加了 th 前缀的属性,是经过模版引擎处理的。

标签名用途示例
th:text显示控制器传入的值th:text=“${userName}”
th:object显示控制器传入的对象th:object=${user}
th:action指定表单提交地址<form th:action=”@{/user/}+${user.id}”></form>
th:value替换为value的属性值<input th:value=”${user.id}” name=”id”/>
th:field绑定后台对象和表单数据<input th:field=”${userCode}” id=”userCode”/>
th:href添加链接地址<a th:href=”@{css/index.css}”>css目录</a>
th:switch支持多分支需要<th:case>的配合

1.1 th:action

  • 定义后台控制器的路径,类似<form>标签的 action 属性,主要结合 URL 表达式,获取动态变量
<form id="login" th:action="@{/login}" th:method="post">......</form>

1.2 th:method

  • 设置请求方法
<form id="login" th:action="@{/login}" th:method="post">......</form>

1.3 th:href

  • 定义超链接,主要结合 URL 表达式,获取动态变量
<a th:href="@{/query/student}">相对地址没有传参数</a>

1.4 th:src

  • 用于外部资源引入,比如<script>标签的 src 属性,<img>标签的 src 属性,常与@{}表达式结合使用
  • 在 SpringBoot 项目的静态资源都放到 resources 的 static 目录下,放到 static 路径下的内容,写路径时不需要写上 static
<script type="text/javascript" th:src="@{/js/jquery-3.4.1.js}"></script>

1.5 th:text

  • 用于文本的显示,该属性显示的文本在标签体中
  • 如果是文本框,数据会在文本框外显示,要想显示在文本框内,使用 th:value
<input type="text" id="realName" name="reaName" th:text="${realName}">

1.6 th:style

  • 设置样式
<a th:onclick="'fun1('+${user.id}+')'" th:style="'color:red'">点击我</a>

1.7 th:each

  • 这个属性非常常用,比如从后台传来一个对象集合那么就可以使用此属性遍历输出
  • 它与JSTL 中的<c: forEach>类似,此属性既可以循环遍历集合,也可以循环遍历数组及 Map.
1.7.1 循环 List
<div th:style="'margin-left: 350px'">
 <p>在一个 div 中循环 p 标签</p>
 <div >
 <p th:each="str,strSt:${strlist}" th:text="${str}"></p>
 </div>
 <br/>
<div th:each="u:${userList}">
<p th:text="${uStat.count}+'/'+${uStat.size}"></p>
 <p th:text="${u.id}"></p>
 <p th:text="${u.name}"></p>
 <p th:text="${u.sex}"></p>
  <p th:text="${u.age}"></p>
 </div>
</div>
语法说明

th:each="user, iterStat : ${userlist}"中的 ${userList} 是后台传过来的集合

  • user
    • 定义变量,去接收遍历${userList}集合中的一个数据
  • iterStat
    • ${userList} 循环体的信息
  • 其中 user 及 iterStat 自己可以随便取名
  • interStat 是循环体的信息,通过该变量可以获取如下信息
    • index: 当前迭代对象的 index(从 0 开始计算)
    • count: 当前迭代对象的个数(从 1 开始计算)这两个用的较多
    • size: 被迭代对象的大小
    • current: 当前迭代变量
    • even/odd: 布尔值,当前循环是否是偶数/奇数(从 0 开始计算)
    • first: 布尔值,当前循环是否是第一个
    • last: 布尔值,当前循环是否是最后一个
  • 注意:循环体信息 interStat 也可以不定义,则默认采用迭代变量加上 Stat 后缀,即
    userStat
1.7.2 循环 Map
<p>普通Map封装的对象</p>
 <div th:each="m,mSt:${users}">
 <p th:text="${mSt.count}"></p>
 <p th:text="${m.key}"> </p>
 <p th:text="${m.value.id}"></p>
 <p th:text="${m.value.name}"></p>
 <br/>
 </div>
<p>list-map</p>
 <div th:each="ul:${listmap}">
 <div th:each="um:${ul}">
 <p th:text="${um.key}"></p>
 <p th:text="${um.value.id}"></p>
 <p th:text="${um.value.name}">姓名是</p>
 </div>

1.8 条件if

  • 语法:th:if=”boolean 条件” , 条件为 true 显示体内容
  • th:unless 是 th:if 的一个相反操作
<p th:if="${sex =='m'}">
 性别是 男
</p>
<p th:unless="${sex == 'f'}">
 性别是女
</p>
<p th:if="${isLogin}">
 用户已经登录
</p>
<p th:if="${age > 50}">
 年龄是大于 50
</p>
<p th:if="5>0">
 5>0
</p>
<!-- 空字符串是 true-->
<p th:if="${name}">
 name 是 ‘’
</p>
        <tr th:if="${#lists.isEmpty(userList)}">
            <td colspan="5">暂无数据</td>
        </tr>
        <tr th:unless="${#lists.isEmpty(userList)}" th:each="user: ${userList}">
            <td th:text="${userStat.count}"></td>
            <td th:text="${user.userCode}"></td>
            <td th:text="${user.userName}"></td>
            <td th:text="${user.userRole}"></td>
            <td th:text="${user.address}"></td>
        </tr>
        </tbody>

1.9 switch,case 判断语句

  • 语法:类似 java 中的 switch,case
<div th:switch="${sex}">
 <p th:case="m">显示男</p>
 <p th:case="f">显示女</p>
 <p th:case="*">未知</p>
</div>
  • 一旦某个 case 判断值为 true,剩余的 case 则都当做 false,“*”表示默认的case,前面的 case 都不匹配时候,执行默认的 case

1.10 th:inline

  • th:inline 有三个取值类型 (text, javascript 和 none)
1.10.1 内联text
  • 可以让 Thymeleaf 表达式不依赖于 html 标签,直接使用内敛表达式[[表达式]]即可获取动态数据,要求在父级标签上加 th:inline = “text”属性
    <div th:inline="text">
     姓名是:[[${name}]] <br/>
     登录了吗:[[${isLogin}]]
    </div>
    <br/>
    <!--不用加入 th:inline='text'-->
    <div>
     姓名是:[[${name}]] <br/>
     登录了吗:[[${isLogin}]]<br/>
     性别:[[${sex}]]
    </div>
    
1.10.2 内联javaScript
  • 可以在 js 中,获取模版中的数据。
  • 在上面的模版页面中,增加
<button onclick="fun()">单击按钮</button>
<script type="text/javascript" th:inline="javascript">
 var name = [[${myuser.name}]];
 var id = [[${myuser.id}]];
 function fun() {
 alert("click 用户是"+name+",他的 id 是"+id);
 }
</script>

2.表达式

表达式是在页面获取数据的一种 thymeleaf 语法。类似 ${key}

表达式名字语法用途
变量取值${…}获取请求域、session域、对象等值
选择变量*{…}获取上下文对象值
获取消息值#{…}获取国际化等值
链接@{…}生成链接
片段表达式~{…}引入公共页面片段

2.1 标准变量表达式

  • 注意:th:text=“” 是 Thymeleaf 的一个属性,用于文本的显示
  • 语法: ${key}
  • 说明:
    • 标准变量表达式用于访问容器(tomcat)上下文环境中的变量,功能和 EL 中的 ${} 相同。
    • Thymeleaf 中的变量表达式使用 ${变量名} 的方式获取 Controller 中 model 其中的数据。也就是 request 作用域中的数据。
    • 模版文件(html)修改后,可以使用 idea—Build 菜单-Recompile 编译文件。重新 Recompile即可生效。

2.2 选择变量表达式

  • 语法:*{key}
  • 说明:需要配和 th:object 一起使用。选择变量表达式,也叫星号变量表达式,使用 th:object 属性来绑定对象,选择表达式首先使用 th:object 来绑定后台传来的对象,然后使用 * 来代表这个对象,后面 {} 中的值是此对象中的属性。
  • 选择变量表达式 *{…} 是另一种类似于标准变量表达式${…} 表示变量的方法
  • 选择变量表达式在执行时是在选择的对象上求解,而${…}是在上下文的变量 model 上求解
<div style="margin-left: 350px">
 <p>学习选择表达式</p>
 <div th:object="${myuser}">
 <p th:text="*{id}">id</p>
 <p th:text="*{name}">name</p>
 <p th:text="*{sex}">sex</p>
 <p th:text="*{age}">age</p>
 </div>
 <p th:text="*{myuser.name}"></p>
</div>

2.3 链接表达式(URL 表达式)

  • 语法:@{链接 url}
  • 说明:主要用于链接、地址的展示,可用于<script src=“…”>、<link href=“…”>、<a href=“…”>、<form action=“…”>、<img src=“”>等,可以在 URL 路径中动态获取数据
<div style="margin-left: 350px">
 <p>链接表达式</p>
 <p>链接到绝对地址</p>
 <a th:href="@{http://www.baidu.com}">百度</a>
 <br/>
 <br/>
 <p>链接到相对地址</p>
 <a th:href="@{/query/student}">相对地址没有传参数</a>
 <br/>
 <br/>
 <p>链接到相对地址,传参数方式 1</p>
 <a th:href="@{'/query/student?id='+${stuId}}">相对地址传参数方式1</a>
 <br/>
 <br/>
 <p>链接到相对地址,传参数方式 2,推荐方式</p>
 <a th:href="@{/find/school(id=${stuId},name='lisi')}">相对地址传参数方式 2</a>
</div>
//链接表达式
@GetMapping("/thy/link")
public String link(Model model){
 model.addAttribute("stuId",1001);
 return "03-link";
}
@GetMapping("/query/student")
@ResponseBody
public String query(Integer id){
 return "查询学生 id="+id;
}
@GetMapping("/find/school")
@ResponseBody
public String query2(Integer id, String name){
 return "查询 2,id="+id+",姓名="+name;
}

3.字面量

Controller 增加方法:

//字面量
@GetMapping("/thy/text")
public String text(Model model){
 model.addAttribute("sex","m");
 model.addAttribute("isLogin",true);
 model.addAttribute("age",20);
 model.addAttribute("name",null);
 model.addAttribute("city","郑州");
 model.addAttribute("myuser",new SysUser(1005,"张三","f",23));
 return "index";
}

3.1 文本字面量

用单引号’…'包围的字符串为文本字面量

<p th:text="'城市是'+${city}+' 用户登录'+${isLogin}"></p>

3.2 数字字面量

<p th:if="${age > 10}"> age > 10 </p>
<p th:if="20 > 5">20 大于 5</p>

3.3 boolean字面量

<p th:if="${isLogin == true}">用户登录了</p>

3.4 null字面量

<p th:if="${name == null}"> name 是 null </p>

4. 字符串连接

<p>字符串的连接,1 使用'';2 使用|字符串内容|</p>
<p th:text="'城市是'+${city}+' 用户登录'+${isLogin}"></p>
<p th:text="|城市是${city}用户登录${isLogin}|"></p> 

5.运算符

5.1 算术运算:

  • + , - , * , / , %

5.2 关系比较:

  • > , < , >= , <= ( gt , lt , ge , le )
  • 相等判断:== , != ( eq , ne )
<p th:if="${age > 10}"> age > 10 </p>
<p th:if="20 > 5">20 大于 5</p>
<p th:text="${sex =='m' ? '男':'女'}"></p>
<p th:text="${sex =='m' ? (isLogin?'男已经登录':'男的没有登录'):'女'}"></p>

5.3 布尔运算符:

  • and,or, not,!

5.4 条件运算符:

  • if-then: (if) ? (then)
  • if-then-else: (if) ? (then) : (else)
  • Default: (value) ?: (defaultvalue)

6.Thymeleaf 基本对象

  • 模板引擎提供了一组内置的对象,这些内置的对象可以直接在模板中使用,这些对象由#号开始引用,我们比较常用的内置对象
  • 创建Controller
//模版中基本对象
@GetMapping("/thy/baseObject")
public String baseObject(Model model, HttpServletRequest request, HttpSession session ){
 request.setAttribute("reqdata","request 中的数据");
 request.getSession().setAttribute("sessdata","session 中数据");
session.setAttribute("loginname","zhangsan");
 return "index";
}
  • #request 表示 HttpServletRequest
  • #session 表示 HttpSession 对象
  • session 对象,表示 HttpSession 对象
<div th:style="'margin-left: 350px'">
<p th:text="${#request.getAttribute('reqdata')}">request 作用域</p>
 <p th:text="${#request.getServerName()}"></p>
 <p th:text="${#request.getServerPort()}"></p>
 <p th:text="${#request.getServletPath()}"></p>
 <br/>
<p th:text="${#session.getAttribute('sessdata')}">session 中数据</p>
<p>处理#request,#session,session</p>
<p th:text="${#request.getServerName()}"></p>
<p th:text="${#request.getServerPort()}"></p>
<p th:text="${#request.getRequestURL()}"></p>
<p th:text="${#request.getRequestURI()}"></p>
<p th:text="${#request.getQueryString()}"></p>
<br/>
<br/>
<p th:text="${#session.getAttribute('loginname')}"></p>
<p th:text="${session.loginname}"></p>
</div>

7.Tymeleaf 内置工具类对象

  • 模板引擎提供的一组功能性内置对象,可以在模板中直接使用这些对象提供的功能方法
  • 工作中常使用的数据类型,如集合,时间,数值,可以使用 Thymeleaf 的提供的功能性对象来处理它们
  • 内置功能对象前都需要加#号,内置对象一般都以 s 结尾
  • 官方手册:http://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html
    • #dates: java.util.Date 对象的实用方法,
      <span th:text="${#dates.format(curDate, 'yyyy-MM-dd HH:mm:ss')}"></span>
      
    • #calendars: 和 dates 类似, 但是 java.util.Calendar 对象;
    • #numbers: 格式化数字对象的实用方法;
    • #strings: 字符串对象的实用方法: contains, startsWith, prepending/appending 等;
    • #objects: 对 objects 操作的实用方法;
    • #bools: 对布尔值求值的实用方法;
    • #arrays: 数组的实用方法;
    • #lists: list 的实用方法,比如<span th:text="${#lists.size(datas)}"></span>
    • #sets: set 的实用方法;
    • #maps: map 的实用方法;
    • #aggregates: 对数组或集合创建聚合的实用方法

示例(后台)

@GetMapping("/thy/utilObject")
public String utilObject(Model model, HttpSession session){
 model.addAttribute("mydate",new Date());
 model.addAttribute("mynum",26.695);
 model.addAttribute("mystr","bjpowernode");
 List<String> mylist = Arrays.asList("a","b","c");
 model.addAttribute("mylist",mylist);
 //model.addAttribute("mylist",null);
 session.setAttribute("loginname","zhangsan");
 Dog dog = new Dog();
 dog.setName("二哈");
 Cat cat = new Cat();
 cat.setName("英短");
 Zoo zoo = new Zoo();
 zoo.setCat(cat);
 //zoo.setDog(dog);
 zoo.setDog(null);
 model.addAttribute("zoo",zoo);
 return "index";
}

示例(前端)

<p th:text="${#dates.format(mydate,'yyyy-MM-dd')}"></p>
<p th:text="${#dates.format(mydate,'yyyy-MM-dd HH:mm:ss')}"></p>
<p th:text="${#dates.year(mydate)}"></p>
<p th:text="${#dates.month(mydate)}"></p>
<p th:text="${#dates.createNow()}" />
<br/>
<br/>
<p th:text="${#numbers.formatCurrency(mynum)}"></p>
<p th:text="${#numbers.formatDecimal(mynum,5,2)}"></p>
<br/>
<p>处理@#strings</p>
<p th:text="${#strings.toUpperCase(mystr)}"></p>
<p th:text="${#strings.indexOf(mystr,'power')}"></p>
<p th:text="${#strings.substring(mystr,2,5)}"></p>
<p th:text="${#strings.concat(mystr,'----java 开发')}"></p>
<br/>
<br/>
<p>处理#lists</p>
<p th:text="${#lists.isEmpty(mylist)}"></p>
<p th:if="!${#lists.isEmpty(mylist)}" ></p>
<p th:text="${#lists.size(mylist)}"></p>
<p>空值</p>
<p th:text="${zoo?.dog?.name}"></p>

8.模板

  • 自定义模板是复用的行为。可以把一些内容,多次重复使用

8.1定义模板

  • 语法:th:fragment=“top” , 定义摸模板,自定义名称是 top。例如:
<div th:fragment="top">
 <p>北大青鸟课工场</p>
 <p>kgc.cn</p>
</div>

8.2 引用模板

  • 语法:引用模板 ~{ templatename :: selector} 或者 templatename :: selector。例如:
<div th:insert="~{head :: top}"></div>
<div th:include="head :: top"></div>

8.3 模板例子

templates/common目录下创建 header.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
 <meta charset="UTF-8">
</head>
<body>
 <!--定义模板, 就是一段页面代码-->
 <div th:fragment="top">
 <p>XX系统首页</p>
 <p>www.baidu.com</p>
 </div>
</body>
</html>
templates/common目录下创建 footer.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<div th:fragment="foot">
  footer
  www.baidu.com @copy; 百度 2024
</div>
</body>
</html>
在其他文件中,使用模板内容
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div th:replace="common/head::top"></div>
<h1>hello,<span th:text="${session.loginUser.userName}"></span></h1>
<a th:href="@{/user/list}">用户列表</a>
<a th:href="@{/user/list(userName=${session.loginUser.userName},userRole=1)}">用户列表2</a>
</body>
<div th:replace="common/footer::foot"></div>
</html>
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐