3、Spring Boot的Web开发
3.1 静态资源的映射规则
当接受到 /** 请求访问资源时, 会被映射到下面4个类路径下的静态资源目录中查找(html、css、js、favicon.ico等静态资源文件)。
"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"
3.2 Thymeleaf模版引擎
Spring Boot 官方不推荐使用JSP,因为内嵌的 Tomcat 、Jetty 容器不支持以 jar 形式运行 JSP。Spring Boot 中
提供了大量模板引擎,包含 Freemarker、Mastache、Thymeleaf 等。 而 Spring Boot 官方推荐使用
Thymeleaf 作为模板引擎, 因为 Thymeleaf 提供了完美的 SpringMVC 的支持。
-
引入 Thymeleaf
pom.xml 加入 Thymeleaf 启动器<!-- thymeleaf 模板启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
-
模板文件放在哪里 ?
将 HTML 页面放到 classpath:/templates/ 目录下, Thymeleaf 就能自动渲染。
package cn.korb1n.hellospringboot.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import java.util.HashMap; import java.util.Map; @Controller public class TestController { @RequestMapping("hello") public String hello(Map<String, String> map){ map = new HashMap<String, String>(); map.put("name","korbin"); map.put("age","21"); return "hello"; } }
浏览器请求http://localhost:8080/hello后, 通过上面代码转到 classpath:/templates/hello.html。
-
导入 Thymeleaf 的名称空间
在 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</title> </head> <body> <h1>hello springboot</h1> <!--th:text 设置p标签的标签体内容--> <p th:text="${name}">这里显示名字</p> </body> </html>
- Thymeleaf 常用属性:
参考 Thymeleaf 官方文档 10 Attribute Precedence
优先级 属性名 作用 1 th:insert、th:replace 引入片段,与th:fragment声明组合使用; 类似于 jsp:include 2 th:each 遍历,类似于c:foreach 3 th:if、th:unless、th:switch、th:case 条件判断,类似于c:if 4 th:object、th:with 声明变量,类似于c:set 5 th:attr、th:attrprepend、th:attrappend 修改任意属性, prepend前面追加, append后面追加 6 th:value、th:href、th:src… 修改任意html原生属性值 7 th:text、th:utext 修改标签体中的内容, th:text 转义特殊字符, 即 h1标签以文本显示出来,th:utext 是不转义特殊字符, 即 h1 标签展现出本来效果 8 th:fragment 声明片段 9 th:remove 移除片段 - Thymeleaf 常用属性:
-
Thymeleaf 标准表达式语法:
参考 Thymeleaf 官方文档 4 Standard Expression Syntax。一、Simple expressions(表达式语法) 1. Variable Expressions(变量表达式): ${...} (参考: 4.2 Variables) 1)、获取变量值;使用OGNL表达式; 2)、获取对象的属性, 调用方法 3)、使用内置的基本对象: #ctx : the context object.(当前上下文对象) #vars: the context variables.(当前上下文里的变量) #locale : the context locale. (当前上下文里的区域信息) 下面是Web环境下的隐式对象 #request : (only in Web Contexts) the HttpServletRequest object. #response : (only in Web Contexts) the HttpServletResponse object. #session : (only in Web Contexts) the HttpSession object. #servletContext : (only in Web Contexts) the ServletContext object. 示例: ${session.foo} (用法参考: 18 Appendix A: Expression Basic Objects) 4)、使用内置的工具对象:(用法参考: 19 Appendix B: Expression Utility Objects) #execInfo : information about the template being processed. #messages : methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{…} syntax. #uris : methods for escaping parts of URLs/URIs #conversions : methods for executing the configured conversion service (if any). #dates : methods for java.util.Date objects: formatting, component extraction, etc. #calendars : analogous to #dates , but for java.util.Calendar objects. #numbers : methods for formatting numeric objects. #strings : methods for String objects: contains, startsWith, prepending/appending, etc. #objects : methods for objects in general. #bools : methods for boolean evaluation. #arrays : methods for arrays. #lists : methods for lists. #sets : methods for sets. #maps : methods for maps. #aggregates : methods for creating aggregates on arrays or collections. #ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration). 2.Selection Variable Expressions(选择表达式): *{...} (参考:4.3 Expressions on selections) 1)、和${}在功能上是一样, 额外新增:配合 th:object 使用 <div th:object="${session.user}"> 省得每次写${session.user.firstName}, 直接取出对象,然后写对象名即可 <p>Name: <span th:text="*{firstName}">Sebastian</span> </p> <p>Email: <span th:text="*{email}">Saturn</span> </p> </div> 3. Message Expressions(获取国际化内容): #{...} (参考:4.1 Messages) 4. Link URL Expressions(定义URL): @{...} (参考:4.4 Link URLs) 5. Fragment Expressions(片段引用表达式): ~{...} (参考:4.5 Fragments) <div th:insert="~{commons :: main}">...</div> 二、Literals(字面量) (参考: 4.6 Literals) 1. Text literals: 'one text' , 'Another one!' ,… 2. Number literals: 0 , 34 , 3.0 , 12.3 ,… 3. Boolean literals: true , false 4. Null literal: null 5. Literal tokens: one , sometext , main ,… 三、Text operations(文本操作) (参考: 4.7 Appending texts) 1. String concatenation: + 2. Literal substitutions: |The name is ${name}| 四、Arithmetic operations(数学运算) (参考: 4.9 Arithmetic operations) 1. Binary operators: + , - , * , / , % 2. Minus sign (unary operator): - 五、Boolean operations(布尔运算) 1. Binary operators: and , or 2. Boolean negation (unary operator): ! , not 五、Comparisons and equality(比较运算) (参考: 4.10 Comparators and Equality) 1. Comparators: > , < , >= , <= ( gt , lt , ge , le ) 2. Equality operators: == , != ( eq , ne ) 六、Conditional operators(条件表达式;三元运算符) (参考: 4.11 Conditional expressions) 1. If-then: (if) ? (then) 2. If-then-else: (if) ? (then) : (else) 3. Default: (value) ?: (defaultvalue) 七、Special tokens(特殊操作) (参考: 4.13 The No-Operation token) 1. No-Operation: -
-
示例代码演示:
package cn.korb1n.hellospringboot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
public class TestController {
@RequestMapping("hello")
public String hello(Map<String, Object> map){
List list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
map.put("name","korbin");
map.put("age","21");
map.put("sex","男");
map.put("list",list);
map.put("hello","<h1>你好!Springboot!</h1>");
return "hello";
}
}
hello.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>hello springboot</h1>
<!-- success.html 引入头部公共片段 -->
<!--方式1: header : 公共片段所在模板的文件名 header_common :声明代码片段名 -->
<div th:replace="header :: header_common"></div>
<!--方式2:选择器写法 header : 公共片段所在模板的文件名 #header_common_id: 声明代码片的id值 -->
<div th:replace="header :: #header_common_id"></div>
<!--th:insert 和 th:replace的区别
th:insert和th:replace都可以引入片段,两者的区别在于
th:insert: 保留引入时使用的标签
th:replace:不保留引入时使用的标签, 将声明片段直接覆盖当前引用标签
-->
<h2 th:insert="header :: #header_common_id"></h2>
<!--迭代方式1-->
<ul>
<!-- 作用在同一个标签上 -->
<li th:each="item : ${list}" th:text="${item}"></li>
</ul>
<hr>
<!--迭代方式2-->
<ul th:each="item : ${list}">
<li th:text="${item}"></li>
</ul>
<hr>
<!--获取迭代状态-->
<!--
user : 第1个值,代表每次迭代出对象,名字任意取
iterStat : 第2个值,代表每次迭代器内置对象, 名字任意取, 并有如下属性:
index : 当前迭代下标 0 开始
count : 当前迭代下标 1 开始
size : 获取总记录数
current : 当前迭代出的对象
even/odd : 当前迭代是偶数还是奇数 (1开始算,返回布尔值)
first : 当前是否为第一个元素
last : 当前是否为最后一个元素
-->
<tr th:each="item,iterStat:${list}">
<td th:text="${item}"></td>
<td th:text="${iterStat.count}"></td>
<td th:text="${iterStat.size}"></td>
<td th:text="${iterStat.even} ? '偶数' : '奇数'"></td>
<td th:text="${iterStat.first}"></td>
<td th:text="${iterStat.last}"></td>
<br>
</tr>
<!--
th:text 转义特殊字符, 即 h1标签以文本显示出来
th:utext 不转义特殊字符, 即 h1 标签展现出本来效果
补充:Thymeleaf 行内表达式双中括号: [[表达式]] (就是不在标签上使用属性,参考12 Inlining)
-->
<hr>
<div th:text="${hello}"> </div>
<div th:utext="${hello}"> </div>
</body>
</html>
header.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--声明公共片段-->
<!-- 方式1:-->
<div th:fragment="header_common">
这是th:fragment声明公共片段
</div>
<!-- 方式2:选择器写法-->
<div id="header_common_id">
这是id选择器声明公共片段
</div>
</body>
</html>
3.3 Spring Boot热部署
默认情况下, 在开发中我们修改一个项目文件后,想看到效果不得不重启应用,这会导致浪费大量时间 ,我们希望不重启应用的情况下,程序可以自动部署(热部署)。
如何能实现热部署?
- 在 Spring Boot 开发环境下禁用模板缓存
#开发环境下关闭thymeleaf模板缓存,thymeleaf默认是开启状态 spring.thymeleaf.cache=false
- 添加 Spring Boot Devtools 热部署依赖
<!--热部署--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency>
- Intellij IEDA和Eclipse不同,Intellij IDEA必须做一些小调整:
1.在 Eclipse 中,修改文件后要手动进行保存,它就会自动编译,就触发热部署现象。
2.在Intellij IEDA 中,修改文件后都是自动保存,默认不会自动编译文件,需要手动编译按 Ctrl + F9 (推荐使用) 或 Build -> Build Project ;
或者进行以下设置才会自动编译(效果不明显)(File -> Settings -> Build, Execution, Deployment -> Compiler -> 勾选 Build project automatically)
3.4 扩展 SpringMVC 功能
如果想保留 Spring Boot MVC的特性,而且还想扩展新的功能(拦截器, 格式化器, 视图控制器等),你可以在自定义的 WebMvcConfigurer 类上增加@Configuration注解。
@Configuration
public class MySpringMvcConfigurer implements WebMvcConfigurer{
@Override public void addViewControllers(
ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//发送 /korbin请求来到 hello.html
registry.addViewController("/korbin").setViewName("hello");
}
}