# 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项目 ![image-20250910192932479](C:\Users\CSY\AppData\Roaming\Typora\typora-user-images\image-20250910192932479.png) 注意:我们除了在IDEA中创建Spring Boot外,还可以在https://start.spring.io/网址中创建项目,实际上IDEA就是访问该网址进行创建项目的,所以我们需要保持网络的通畅 ![image-20250910193431192](C:\Users\CSY\AppData\Roaming\Typora\typora-user-images\image-20250910193431192.png) 我们可以进行下一步选择自己需要的起步依赖,然后点击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 > ![image-20250916203323254](C:\Users\CSY\AppData\Roaming\Typora\typora-user-images\image-20250916203323254.png) 选择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(); } } ```