参考文献:狂神:https://www.cnblogs.com/yaolicheng/p/13689796.html
SpringBoot学习笔记
原理初探
核心:
- xxxxAutoConfiguration向容器中自动配置组件
- xxxxProperties:自动配置类,装配配置文件中自定义的一些内容
自动装配
pom.xml
- spring-boot-dependencies:核心依赖在父工程中
- 我们再写或者引入SpringBoot依赖可以不用写版本号,因为有这些版本仓库
- 启动器:SpringBoot的启动场景
<!--启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<!-- <artifactId>spring-boot-starter-XXXXXX</artifactId>-->
</dependency>
- 比如说spring-boot-starter-web,他就会帮助自动导入web环境所有的依赖!
- SpringBoot会将所有的功能功能场景,都变成一个个的启动器
- 如果要使用什么功能,只需要找到对应的启动器就可以了
主程序
@SpringBootApplication
注解标注这是一个Spring Boot的应用;启动类下的所有资源被导入
//@SpringBootApplication```注解标注这是一个Spring Boot的应用
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
// 将SpringBoot应用启动
//开启了一个服务,(参数:应用入口的类,命令行参数)
SpringApplication.run(SpringbootApplication.class, args);
}
}
- 注解
- @SpringBootConfiguration:springBoot的配置
- @Configuration:Spring配置类
- @Component:说明这也是一个组件
- @EnableAutoConfiguration:自动配置
- @AutoConfigurationPackage:自动配置包
- @Import({Registrar.class}):自动配置包‘包注册’
- @Import({AutoConfigurationImportSelector.class}):自动配置导入选择
- List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);:获取所有的配置
- 核心方法(获取候选的配置)
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct."); return configurations; } protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }
SpringBoot所有自动配置都是在启动的时候扫描并加载,所有的自动配置类都在spring.factories文件里面,但是不一定生效,要判断条件是否生效。
只要导入对应的start,就有对应的启动器了,有了启动器,自动装配就会生效,然后配置成功。
- 启动方法SpringApplication.run(SpringbootApplication.class, args);
- 推断应用的类型是普通项目还是web项目
- 查找并加载所有可用初始化器,设置到initializers属性中
- 找出所有应用程序监听器,设置到listeners属性中
- 推断并设置main方法的定义类,找到运行的主类
配置文件
SpringBoot使用一个全局的配置文件,配置文件名称是固定的
- application.properties
- 语法结构:key=value
- application.yaml
- 语法结构:key:空格value
配置文件的作用:修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们配置好了。
yaml可以注入到我们的配置类中,可以直接给实体类赋值
yaml语法
对空格的要求极高
# 普通的key-value
name: yhb
# 对象
student:
name: yhb
age: 13
# 行内写法
student1: {name: yhb,age: 52}
# 数组
pets:
- cat
- dog
- pig
# 行内写法
pets2: [cat,dog,pig]
直接给实体类赋值 例:
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
public class Dog {
private String name;
private String age;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
//和application.yaml当中的personal配对
@ConfigurationProperties(prefix = "personal")
public class Personal {
private String name;
private Integer age;
private Boolean happy;
private Date brith;
private Map<String,Object> maps;
private List<String> list;
private Dog dog;
}
personal:
name: yhb${random.uuid} #获取UUID
age: ${random.int} #随机值
happy: true
brith: 2015/06/3
maps: {a1: b1,a2: b2}
list: [c1,c2,c3]
dog:
name: ${personal.name:ppp}_asd
#三目运算符personal.name有值为personal.name值,
#无值为ppp
age: 3
@SpringBootTest
class SpringBootDom1ApplicationTests {
@Autowired
Personal personal;
@Test
void contextLoads() {
System.out.println(personal);
}
}
/*结果:Personal(name=yhb0f18fbc8-f83f-4ba9-b03f-64bd6a928c60,
age=217018,
happy=true,
brith=Wed Jun 03 00:00:00 CST 2015,
maps={a1=b1, a2=b2},
list=[c1, c2, c3],
dog=Dog(name=yhbccedc12f-2c3a-42cc-b491-9534abb0a760_asd, age=3))
*/
- yaml支持松散绑定:比如
last-name: iop
private String lastName;
也可以进行匹配lastName=“iop”,-后的第一个字母默认大写
- JSR303校验:JSR 303 用于对 Java Bean 中的字段的值进行验证。
SpringBoot 2.3.0版本之后就没有引入validation对应的包,需要手动导入
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.5.4</version>
</dependency>
使用时需要在类上添加@Validated
校验数据
发属性上使用如下注解👇
空检查
@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 对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式,regexp:正则表达式 flags: 指定 Pattern.Flag 的数组,表示正则表达式的相关选项。数值检查
建议使用在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=) 被指定的元素必须在合适的范围内
@Range(min=10000,max=50000,message=”range.bean.wage”)
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
@CreditCardNumber信用卡验证
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=,host=, port=,regexp=, flags=)
- 配置文件可以存放的位置
- 项目根目录下的config目录下:优先级第一
- 项目的根目录下:优先级第二
- classparh路劲下的config目录下:优先级第三
- classpath路径下 :优先级第四
- 多环境测试
server:
port: 8085
spring:
profiles:
active: test
#spring:
# profiles:
##(假设同时存在application-dev.yaml与application-test.yaml等多套环境时)
# active: test #(只需要写-后面的名字)
# 使用---分割多环境
---
server:
port: 8082 # 端口号
spring:
config:
activate:
on-profile: dev # 环境名
---
server:
port: 8082
spring:
config:
activate:
on-profile: test
(核心)配置文件与spring.factories文件的联系
- SpringBoot启动会加载大量的自动配置类
- 我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类中
- 再看配置类中配置了那些组件
- 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性,我们只要在配置文件中指定这些属性的值即可;
- XXXXAutoConfiguration:自动配置类;给容器添加组件
- XXXXProperties:封装配置文件当中的相关属性(yaml文件)
注:使用deubg: true
观察那些配置没有生效(输出日志文件)
静态资源存放位置
- webjars loacalhost:8080/webjars/…
- resources下的public ,static,/**,resources localhost:8080/…
- 在templates目录下的所有页面,只能通过controller来跳转(相当于SpringMVC的WEB-INF)
优先级:resources>static(默认)>public
首页只需要在静态资源目录下存放index.html页面即可
Thymeleaf语法
使用Thymeleaf需要先导入依赖
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
MVC配置
interface ViewResolver 实现了视图解析器接口的类,我们就可以把他看着做视图解析器。
拦截器的添加
编写一个LoginInterceptors
类实现 HandlerInterceptor
接口
//可以自己扩展MVC
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//当URL走到/时跳转到index.html
registry.addViewController("/").setViewName("index");
//当URL走到/index.html时走到index.html
registry.addViewController("/templates/index.html").setViewName("index");
}
//相当于SpringMVC当中的xml配置拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptors()).//添加拦截器
addPathPatterns("\**"). //拦截那些请求
excludePathPatterns("index.html"); //那些请求不拦截
}
}
404或500等等错误码
在templates下建立一个error的目录,在该目录下直接新建404.html或500.html等等页面即可
SpringBoot与JDBC
需要daoru依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
编写yaml配置文件
spring:
datasource:
username:
password:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/text?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8
通过DataSource获取数据库的连接信息
@Autowired
DataSource dataSource;//查询数据库的连接信息
@Test
void contextLoads() {
try {
System.out.println(dataSource.getConnection());
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
增删改查
//查询
@Autowired
JdbcTemplate jdbcTemplate;//获取JdbcTemplate对象
@Test
public void UserList(){
String sql="select * from text";
List<Map<String,Object>> list_maps=jdbcTemplate.queryForList(sql);
for (Map<String,Object> map:list_maps) {
System.out.println(map);
}
}
//增删改类似,会自动提交事务
@Autowired
JdbcTemplate jdbcTemplate;//获取JdbcTemplate对象
@Test
public void AddList(){
String sql="insert into text(50,'qweasasa')";
jdbcTemplate.update(sql);
}
整合Druid数据源
导入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
切换类型
spring:
datasource:
username:
password:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/text?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8
type: com.alibaba.druid.pool.DruidDataSource
SpringBoot整合Mybatis
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
编写POJO
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Text {
private int id;
private String name;
}
编写接口
@Mapper//表示了这是一个Mybatis的Mapper类
@Repository
public interface TextMapper {
List<Text> queryText();
Text queryTextByID(int id);
int setName(int id);
}
编写Mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yhb.springboot.Mapper.TextMapper">
<select id="queryText" resultType="Text">
select * from text;
</select>
</mapper>
编写配置文件
spring:
datasource:
username:
password:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/text?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8
mybatis:
type-aliases-package: com.yhb.springboot.POJO
mapper-locations: [classpath:Mybatis/Mapper/*]
测试
@Autowired
private TextMapper textMapper;
@Test
void contextLoads() {
List<Text> texts=textMapper.queryText();
for (Text text : texts) {
System.out.println(text.toString());
}
}
SpringSecurity(安全)
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
编写方法实现
//添加注解并继承WebSecurityConfigurerAdapter
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//重写授权方法,
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll()//首页所有人都可以访问
.antMatchers("/level1").hasRole("vip1")//level1页只有vip1可以访问
.antMatchers("/level2").hasRole("vip2")
.antMatchers("/level3").hasRole("vip3");
http.formLogin();//如果没有登录就跳转到Loging页(自带)
http.logout();//开启了注销功能
http.rememberMe();//cookie实现自动登录
}
//重写认证的方法
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在磁盘中设置虚拟数据
auth.inMemoryAuthentication()
.withUser("123").password("123").roles("vip1");
}
}
异步任务
- 在主方法所在的类上开启异步任务的注解
@EnableAsync //开启异步任务的注解
- 在某个方法上添加
@Async
告诉SpringBoot这是一个异步的任务
@Async //类似于多线程
例:
public class Mycontroller {
@Async
public String level1(){
return "level1";
}
}
@EnableAsync //开启异步任务的注解
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
// 将SpringBoot应用启动
SpringApplication.run(SpringbootApplication.class, args);
}
}
定时任务
SpringBoot已经集成的最主要的两个方法用于定时任务
TaskScheduler 任务调度者(源码)
TaskExecutor 任务执行者(源码)
@EnableScheduling 开启定时功能的注解
@Scheduled 表示什么时候执行
cron 表达式
@EnableScheduling
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
// 将SpringBoot应用启动
SpringApplication.run(SpringbootApplication.class, args);
}
}
public class Mycontroller {
@Scheduled(cron = "* * * * *")//自行百度cron表达式(有在线生成工具)
public String level1(){
return "level1";
}
}