使用 JSP
-
SpringBoot 中不推荐使用 JSP
- 使用模板技术代替 JSP
-
使用 JSP 需要配置后才能使用
-
添加处理 jsp 的依赖
<dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency>
-
若要使用 servlet、jsp 、jstl 等的功能也需要添加相关依赖
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency>
-
创建存放 jsp 的目录,一般为
webapp
,设为项目中 jsp 资源目录- 创建
index.jsp
- 创建
-
在 pom.xml 文件指定 jsp 文件编译后存放的目录
-
webapp 目录下所有文件编译到 target 目录下
META-INF/resources
目录- 包括子目录文件
-
<resources> <resource> <!-- 指定 jsp 文件的编译路径 --> <directory>src/mian/webapp</directory> <!-- 编译的目标目录 --> <targetPath>META-INF/resources</targetPath> <!-- 包含子目录及所有文件 --> <includes> <include>**/*.*</include> </includes> </resource> </resources>
-
-
创建 Controller 访问 jsp
-
方法参数
HttpRequest
或Model
对象来返回数据@RequestMapping public String doOther(Model model){ //将数据放到 request 作用域;等价于 request.setAttribute() model.addAttribute("data", "废物"); //返回 index.jsp 页面,页面的逻辑名,由视图解析器包装为完整视图 return "index"; }
-
-
在
application.properties
文件中配置视图解析器-
# 配置视图解析器 spring.mvc.view.prefix=/ spring.mvc.view.suffix=.jsp
-
-
Web开发
静态资源
-
通过 Maven 依赖导入 jar 包
- 自动加载 jar 包中的
/META-INF/resources/webjars
路径找到静态资源 WebJars
是将 web 前端资源(如:jQuery、Bootstrap)打成jar
包文件- 借助版本管理工具( Maven、gradle 等)进行版本管理
- 保证这些 Web 资源版本的唯一性。避免了文件混乱、版本不一致等问题
- 自动加载 jar 包中的
-
加载
staticPathPattern = "/**"
路径-
默认到以下四个资源目录中查找静态资源:按优先级顺序排列
-
"classpath:/META-INF/resources/"
-
"classpath:/resources/"
- 一般存放资源文件
-
"classpath:/static/"
:默认生成目录- 一般存放静态资源
-
"classpath:/public/"
- 一般存放公共共享资源
-
-
自定义加载静态资源文件的路径
-
加载系统资源目录后查找自定义资源目录
-
spring.mvc.static-path-pattern
:阐述 HTTP 请求路径-
# 只有静态资源的访问路径为 /resources/** 时,才会处理请求 spring.mvc.static-path-pattern=/resources/**,
-
-
spring.resources.static-locations
:静态资源的存放位置- 添加静态资源文件路径:列表性的配置
- 查找文件时会依赖于配置的先后顺序依次进行
- 添加静态资源文件路径:列表性的配置
spring: # 资源请求路径 mvc: static-path-pattern: \** # 资源访问地址 resources: static-locations: [classpath: /META-INF/resources/, classpath: /resources/, classpath: /static/, classpath: /public/, file: ${web:vue-path}]
-
-
-
MVC 扩展
实现
-
在 SpringBoot 中对 MVC 有默认的支持实现
- 可以自定义实现 mvc 接管 框架的定义
-
创建类实现不同的 mvc 组件接口以自定义拓展组件功能
- 在类中重写方法自定义组件功能
-
创建 MVC 配置类实现 WebMvcConfigurer 接口,此类就是 mvc 的配置类
- 不能添加
@EnableWebMvc
注解- 该注解引入
@Import({DelegatingWebMvcConfiguration.class})
- 这个类继承了
WebMvcConfigurationSupport
- 这个类继承了
- 添加此注解会使
WebAutoMvcConfigurer
自动装配失效WebMvcAutoConfiguration
自动配置类生效需要所有配置类中不存在WebMvcConfigurationSupport.class
- 该注解引入
- 将自定义的组件类注册到容器中
- 不能添加
拦截器
- 拦截器是 SpringMVC 中的一种对象
- 能拦截对 controller 的请求
- 拦截器框架中有系统的拦截器
- 可以自定义拦截器
- 实现对请求预先处理
SpringMVC
自定义拦截器使用
-
创建类实现
HandlerInterceptor
接口- 接口中有三个方法
- 处理方法前执行
- 处理方法后执行
- 请求完成后执行
- 根据需求选择方法重写使用
- 接口中有三个方法
-
在 SpringMVC 配置文件中声明拦截器
<mvc:interceptors> <mvc:interceptor> <mvc:path="url"/> <bean class="拦截器全限定名"> </mvc:interceptor> </mvc:interceptors>
SpringBoot
- 创建类实现
HandlerInterceptor
接口 - 注册拦截器
- 创建配置类实现
WebMvcConfigurer
接口- 此接口中有大量方法处理 SpringMVC 内容
- 注解
@Configuration
使此类作为配置类作为配置类 - 重写
addInterceptors
方法注册拦截器- 创建拦截器对象放入
- 执行拦截的 url
- 排除拦截的 url
- 创建配置类实现
- 创建 controller 类方法处理请求测试拦截器
// 拦截器定义
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("执行了拦截器");
return true;
}
}
// 注册拦截器,将拦截器对象放到容器中
@Configuration
public class WebConf implements WebMvcConfigurer {
// 自动装配;对象赋值
@Resource
private MyInterceptor interceptor;
//注册拦截器
@Override
public void addInterceptors( InterceptorRegistry registry) {
// 将拦截器对象放到容器中,拦截 /doSome 请求,排除 /doOther 请求
registry.addInterceptor(interceptor).addPathPatterns("/doSome"). excludePathPatterns("/doOther");
}
}
Servlet
自定义使用 servlet
- 定义
MyServlet
类继承HttpServlet
- 重写
doGet()
、doPost()
方法处理请求
- 重写
- 创建配置类注册
servlet
对象- 注解
@Configuration
作为配置类使用 - 定义方法注册 servlet 对象
- 方法返回值为
ServletRegistrationBean<T>
对象 - 创建
ServletRegistrationBean<T>
对象注册 myServlet- 使用有参构造传入 servlet 对象和对应请求的 url 地址
- url 参数类型为可变长,可以传入多个 url
- 方法上注解
@Bean
将对象存放到容器
- 方法返回值为
- 注解
- 自定义 servlet 类方法将会覆盖掉 controller 中的处理方法
// MyServlet 类,注解创建对象
@Component
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
// 指定数据类型、编码格式
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
// 输出数据
writer.println("执行了 servlet");
// 刷新并关闭流
writer.flush();
writer.close();
}
}
// 配置类,注册 servlet 对象
@Configuration
public class ServletConf {
// 自动赋值对象
@Resource
private MyServlet servlet;
/*
* 创建对象并放到容器中
* 注册 servlet 对象并处理 /myServlet 请求,
* 注册后 servlet 方法将会覆盖 controller 中对应请求处理方法
*/
@Bean
public ServletRegistrationBean<Servlet> servletRegistrationBean(){
// 有参构造,传入 servlet 对象和对应的 url 地址(可变参数)
return new ServletRegistrationBean<>(servlet, "/myServlet");
/*
无参构造注册 servlet
ServletRegistrationBean<Servlet> bean = new ServletRegistrationBean<>();
bean.setServlet(servlet);
bean.addUrlMappings("/myServlet", "/doSome", "/doOther");
return bean;
*/
}
}
Filter
使用方式
-
Filter 是 Servlet 中的过滤器
-
可以处理请求:对请求的参数、属性进行调整
-
常在过滤器中处理字符编码
-
-
自定义使用 Filter,类似 servlet 的步骤
- 创建过滤器类实现接口
Filter
- 实现方法
doFilter()
- 实现方法
- 注册 Filter
- 创建配置类
- 添加注解
@Configuration
- 添加注解
- 定义方法注册过滤器对象
- 方法上添加注解
@Bean
- 方法返回值
FilterRegistratonBean<>
- 调用方法传入
filter
对象注册 - 设置过滤的
url
请求
- 方法上添加注解
- 创建配置类
- 创建过滤器类实现接口
// 自定义过滤器类
@Component
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain)
throws IOException, ServletException {
System.out.println("执行了过滤器方法");
filterChain.doFilter(servletRequest, servletResponse);
}
}
// 定义配置类,注册 Filter 对象
@Configuration
public class FilterConf {
@Resource
private MyFilter filter;
@Bean
public FilterRegistrationBean<Filter> filterFilterRegistrationBean(){
FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
// 注册过滤器
bean.setFilter(filter);
// 添加过滤请求,相当于 <url-pattern> 标签
bean.addUrlPatterns("/*");
return bean;
}
}
字符集过滤器
CharacterEncodingFilter
:字符集过滤器- 解决 post 请求中文乱码
- 默认编码:
ISO-8859-1
- 默认编码:
encoding
:当前使用的编码方式forceRequestEncoding
:默认 false,不使用当前编码forceResponseEncoding
:默认 false,不使用当前编码
- 解决 post 请求中文乱码
配置类
-
直接在过滤器配置类中创建
CharacterEncodingFilter
对象-
设置对象属性
- 指定编码格式
- 指定使用编码格式
-
将对象放到容器中
-
@Configuration public class FilterConf { @Bean public FilterRegistrationBean<Filter> filterFilterRegistrationBean(){ // 创建返回对象 FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>(); // 创建字符集过滤器 CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter(); // 设置编码格式,并指定使用:将属性赋值为 true encodingFilter.setEncoding("utf-8"); encodingFilter.setForceEncoding(true); bean.setFilter(encodingFilter); bean.addUrlPatterns("/*"); return bean; } }
-
-
修改配置文件
# SpringBoot 已经默认配置了 CharacterEncodingFilter # 但编码格式 ISO-8859-1,将此项设置为 false 以使用自定义过滤器 server.servlet.encoding.enabled: false
配置文件指定
# 使用 SpringBoot 的字符过滤器
server.servlet.encoding.enabled=true
# 设置字符格式为 utf-8
server.servlet.encoding.charset=utf-8
# 强制应答和请求使用 encoding 编码
server.servlet.encoding.force=true
页面
- 页面配置
- 将所有静态资源由
Tymeleaf
接管- 使用表达式动态获取数据
- 将所有静态资源由
- 国际化
- 配置
i18n
文件:国际化文件internationalization
,国际化L10N:localization
,本地化
- 通过按钮自定义切换语言版本
- 需要自定义组件
LocaleResolver
- 需要自定义组件
- 将组件放入容器中:通过
@Bean
- 配置
- 错误
- 在
templates
目录下创建error
目录 - 页面报错时会自动加载目录下页面
- 例如:404 错误会加载 404 页面
- 在
Thymeleaf
介绍
-
Thymeleaf 模板
- 一个流行的模板引擎,采用 Java 开发
- Java 生态下模板引擎有
Thymeleaf
、Freemaker
、Velocity
、Beetl
(国产) 等 - jsp 就是最早的模板技术
- Java 生态下模板引擎有
- 模板做视图层显示数据
- 一个流行的模板引擎,采用 Java 开发
-
Thymeleaf 对网络环境没有严格要求
- 能用于 web 环境和非 web 环境
- 在非 web 环境下能直接显示模板上的静态数据
- web 环境下能像 jsp 一样从后台接收数据并替换模板的静态数据
- 基于 html,以 html 标签为载体实现
- 语法应用在 html 标签中
- 能用于 web 环境和非 web 环境
-
SpringBoot 集成了 Thymeleaf 模板技术
- 官方推荐使用 Thymeleaf 代替 jsp 技术
- jsp 需要编译运行,效率低
- 官方推荐使用 Thymeleaf 代替 jsp 技术
配置
-
创建 SpringBoot 项目添加 Thymeleaf 起步依赖
- 自动引入最新版本 Thymeleaf 依赖
-
基本都为默认配置,无需修改
- 根据需求自定义修改
# 模板缓存: 默认打开;开发阶段关闭模板缓存,使修改立即生效 spring.thymeleaf.cache=false # 编码格式: 默认 UTF-8 spring.thymeleaf.encoding=UTF-8 # 模板类型: 默认 HTML 文件 spring.thymeleaf.mode=HTML # 模板前缀: 默认类路径的前缀 classpath:/templates/ spring.thymeleaf.prefix=classpath:/templates/ # 模板后缀: 默认后缀 .html spring.thymeleaf.suffix=.html
表达式
${key}
th:text="${key}"
:标准变量表达式- 获取 key 对应的文本数据
- 在页面 html 标签中使用
tx:text="${key}"
接收替换数据th:test=""
:Thymeleaf 的属性,用于文本显示
- key 是 request 作用域中的 key
- 使用
reque st.setAttribute(key, value);
添加数据 - 或
model.addAttribute(key, value);
- 使用
<!-- key 是 request 作用域内的 key,获取对应的 value -->
<p th:text="${key}">正常的静态数据</p>
<body>
<h1>标准变量表达式 ${} </h1>
<h2 th:text="${data}">全部信息</h2>
<div>
<!-- date 对应 value 为 Java 对象时,可获取其属性或方法使用 -->
<h3>id = </h3><h3 th:text="${data.id}">id</h3><br/>
<h3>name = </h3><h3 th:text="${data.name}">id</h3><br/>
<h3>age = </h3><h3 th:text="${data.getAge()}">id</h3><br/>
<h3>date = </h3><h3 th:text="${data.getDate()}">id</h3><br/>
</div>
</body>
*{key}
th:text="*{}"
:选择变量表达式- 获取 key 对应的 value 对象的属性
- 需要和
th:object="${key}"
一起使用- 简单获取对象的属性值
th:object="${key}"
作用范围内可以直接使用 key 对应 value 对象的属性*{field}
:通过对象字段直接获取值- 等价于:
th:text=${data.name}
- 或通过完整名获取属性
th:text="{data.name}"
:和${key}
格式相同
<body>
<h1>选择变量表达式 *{}</h1>
<h2 th:text="${data}">全部信息</h2>
<!-- 获取 value 对象 -->
<div th:object="${data}">
<!-- 作用范围内直接获取属性、方法;等价于 data.id -->
<h3>id = </h3><h3 th:text="*{id}">id</h3><br/>
<h3>name = </h3><h3 th:text="*{name}">name</h3><br/>
<h3>age = </h3><h3 th:text="*{getAge()}">age</h3><br/>
<h3>date = </h3><h3 th:text="*{getDate()}">date</h3><br/>
</div>
<h3>age</h3><h3 th:text="*{data.age}">使用完整名</h3>
</body>
@{url}
-
th:href="@{url}"
:链接表达式-
表示链接,使用在链接中
<!-- 可用在链接中 --> <script src=" "></script> <link href=" "></link> <a href=" "></a> <form action=" "></form> <img src=""></img>
-
url 可以是绝对地址或相对地址
-
-
传参
()
内传递参数:th:href="@{do4/(id=${id}, name=${name})}"
- 多个参数使用
,
分隔
- 多个参数使用
- 嵌套表达式、拼接字符串:
"@{'do3?id=' + ${id}}"
<body> <h2>链接表达式 @{url}</h2> <h3>链接绝对路径</h3> <a th:href="@{https://www.baidu.com}">绝对地址,链接到百度</a> <h3>链接相对路径</h3> <!-- url中拼接传参 --> <a th:href="@{'do3?id=' + ${id}}">相对地址,传参</a> <h3>相对地址,使用字符串传参</h3> <a th:href="@{'do4?id=' + ${id} + '&name=' + ${name}}">相对地址,使用字符串传参</a> <!-- () 内引用参数 --> <h3>推荐使用的传参方式</h3> <a th:href="@{do3/(id=${id})}">单个参数</a> <a th:href="@{do4/(id=${id}, name=${name})}">多参数</a> </body>
属性
- 大部分属性和 HTML 相同,作用和原来相同
- 添加前缀
th
- 添加
th
之后经过模板引擎处理
- 添加
- 可以使用变量表达式
- 添加前缀
th:action
- 定义后台控制器路径
- 类似
<form>
标签的 action 属性 - 结合 URL 表达式,获取动态变量
- 类似
<form id="login" th:action="@{/login}" th:method="post"></form>
th:method
设置请求的方法
<form id="login" th:action="@{/login}" th:method="post"></form>
th:href
定义超链接,结合 URL 表达式获取动态变量
<a th:href="@{do3/(id=${id})}">单个参数</a>
th:src
- 用于外部资源引用
- 比如:
<script>
标签的 src 属性、<img>
标签的 src 属性
- 比如:
- 常与
@{}
表达式结合使用 - 在 SpringBoot 项目的静态资源都放到 resoruces 目录下的 static 目录
- 写路径时不含
static
目录
- 写路径时不含
<!-- 引入 JQuery 文件 -->
<script type="text/javascript" th:src="@{/js/jquery-3.4.1.js}"></script>
th:text
- 用于文本显示
- 该属性显示的文本在标签体中
- 如果是文本框数据会在文本框外显示
- 想要显示在文本框内使用
th:value
- 想要显示在文本框内使用
<input type="text" id="reakName" name="realName" th:text="${realName}">
th:utext
- 将文本转义
- 按照 html 语法格式执行
th:style
设置样式
<a th:onclick="'fun1(' + ${user.id} + ')'" th:style="'color:red'">点击</a>
th:each
循环遍历
- 从后台传来对象集合就可以使用此属性遍历输出
- 与 JSTL 中
<c:forEach>
类似 - 可以循环遍历集合、数组、Map
- 与 JSTL 中
- th:each 所在的标签会被循环
- 语法:
th:each="demo,demoStat:${Demo}"
- demo:自定义的循环变量名
- demoStat: ${Demo} 循环体信息
- index:获取当前迭代对象的下标,从 0 开始
- count:当前迭代对象序列,从 1 开始
- size:被迭代对象大小
- current:当前迭代变量
- even、odd:布尔值,当前循环是否是偶数,从 0 开始
- first、last:布尔值,当前循环是否是第一个、最后一个
- demoStat 可不定义,默认存在:变量+Stat
demo:${Demo}
,默认循环体信息demoStat
- 使用
th:text=${demo}
接收循环变量
循环 List、Array
<table th:border="1" th:cellpadding="5" th:cellspacing="0" >
<thead>
<tr>
<td> id </td>
<td> name </td>
<td> age </td>
<td> date </td>
</tr>
</thead>
<tbody>
<!-- demo:${Demo} 等价于 demo,demoStat:${Demo} -->
<tr th:each="demo:${Demo}">
<td th:text="${demo.getId()}">id</td>
<td th:text="${demo.getName()}">name</td>
<td th:text="${demo.age}">age</td>
<td th:text="${demo.date}">date</td>
</tr>
</tbody>
</table>
循环 Map
- Map 循环无序
- 通过 key 获取 Map 的 key
- 通过 value 获取 Map 的 value
<table th:border="1" th:cellpadding="5" th:cellspacing="0" >
<thead>
<tr>
<td> 编号 </td>
<td> key </td>
<td> id </td>
<td> 姓名 </td>
<td> 年龄 </td>
<td> 生辰 </td>
</tr>
</thead>
<tbody>
<tr th:each="map:${Demo}">
<!-- map 定义 id 为 key, demo 对象为 value -->
<td th:text="${mapStat.count} + '/' + ${mapStat.size}"></td>
<!-- key 属性获取 Map 中的 key -->
<td th:text="${map.key}"></td>
<!-- value 属性获取对应的 value 值,通过对象获取属性或方法 -->
<td th:text="${map.value.id}">id</td>
<td th:text="${map.value.name}">name</td>
<td th:text="${map.value.getAge()}">age</td>
<td th:text="${map.value.getDate()}">date</td>
</tr>
</tbody>
</table>
循环 List-Map
- 先循环外层 List
- 再循环内层 Map
- 注意 th:each 的循环范围
<table th:border="1" th:cellpadding="5" th:cellspacing="0">
<thead>
<tr>
<td> 编号</td>
<td> key</td>
<td> id</td>
<td> 姓名</td>
<td> 年龄</td>
<td> 生辰</td>
</tr>
</thead>
<tbody>
<div th:each="list:${Demo}">
<tr th:each="map:${list}">
<td th:text="${mapStat.count}"></td>
<td th:text="${map.key}"></td>
<td th:text="${map.value.id}"></td>
<td th:text="${map.value.name}"></td>
<td th:text="${map.value.age}"></td>
<td th:text="${map.value.date}"></td>
</tr>
</div>
</tbody>
</table>
th:if
- 条件判断 if
- 语法:
th:if="boolean 条件"
- 条件为 true 显示标签体内容
- 非 null 的内容不进行表达式判断时都为 true
th:“${name}”
:name 只要不是 null 就显示内容
- 对于 null 默认为 false
- 只有进行
th:if${name == null}
才会显示内容
- 只有进行
th:unless
是th:if
的相反操作
<div th:if="true">显示文本内容</div>
<div th:unless="false">显示文本内容</div>
<!--
添加的数据
model.addAttribute("test1", true);
model.addAttribute("test2", false);
model.addAttribute("name", "张三");
model.addAttribute("hobby", "");
model.addAttribute("age", 18);
model.addAttribute("date", null);
-->
<body>
<h2>测试 if、unless 判断条件</h2>
<h3 th:if="${test1}">if 为 true 显示</h3>
<h3 th:unless="${test2}">unless 为 false 显示</h3>
<h3 th:if="${name}"> name非空,可以显示 </h3>
<h3 th:if="${hobby}">hobby="" 默认为 true,可以显示</h3>
<h3 th:if="${age}"> age非空,可以显示</h3>
<h3 th:if="${date}">date=null 默认为 false,不显示</h3>
<h3 th:unless="${date}">date=null 默认为 false,可以显示</h3>
</body>
switch case
- 判断语句:用法类似 Java
- 最多只有一个匹配成功
<div th:switch="${key}">
<p th:case="value1">结果1</p>
<p th:case="value2">结果2</p>
<p th:case="*">默认值</p>
<!-- 只有一个能匹配成功,都不匹配时执行默认case -->
</div>
<!-- model.addAttribute("age", 18); -->
<div th:switch="${age}">
<h3 th:case=10>年龄为 10 岁</h3>
<h3 th:case=12>年龄为 12 岁</h3>
<h3 th:case=18>年龄为 18 岁,显示此行</h3>
<h3 th:case="*">年龄未知,默认语句,都不匹配时显示</h3>
</div>
th:inline
- 内联
- 三个取值类型
text
、javascript
、none
内联 text
-
可以让
Thymeleaf
不依赖于 html 标签,- 直接使用
内联表达式[[表达式]]
即可获取动态数据 - 父级标签上加
th:inline="text"
属性- 可省略
<p>显示姓名是:[[${name}]]</p>
- 直接使用
<body>
<h1>测试 inLine 内联使用</h1>
<h2>inLine text 内联文本</h2>
<div th:inline="text">
<h3>数据 data = [[${data}]]</h3>
</div>
<h2>省略 th:inline 标签</h2>
<h3>数据:[[${data}]]</h3>
</body>
内联 javascript
- 将模板数据和 Java 数据联合
- 在 JS 脚本中可以直接使用 Thymeleaf 取值表达式
<head>
<meta charset="UTF-8">
<title>内联 inLine</title>
<script type="text/javascript" th:inline="javascript">
function fun(){
alert([[${data}]]);
}
</script>
</head>
<body>
<h2>测试 javascript 使用 inline</h2>
<input type="button" name="btn" value="单机获取数据" onclick="fun()">
</body>
字面量
-
在模板文件中直接写,可以正常显示
- 模板表达式中引用的是 model 中数据
-
文本字面量:
''
包围的字符串- 引用变量不存在时会显示
null
- 引用变量不存在时会显示
-
数字、布尔值、null 字面量直接使用
<h2>测试字面量</h2>
<!-- 后台数据
model.addAttribute("test1", true);
model.addAttribute("name", "张三");
model.addAttribute("date", null);
-->
<div>
<!--
${name} 引用 name 值,不存在时显示为 null,其他内容正常显示
若例如 ${111} 使用数字,作为数字字面量直接显示
-->
<h3 th:text="'文本字面量' + ';动态数据 name = ' + ${name}">姓名</h3>
<h3 th:if="${20 > 5}">数字字面量直接使用,正常显示</h3>
<h3 th:if="${test1 == true}">布尔字面量 true 直接使用,正常显示</h3>
<h3 th:if="${date == null}">null 字面量直接使用,正常显示</h3>
</div>
字符串连接
- 使用
''
将静态字符串包裹,使用+
连接动态数据 - 使用双竖线
||
包裹字符串和表达式
<!-- 文本字面量,'' 和 + 连接字符串 -->
<h3 th:text="'正常显示文本字面量' + ';动态数据 name = ' + ${name}">姓名</h3>
<!-- 使用 || 包裹连接字符串-->
<h3 th:text="|正常显示,拼接数据 name = ${name}|">姓名</h3>
运算符
- 算术运算:
+ - * / %
- 别名:
div
(除)、mod
(求余)
- 别名:
- 关系比较:
>、<、>=、<=
- 别名:
gt、lt、ge、le
- html 页面中部分符号无法正常显示,需要使用转义字符
- 别名:
- 相等判断:
==、!=
- 别名:
eq、ne
- 别名:
- 三元运算符:
... ? ... : ...
<div>
<!-- th:text 直接显示运算结果, th:if 根据表达式结果判断是否显示-->
<p th:text="${ 20 > 10}">xtrue</p>
<p th:test="${20 + 50}"> 70 </p>
<p th:if="${false == false}"></p>
<!-- 三元运算符 -->
<p th:text="${ date == null ? '张三' : '李四' }"></p>
<!-- 嵌套三元运算符 -->
<p th:text="${age == null ? '废物' : (age > 10 ? '大于10':'小于10')}"></p>
</div>
内置基本对象
介绍
-
模板引擎提供了一组内置的对象
-
可以直接在模板中使用
-
对象由
#
开始引用
-
-
常用对象
#request
:表示HttpServletRequest
- 数据类型:
HttpServletRequest
- 可使用类中所有方法
- 数据类型:
#session
:表示HttpSession
- 数据类型:
HttpSession
- 可使用类中所有方法
- 数据类型:
session
表示 Map 对象- 类型:Map,存储在 Map 结构中
- 对
#session
的简化形式,获取session
中指定key
的值 session.getSession
等价session.getAttribute("getSession")
param
:表示参数对象- 请求的参数集合
application
:servletContext
//添加数据
@GetMapping("/baseObject")
public String baseObject(Model model, HttpServletRequest request, HttpSession session) {
model.addAttribute("name", "李四");
request.setAttribute("requestData", "request 中数据");
request.getSession().setAttribute("getSession", "getSession 中数据");
session.setAttribute("session", "session 中数据");
return "baseObject";
}
<!-- 获取数据 -->
<body>
<h2>测试基本内置对象</h2>
<h2 th:text="${#request.getAttribute('requestData')}"></h2>
<h2 th:text="${#session.getAttribute('getSession')}"></h2>
<h2 th:text="${session.session}"></h2>
<h2 th:text="${session.getSession}"></h2>
</body>
#request
- 内置对象的方法
<h2>#request 方法</h2>
完整 url,不含参数: <span th:text="${#request.getRequestURL()}"></span><br/>
访问地址,不含参数: <span th:text="${#request.getRequestURI()}"></span><br/>
参数部分: <span th:text="${#request.getQueryString()}"></span><br/>
上下文: <span th:text="${#request.getContextPath()}"></span><br/>
ip: <span th:text="${#request.getServerName()}"></span><br/>
端口号: <span th:text="${#request.getServerPort()}"></span><br/>
<!-- 还有很多操作方法 -->
<!--
url:http://localhost:8080/baseObject
显示结果:
完整 url,不含参数http://localhost:8080/baseObject
访问地址,不含参数/baseObject
参数部分
上下文
iplocalhost
端口号8080
-->
param
- 获取请求中的参数
name的参数值 <span th:text="${param.name}"></span><br/>
参数的数量 <span th:text="${param.size}"></span><br/>
内置工具类对象
- 模板自带的对 日期、数字、字符串、集合 等的处理
- 内置对象前都需要加
#
,一般都以s
结尾
#dates
- 测试部分方法
<!-- 数据 model.addAttribute("date", new Date()); -->
<!-- 默认格式化显示日期 -->
<p th:text="${#dates.format(date)}"></p>
<!-- 自定义格式化日期 -->
<p th:text="${#dates.format(date, 'yyyy-MM-dd HH:mm:ss')}"></p>
<!-- 获取年(月、日)信息 -->
<p th:text="${#dates.year(date)}">
<!-- 创建日期,当前日期(可自定义) -->
<p th:text="${#dates.createNow()}">
#numbers
- 操作数字、格式化显示等
- 测试部分方法
<!-- 数据:model.addAttribute("doubleNum",12.3456); -->
<!-- 数字货币格式化,默认当前本国货币 -->
<p th:text="${#numbers.formatCurrency(doubleNum)}"></p>
<!-- 格式化显示小数,整数部分 5 位,小数部分 2 位-->
<p th:text="${#numbers.formatDecimal(doubleNum, 5, 2)}"></p>
#strings
- 操作字符串:格式化、截取等操作
- 测试部分方法
<!-- 数据:model.addAttribute("string","asdfgghj"); -->
<!-- 字符串全部大写 -->
<p th:text="${#strings.toUpperCase(string)}">
<!-- 查找匹配的第一个子字符串位置 -->
<p th:text="${#strings.indexOf(string, 'gg')}">
<!-- 截取字符串,自定义范围(可只指定开始范围截取到最后) -->
<p th:text="${#strings.substring(string, 3, 6)}">
#lists
- 操作 List 集合
- 测试部分方法
<!-- 是否存在指定元素(结果取反处理了), boolean 类型 -->
<p th:if="!${#lists.contains(list, demo)}">存在成员</p>
<!-- 集合长度,lsit 不能为 null,可以是空集合 -->
<p th:text="${#lists.size(list)}"></p>
<!-- 集合元素是否为 null -->
<p th:text="${#lists.isEmpty(list)}"></p>
null 处理
th:text=“demo?.name”
:引用 demo 对应的对象的 name 属性?
:询问前面对象是否为null
- 不为
null
时正常处理 - 为
null
不执行后面的语句
- 不为
- 在直接执行对象为 null 时无需处理
<!-- 数据
Demo demo = null;
Demo demo1 = new Demo();
-->
<!-- demo 为 null 且未处理引用属性;报异常 -->
<p th:text="${demo.name}"></p>
<!-- demo 为 null 但直接使用,不显示此句,无异常 -->
<p th:text="${demo}"></p>
<!-- 对 null 的处理,先判断 ? 前是否为 null;为 null 时不显示此句,无异常 -->
<p th:text="${demo?.name}"></p>
<!-- demo1 不为 null,但 name 为 null;不显示此句,无异常 -->
name=<p th:text="${demo1.name}">name</p>
自定义模板
自定义
-
定义
-
<!-- 语法格式 --> th:fragment="自定义模板名" <!-- 示例 --> <div th:fragment="demo"> <p>测试模板</p> <p>废物</p> </div>
-
-
引用
- 使用模板方式
th:include
:包含模板- include 插入模板将 引用标签体全部替换
th:insert
:插入模板- insert 插入模板时将内容都插入 引用的标签体内
- 使用模板方式
<!-- 语法格式 -->
~{templatename :: selector} 或 templatename :: selector
<!--
templatename:模板所在的文件名,后缀可带可不带
selector:自定义的模板名
之间空格分隔
-->
示例
模板定义
- head 和 end 两个模板
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>自定义 head 模板</title>
</head>
<body>
<div th:fragment="head">
<p>name:二狗</p>
<p>地址:泰国</p>
</div>
<div th:fragment="end">
<p>end</p>
<p>版权所有</p>
</div>
</body>
</html>
使用 th:insert
<!-- 使用:插入模板 -->
<h3>插入模板 th:insert </h3>
<div th:insert="head :: head">
<!-- 或 ~{head :: head} -->
两种方式使用模板:插入模板效果相同
</div>
<!-- 页面效果源码 -->
<h3>插入模板 th:insert </h3>
<!-- 保留原 div 标签 -->
<div>
<!-- 整个模板内容插入 div 标签体内 -->
<head>
<meta charset="UTF-8">
<title>自定义 head 模板</title>
</head>
<div>
<p>name:二狗</p>
<p>地址:泰国</p>
</div>
</div>
<!-- 到此结束 -->
使用 th:include
<!-- 使用:包含模板 -->
<h3>包含模板 th:include </h3>
<div th:include="end :: end">
包含模板使用
</div>
<!-- 页面效果源码 -->
<h3>包含模板 th:include </h3>
<!-- 模板内容整个替换掉标签体 -->
<div>
<p>end</p>
<p>版权:二狗所有,盗版必究</p>
</div>
使用整个文件作为模板
- 使用
html
标签引用整个模板
<!-- 使用包含将整个文件引入 -->
<h3>使用整个文件作为模板</h3>
<div th:include="head :: html">
包含模板使用
</div>
<!-- 页面效果源码 -->
<!-- 使用整个模板内容替换掉 div 标签体 -->
<div>
<head>
<meta charset="UTF-8">
<title>自定义 head 模板</title>
</head>
<body>
<div>
<p>name:二狗</p>
<p>地址:泰国</p>
</div>
<div>
<p>end</p>
<p>版权所有</p>
</div>
</body>
</div>
<!-- 使用 insert 插入模板时将内容都插入 div 标签体内 -->
使用其他目录模板
- 使用
目录名/文件名
引用其他目录模板 <div th:include="目录名/文件名 :: 模板名">
<h3>引用其他目录模板 </h3>
<div th:insert="test/head :: head">
<!-- 或 ~{head :: head} -->
两种方式使用模板:插入模板效果相同
</div>