Springboot

学习路线

image-20260128121047698

springboot简介

是什么

Spring是一个开源框架,2003 年兴起的一个轻量级的Java 开发框架 。

Spring是为了解决企业级应用开发的复杂性而创建的,简化开发。

啰嗦一点就是

Spring Boot 基于 Spring 开发,Spirng Boot 本身并不提供 Spring 框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于 Spring 框架的应用程序。也就是说,它并不是用来替代 Spring 的解决方案,而是和 Spring 框架紧密结合用于提升 Spring 开发者体验的工具。Spring Boot 以约定大于配置的核心思想,默认帮我们进行了很多设置,多数 Spring Boot 应用只需要很少的 Spring 配置。同时它集成了大量常用的第三方库配置(例如 Redis、MongoDB、Jpa、RabbitMQ、Quartz 等等),Spring Boot 应用中这些第三方库几乎可以零配置的开箱即用。

简单来说就是SpringBoot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包,spring boot整合了所有的框架

Spring是如何简化Java开发的

为了降低Java开发的复杂性,Spring采用了以下4种关键策略:

1、基于POJO的轻量级和最小侵入性编程,所有东西都是bean

POJO 就是 “普通的 Java 类” 像你自己画的一张白纸(POJO),没有被任何框架(比如 Spring、EJB)在上面印固定的格子、写固定 的要求;

“非 POJO” 就像学校发的答题卡,必须按固定格子填、必须用对应继承框架的类、实现框架的接口

Spring 里的 “bean”,本质就是把你写的 POJO 交给 Spring 容器管理而已,并没有改变这个类的本质。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 非POJO必须继承EJB的特定父类,否则根本用不了这个框架
// 这就是“高侵入性”:你的类被框架绑架了
public class UserService extends EJBObject {
// 必须实现EJB要求的方法,哪怕你根本用不上
@Override
public void ejbCreate() throws CreateException {
// 框架要求必须写,哪怕是空的
}

// 你的核心业务方法
public void addUser() {
System.out.println("添加用户");
}
}

这个类的问题:

  • 脱离 EJB 框架就废了 删掉 EJB 依赖,这个类会直接报错(因为继承了 EJBObject);
  • 你必须按框架的要求写代码(比如实现 ejbCreate 方法),哪怕这些代码和你的业务无关。

低侵入性

Spring 只是 “接管” 了你的 POJO 的创建、管理,没有要求你的类继承 / 实现任何 Spring 的类 / 接口;

你的业务代码(比如 addUser 方法)只关注自己的逻辑,没有任何框架强加的多余代码;

想脱离 Spring只需要去掉注解,手动 new 对象就行,代码不用改

把这个 POJO 变成 Spring 的 bean(只加 “标记”,不改类本身)

1
2
3
4
5
6
7
// 只加了@Service注解(标记),类本身还是原来的POJO,没有任何改动
@Service
public class UserService {
public void addUser() {
System.out.println("添加用户");
}
}
1
2
3
4
5
6
7
8
9
// 依然是POJO,只是加了一个@Service注解(相当于“告诉Spring:这个类你帮我管一下”)
// 注解只是“标记”,不是“绑定”,就算删掉注解,类本身完全能用
@Service
public class UserService {
// 你的核心业务方法(没有任何框架要求的多余代码)
public void addUser() {
System.out.println("添加用户");
}
}

差别就是

就算把 Spring 删掉,把 @Service 注解去掉,这个 UserService 类依然能正常用

2、通过IOC,依赖注入(DI)和面向接口实现松耦合;

耦合就是代码之间的 “绑定程度”:

  • 高耦合:A 类直接依赖 B 类的具体实现,改 B 就要改 A
  • 松耦合:A 类只依赖 B 类的 “规则(接口)”,不管 B 怎么改,只要遵守规则,A 就不用改

Spring 的 IOC+DI + 面向接口,就是把代码从 “专用接口” 改成 “通用接口”,实现松耦合

3、基于切面(AOP)和惯例进行声明式编程;

声明式编程的核心是 “用注解 / 配置声明要做什么,AOP 自动完成拦截”,这也是安全漏洞的高发区

切点是 “AOP 要拦截哪些方法” 的规则

通知是 “AOP 拦截方法后要做什么”,尤其是Around通知(可完全控制目标方法的执行)

切面是 “切点 + 通知” 的组合

4、通过切面和模版减少样式代码,RedisTemplate,xxxTemplate;

Template 类的本质:“封装了底层操作的工具类”

HelloWord

image-20260209130921560

idea可以直接很方便的去创建项目

完成了项目创建就会自动生成以下文件

1、程序的主启动类

2、一个 application.properties 配置文件

3、一个 测试类

4、一个 pom.xml

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>based1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>based1</name>
<description>based1</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

这个文件可以改端口

image-20260209132223664

运行原理

Spring Boot 之所以「开箱即用」,核心是做了三件事:

  1. 版本统一管理:通过父依赖固化所有组件的版本,避免版本冲突;
  2. 场景化启动器:把特定功能的所有依赖打包成「启动器」,一键导入;
  3. 自动配置:通过注解和配置文件,自动完成 Spring 繁琐的 XML/Java 配置,无需手动写。

pom.xml 父依赖

<parent> 节点是 Spring Boot 版本管理的核心

第一层

1
2
3
4
5
6
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.2</version>
<relativePath/>
</parent>

管理资源过滤(比如 .properties/.yml 文件的编码、加载规则);

管理构建插件(比如 spring-boot-maven-plugin 的默认配置);

第二层(Spring Boot 的版本控制中心)

1
2
3
4
5
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.6.2</version>
</parent>

它在 <dependencyManagement> 里定义了几乎所有 Spring 生态组件的版本(比如 Spring Core、Tomcat、MyBatis 等);

你项目中引入 spring-boot-starter-web 时不用写版本,就是因为这里已经定好了;

只有引入「不在这个清单里」的依赖(比如一些小众组件),才需要手动写版本号。

启动器spring-boot-starter

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

启动器:说白了就是SpringBoot的启动场景

比如spring-boot-starter-web,会帮我们自动导入web环境所有的依赖

springboot会将所有功能场景,都变成一个个的启动器

我们要是用什么功能,就需要找到一个个启动器就可以了

有官方文件可以看Spring Boot Reference Documentation

image-20260211080023645

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.example.based1;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

//标记这是Spring Boot应用的主类(复合注解,核心作用之前讲过)
@SpringBootApplication
// 标准main方法:Java程序的入口,JVM启动时执行
public class Based1Application {

public static void main(String[] args) {
SpringApplication.run(Based1Application.class, args);
}

}

META-INF/spring.factories:自动配置的核心文件

SpringBoot所有的自动配置,都在启动类中被扫描并加载:所有的自动配置类都在这里面,但是不一定生效,要判断条件是否成立,只要导入了对应的starter们就有对应的启动器了,有了启动器,我们的自动装配就会生效,然后就配置成功了

SpringBoot在启动的时候,从类路径下/META-INF/spring.factories获取指定的值
将这些自动配置的类导入容器,自动配置类就会生效,帮我们进行自动配置
以前我们需要自动配置的东西,现在不需要了
整合javaEE,解决方案和自动配置的东西都在Spring-boot-autoconfigure下
它会把所有需要导入的组件,以类名的方式返回这些组件,这些组件就会被添加到容器
容器中也会存在非常多的XXXAutoConfigure的文件(@Bean),就是这个类给容器导入了这个场景所需要的所有组件并自动配置

SpringApplication.run()

SpringApplication.run() 不是普通的 main 方法执行,而是把普通 Java 程序,通过「初始化准备 + 全流程启动」,变成一个能持续运行的 Spring Boot 应用(含 Web 服务)

主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行

SpringApplication
这个类主要做了以下四件事情:

1、推断应用的类型是普通的项目还是Web项目
2、查找并加载所有可用初始化器 , 设置到initializers属性中
3、找出所有的应用程序监听器,设置到listeners属性中
4、推断并设置main方法的定义类,找到运行的主类
img

yaml

这种语言以数据作为中心,而不是以标记语言为重点

传统xml配置:

1
2
3
<server>
<port>8081<port>
</server>

yaml配置:

1
2
server:
prot: 8080

yaml文件更强大的地方在于,他可以给我们的实体类直接注入匹配值

image-20260211085159250

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
# resources/application.yml
person:
name: xiaoqi
age: 13
happy: false
birth: 2009/01/15
maps: {k1: v1, k2: v2} # Map集合的简洁写法
lists: # List集合的标准写法
- code
- dog
dog: # 嵌套对象Dog
name: qq
age: 1

测试文件

image-20260211102257285

JSR303检验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
空检查 
@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=)]()]()

springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件

1
2
3
4
优先级1:项目路径下的config文件夹配置文件优先级
2:项目路径下配置文件优先级
3:资源路径下的config文件夹配置文件优先级
4:资源路径下配置文件

SpringBootWeb开发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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是将web前端资源(js,css等)打成jar包文件,然后借助Maven工具,以jar包形式对web前端资源进行统一依赖管理,保证这些Web资源版本唯一性。WebJars的jar包部署在Maven中央仓库上。

拿到静态资源的第一种方式

1
http://localhost:8080/webjars/github-com-jquery-jquery/3.4.1/jquery.js

使用/**/static或者/resources或者/public来访问静态资源

1
localhost:8080/**/

优先级:resources>static(默认)>puiblic

很少使用webjar

Thymeleaf模板引擎

模板引擎

前端交给我们的页面,是html页面。如果是我们以前开发,我们需要把他们转成jsp页面,jsp好处就是当我们查出一些数据转发到JSP页面以后,我们可以用jsp轻松实现数据的显示,及交互等。

jsp支持非常强大的功能,包括能写Java代码,但是呢,我们现在的这种情况,SpringBoot这个项目首先是以jar的方式,不是war,像第二,我们用的还是嵌入式的Tomcat,所以呢,他现在默认是不支持jsp的。

那不支持jsp,如果我们直接用纯静态页面的方式,那给我们开发会带来非常大的麻烦,那怎么办呢?

SpringBoot推荐你可以来使用模板引擎:

模板引擎,我们其实大家听到很多,其实jsp就是一个模板引擎,还有用的比较多的freemarker,包括SpringBoot给我们推荐的Thymeleaf,模板引擎有非常多,但再多的模板引擎,他们的思想都是一样的
image-20260211113312265

引入Thymeleaf

1
2
3
4
5
6
7
8
Thymeleaf 官网:https://www.thymeleaf.org/

Thymeleaf 在Github 的主页:https://github.com/thymeleaf/thymeleaf

Spring官方文档:找到我们对应的版本

https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#using-boot-starter

https://www.thymeleaf.org/

语法直接看官方 文档就可以了

Thymeleaf的自动配置类:ThymeleafProperties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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";
private boolean checkTemplate = true;
private boolean checkTemplateLocation = true;
private String prefix = "classpath:/templates/";
private String suffix = ".html";
private String mode = "HTML";
private Charset encoding;
}

我们只需要把我们的html页面放在类路径下的templates下,thymeleaf就可以帮我们自动渲染了。

使用thymeleaf什么都不需要配置,只需要将他放在指定的文件夹下即可!

修改SpringBoot的默认配置

SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(如果用户自己配置@bean),如果有就用用户配置的,如果没有就用自动配置的;

所有的WebMvcConfiguration都会被作用,不止Spring自己的配置类,我们自己的配置类当然也会被调用

整合JDBC

对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系型数据库),Spring Boot 底层都是采用 Spring Data 的方式进行统一处理。

Spring Boot 底层都是采用 Spring Data 的方式进行统一处理各种数据库,Spring Data 也是 Spring 中与 Spring Boot、Spring Cloud 等齐名的知名项目。

Sping Data 官网:https://spring.io/projects/spring-data

SpringBoot 整合 JDBC 核心是配置application.yml+ 引入spring-boot-starter-jdbc和 MySQL 驱动

数据源测试通过注入DataSource获取连接,验证配置是否正确;

JdbcTemplate 是 Spring 封装的 JDBC 工具,自动配置后可直接注入,通过update()做增删改,query()系列做查询;

数据源自动配置核心类是DataSourceAutoConfiguration,默认使用 HikariDataSource,可通过spring.datasource.type自定义。

SpringBoot 集成 Druid 数据源

集成 Druid 的核心价值:

  1. 替换默认数据源,使用阿里 Druid(更优的性能 + 监控能力);
  2. 配置 Druid 专属参数(如连接池大小、超时时间);
  3. 开启 Druid 的 Web 监控功能(查看 SQL 执行、连接池状态、防 SQL 注入等)。

引入 Druid 和 Log4j 依赖(pom.xml)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!-- Druid数据源依赖(阿里官方) -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.20</version> <!-- 稳定版,兼容SpringBoot 2.x/3.x -->
</dependency>

<!-- Log4j依赖(解决Druid监控的日志依赖) -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

<!-- 基础依赖(必须) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>

编写 Druid 专属配置(application.yml)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
spring:
datasource:
# 基础数据库配置
username: root
password: 123456
url: jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
# 1. 指定数据源类型为Druid(替换默认Hikari)
type: com.alibaba.druid.pool.DruidDataSource

# 2. Druid专属配置(SpringBoot默认不注入,需自定义配置类绑定)
druid:
# 连接池基础配置
initial-size: 5 # 初始化连接数
min-idle: 5 # 最小空闲连接数
max-active: 20 # 最大活跃连接数
max-wait: 60000 # 获取连接的最大等待时间(毫秒)
time-between-eviction-runs-millis: 60000 # 检测空闲连接的间隔时间
min-evictable-idle-time-millis: 300000 # 空闲连接的最小存活时间
validation-query: SELECT 1 FROM DUAL # 验证连接是否有效
test-while-idle: true # 空闲时检测连接有效性
test-on-borrow: false # 获取连接时不检测(提升性能)
test-on-return: false # 归还连接时不检测
pool-prepared-statements: true # 开启预编译语句池

# 3. 监控配置
filters: stat,wall,log4j # 开启监控(stat)、防SQL注入(wall)、日志(log4j)
max-pool-prepared-statement-per-connection-size: 20 # 预编译语句池大小
use-global-data-source-stat: true # 全局统计开关
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500 # 合并SQL统计、慢SQL阈值(500ms)

自定义 Druid 配置类(DruidConfig.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.example.springboot04date.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

// 标记为配置类,Spring启动时加载
@Configuration
public class DruidConfig {

// ========== 1. 配置Druid数据源(绑定yml中的druid配置) ==========
@Bean
// 绑定前缀:spring.datasource(包含基础配置+druid专属配置)
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druidDataSource() {
// 返回Druid数据源,替代SpringBoot默认的Hikari
return new DruidDataSource();
}

// ========== 2. 配置Druid监控Servlet(后台管理页面) ==========
// SpringBoot无web.xml,通过ServletRegistrationBean注册Servlet
@Bean
public ServletRegistrationBean<StatViewServlet> statViewServlet() {
// 注册StatViewServlet,映射路径:/druid/*(固定,访问该路径进入监控页面)
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(
new StatViewServlet(), "/druid/*"
);

// 配置监控页面的登录账号密码(key是固定的,不能改)
Map<String, String> initParams = new HashMap<>();
initParams.put("loginUsername", "admin"); // 登录用户名
initParams.put("loginPassword", "123456");// 登录密码
initParams.put("allow", ""); // 允许所有IP访问(空字符串=所有)
// initParams.put("deny", "192.168.1.100"); // 禁止指定IP访问(可选)

bean.setInitParameters(initParams); // 设置初始化参数
return bean;
}

// ========== 3. 配置Druid监控Filter(过滤请求,统计SQL执行) ==========
@Bean
public FilterRegistrationBean<WebStatFilter> webStatFilter() {
FilterRegistrationBean<WebStatFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(new WebStatFilter()); // 绑定Druid的WebStatFilter

// 配置过滤规则:排除静态资源和监控页面
Map<String, String> initParams = new HashMap<>();
// 排除的请求:js/css文件、druid监控页面
initParams.put("exclusions", "*.js,*.css,/druid/*");
bean.setInitParameters(initParams);

// 配置需要过滤的请求(所有请求)
bean.addUrlPatterns("/*");
return bean;
}
}

@ConfigurationProperties(prefix = "spring.datasource"):将 yml 中的数据源配置绑定到 DruidDataSource 对象;

StatViewServlet:提供 Druid 的 Web 监控页面(登录后可查看连接池、SQL 执行等);

WebStatFilter:过滤请求,统计所有 SQL 执行、请求耗时等数据。

编写测试类,检查数据源类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.example.springboot04date;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import javax.sql.DataSource;

@SpringBootTest
class DruidTest {

@Autowired
private DataSource dataSource;

@Test
void testDruidDataSource() {
// 打印数据源类型,验证是否为Druid
System.out.println("当前数据源类型:" + dataSource.getClass());
// 正确输出:class com.alibaba.druid.pool.DruidDataSource
}
}

SpringBoot 整合 MyBatis

通过 MyBatis 实现数据库的 CRUD 操作(替代之前的 JdbcTemplate)

核心是:

  1. 引入 MyBatis 的 SpringBoot Starter,简化配置;
  2. 通过@Mapper注解标识 Mapper 接口,让 MyBatis 扫描并生成代理实现类;
  3. 配置 MyBatis 的别名、Mapper.xml 路径,让 Spring 能识别映射文件;
  4. 注入 Mapper 接口,调用方法实现数据库 CRUD

官方文档:http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/

Maven仓库地址:Maven Repository: org.mybatis.spring.boot » mybatis-spring-boot-starter » 2.1.3

SpringSecurity 整合 SpringBoot

SpringSecurity 的核心是认证(Authentication)授权(Authorization)

  • 认证:验证用户身份(如用户名密码是否正确);
  • 授权:验证用户是否有访问某个资源的权限(如 vip1 只能访问 level1 页面);
  • 核心类:WebSecurityConfigurerAdapter(自定义安全策略)、AuthenticationManagerBuilder(自定义认证规则);
  • 核心注解:@EnableWebSecurity(开启 Web 安全模式)。

确保前端页面路径和 Controller 映射一致

比如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
src/main/resources/templates/
├── index.html # 首页
├── views/
│ ├── login.html # 自定义登录页
│ ├── level1/
│ │ ├── 1.html # vip1权限页面
│ │ ├── 2.html
│ │ └── 3.html
│ ├── level2/
│ │ ├── 1.html # vip2权限页面
│ │ ├── 2.html
│ │ └── 3.html
│ └── level3/
│ ├── 1.html # vip3权限页面
│ ├── 2.html
│ └── 3.html

Controller 层(RouterController.java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.xiaoqi.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class RouterController {
// 首页(所有人可访问)
@RequestMapping({"/","/index"})
public String index(){
return "index";
}

// 跳转到自定义登录页
@RequestMapping("/toLogin")
public String toLogin(){
return "views/login";
}

// vip1权限页面
@RequestMapping("/level1/{id}")
public String level1(@PathVariable("id") int id){
return "views/level1/" + id;
}

// vip2权限页面
@RequestMapping("/level2/{id}")
public String level2(@PathVariable("id") int id){
return "views/level2/" + id;
}

// vip3权限页面(原代码拼写错误:levle3 → level3)
@RequestMapping("/level3/{id}")
public String level3(@PathVariable("id") int id){
return "views/level3/" + id;
}
}

核心配置类(SecurityConfig.java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.xiaoqi.config;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

// 开启WebSecurity模式,加载自定义安全配置
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

// ========== 1. 授权规则配置(哪些URL需要哪些权限) ==========
@Override
protected void configure(HttpSecurity http) throws Exception {
// 授权规则:链式编程
http.authorizeHttpRequests()
.antMatchers("/", "/index").permitAll() // 首页所有人可访问
.antMatchers("/level1/**").hasRole("vip1") // level1/**需要vip1角色
.antMatchers("/level2/**").hasRole("vip2") // level2/**需要vip2角色
.antMatchers("/level3/**").hasRole("vip3") // level3/**需要vip3角色
.anyRequest().authenticated(); // 其他所有请求都需要认证(登录)

// ========== 2. 自定义登录配置 ==========
http.formLogin()
.loginPage("/toLogin") // 自定义登录页路径(对应Controller的/toLogin)
.loginProcessingUrl("/login") // 登录表单提交的URL(SpringSecurity自动处理,无需写Controller)
.usernameParameter("username") // 登录表单的用户名参数名(需和login.html的input name一致)
.passwordParameter("password") // 登录表单的密码参数名
.defaultSuccessUrl("/index"); // 登录成功后跳转的页面

// ========== 3. 注销配置 ==========
http.logout()
.logoutUrl("/logout") // 注销请求URL(默认就是/logout)
.logoutSuccessUrl("/index") // 注销成功后跳转首页
.invalidateHttpSession(true); // 注销时销毁session

// ========== 4. 记住我功能 ==========
http.rememberMe()
.rememberMeParameter("remember") // 登录表单的“记住我”参数名(需和login.html的input name一致)
.tokenValiditySeconds(60*60*24*7); // 记住我有效期:7天(默认2周)

// ========== 5. 关闭CSRF(开发环境简化,生产环境需开启) ==========
http.csrf().disable();
}

// ========== 2. 认证规则配置(用户、密码、角色) ==========
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 基于内存的认证(生产环境需替换为数据库认证)
auth.inMemoryAuthentication()
.passwordEncoder(new BCryptPasswordEncoder()) // 密码加密(SpringSecurity5必须配置)
// 用户1:xiaoqi,密码123456,角色vip2、vip3
.withUser("xiaoqi")
.password(new BCryptPasswordEncoder().encode("123456"))
.roles("vip2", "vip3")
.and()
// 用户2:root,密码123456,角色vip1、vip2、vip3
.withUser("root")
.password(new BCryptPasswordEncoder().encode("123456"))
.roles("vip1", "vip2", "vip3")
.and()
// 用户3:guest,密码123456,角色vip1
.withUser("guest")
.password(new BCryptPasswordEncoder().encode("123456"))
.roles("vip1");
}
}

之后就是前端页面配置

SpringBoot集成Swagger

SpringBoot集成Swagger => springfox,两个jar包

  • Springfox-swagger2
  • swagger-springmvc