# springboot-study
**Repository Path**: ChengSongyun/springboot-study
## Basic Information
- **Project Name**: springboot-study
- **Description**: 关于Spring Boot的相关课堂学习以及案例
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-09-18
- **Last Updated**: 2025-10-21
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Spring Boot
> springboot有三个主要的特点:自动配置,起步依赖,嵌入式服务器
>
> - 自动配置:Spring Boot根据类路径中的依赖、配置文件和其他条件,自动为应用添加必要的配置和Bean,无需手动编写xml或配置类
> - 起步依赖:起步依赖是一组预定义的Maven依赖集合,将某一功能所需的所有相关库打包在一起,只需引入一个起步依赖,即可获得该功能的全部依赖,无需手动导入大量依赖
> - 嵌入式服务器:Spring Boot内嵌Tomcat、Jetty、Undertow,无需将项目单独部署到外部服务器
>
>
## 一、创建Spring Boot项目

注意:我们除了在IDEA中创建Spring Boot外,还可以在https://start.spring.io/网址中创建项目,实际上IDEA就是访问该网址进行创建项目的,所以我们需要保持网络的通畅

我们可以进行下一步选择自己需要的起步依赖,然后点击create即可创建SpringBoot项目
## 二、pom配置文件
> 接下来对初始的pom.xml配置文件进行详细解释
```xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.5.5
top.csy8888
ch01
0.0.1-SNAPSHOT
ch01
ch01
21
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
```
## 三、核心启动类
> SpringBoot的核心启动类在项目创建时会自动创建,使用@SpringBootApplication注解标注
>
> 启动类的名称有项目名+Application组成
>
> springboot默认的扫描路径是从当前启动类所在的包开始扫描(包含所有子包)
>
> 也可以通过scanBasePackages属性重新指定扫描的包路径(不建议修改)
```java
package top.csy8888.ch01;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import top.csy8888.ch01.service.UserService;
/**
* springboot应用的核心启动类(springboot应用时通过main方法直接启动)
* 这个类上包含一个@SpringBootApplication注解,它是一个复合注解
* 这个注解又包含了@Configuration,@ComponentScan,@EnableAutoConfiguration
* 因此,这个启动类既是一个启动类同时也是一个spring的配置类
* 还具备扫描的功能以及启用自动配置的功能
*
* 注意:springboot默认的扫描路径是从当前启动类所在的包开始扫描(包含所有子包)
* 也可以通过scanBasePackages属性重新指定扫描的包路径(不建议修改)
*
* @EnableAutoConfiguration注解时启用springboot的自动配置功能,
* 它的作用是通过一个导入选择器将所有自动配置类加载到spring容器中
* 完成自动化装配
*/
//@SpringBootApplication(scanBasePackages = "")
@SpringBootApplication
public class Ch01Application {
public static void main(String[] args) {
//运行springboot应用,run方法运行完成后会返回一个初始化好的IOC容器
//注意:这个IOC容器会根据当前部署环境而改变
//在没有集成web环境时初始化的就是一个普通的IOC容器
//如果集成了web,那么初始化的就是一个WebApplicationContext
ApplicationContext context = SpringApplication.run(Ch01Application.class, args);
//获取bean
UserService service = context.getBean(UserService.class);
System.out.println(service);
}
}
```
## 四、yml配置文件
> properties配置文件的层级不突出,并且会有重复代码,yml的层级清晰,减少重复代码等
### 1、语法
> 1. 属性节点之间使用换行缩进(缩进使用空格)
> 2. 节点赋值的时候冒号后面必须加上空格
>
> 注意:yml值允许空格缩进,不支持tab(IDEA在yml文件中会自动将tab转换为空格)
#### 1.基础语法
> 在这里student代表一个Student对象,userId、userName、age都是其下的属性
```yaml
student:
userId: 1001
userName: User1
age: 21
```
#### 2.子对象
> student属性下的card对象下的cardNum属性
>
> 每换行并缩进一次代表一个对象,直至最后一个才是属性值
```yaml
student:
#private Card card;
card:
cardNum: 362330200602156598
```
#### 3.数组
> 绑定数组的方式同样适用于list和set集合(两种方式):
>
> - 使用逗号分隔
> - 使用换行加”-"线
方式一:使用逗号分隔(不推荐)
```yaml
student:
#private String[] phones;
phones: 14568945683,13765214568
```
方式二:使用换行加”-"线
```yaml
student:
#private String[] phones;
phones:
- 14568945683
- 13765214568
```
#### 4.Map集合
> 对于Map集合使用的是键值对的方式进行绑定
```yaml
student:
#private Map score;
score:
chinese: 90
english: 99
```
#### 5.List集合+对象
> 当我们的属性是集合并且所指定的对象有对个属性时,我们需要回车+缩进指定属性值
```yaml
student:
#private List teachers;
teachers:
- name: Mr.Wang
age: 40
- name: Mr.Cheng
age: 39
```
### 2、数据绑定
> 将yml中配置的具体的值绑定到某个Java对象中
#### 1.基础数据绑定
> 基础的数据绑定我们使用@Value+SPEL表达式来绑定yml的属性名即可
```yaml
student:
userId: 1001
userName: user1
age: 21
```
```java
package top.csy8888.ch03.entity;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
/**
* @author CSY
* @date 2025 - 09 - 11
*
* Spring Boot默认会读取application.properties或者application.yml文件
* 读取的内容通常会绑定到具体的某个Java对象中,用于后续的解析和配置
*
* 方式一:使用@Value注解来实现属性的绑定(固定值的属性绑定)
* @Value注解使用SPEL表达式绑定yml的属性名
*/
@Component
@Data
public class Student {
@Value("${student.userId}")
private Integer userId;
@Value("${student.userName}")
private String userName;
@Value("${student.age}")
private Integer age;
}
```
#### 2.复杂数据绑定(松散绑定)
> 对于复杂的数据绑定,@Value注解就不够用了,我们需要在类上标注@ConfigurationProperties注解来实现松散绑定
>
> 松散绑定:只需要绑定属性名的前缀即可,绑定的Java类属性名不需要精准匹配,在yml中可以根据约定使用驼峰模式(如:userName)、“-”线(如:user-name)或者全大写+下划线(如:USER_NAME)
```yaml
#1、值绑定:将yml中配置的具体的值绑定到某个Java对象中
student:
userId: 1001
userName: user1
age: 21
#绑定子对象
card:
cardNum: 362330200602156598
#绑定集合(适用于数组、list、set集合):两种方式
#方式一:使用逗号分隔
# phones: 14568945683,13765214568
#方式二:使用换行加“-”线
phones:
- 14568945683
- 13765214568
#绑定Map集合
score:
chinese: 90
english: 99
#绑定复杂类型
teachers:
- name: Mr.Wang
age: 40
- name: Mr.Zhang
age: 38
#保持彩色日志
spring:
output:
ansi:
enabled: always
```
```java
package top.csy8888.ch03.entity;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
/**
* @author CSY
* @date 2025 - 09 - 11
*
* Spring Boot默认会读取application.properties或者application.yml文件
* 读取的内容通常会绑定到具体的某个Java对象中,用于后续的解析和配置
*
* 方式二:使用@ConfigurationProperties注解实现松散绑定
* 松散绑定只需要绑定属性名的前缀即可,绑定的Java类属性名不需要精确匹配,在yml中
* 可以根据约定使用驼峰模式(如:userName)、“-”线(如:user-name)或者是
* 全大写加下划线(如:USER_NAME)进行绑定
*/
@Component
@Data
@ConfigurationProperties(prefix = "student")
public class Student {
private Integer userId;
private String userName;
private Integer age;
private Card card;
private String[] phones;
private Map score;
private List teachers;
}
```
```java
package top.csy8888.ch03.entity;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
/**
* @author CSY
* @date 2025 - 09 - 11
*/
@Data
public class Card {
//无法绑定值
//@Value("${student.card.cardNum}")
private String cardNum;
}
```
```java
package top.csy8888.ch03.entity;
import lombok.Data;
/**
* @author CSY
* @date 2025 - 09 - 11
*/
@Data
public class Teacher {
private String name;
private int age;
}
```
```java
package top.csy8888.ch03;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import top.csy8888.ch03.entity.Student;
@SpringBootTest
@Slf4j
class Ch03ApplicationTests {
@Autowired
private Student student;
@Test
void testValue() {
log.info("userId: {}",student.getUserId());
log.info("userName: {}",student.getUserName());
log.info("age: {}",student.getAge());
log.info("cardNum: {}",student.getCard().getCardNum());
log.info("phone:{},{}",student.getPhones()[0],student.getPhones()[1]);
student.getScore().forEach((key,value) -> {log.info("{}:{}",key,value);});
student.getTeachers().forEach(teacher -> {log.info("{}:{}",teacher.getName(),teacher.getAge());});
}
}
```
### 3、多环境配置
> 当我们需要在不同的环境采用不同的配置时,就可以使用多环境配置
>
> 比如说在测试环境下只要配置10个数据库的最大连接数,而在开发环境则要配置100个最大连接数
>
> 将不同环境的配置分别放在不同的yml配置中
>
> 多个文件应该遵循application-xxx的命名约定
>
> 主配置文件用于激活指定环境的配置
application-test.yml
```yaml
#测试环境的所有配置示例
spring:
datasource:
driver-class-name: xxx
url: xxx
username: root
password: root
#连接池
hikari:
minimum-idle: 5
maximum-pool-size: 10
```
application-dev.yml
```yaml
#开发环境的所有配置
spring:
datasource:
driver-class-name: aaa
url: aaa
username: root
password: root
#连接池
hikari:
minimum-idle: 10
maximum-pool-size: 100
```
application.yml
```yaml
#多环境配置
#多环境配置有两种方式,一种实在一个yml中配置不同环境的配置
#另一种是将不同环境的配置分别放在不同的yml配置中
#多个文件应该遵循application-xxx的命名约定
#在主配置文件中激活某一套环境配置
#激活时只需要配置-xxx的名称即可
spring:
profiles:
#激活配置
active: test
```
### 4、模块化配置
> 我们可以像spring的配置类一样,将mysql和web等的配置分为多个配置类一样,将yml配置文件创建多个来存储配置信息,用一个主配置文件来包含其他的yml配置文件
>
> 其他模块的配置文件命名规范:application-xxx.yml
application-web.yml
```yaml
server:
port: 8080
servlet:
context-path: /
encoding:
charset: UTF-8
```
application-dao.yml
```yaml
#持久层配置(数据源、连接池、mybatis)
spring:
datasource:
driver-class-name: aaa
url: aaa
username: root
password: root
#连接池
hikari:
minimum-idle: 10
maximum-pool-size: 20
```
application.yml
```yaml
#主配置文件,用来包含其他模块的yml配置
spring:
profies:
include: web,dao
```
### 5、数据库配置
> 当我们需要连接数据库时,我们需要配置一些数据库的相关配置,使我们能够连接到数据库,还可以配置连接池
#### 1.配置连接属性
> 连接属性极其重要,它关乎着我们能否成功连接到数据库
```yaml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3307/city?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
```
#### 2.配置连接池
> 配置数据库连接池管理数据库连接,我们可以使用springboot自带的Hikari连接池,也可以引入Druid的依赖来使用Druid连接池
##### 配置Hikari连接池
> 使用该连接池不需要引入任何依赖,直接配置即可
```yaml
spring:
datasource:
hikari:
#配置最小空闲连接数
minimum-idle: 5
#允许的最大连接数
maximum-pool-size: 200
#最大空闲时长
idle-timeout: 90000
#获取连接的超时时间
connection-timeout: 5000
#检查连接是否有效
connection-test-query: select 1
```
##### 配置Druid连接池
> 我们想要使用Druid连接池,首先需要引入Druid的springboot依赖
```xml
com.alibaba
druid-spring-boot-starter
1.2.27
```
> 在yml中配置时需要配置type为com.alibaba.druid.pool.DruidDataSource
```yaml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
#配置Druid连接池
druid:
#最大连接数
max-active: 200
#最小空闲连接
min-idle: 5
#初始化连接池大小
initial-size: 5
#获取连接的最大等待时间
max-wait: 5000
#检查连接是否有效
validation-query: select 1
#是否缓存PreparedStatement
pool-prepared-statements: false
```
### 6、Mybatis和分页配置
> 配置mybatis和分页配置之前我们需要将数据库的连接配置好
#### 1.Mybatis配置
> mybatis的级层和spring的一样
```yaml
mybatis:
# 扫描实体所在的包
type-aliases-package: top.csy8888.ch05.entity
# mapper映射路径
mapper-locations: classpath:/mappers/*.xml
# 输出sql日志
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
```
#### 2.分页插件配置
> 配置分页插件,这样我们在写sql语句的时候就不需要添加limit
```yaml
pagehelper:
# 指定数据库方言
helper-dialect: mysql
#分页合理化
reasonable: true
#启用注解分页参数
support-methods-arguments: true
```
### 7、内嵌容器配置
> Spring Boot支持三种内嵌容器(Tomecat、Jetty、Undertow)
>
> 我们可以在yml配置中更改端口号、错误页面配置等
1. 更改内嵌容器
> 我们更改内嵌容器需要将springboot起步依赖中的tomcat依赖排除
>
> 然后在后面引入想要用的内嵌容器依赖
```xml
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-tomcat
org.springframework.boot
spring-boot-starter-jetty
```
2. 内嵌容器配置
> 优雅停机:在停机时等待指定时间再停机
>
> 需要在内嵌容器和mvc配置中同时配置
```yaml
server:
# 修改端口号
port: 8081
# springboot2.3提供的特性:优雅停机
shutdown: graceful
# 配置访问项目的上下文路径
servlet:
context-path: /
# 配置字符编码过滤器
encoding:
enabled: true
charset: UTF-8
force: true
# 错误页面配置
error:
# 是否启用springboot提供的白色错误页面
# 白色错误页面:springboot自带的报错页面
whitelabel:
enabled: true
```
### 8、Mvc配置
> 进行Mvc配置:静态资源、视图解析器等
>
> 注意:springboot默认就启用了静态资源处理器,只需要将静态资源
> 存放在约定的目录中即可(public、resources、static)
```yaml
# springboot默认就启用了静态资源处理器,只需要将静态资源
# 存放在约定的目录中即可(public、resources、static)
# 也可以自定义静态资源目录
spring:
lifecycle:
# 设置优雅停机的缓冲时间,这里设置为30秒
# 也就是在停机时先等待30秒,给其他线程执行为完成的任务
# 超时后不管是否执行完都会执行停机
timeout-per-shutdown-phase: 30s
# 手动配置静态资源处理
web:
resources:
# 逗号隔开指定多个
static-locations: classpath:my,classpath:static,classpath:resource,classpath:public
#视图解析器配置
mvc:
view:
prefix: /WEB-INF/jsp
suffix: .jsp
# jackson配置
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
# 启用你文件上传配置
servlet:
multipart:
enabled: true
max-file-size: 50MB
max-request-size: 800MB
```
## 五、过滤链执行顺序
> 当我们有多个过滤器时,我们需要将它们形成一个过滤链来一个一个执行
>
> 方式一:使用@ServletComponentScan注解:该注解是springboot提供的专门用于扫描servlet组件(Servlet、Filter、Listener),但是这种扫描有一个缺点:当有多个过滤器形成过滤链的时候,无法按照指定的顺序来执行
>
> 方式二:使用springboot提供的动态注册器(RegistrationBean)来注册servlet组件,有点是可以控制过滤链的执行顺序,有三种动态注册器分别注册Servlet(ServletRegistrationBean)、Filter(FilterRegistrationBean)、Listener(ServletListenerRegistrationBean)
### 方式一:@ServletComponentScan
```java
@Configuration
@ServletComponentScan(basePackages = "top.csy8888.ch06.filter")
public class MvcConfig{}
```
### 方式二:动态注册器(RegistrationBean)
```java
@Configuration
public class MvcConfig{
@Bean
public FilterRegistrationBean TestFilter(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
//装配过滤器
filterRegistrationBean.setFilter(new TestFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setName("testFilter");
//设置优先级别 - 数值越小,优先级越高
filterRegistrationBean.setOrder(1);
return filterRegistrationBean;
}
@Bean
public FilterRegistrationBean MyFilter(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
//装配过滤器
filterRegistrationBean.setFilter(new MyFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setName("myFilter");
//设置优先级别 - 数值越小,优先级越高
filterRegistrationBean.setOrder(2);
return filterRegistrationBean;
}
}
```
## 六、手动配置自动配置类
> 当我们导入不同工具的starter的依赖时,并不是没有了配置类,而是starter依赖帮我创建好了配置类,我们只需在yml中修改配置属性即可
>
> 关于自动配置的一些注解可以看ch07文件下的**自动配置.md**文件
>
> **注意:**
>
> 1. 项目的命名规范为 :**工具名-spring-boot-starter**,因为我们是第三方自动配置依赖
> 2. 创建项目后我们需要创建指定规则的包:**组织.工具名.spring.boot.autoconfigure(org.c3p0.spring.boot.autoconfigure)**
> 3. **必须有xxxAutoConfigure类**
> 4. **必须有xxxProperties类**,且该类必须在**autoconfigure.properties包**下
> 5. 在resources静态资源包下**必须有META-INF.spring包**
> 6. 在META-INF.spring包下**必须有org.springframework.boot.autoconfigure.AutoConfiguration.imports文件**
接下来我来逐个解说这些包和类的作用及用法 - 以c3p0连接池为例
### 1、创建java项目
> 我需要创建一个java项目来作为starter依赖 - c3p0-spring-boot-starter
>

选择java项目->项目名符合规范->选择项目管理工具(Maven)->选择jdk版本
### 2、编写C3p0DataSourceAutoConfigure类
> 用于实现自动配置逻辑核心功能:
>
> - 条件装配:通过@Conditional系列注解(如@ConditionalOnClass等)判断是否满足配置条件
> - Bean定义:在满足条件时,向Spring容器中注册相关的Bean
> - 属性绑定:通过@EnableConfigurationProperties关联配置属性类,实现外部化配置
> - 依赖管理:处理Bean之间的依赖关系,确保配置的完整性
>
> 注意:以下代码纯手打,可能会有错误,需以IDEA的提示为主
```java
@Configuration
@ConditionalOnClass(ComboPooledDataSource.class)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties({DataSourceProperties.class,C3p0DataSourceProperties.class})
public class C2p0DataSourceAutoConfigure{
@Autowired
private C3p0DataSourceProperties properties;
@Autowired
private DataSourceProperties dataSourceProperties;
@Bean
@ConditionalOnMissingBean(CoomboPooledDataSource.class)
public DataSource dataSource() throw Exception{
//初始化C3p0连接池
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//设置C3p0连接池的数据库连接属性
if(dataSourceProperties.getUrl() != null){
dataSource.setJdbcUrl(dataSourceProperties.getUrl());
}
if(dataSourceProperties.getDriverClassName() != null){
dataSource.setDriverClass(dataSourceProperties.getDriverClassName());
}
if(dataSourceProperties.getUsername() != null){
dataSource.setUser(dataSourceProperties.getUsername());
}
if(dataSourceProperties.getPassword != null){
dataSource.setPassword(dataSourceProperties.getPassword());
}
//配置C3p0连接池属性
dataSource.setMaxIdleTime(properties.getMaxIdleTime());
dataSource.setMaxPoolSize(properties.getMaxPoolSize());
dataSource.setMinPoolSize(properties.getMinPoolSize());
dataSource.setInitialPoolSize(properties.getInitialPoolSize());
return dataSource;
}
}
```
> 接下来对以上代码用到的注解进行解释:
>
> - @ConditionalOnClass(XXX.class):标注在类上,当指定class存在classpath时则初始化配置
> - @ConditionalOnMissingBean(Xxx.class):标注在方法上,当指定class不存在则装配Bean
> - @AutoConfigureBefore(XXX.class):标注在类上,当前配置类会在指定的class(XxxAutoConfigure)之前先加载
> - @EnableConfigurationProperties(Xxx.class):标注在类上,支持数组。将带有该注解的类纳入Spring容器中管理,便于注入使用。在上面的代码中DataSourceProperties绑定的是Spring数据源链接属性,C3p0DataSourceProperties绑定的是C3o0的连接池属性
> - @ConfigurationPropertiesScan("包名"):在指定包下扫描带有@ConfigurationProperties注解的类,并将扫描到的类纳入到Spring容器中管理
>
> @EnableConfigurationProperties(Xxx.class)和@ConfigurationPropertiesScan("包名")注解的作用相同,但是一个是直接指定类来纳入容器中管理,一个是根据注解和包来扫描纳入到容器中
### 3、编写C3p0DataSourceProperties类
> 该类用于定义工具所需要的属性,应该在properties包下
>
> @ConfigurationProperties()注解会在yml中松散读取属性值
>
> 注意:不建议在自动配置的项目中使用lombok
```java
@ConfigurationProperties(prefix = "spring.datasource.c3p0")
public class C3p0DataSourceProperties{
private Integer maxPoolSize = 200;
private Integer minPoolSize = 5;
private Intefer initialPoolSize = 5;
private Intefer maxIDleTime = 60000;
public Integer getMaxPoolSize() {
return maxPoolSize;
}
public void setMaxPoolSize(Integer maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public Integer getMinPoolSize() {
return minPoolSize;
}
public void setMinPoolSize(Integer minPoolSize) {
this.minPoolSize = minPoolSize;
}
public Integer getInitialPoolSize() {
return initialPoolSize;
}
public void setInitialPoolSize(Integer initialPoolSize) {
this.initialPoolSize = initialPoolSize;
}
public Integer getMaxIdleTime() {
return maxIdleTime;
}
public void setMaxIdleTime(Integer maxIdleTime) {
this.maxIdleTime = maxIdleTime;
}
}
```
### 4、创建org.springframework.boot.autoconfigure.AutoConfiguration.imports文件
> 该文件**必须存在**与resources.META-INF.spring包下
>
> 该文件用于扫描自动配置类,告诉Spring Boot有哪些自动配置类需要加载
```yaml
# 告诉Spring Boot配置类C3p0DataSourceAutoConfigure类需要加载
org.c3p0.spring.boot.autoconfigure.C3p0DataSourceAutoConfigure
```
### 5、使用自定义的自动配置类
> 当我构建好了我们的自动配置项目就可以使用了
>
> 注意:编写好我们的项目后我们需要在Maven中clear和install一下,使我们的项目保存到我们的Maven本地仓库中
#### 1.引入自定义自动配置依赖
> 当我们的自动配置项目编写好后我们在需要用到的springboot项目中引入依赖即可使用
```xml
org.c3p0.spring.boot
c3p0-spring-boot-starter
1.0
```
#### 2.在yml配置文件中配置
> 引入依赖后我们就可以在yml配置文件中修改c3p0连接池的属性值了
```yaml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3307/city?serverTimeZone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
username: root
password: root
type: com.mchange.v2.c3p0.ComboPooledDataSource
c3p0:
initial-pool-size: 10
max-idle-time: 700000
max-pool-size: 100
min-pool-size: 20
```
> 如果还想了解可以看一下minio的自动配置项目
## 七、REST风格与RESTful架构
> 详细讲解可以看ch08下的**Restful教程.md**
>
> REST的核心约束:
>
> - 前后端分离
> - 无状态 - 每个请求必须包含所有必要信息(如身份凭证、数据参数),请求JWT令牌携带
> - 可缓存
> - 统一接口
> - 资源表示:每个资源必须有唯一的标识符(如:/users/1001)...
>
> RESTful API:
>
> - 资源URI设计:必须用名词而非动词(如:/user/addUser是不允许的)
> - HTTP 方法映射资源操作(CRUD 对应):指定的操作必须使用指定的HTTP方法
> - 资源过滤、排序、分页:用查询参数(Query Parameter):对资源的筛选、排序等附加操作,需通过URI的查询参数实现(如:?pageNum=1&pageSize=10)
> - 响应格式与状态码:使用json响应数据和状态码(自定义ResultVO)
> - 版本控制:为避免 API 变更影响旧客户端,可在 URI 中添加版本号(如:/api/v1)
## 八、OpenAPI
> 在我们的前后端分离的项目中后端项目会有大量的接口API交由前端去使用
>
> 为了让前端能够使用的更加轻松,方便
>
> 我们后端一般需要为我们的每一个接口去写API接口文档
>
> 当接口API的数量过多时,对于文档的书写工作量是巨大的
>
> 我们可以使用**OpenAPI**来根据注解来自动帮我编写文档
>
> 注意:使用时需要访问localhost:8080/swagger.html
### 1、引入依赖
> 我们首先需要引入openapi的依赖,可以在Maven中央仓库中找到
```xml
org.springdoc
springdoc-openapi-starter-webmvc-ui
2.8.13
```
### 2、配置yml
> 我们需要在yml配置文件中配置一些openapi所需要的属性
```yaml
springdoc:
# swagger-ui页面的相关配置
swagger-ui:
# 设置swagger页面的访问路径
path: /swagger.html
# 扫描需要生成api的类所在的包
package-toscan: top.csy888.ch08.web.api
api-docs:
# 该属性需要在生产环境中设置为false
enabled: true
```
### 3、编写OpenApiConfig配置类
> 该配置类主要用于定义API文档的基本信息和JWT认证方式
>
> @OpenAPIDefinition:该注解用与配置OpenAPI文档的基本信息
>
> - `info` 属性:定义了文档的标题、版本、描述和许可证信息
> - `security` 属性:指定全局的安全要求,这里引用了名为 "JWT" 的安全方案
>
> @SecurityScheme:该注解定义了JWT认证的具体方案
>
> - `name = "JWT"`:安全方案的名称,与上面的 @SecurityRequirement 对应
> - `type = SecuritySchemeType.HTTP`:认证类型为 HTTP
> - `scheme = "Bearer"`:使用 Bearer 令牌方案
> - `in = SecuritySchemeIn.HEADER`:令牌放在 HTTP 请求头中
```java
@Configuration
@OpenAPIDefinition(
info = @Info(
title = "移动端接口文档",
version = "1.0",
description = "百货商城移动端API接口",
license = @License(name = "MIT", url = "http://mit.org")
)
//所有需要JWT认证(Token),name属性引用下面@SecurityScheme注解的name值
security = @SecurityRequirement(name = "JWT")
)
//设置JWT的认证模式
@SecurityScheme(
name = "JWT",
type = SecuritySchemeType.HTTP,
scheme = "Bearer",
in = SecuritySchemeIn.HEADER
)
public class OpenApiConfig{}
```
### 4、编写UserController
> 测试生成的API文档
```java
@RestController
//URI定义版本号 - 不同版本应该使用不同的Controller
@RequestMapping("/api/v1")
@Tag(name = "用户服务接口",description = "提供用户信息相关的API操作接口")
public class UserController{
//假设User对象已存在
private final static List users;
static {
User u1 = new User(1,"张三",18);
User u2 = new User(2,"李四",20);
User u3 = new User(3,"王五",21);
users = Arrays.asList(u1,u2,u3);
}
//查询使用GET,并且URI中不能使用动词
@GetMapping("/users")
//描述这个api的作用和HTTP方法
@Operation(description = "查询系统中所有用户的基本信息",method = "GET",summary = "查询用户列表")
@ApiResponses({
@ApiResponse(responseCode = "200",description = "响应成功"),
@ApiResponse(responseCode = "500",description = "查询失败,服务器错误")
})
public ResultVO> listUsers(){
return ResultVO.success(users);
}
@GetMapping("/user/{id}")
@Operation(description = "根据id查询用户的基本信息",method = "GET",summary = "查询用户")
@ApiResponses({
@ApiResponse(responseCode = "200",description = "响应成功"),
@ApiResponse(responseCode = "500",description = "查询失败,服务器错误")
})
//参数描述
//required属性表示参数是否必须传参
//in表示参数通过什么途径传入(请求头,请求参数,路径参数)(ParameterIn.PATH表示参数通过路径传递)
@Parameters({
@Parameter(description = "用户id",name = "id",required = true,in = ParameterIn.PATH)
})
public ResultVO getUser(@PathVariable("id") Integer id){
for (User user : users) {
if (id == user.getId()) {
return ResultVO.success(user);
}
}
return ResultVO.error(404,"没有该用户信息!");
}
@PostMapping("/user")
@Operation(description = "根据传入的User对象添加用户",summary = "添加用户",method = "POST")
@Parameters({
//in = ParameterIn.DEFAULT为默认可以不用设置
@Parameter(name = "user",required = true,in = ParameterIn.DEFAULT)
})
public ResultVO addUser(@RequestBody User user){
return ResultVO.success();
}
}
```