Spring Boot 框架学习笔记(三)
九. SpringBoot Web开发
1.引入静态资源
- 打开
WebMvcAutoConfiguration
,查看导入静态资源源码:
//配置本地资源映射路径
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//如果静态资源已经自定义,直接返回
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
//第一种方法:wenjars引入依赖,路径映射
this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
//第二种方法:放于指定文件路径下识别
this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
registration.addResourceLocations(new Resource[]{resource});
}
});
}
}
第一种方法:webjars(很少使用)
由上述代码可知,引入webjars.org下的依赖,路径8080/webjars会对应本地依赖库中的路径:
访问:
第二种方法,映射指定路径文件(默认使用static)
点击
mvcProperties.getStaticPathPattern()
查看mvcProperties
源码:
private String staticPathPattern = "/**";
默认情况下SpringBoot是帮我们映射的路径是 /** ,如果想要做登录拦截的话,可以在配置文件application.properties中给所有静态资源添加一个前缀统一拦截
再点击
resourceProperties.getStaticLocations()
查看resourceProperties源码:
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
private String[] staticLocations;
public Resources() {
this.staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
}
发现这四种路径满足
所以我们可以按此代码中的路径新建文件
所以,有四个位置可以建立静态资源导入路径:
这四个位置优先级与其在源码中先后顺序一致
new String[] {"classpath:/META-INF/resources/"
,
"classpath:/resources/"
,
"classpath:/static/"
,
"classpath:/public/"
}
2.定制首页
源码:
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
//处理welcomepage的映射
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations());
return welcomePageHandlerMapping;
}
private Resource getWelcomePage() {
//从配置文件中找到静态资源路径并遍历路径数组
String[] var1 = this.resourceProperties.getStaticLocations();
int var2 = var1.length;
for(int var3 = 0; var3 < var2; ++var3) {
String location = var1[var3];
Resource indexHtml = this.getIndexHtml(location);
if (indexHtml != null) {
return indexHtml;
}
}
ServletContext servletContext = this.getServletContext();
if (servletContext != null) {
return this.getIndexHtml((Resource)(new ServletContextResource(servletContext, "/")));
} else {
return null;
}
}
//映射到首页
private Resource getIndexHtml(String location) {
return this.getIndexHtml(this.resourceLoader.getResource(location));
}
private Resource getIndexHtml(Resource location) {
try {
Resource resource = location.createRelative("index.html");
if (resource.exists() && resource.getURL() != null) {
return resource;
}
} catch (Exception var3) {
}
return null;
}
遍历静态资源路径,符合index.html命名的进行读取到前端
十. Thymeleaf模版引擎
Spring Boot官方推荐的模版引擎,Thymeleaf是一款渲染XML/HTML/HTM5内容,模版引擎,本身就是HTML文件,可以单独运行(做到跟前端开发人员不冲突)。
(1)提高开发效率:安装Thymeleaf插件
(2)添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
或者在spring官网找thymeleaf配置:
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
(3) Thymeleaf源码
ConfigurationProperties(
prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
}
(4)Thymeleaf模版设置
# 是否启用模版缓存,开发期间不推荐使用
spring.thymeleaf.cache=false
# 模版模式:支持HTML(4/5) ,如果设置为HTML5就只能支持HTML5
spring.thymeleaf.mode=HTML5
#以下都是默认配置
#检查模版是否存在
spring.thymeleaf.check-template=true
#是否启用模版
spring.thymeleaf.enabled=true
#模版编码
spring.thymeleaf.encoding=UTF-8
# spring.thymeleaf.suffix=.html
# spring.thymeleaf.prefix=classpath:/templates/
# 应该从解析中排除属于列表的名称,可以使用逗号分隔
# spring.thymeleaf.excluded-view-names=
(5)关键:HTML中需要由提示设置
<html lang="en" xmlns:th="http://www.thymeleaf.org">
引入命名空间,才会有th:*
提示
10.1 基本语法使用
测试使用的前端页面:
<ul>
<!--转义-->
<li th:text="${bookName}">恶魔</li>
<!--解析-->
<li th:utext="${bookName}">克苏鲁</li>
<!-- 破坏前端数据:转义 -->
<li> [[${bookName}]]</li>
</ul>
(1)${}
变量表达式,最常用
@Controller
@RequestMapping("/doom")
public class DataController {
@GetMapping("test")
public String m1(Model model){
model.addAttribute("bookName","<b>夜雨</b>");
return "demo01";
}
}
<!--假设前端页面如下-->
<!-- 应该尽量不破坏前端的数据,修改元素内容 -->
<ul>
<!--转义-->
<li th:text="${bookName}">恶魔</li>
<!--解析-->
<li th:utext="${bookName}">克苏鲁</li>
<!-- 破坏前端数据:转义 -->
<li> [[${bookName}]]</li>
10.2 设置属性值
th:text
或者th:utext
替换的元素内容,标签中还会涉及很多的属性,关于属性的设置Thymeleaf提供基本上所有的th:HTML属性
的形式
控制器:
@GetMapping("/attr")
public String m2(Model model) {
model.addAttribute("bookName", "月色");
model.addAttribute("author", "夜雨");
model.addAttribute("price", 666);
model.addAttribute("css", "color:deeppink");
model.addAttribute("cssClass", "abc");
model.addAttribute("title", "提示");
model.addAttribute("tip", "请输入内容");
return "demo02";
}
简单测试:
<h3 th:text="${bookName}"></h3>
<input th:value="${author}" th:placeholder="${tip}" th:style="${css}"><br/>
<p th:text="${price}" th:class="${cssClass}" th:title="${title}"></p>
<p th:text="${price}" th:attr="class=${cssClass},style=${css}"></p><!--等价上一行-->
针对行内样式测试:
<h3 >针对样式操作</h3>
<p class="mydiv" th:text="${bookName}" th:class="${cssClass}"></p><!--覆盖替换-->
<p class="mydiv" th:text="${bookName}" th:attrappend="class=${' '+cssClass}"></p><!--往后追加-->
<p class="mydiv" th:text="${bookName}" th:attrprepend="class=${cssClass+' '}"></p><!--往前追加-->
<!--等价写法-->
<p class="mydiv" th:text="${bookName}" th:classappend="${cssClass}"></p>
<p style="font-weight: bold;" th:text="${bookName}" th:styleappend="${css}"></p>
10.3 简单的运算符
(1)字符串拼接
<h3>字符串拼接</h3>
<!--这个不算,但是起到的效果相同-->
<h3>书名:[[${bookName}]]</h3>
<!--三种方式-->
<h3 th:text="'书名:'+${bookName}">书名:小楼一夜</h3>
<h3 th:text="|书名:${bookName}|">书名:小楼一夜</h3>
<!-- Thymeleaf内置工具对象 -->
<h3 th:text="${#strings.concat('书名:',bookName,'!!')}">书名:小楼一夜</h3>
(2)算术运算符、比较运算符、逻辑运算符、条件运算符
<h3>运算符</h3>
<p th:text="10*20"></p>
<p th:text="${price}"></p>
<p th:text="${price}/2"></p>
<p th:text="${price}>20"></p>
<p th:text="${price}<=20"></p>
<p th:text="${abcdef}">====</p><!-- 数据中没有值得时候为空 在前端页面不显示 -->
<p th:text="${abcdef}==null">====</p><!-- 显示为true -->
<hr/>
<h4>字符串比较</h4>
<p th:text="${#strings.equals('月色',bookName)}">====</p>
<p th:text="${bookName}=='月色'">====</p>
<hr/>
<p th:text="${price}%2==0"></p>
<p th:text="${price}%2 eq 0"></p><!-- 相等 -->
<p th:text="${price}%2 ne 0"></p><!-- 不等 -->
<hr/>
<h4>逻辑运算符</h4>
<p th:text="${price}>10 and ${price}<20"></p>
<hr/>
<h4>条件运算符</h4>
<p th:text="${price}%2==0?'真的结果':'假的结果'"></p>
<p th:text="${price}%2==0?'真的结果'"></p><!--可以少后半部分 如果条件判定假 不显示 为空-->
10.4 URL:传递参数
解决方式一:<base>
标签
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<base th:href="|${#request.getContextPath()}/|">
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a th:href="|book/add?id=${id}&bookName=${bookName}|">自己拼接,传递参数</a><br/>
<a th:href="|book/add/${id}/${bookName}|">占位符传递数据</a><br/>
</body>
</html>
解决方式二:@{}
(推荐)
<a th:href="@{/book/add(userId=${uid})}">传递数据一个数据</a><br/>
<a th:href="@{/book/add(userId=${uid},id=${id},name='tomcat',bookName=${bookName})}">传递数据多个数据</a><br/>
<a th:href="@{/book/add?id={uuid}&userName={uName}(uuid=${uid},uName='jackson')}">传递数据多个数据</a><br/>
<a th:href="@{/book/add/{uuid}/{uName}(uuid=${uid},uName=${bookName})}">占位符传递数据</a><br/>
10.5 显示对象数据
@GetMapping("/test04")
public String m5(Model model){
model.addAttribute(new Book("小楼一夜","夜雨",new Random().nextInt(66)));
return "demo04";
}
<!-- 第一种写法 -->
<form>
书名:<input th:value="${book.bookName}"/><br/>
作者:<input th:value="${book.author}"/><br/>
价格:<input th:value="${book.price}"/><br/>
</form>
<hr/>
<!-- 第二种写法 -->
<form th:object="${book}">
书名:<input th:value="*{bookName}"/><br/>
作者:<input th:value="*{author}"/><br/>
价格:<input th:value="${book.price}"/><br/>
</form>
10.6 语句控制
Thymeleaf语法中认为是true
的情况如下:
- 值是非空
- 值是
character
类型,但不是0
- 值是非0的数字
- 值是字符串,但是字符串不能是
false/off/no
- 值不是boolean值
(1)IF和SWITCH语句
@GetMapping("/test06")
public String m6(Model model){
model.addAttribute("price",new Random().nextInt(30));
model.addAttribute("num",new Random().nextInt(10));
return "demo06";
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p th:if="${price}<15">
小于15的数据:
<strong th:text="${price}"></strong>
</p>
<p th:unless="${price}<15"><!-- >=15 -->
大于15的数据:
<strong th:text="${price}"></strong>
</p>
<hr/>
<p th:switch="${num}">
<strong th:case="1">夜雨:[[${num}]]</strong>
<strong th:case="2">月色:[[${num}]]</strong>
<strong th:case="3">小楼:[[${num}]]</strong>
<strong th:case="4">听风雨:[[${num}]]</strong>
<strong th:case="*">毕业:[[${num}]]</strong>
</p>
</body>
</html>
(2)循环
@GetMapping("/test07")
public String m7(Model model){
List<Book> bookList = new ArrayList<>();
bookList.add(new Book("月色","01",new Random().nextInt(66)));
bookList.add(new Book("夜雨","02",new Random().nextInt(66)));
bookList.add(new Book("小楼一夜","03",new Random().nextInt(66)));
bookList.add(new Book("毕业","04",new Random().nextInt(66)));
bookList.add(new Book("长亭外","古道边",new Random().nextInt(66)));
model.addAttribute("bookList",bookList);
return "demo07";
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table border="1" style="border-collapse: collapse;width: 500px">
<tbody>
<tr th:each="book,vs:${bookList}" th:style="|background:${vs.even?'yellow':'#ccc'}|">
<td th:text="${vs.count}"></td>
<td th:text="${book.bookName}"></td>
<td th:text="${book.price}"></td>
<td th:text="${book.author}"></td>
</tr>
</tbody>
</table>
</body>
</html>
10.7 包含和替换(简述)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p th:include="commons/header"></p>
<p th:replace="commons/footer"></p>
</body>
</html>
包含只是加载,不会让原来的标签(也就是p标签消失)
替换会直接让原来标签消失
10.8 经典回显数据
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<base th:href="|${#request.getContextPath()}/|">
<meta charset="UTF-8">
<title>模版引入</title>
</head>
<body>
<h2>下拉框选中[[${num1}]]</h2>
<select>
<option value="">请选择爱好</option>
<option th:each="hobby:${hobbyList}" th:text="${hobby['name']}" th:value="${hobby['id']}"
th:selected="${hobby['id'] eq num1}"
></option>
</select>
<h2>下拉框选中[[${num1}]]</h2>
<select id="hobby">
<option value="">请选择爱好</option>
<option th:each="hobby:${hobbyList}" th:text="${hobby['name']}" th:value="${hobby['id']}"></option>
</select>
<script>
var hobbyId = '[[${num1}]]';
document.getElementById("hobby").value=hobbyId;
</script>
<h2>单选框[[${num1}]]</h2>
<input type="radio" name="hobbyRadio" th:each="hobby:${hobbyList}" th:text="${hobby['name']}" th:value="${hobby['id']}" th:checked="${hobby['id'] eq num1}">
<h2>多选框[[${num1}]]</h2>
<input type="checkbox" name="hobbyCheckBox" th:each="hobby:${hobbyList}" th:text="${hobby['name']}" th:value="${hobby['id']}" th:checked="${#arrays.contains(num2,hobby['id'])}">
</body>
</html>