Spring Boot 基础笔记
1、什么是Spring Boot框架
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。
Spring Boot 以约定大于配置的核心思想,默认帮我们进行了很多的设置,多数的Spring Boot应用只需要很少的Spring配置。同时它还集成了很多第三方库配置,例如:Redis、MongDB、Jpa等。
Spring Boot 的主要优点
- 为所有的Spring开发者更快的入门。
- 开箱即用,提供各种的配置来简化项目配置。
- 内嵌式容器,简化web项目。
- 没有冗余的代码生成和XML配置要求。
2、第一个Spring Boot程序
- 环境
- jdk1.8
- maven 3.1.6
- springboot最新版
- IDEA
- 在IDEA中创建第一个spring boot项目
-
项目结构
- 删除没用的文件,形成最终的项目结构
注意事项:
- 主入口不能修改和删除。
- 所有的业务包必须和主入口程序在同一个包下面,在同个包下面的包会被自动扫描。
spring boot 的常用设置:
- 端口号设置,默认的端口号为8080,但是可以修改,在application.properties下修改
# 修改访问的端口号
server.port=80
- 修改默认的banner图片
在resources文件夹下,创建一个banner.txt文件,然后取网上找一个在线的spring boot banner的制作网站。
我自己网上找了一个
${AnsiColor.BRIGHT_YELLOW}
// _ooOoo_ //
// o8888888o //
// 88" . "88 //
// (| ^_^ |) //
// O\ = /O //
// ____/`---'\____ //
// .' \\| |// `. //
// / \\||| : |||// \ //
// / _||||| -:- |||||- \ //
// | | \\\ - /// | | //
// | \_| ''\---/'' | | //
// \ .-\__ `-` ___/-. / //
// ___`. .' /--.--\ `. . ___ //
// ."" '< `.___\_<|>_/___.' >'"". //
// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
// \ \ `-. \_ __\ /__ _/ .-` / / //
// ========`-.____`-.___\_____/___.-`____.-'======== //
// `=---=' //
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
// 佛祖保佑 永不宕机 永无BUG //
${AnsiColor.BRIGHT_RED}
Application Version: ${application.version}${application.formatted-version}
Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version}
3、简单了解Spring Boot 自动装配原理
3.1、pom.xml文件
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
在pom.xml文件中存在parent标签,这个标签是父依赖,所有需要的jar版本包全部由父工程来管理的。在引入需要的依赖时,可以不需要指定依赖的版本,就是因为存在父依赖仓库在管理这些版本。
3.2、启动器
在pom.xml文件中以 spring-boot-starter
开头的都是一个个启动器。
例如:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
是web项目的启动器,如果你需要使用哪个启动器,就以 spring-boot-starter-XXX 就可以自动给你导入。如果我们需要使用什么功能就直接找到对应的启动器就可以了。例如需要导入web项目所有的依赖,就只需要导入spring-boot-starter-web这个依赖就可以了。这样我们需要使用什么样的功能就只需要启动对应的启动器就可以了,所有的依赖着父工程的统一管理了滴。
3.3、主程序
springboot的所有自动配置在启动的时候扫描并加载,所有的自动扫描类都在spring.factories
,但是不是所有的配置都会生效,只有导入对应的start启动器才会生效,然后在配置成功。下面是几个主要的注解程序:
@SpringBootApplcation注解:
标志这个项目为SpringBoot项目,它的下面还有其他几个注解。
- @SpringBootConfiguration注解:SpringBoot的配置注解
- @Configuration注解:Spring的配置类
- @Component注解:标志为一个Spring组件
- @Configuration注解:Spring的配置类
- @EnableAutoConfiguration注解:SpringBoot自动装配的注解
- @AutoConfigurationPackage注解:自动配置包
- @Import(AutoConfigurationPackages.Registrar.class)注解: 自动配置包注册->这就说明在SpringBoot项目中,创建的包必须和这个SpringBoot主程序在同一个目录下,这样才能够扫描到对应的包,不然不能扫描到对应的包。
- @Import(AutoConfigurationImportSelector.class)注解:自动配置导入选择,AutoConfigurationImportSelector这个类中就选择对应的配置。
- AutoConfigurationImportSelector类:
- getCandidateConfigurations方法:获取候选的配置,核心方法。
- AutoConfigurationImportSelector类:
- @AutoConfigurationPackage注解:自动配置包
META-INF/spring.factories文件:
注意:在自动配置的时候会将所有的配置全部导入到项目中,但是一些配置生效了,有一些配置没有生效呢?
如果我们需要使用某一些自动装配的功能时,我们需要通过一个spring-boot-starter启动器来启动,例如spring-boot-starter-web启动器来启动web开发对应的自动装配生效。有一个核心的注解来查看这个自动装配是否生效-> @ConditionalOnClass
,如果配置了对应的启动器,这个注解的条件就会满足,自动装配就会生效,如果没有配置对应的启动器,这个自动装配就不会生效。
结论:
SpringBoot所有的自动配置都会在项目启动的时候进行扫描和加载,但是不是所有的自动装配都会生效,需要配置对应的启动器来使对应的自动装配生效,有了启动器对应的自动转配就可以配置成功!!!!
4、Spring Boot 的配置
spring boot 使用一个全局的配置文件,配置文件的名称必须固定application,可以同时存在多个配置文件,但是存在优先级问题。
- application.properties:语法:
key=value
使用的是键值对的形式。例如之前的 server.port=80。来配置端口号 - application.yml:语法:
key:空格value
空格不能省略。
配置文件的好处就是可以修改spring boot 默认的配置,能够让我们自定义配置。推荐使用yaml文件来定义配置。
4.1、使用 yaml 给spring-boot实体赋值
- 创建两个实体对象
package com.tanke.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dog {
@Value("旺财")
private String name;
@Value("18")
private int age;
}
package com.tanke.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private String name;
private int age;
private boolean happy;
private Date birthday;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
- 编写 yaml 配置文件
# 配置了一个person对象
person:
name: 张三
age: 18
happy: true
birthday: 2021/11/16
maps: {k1: v1,k2: v2}
lists:
- 篮球
- 代码
dog: # 属性是一个对象,使用对象的数据配置
name: 小狗
age: 3
- 使用
@ConfigurationProperties
把配置的文件注入到spring的实体中
@ConfigurationProperties(prefix = "person") // prefix这个注解属性指定了在yaml中配置的对象名称
public class Person {
private String name;
private int age;
private boolean happy;
private Date birthday;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
4.2、JSR303 校验
导入校验需要的包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
yaml 语法可以支持 JSR303
校验,如果检验不成功就会报错!
空检查
@Null 验证对象是否为null
@NotNull 验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty 检查约束元素是否为NULL或者是EMPTY.
Booelan检查
@AssertTrue 验证 Boolean 对象是否为 true
@AssertFalse 验证 Boolean 对象是否为 false
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Length(min=, max=) Validates that the annotated string is between min and max included.
日期检查
@Past 验证 Date 和 Calendar 对象是否在当前时间之前
@Future 验证 Date 和 Calendar 对象是否在当前时间之后
@Pattern 验证 String 对象是否符合正则表达式的规则
数值检查,建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为"",Integer为null
@Min 验证 Number 和 String 对象是否大等于指定的值
@Max 验证 Number 和 String 对象是否小等于指定的值
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
@Digits 验证 Number 和 String 的构成是否合法
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
@Range(min=, max=) 检查数字是否介于min和max之间.
@Range(min=10000,max=50000,message="range.bean.wage")
private BigDecimal wage;
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
@CreditCardNumber信用卡验证
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=,host=, port=,regexp=, flags=)
- 开启yaml校验,使用
@Validated
注解开启校验
@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
@ConfigurationProperties(prefix = "person")
@Validated // 开启jsr303校验
public class Person {
private String name;
private int age;
private boolean happy;
private Date birthday;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
- 设个属性对应的校验,例如将name属性校验为
NotNull
@NotNull // 注意使用的是那个包下的注解
private String name; // 在yaml的配置中就不能为空,如果为空就会报错
4.3、配置文件的编写位置及多环境配置
配置文件的编写位置一共存在四个,分别是当前项目的目录的config文件夹下、当前项目的根目录下、项目resources的config文件下、项目resources根目录下(classpath下),但是配置的文件名必须是application,不能是其他名称。(约定大于配置)
注意:优先级越高,项目启动时越先加载,并且会覆盖优先级低的相同配置。如果一个项目中存在多个模块,并且在项目的根目录(根目录下的config文件)下配置了配置文件,则所有的子模块启动时就会先加载项目根目录下的配置,这就可以于配置项目的公共配置项。但是在子模块的根目录下的配置文件无效。
多环境配置:
- 方式一:通过创建多个配置文件,使用哪套配置就激活对应的配置文件即可。例如创建一个开发环境、测试环境和默认环境。
如果没有显示的激活其他环境,就使用默认的配置环境。
# 激活开发环境,只需要指定开发环境的后面的名称即可
# 激活了开发环境就直接使用开发环境的配置文件,默认环境下就不起作用了
spring:
profiles:
active: dev
server:
port: 8081
- 方式二:通过yaml文件的多模块开发,在一个文件中配置多个环境。
在yaml中,可以使用 - - -
三个横线来将各个模块进行分离。
# 激活开发环境,只需要指定开发环境的后面的名称即可
# 激活了开发环境就直接使用开发环境的配置文件,默认环境下就不起作用了
spring:
profiles:
active: test
# 默认环境
server:
port: 8081
---
# 开发环境
server:
port: 8082
# 给这个环境取一个名称
spring:
profiles: dev
---
# 测试环境
server:
port: 8083
# 给这个环境取一个名称
spring:
profiles: test
4.4、深入理解SpringBoot自动装配原理
自动装配的步骤:
- SpringBoot项目启动时,会自动扫描并配置大量的自动配置类
XXXXAutoConfiguration
(在META-INF/spring.factories
中)。 - 自动配置类会将生效的组件自动注入到spring容器中。
- 在向spring容器中注入组件时,会对应一个
XXXXproperties
文件,这个文件中包含了组件属性的默认值,如果在配置文件中没有配置就是用默认是的配置。 - 如果在配置文件中配置了对应的自动装配的属性,就是用配置文件中指定的属性值。这样可以自定义自己的配置,通过在配置文件中来自定义配置并且有规律。
例如:自动装配 HttpEncodingAutoConfiguration
这个自动装配类。
自动加载 HttpEncodingAutoConfiguration
这个类,并从 ServerProperties
这个配置类中获取属性值。
4.5、debug
通过这个配置在项目启动时会打印生效和未生效的自动装配类,在配置文件中设置debug
为true
。
5、Spring Boot Web 开发
5.1、静态资源配置
配置静态资源的访问路径,通过阅读源码总结了一下三种方式。源码就是 WebMvcAutoConfiguration
这个自动装配类,静态资源的配置核心方法是 addResourceHandlers()
。
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 这句代码的意思就是检查是否存在自定义静态资源的访问路径,如果存在则使用配置,不存在就跳过
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
registration.addResourceLocations(resource);
}
});
}
webjars方式:通过maven的方式将需要的静态资源导入,可以去webjars官网查询静态资源的maven坐标。(这种方式不常用,了解即可)
// 这句话的意思就是如果访问 /webjars/** 下的文件,就会自动映射到classpath:/META-INF/resources/webjars/这个目录下
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
classpath:/META-INF/resources/webjars/
这个目录在:
如果我需要访问 jquery.js
,就直接通过 http://localhost/webjars/jquery/3.6.0/dist/jquery.js
进行访问,因为 /webjars/**
就直接映射到了 /META-INF/resources/webjars/
这个目录下,可以直接访问这个目录下的静态资源。
SpringBoot默认的静态资源访问路径:
// SpringBoot设置的默认的资源访问路径
// this.mvcProperties.getStaticPathPattern() 这个方法获取静态资源的访问路径,这个就相当于是 /webjars/**,但是这个方法返回的是 /** 这个路径
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
// 通过这个方法this.resourceProperties.getStaticLocations()获取映射路径
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
registration.addResourceLocations(resource);
}
});
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
// 这个方法返回一个字符串数组,就是SpringBoot默认的静态资源的映射路径,只要访问 /** 就可以映射到上面数组中对应的静态资源路径
public String[] getStaticLocations() {
return this.staticLocations;
}
/META-INF/resources/
:在resources目录下可以再创建一个/META-INF/resources/文件夹,可以在这个文件夹下放静态资源。这个和webjars映射路径有点相似,就只少了一层webjars。/resources/
:在resources目录下可以再创建一个resources文件夹,可以在这个文件夹下放静态资源。/static/
:与上一样。/public/
:与上一样。
这四个静态资源的访问路径都是 http://localhost/1.js
,当访问 /**
这个路径时,会自动映射到这四个文件夹下。这四个默认的静态资源的映射路径都可以存放静态资源,但是它们之间存在优先级的先后的关系。优先级高的资源访问路径相同的资源会覆盖优先级低的相同资源。
/META-INF/resources/ -》/resources/ -》 /static/ -》 /public/
5.2、定义首页
直接阅读源码:
private Resource getWelcomePage() {
// 这里就是获取springboot默认的静态资源访问路径
for (String location : this.resourceProperties.getStaticLocations()) {
Resource indexHtml = getIndexHtml(location);
if (indexHtml != null) {
return indexHtml;
}
}
ServletContext servletContext = getServletContext();
if (servletContext != null) {
return getIndexHtml(new ServletContextResource(servletContext, SERVLET_LOCATION));
}
return null;
}
private Resource getIndexHtml(String location) {
return getIndexHtml(this.resourceLoader.getResource(location));
}
private Resource getIndexHtml(Resource location) {
try {
// 在默认的路径中是否存在index.html这个文件,如果存在就会映射到首页
Resource resource = location.createRelative("index.html");
if (resource.exists() && (resource.getURL() != null)) {
return resource;
}
}
catch (Exception ex) {
}
return null;
}
启动项目时如果没有定义一个首页,访问localhost:8080
会出现它默认的错误页面。定义一个首页只需要在静态文件夹(默认)下创建一个index.html
的页面就可以了,这个名称不能改变,这样访问 localhost:8080
就会直接跳到这个页面。
5.3、 thymeleaf 模板引擎
我们一般开发使用的是html页面,但是我们需要将他们转换成jsp页面,这样我们就可以将后台查询的数据在前端展示出来。jsp就是一个模板引擎,但是spring boot 推荐我们使用thymeleaf这个模板引擎。
在resources文件夹下的template文件夹就是放thymeleaf的模板引擎的,相当于是WEB-INF下的文件,不能直接访问,而是通过controller跳转进行访问。它给我们拼接了一个访问路劲:没有前缀,只有后缀 .html
,所以访问页面都是html页面,不能使用jsp页面。
- 导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
- 阅读源码
thymeleaf也存在一个自动装配类和一个配置类:
// 在这个配置类中,可以看出默认写了页面访问的前缀和后缀,前缀是 /templates/,后缀是.html
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
== templates
文件下的文件只能通过controller跳转访问,相当于是WEB-INF目录,上面的配置类相当于是一个视图解析器,通过视图解析器,跳转到对应的页面中。控制跳转的页面必须放在templates
目录下,并且必须是html
页面。==
- 在创建一个控制器跳转到模板引擎
@RequestMapping("/")
public String test(Model model){
model.addAttribute("msg","你好,Thymeleaf!");
return "index";
}
- 在template文件夹下创建一个index.html文件
<!DOCTYPE html>
<html lang="zh_CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text=${msg}></h1>
</body>
</html>
这样就可以通过controller跳转到首页,并且在首页显示后端传入的数据。
5.4、错误页面
在springboot中的错误页面很好配置,只需要在templates
的error
的文件下创建404.html
、500.html
等对应错误代码名称的页面,当发生错误时,对应就会跳转到对应的页面。
当发生对应的错误时,就会自动跳转到对应的页面中,页面的名称必须和错误代码一样。
6、Thymeleaf 基础语法
Thymeleaf官网:https://www.thymeleaf.org/
==HTML中的所有元素都可以使用thymeleaf模板引擎来代替。th:元素名
==
6.1、简单的表达式
- 简单表达式:
- 变量表达式:
${...}
:<h1 th:text="${msg}"></h1>
- 选择表达式:
*{...}
- 国际消息表达式:
#{...}
- URL 表达式:
@{...}
:<a th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a>
- 片段表达式:
~{...}
- 变量表达式:
- 字面量
- 文本字面量:
'one text'
,'Another one!'
,… :需要使用单引号 - 数字字面量:
0
,34
,3.0
,12.3
,… - 布尔字面量:
true
,false
- 空值字面量:
null
- 标识符字面量:
one
,sometext
,main
,…
- 文本字面量:
- 文本操作符:
- 字符串拼接:
+
- 字面替换:
|The name is ${name}|
:两个竖线不能省略。
- 字符串拼接:
- 算数运算符:
- 二元运算符:
+
,-
,*
,/
,%
- 一元运算符:
-
- 二元运算符:
- 布尔运算符:
- 二元运算符:
and
,or
- 一元运算符:
!
,not
- 二元运算符:
- 关系运算符:
- 比较:
>
,<
,>=
,<=
(gt
,lt
,ge
,le
) - 相等和不等:
==
,!=
(eq
,ne
)
- 比较:
- 条件操作符:
- 如果那么:
(if) ? (then)
: - If-then-else:
(if) ? (then) : (else)
:<p th:text="${msg}==99 ? '这个数等于99' : '这个数不等于99'"></p>
这个表达式很像三元运算符。 - 默认值:
(value) ?: (defaultvalue)
- 如果那么:
- 无操作表示:
- No-Operation:
_
- No-Operation:
6.2、遍历
使用 th:each
来进行遍历数据,对于java中的数组、顺序表、链表、Map等都可以遍历。
<ul>
<!-- users是后端的数据,user就是遍历出来的每一项-->
<li th:each="user : ${users}" th:text="${user}"></li>
</ul>
<tr th:each="prod : ${prods}">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
<tr th:each="prod : ${prods}">
<td th:text="*{name}">Onions</td>
<td th:text="*{price}">2.41</td>
<td th:text="*{inStock}? #{true} : #{false}">yes</td>
</tr>
这三种方式的遍历都可以。
迭代状态:
thymeleaf模板引擎的遍历提供了踪迭代状态的有用机制:状态变量。
- 当前迭代索引,从 0 开始。这是
index
属性。 - 当前迭代索引,从 1 开始。这是
count
属性。 - 迭代变量中的元素总数。这是
size
属性。 - 每次迭代的iter 变量。这是
current
属性。 - 当前迭代是偶数还是奇数。这些是
even/odd
布尔属性。 - 当前迭代是否是第一个。这是
first
布尔属性。 - 当前迭代是否是最后一次。这是
last
布尔属性。
<table>
<tr th:each="user,itemStat : ${users}">
<!-- 每一项的序号-->
<td th:text="${itemStat.count}"></td>
<!-- 每一项的值-->
<td th:text="${user}"></td>
<!-- 集合中的长度-->
<td th:text="${itemStat.size}"></td>
</tr>
</table>
6.3、条件判断语句
条件评估:
- 如果值不为空:(这些判断成立)
- 如果 value 是一个布尔值并且是
true
. - 如果 value 是一个数字并且不为零
- 如果 value 是一个字符且非零
- 如果 value 是 String 并且不是“false”、“off”或“no”
- 如果 value 不是布尔值、数字、字符或字符串。
- 如果 value 是一个布尔值并且是
- (如果值为 null,则 th:if 将评估为 false)。
th:if:如果条件成立就显示这个标签,如果不成立就不显示该标签。
<p th:if="${users}!=null">不为空</p>
th:unless:如果条件不成立才显示对应的标签,与 th:if
相反。
<p th:unless="${users}!=null">为空</p>
th:switch:与java中的switch类似。
<div th:switch="${user.role}">
<p th:case="'admin'">User is an administrator</p>
<p th:case="#{roles.manager}">User is a manager</p>
<p th:case="*">User is some other thing</p>
</div>
请注意,一旦一个th:case
属性被评估为true
,th:case
同一切换上下文中的所有其他属性都被评估为false
。默认选项指定为th:case="*"
:
6.4、thymeleaf 布局
th:insert
、th:replace
、th:include
,三个表示插入、替换和包含,可以将公共的页面抽出出来,然后实现页面部分的复用。
用法:
这三个标签和th:fragment
联合使用,使用th:fragment
定义一个id,然后使用上面的三个进行复用。
<!-- commons.html页面-->
<!-- th:fragment抽取为一个公共部分-->
<!--导航栏部分-->
<div th:fragment="nav">
这是导航栏
</div>
<!-- 在其他页面中引入公共部分-->
<!--导航栏公共-->
<!-- 第一个参数是公共页面的名称,如果存在路径,需要带有路径信息-->
<!-- 第二个参数是公共页面中的th:fragment="nav"设置的值-->
<div th:replace="~{commons :: nav}"></div>
上面三个的使用方式是一样的,一个是插入,相当于把公共部分添加一个div然后进行显示,一个是替换直接替换当前的元素。
7、国际化
-
编写国际化的配置文件
在resources目录下创建一个i18n的文件夹,下面创建
index.properties
,然后创建一个index_zh_CN.properties
,然后就会发现这两个文件合并成了一个文件,然后右键添加index_en_US.properties
文件,对应是默认显示、英文显示、中文显示。编写对应的文件,通过键值对的显示编写,也可以通过可视化的界面进行编写,可视化的编写需要下载一个插件
Resource Bundle Editor
,在文件的左下方有一个Resource Bundle
,点击就会进入可视界面的配置。 -
编写springboot的配置文件
在application.yaml
中编写
# message是国际化配置,basename是配置文件的位置和名称,i18n是文件夹名称,index是文件名称
spring:
messages:
basename: i18n.index
- thymeleaf 获取国际化文本
在前端页面名,通过 thymeleaf
的 #{ }
来获取国际化的默认文本。
<!-- login.title是在国际化配置文件中的键值对-->
<h2 class="text-center" th:text="#{login.title}">登录</h2>
- 编写国际化解析器
@Override
@Bean
@ConditionalOnMissingBean(name = DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)
public LocaleResolver localeResolver() {
// 如果用户配置了国际化,就是使用用户配置的
if (this.webProperties.getLocaleResolver() == WebProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.webProperties.getLocale());
}
// 如果没有配置,就是用默认的国际化配置
// AcceptHeaderLocaleResolver这个类实现了LocaleResolver接口,这就实现了国际化
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.webProperties.getLocale());
return localeResolver;
}
public Locale resolveLocale(HttpServletRequest request) {
// 获取默认的地区语言
Locale defaultLocale = this.getDefaultLocale();
// 解析请求,如果请求的语言为空,就是用默认的语言
if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
return defaultLocale;
} else {
// 如果不为空就是进行以下的操作
Locale requestLocale = request.getLocale();
List<Locale> supportedLocales = this.getSupportedLocales();
if (!supportedLocales.isEmpty() && !supportedLocales.contains(requestLocale)) {
Locale supportedLocale = this.findSupportedLocale(request, supportedLocales);
if (supportedLocale != null) {
return supportedLocale;
} else {
return defaultLocale != null ? defaultLocale : requestLocale;
}
} else {
return requestLocale;
}
}
}
上面是SpringBoot为我们已经编写好的语言解析器,我们需要自己自定义一个语言解析器。这个解析器需要实现LocaleResolver
,并重写其中的resolveLocale
方法。
public class MyLocaleResolver implements LocaleResolver {
// 重写的resolveLocale方法
@Override
public Locale resolveLocale(HttpServletRequest request) {
// 获取请求参数
String lang = request.getParameter("lang");
Locale locale = Locale.getDefault();
if (lang==null || "".equals(lang)){
return locale;
}
String[] temp = lang.split("-");
// 第一个参数是国家,第二个参数是地区
return new Locale(temp[0],temp[1]);
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
将我们自定义的语言解析器注入到spring容器中,交给springboot管理。在MvcConfig的配置文件中,使用@Bean
注解注入。
@Bean
public LocaleResolver localeResolver() {
return new MyLocaleResolver();
}
前端请求需要传入请求语言的参数,这样才能更改浏览器自带的语言请求参数。
<a th:href="@{/index.html(lang='zh-CN')}">中文</a>
<a th:href="@{/index.html(lang='en-US')}">English</a>
8、拦截器
- 编写一个拦截器
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Admin admin = (Admin) request.getSession().getAttribute("admin");
if (admin==null){
request.setAttribute("msg","您还未登录,请先登录!!!");
request.getRequestDispatcher("/login.html").forward(request,response);
return false;
}
return true;
}
}
- 将拦截器通过webmvcconfig的配置生效,写在配置类中。
@Override
public void addInterceptors(InterceptorRegistry registry) {
// new LoginInterceptor() 自己编写的拦截器
// addPathPatterns() 设置拦截的请求,可以设置多个,使用逗号隔开,也可以传入一个List集合
// excludePathPatterns() 配置不拦截的请求路径,也可以配置多个,一般会放行静态请求和登录请求
// 配置拦截器,拦截的请求和放行的请求
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/","/index.html","/login.html","/login","/assets/**");
}