SpringBoot2笔记
SpringBoot2:
注意事项:
1、SpringBoot的启动类需要和逻辑代码所在的包在同一个包下。(主程序所在的包及其以下子包中的组件都会进行扫描)
2、SpringBoot有一个全局配置文件,可以配置SpringBoot项目中的属性(例如:service的端口号)
SpringBoot中的启动类的写法:
package com.littleshark.SpringBoot.application;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//作用是将这个类作为SpringBoot的入口方法,标志这是一个SpringBoot项目
@SpringBootApplication
public class Application {
public static void main(String[] args) {
//进行启动这个SpringBoot项目
SpringApplication.run(Application.class,args);
}
}
@RestController注解的作用:
这个注解将两个注解的作用相结合(@ResponseBody注解和@Controller注解)
@ResopnseBody注解的作用:将修饰的方法的返回值直接输出到页面中,不进行跳转到view视图
SpringBoot可以直接使用插件进行打包成为jar包(尽管是一个web项目),这个jar包可以在cmd窗口直接运行。
进行创建jar包的依赖
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.0</version>
</plugin>
</plugins>
</build>
SpringBoot中的父项目的作用是用来规定当前maven管理的jar的版本号:
这是在Spring-Boot-dependencies中进行配置的版本号:(在SpringBoot中叫做自动版本仲裁)
<properties>
<activemq.version>5.15.13</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
<appengine-sdk.version>1.9.82</appengine-sdk.version>
<artemis.version>2.12.0</artemis.version>
<aspectj.version>1.9.6</aspectj.version>
<assertj.version>3.16.1</assertj.version>
<atomikos.version>4.0.6</atomikos.version>
<awaitility.version>4.0.3</awaitility.version>
<bitronix.version>2.1.4</bitronix.version>
<build-helper-maven-plugin.version>3.1.0</build-helper-maven-plugin.version>
<byte-buddy.version>1.10.14</byte-buddy.version>
<caffeine.version>2.8.5</caffeine.version>
<cassandra-driver.version>4.6.1</cassandra-driver.version>
<classmate.version>1.5.1</classmate.version>
<commons-codec.version>1.14</commons-codec.version>
<commons-dbcp2.version>2.7.0</commons-dbcp2.version>
<commons-lang3.version>3.10</commons-lang3.version>
<commons-pool.version>1.6</commons-pool.version>
<commons-pool2.version>2.8.1</commons-pool2.version>
<couchbase-client.version>3.0.8</couchbase-client.version>
<db2-jdbc.version>11.5.4.0</db2-jdbc.version>
<dependency-management-plugin.version>1.0.10.RELEASE</dependency-management-plugin.version>
<derby.version>10.14.2.0</derby.version>
<dropwizard-metrics.version>4.1.12.1</dropwizard-metrics.version>
<ehcache.version>2.10.6</ehcache.version>
<ehcache3.version>3.8.1</ehcache3.version>
<elasticsearch.version>7.6.2</elasticsearch.version>
<embedded-mongo.version>2.2.0</embedded-mongo.version>
<exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>
<flatten-maven-plugin.version>1.2.5</flatten-maven-plugin.version>
<flyway.version>6.4.4</flyway.version>
<freemarker.version>2.3.30</freemarker.version>
<git-commit-id-plugin.version>3.0.1</git-commit-id-plugin.version>
<glassfish-el.version>3.0.3</glassfish-el.version>
<glassfish-jaxb.version>2.3.3</glassfish-jaxb.version>
<groovy.version>2.5.13</groovy.version>
<gson.version>2.8.6</gson.version>
<h2.version>1.4.200</h2.version>
<hamcrest.version>2.2</hamcrest.version>
<hazelcast.version>3.12.9</hazelcast.version>
<hazelcast-hibernate5.version>1.3.2</hazelcast-hibernate5.version>
<hibernate.version>5.4.21.Final</hibernate.version>
<hibernate-validator.version>6.1.5.Final</hibernate-validator.version>
<hikaricp.version>3.4.5</hikaricp.version>
<hsqldb.version>2.5.1</hsqldb.version>
<htmlunit.version>2.40.0</htmlunit.version>
<httpasyncclient.version>4.1.4</httpasyncclient.version>
<httpclient.version>4.5.12</httpclient.version>
<httpcore.version>4.4.13</httpcore.version>
<infinispan.version>10.1.8.Final</infinispan.version>
<influxdb-java.version>2.18</influxdb-java.version>
<jackson-bom.version>2.11.2</jackson-bom.version>
<jakarta-activation.version>1.2.2</jakarta-activation.version>
<jakarta-annotation.version>1.3.5</jakarta-annotation.version>
<jakarta-jms.version>2.0.3</jakarta-jms.version>
<jakarta-json.version>1.1.6</jakarta-json.version>
<jakarta-json-bind.version>1.0.2</jakarta-json-bind.version>
<jakarta-mail.version>1.6.5</jakarta-mail.version>
<jakarta-persistence.version>2.2.3</jakarta-persistence.version>
<jakarta-servlet.version>4.0.4</jakarta-servlet.version>
<jakarta-servlet-jsp-jstl.version>1.2.7</jakarta-servlet-jsp-jstl.version>
<jakarta-transaction.version>1.3.3</jakarta-transaction.version>
<jakarta-validation.version>2.0.2</jakarta-validation.version>
<jakarta-websocket.version>1.1.2</jakarta-websocket.version>
<jakarta-ws-rs.version>2.1.6</jakarta-ws-rs.version>
<jakarta-xml-bind.version>2.3.3</jakarta-xml-bind.version>
<jakarta-xml-soap.version>1.4.2</jakarta-xml-soap.version>
<jakarta-xml-ws.version>2.3.3</jakarta-xml-ws.version>
<janino.version>3.1.2</janino.version>
<javax-activation.version>1.2.0</javax-activation.version>
<javax-annotation.version>1.3.2</javax-annotation.version>
<javax-cache.version>1.1.1</javax-cache.version>
<javax-jaxb.version>2.3.1</javax-jaxb.version>
<javax-jaxws.version>2.3.1</javax-jaxws.version>
<javax-jms.version>2.0.1</javax-jms.version>
<javax-json.version>1.1.4</javax-json.version>
<javax-jsonb.version>1.0</javax-jsonb.version>
<javax-mail.version>1.6.2</javax-mail.version>
<javax-money.version>1.0.3</javax-money.version>
<javax-persistence.version>2.2</javax-persistence.version>
<javax-transaction.version>1.3</javax-transaction.version>
<javax-validation.version>2.0.1.Final</javax-validation.version>
<javax-websocket.version>1.1</javax-websocket.version>
<jaxen.version>1.2.0</jaxen.version>
<jaybird.version>3.0.9</jaybird.version>
<jboss-logging.version>3.4.1.Final</jboss-logging.version>
<jboss-transaction-spi.version>7.6.0.Final</jboss-transaction-spi.version>
<jdom2.version>2.0.6</jdom2.version>
<jedis.version>3.3.0</jedis.version>
<jersey.version>2.30.1</jersey.version>
<jetty-el.version>8.5.54</jetty-el.version>
<jetty-jsp.version>2.2.0.v201112011158</jetty-jsp.version>
<jetty-reactive-httpclient.version>1.1.4</jetty-reactive-httpclient.version>
<jetty.version>9.4.31.v20200723</jetty.version>
<jmustache.version>1.15</jmustache.version>
<johnzon.version>1.2.8</johnzon.version>
<jolokia.version>1.6.2</jolokia.version>
<jooq.version>3.13.4</jooq.version>
<json-path.version>2.4.0</json-path.version>
<json-smart.version>2.3</json-smart.version>
<jsonassert.version>1.5.0</jsonassert.version>
<jstl.version>1.2</jstl.version>
<jtds.version>1.3.1</jtds.version>
<junit.version>4.13</junit.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<kafka.version>2.5.1</kafka.version>
<kotlin.version>1.3.72</kotlin.version>
<kotlin-coroutines.version>1.3.8</kotlin-coroutines.version>
<lettuce.version>5.3.4.RELEASE</lettuce.version>
<liquibase.version>3.8.9</liquibase.version>
<log4j2.version>2.13.3</log4j2.version>
<logback.version>1.2.3</logback.version>
<lombok.version>1.18.12</lombok.version>
<mariadb.version>2.6.2</mariadb.version>
<maven-antrun-plugin.version>1.8</maven-antrun-plugin.version>
<maven-assembly-plugin.version>3.3.0</maven-assembly-plugin.version>
<maven-clean-plugin.version>3.1.0</maven-clean-plugin.version>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<maven-dependency-plugin.version>3.1.2</maven-dependency-plugin.version>
<maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version>
<maven-enforcer-plugin.version>3.0.0-M3</maven-enforcer-plugin.version>
<maven-failsafe-plugin.version>2.22.2</maven-failsafe-plugin.version>
<maven-help-plugin.version>3.2.0</maven-help-plugin.version>
<maven-install-plugin.version>2.5.2</maven-install-plugin.version>
<maven-invoker-plugin.version>3.2.1</maven-invoker-plugin.version>
<maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
<maven-javadoc-plugin.version>3.2.0</maven-javadoc-plugin.version>
<maven-resources-plugin.version>3.1.0</maven-resources-plugin.version>
<maven-shade-plugin.version>3.2.4</maven-shade-plugin.version>
<maven-source-plugin.version>3.2.1</maven-source-plugin.version>
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<maven-war-plugin.version>3.2.3</maven-war-plugin.version>
<micrometer.version>1.5.5</micrometer.version>
<mimepull.version>1.9.13</mimepull.version>
<mockito.version>3.3.3</mockito.version>
<mongodb.version>4.0.5</mongodb.version>
<mssql-jdbc.version>7.4.1.jre8</mssql-jdbc.version>
<mysql.version>8.0.21</mysql.version>
<nekohtml.version>1.9.22</nekohtml.version>
<neo4j-ogm.version>3.2.16</neo4j-ogm.version>
<netty.version>4.1.52.Final</netty.version>
<netty-tcnative.version>2.0.34.Final</netty-tcnative.version>
<nio-multipart-parser.version>1.1.0</nio-multipart-parser.version>
<oauth2-oidc-sdk.version>7.1.1</oauth2-oidc-sdk.version>
<nimbus-jose-jwt.version>8.19</nimbus-jose-jwt.version>
<ojdbc.version>19.3.0.0</ojdbc.version>
<okhttp3.version>3.14.9</okhttp3.version>
<oracle-database.version>19.3.0.0</oracle-database.version>
<pooled-jms.version>1.1.2</pooled-jms.version>
<postgresql.version>42.2.16</postgresql.version>
<prometheus-pushgateway.version>0.9.0</prometheus-pushgateway.version>
<quartz.version>2.3.2</quartz.version>
<querydsl.version>4.3.1</querydsl.version>
<r2dbc-bom.version>Arabba-SR7</r2dbc-bom.version>
<rabbit-amqp-client.version>5.9.0</rabbit-amqp-client.version>
<reactive-streams.version>1.0.3</reactive-streams.version>
<reactor-bom.version>Dysprosium-SR12</reactor-bom.version>
<rest-assured.version>3.3.0</rest-assured.version>
<rsocket.version>1.0.2</rsocket.version>
<rxjava.version>1.3.8</rxjava.version>
<rxjava-adapter.version>1.2.1</rxjava-adapter.version>
<rxjava2.version>2.2.19</rxjava2.version>
<saaj-impl.version>1.5.2</saaj-impl.version>
<selenium.version>3.141.59</selenium.version>
<selenium-htmlunit.version>2.40.0</selenium-htmlunit.version>
<sendgrid.version>4.4.8</sendgrid.version>
<servlet-api.version>4.0.1</servlet-api.version>
<slf4j.version>1.7.30</slf4j.version>
<snakeyaml.version>1.26</snakeyaml.version>
<solr.version>8.5.2</solr.version>
<spring-amqp.version>2.2.11.RELEASE</spring-amqp.version>
<spring-batch.version>4.2.4.RELEASE</spring-batch.version>
<spring-data-releasetrain.version>Neumann-SR4</spring-data-releasetrain.version>
<spring-framework.version>5.2.9.RELEASE</spring-framework.version>
<spring-hateoas.version>1.1.2.RELEASE</spring-hateoas.version>
<spring-integration.version>5.3.2.RELEASE</spring-integration.version>
<spring-kafka.version>2.5.6.RELEASE</spring-kafka.version>
<spring-ldap.version>2.3.3.RELEASE</spring-ldap.version>
<spring-restdocs.version>2.0.5.RELEASE</spring-restdocs.version>
<spring-retry.version>1.2.5.RELEASE</spring-retry.version>
<spring-security.version>5.3.4.RELEASE</spring-security.version>
<spring-session-bom.version>Dragonfruit-SR1</spring-session-bom.version>
<spring-ws.version>3.0.10.RELEASE</spring-ws.version>
<sqlite-jdbc.version>3.31.1</sqlite-jdbc.version>
<sun-mail.version>1.6.5</sun-mail.version>
<thymeleaf.version>3.0.11.RELEASE</thymeleaf.version>
<thymeleaf-extras-data-attribute.version>2.0.1</thymeleaf-extras-data-attribute.version>
<thymeleaf-extras-java8time.version>3.0.4.RELEASE</thymeleaf-extras-java8time.version>
<thymeleaf-extras-springsecurity.version>3.0.4.RELEASE</thymeleaf-extras-springsecurity.version>
<thymeleaf-layout-dialect.version>2.4.1</thymeleaf-layout-dialect.version>
<tomcat.version>9.0.38</tomcat.version>
<unboundid-ldapsdk.version>4.0.14</unboundid-ldapsdk.version>
<undertow.version>2.1.4.Final</undertow.version>
<versions-maven-plugin.version>2.7</versions-maven-plugin.version>
<webjars-hal-browser.version>3325375</webjars-hal-browser.version>
<webjars-locator-core.version>0.45</webjars-locator-core.version>
<wsdl4j.version>1.6.3</wsdl4j.version>
<xml-maven-plugin.version>1.0.2</xml-maven-plugin.version>
<xmlunit2.version>2.7.0</xmlunit2.version>
</properties>
如果我们需要进行自定义,具体操作如下:
1、现在Spring-boot-dependencies中进行查看jar包的版本号是否和自己想要的一致
2、在pom.xml文件中直接进行配置自己需要的jar包的版本号
实例代码:
<properties>
<!--进行自定义Mysql的版本号-->
<mysql.version>8.0.27</mysql.version>
</properties>
Starter场景启动器:
模板:spring-boot-starter-* 这里的*就是应用场景 ,例如spring-boot-starter-web 就是关于web项目的starter启动器
作用:进行下载对应场景需要的一般依赖(jar包)
Spring中包含的Starter有哪些:
*-spring-boot-starter- * 这个是第三方提供的简化的starter
所有场景的最底层依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
@SpringBootApplication这个注解相当于以下三个注解的作用:
1、@SpringBootConfiguration
2、@EnableAutoConfiguration
3、@ComponentScan
SpringBoot中进行添加组件,通过注解的方式进行设置配置类进行添加
/**
* 1、@Configuration注解说明这是一个配置类,其本身就是一个组件(对象)
* 2、@Configuration注解中的proxyBeanMethod这个属性值默认为true
* proxyBeanMethod属性值的作用:是否将这个配置类设置为代理对象(就是真实对象的一个副本,内容和真实对象相同)
* full模式:
* 如果是一个代理对象,通过这个代理对象中的user()方法和cat()方法获取对象的时候,Spring会先在IOC容器中进行检查是否有之前创建的对象,有就从IOC容器中进行获取。(如果当proxyBeanMethod的属性值为true的时候,目的是为了保证对象的唯一性)
*
* lite模式:
* 如果不是一个代理对象(ProxyBeanMethod的属性值为false),通过配置类对象调用user()和cat()方法的时候,Spring不会检查IOC容器 ,每调用一次方法,就会创建一次对象(用于组件依赖(组件中含有另一个组件))
*
* 3、@Import注解(作用到组件上)的作用:将value属性中的类型创建出对象存入IOC容器中,组件默认的id为这个类的全类名
*/
@Configuration(proxyBeanMethods = true) //这是一个配置类 ,相当于Spring的xml文件
@Import({User.class,Pet.class})
public class MyConfig {
//向ioc容器中进行添加一个组件
@Bean("user1") //相当于在Spring的xml文件中进行创建一个Bean对象,这个Bean对象中的id属性默认是当前的方法名,类型就是这个方法的返回值的类型
//这个方法在xml文件中相当于 <bean id="user" class="com.littleshark.SpringBoot.application.pojo.User"/>
//如果@Bean中的value值不为null,就会将@Bean中的value属性值作为这个bean的id
public User user(){
return new User("张三",18);
}
@Bean
public Pet cat(){
return new Pet("猫米");
}
}
@Conditional注解的作用:
作用:进行有添加的添加组件,只有满足条件之后,才会进行添加组件。
@Conditional注解的子类:
在使用的时候,如果出现不生效的情况,可能是组件之间的顺序出现了错误。
@Configuration(proxyBeanMethods = true) //这是一个配置类 ,相当于Spring的xml文件
@Import({User.class,Pet.class})
public class MyConfig {
//向ioc容器中进行添加一个组件
@Bean("cat2")
public Pet cat(){
return new Pet("猫米");
}
@Bean("user1") //相当于在Spring的xml文件中进行创建一个Bean对象,这个Bean对象中的id属性默认是当前的方法名,类型就是这个方法的返回值的类型
//这个方法在xml文件中相当于 <bean id="user" class="com.littleshark.SpringBoot.application.pojo.User"/>
//如果@Bean中的value值不为null,就会将@Bean中的value属性值作为这个bean的id
@ConditionalOnBean(name = "cat1") //表示只有当组件id为cat的组件存在的时候才创建user1组件 ,需要注意顺序
public User user(){
return new User("张三",18);
}
}
@ImportResource注解的作用:
@ImportResource注解的作用是:使用xml的方式进行创建的组件进行加载。
实例代码:
通过xml方式进行创建的bean对象
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="test" class="com.littleshark.SpringBoot.application.pojo.User"/>
</beans>
如果我们不进行任何操作,就不能将这个xml文件中的组件进行创建后加载到IOC容器中,所以需要用到@ImportResouce注解
@Configuration(proxyBeanMethods = true) //这是一个配置类 ,相当于Spring的xml文件
@Import({User.class,Pet.class})
@ImportResource("classpath:bean.xml") //将classpath:中的bean.xml(Spring的配置文件)文件中的组件进行创建,并加载到IOC容器中
public class MyConfig {
//向ioc容器中进行添加一个组件
@Bean("cat1")
public Pet cat(){
return new Pet("猫米");
}
@Bean("user1") //相当于在Spring的xml文件中进行创建一个Bean对象,这个Bean对象中的id属性默认是当前的方法名,类型就是这个方法的返回值的类型
//这个方法在xml文件中相当于 <bean id="user" class="com.littleshark.SpringBoot.application.pojo.User"/>
//如果@Bean中的value值不为null,就会将@Bean中的value属性值作为这个bean的id
@ConditionalOnBean(name = "cat1") //表示只有当组件id为cat的组件存在的时候才创建user1组件 ,需要注意顺序
public User user(){
return new User("张三",18);
}
}
@ConfigurationProperties注解的作用:
通过@ConfigurationProperties注解中的prefix属性值进行将properties文件中的匹配的key和被标识的该类的属性进行属性注入。
实例代码:
#注意,这里的properties文件需要是application.properties文件(可以设置SpringBoot任意属性的配置文件,全局配置文件),
#因为不能找到自己编写的其他properties文件
myphone.band=mi
myphone.price=1999
/**
* 只有在容器中的组件才能够被SpringBoot进行操作
*/
@Component //为什么要添加@Component注解:让这个类归于Spring进行管理,否则下面的注解无效
@ConfigurationProperties(prefix = "myphone")
//因为前缀为myphone,所以会找到上面的两个key,再将key对应的value和Phone类中的属性名进行对应赋值
public class Phone {
private String band;
private Integer price;
public Phone() {
}
public Phone(String band, Integer price) {
this.band = band;
this.price = price;
}
public String getBand() {
return band;
}
public void setBand(String band) {
this.band = band;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
@Override
public String toString() {
return "Phone{" +
"band='" + band + '\'' +
", price=" + price +
'}';
}
}
@EnableConfigurationProperties注解的作用:
@EnableConfigurationProperties注解可以开启指定类的属性配置,并进行属性注入,在交予Spring的IOC容器进行管理
实例代码:
@Configuration(proxyBeanMethods = true) //这是一个配置类 ,相当于Spring的xml文件
@Import({User.class,Pet.class})
@ImportResource("classpath:bean.xml")
@EnableConfigurationProperties(Phone.class) //这是一个数组
//@EnableConfigurationProperties注解的作用:
//1、开启指定类的属性绑定(这个类不需要在Spring的IOC容器中)
//2、进行属性的注入,在交予Spring进行管理
public class MyConfig {
//向ioc容器中进行添加一个组件
@Bean("cat1")
public Pet cat(){
return new Pet("猫米");
}
@Bean("user1") //相当于在Spring的xml文件中进行创建一个Bean对象,这个Bean对象中的id属性默认是当前的方法名,类型就是这个方法的返回值的类型
//这个方法在xml文件中相当于 <bean id="user" class="com.littleshark.SpringBoot.application.pojo.User"/>
//如果@Bean中的value值不为null,就会将@Bean中的value属性值作为这个bean的id
@ConditionalOnBean(name = "cat1") //表示只有当组件id为cat的组件存在的时候才创建user1组件 ,需要注意顺序
public User user(){
return new User("张三",18);
}
}
//这里就不需要将这个类交于Spring进行管理了,因为是通过@EnableConfigurationProperties注解进行开启的属性绑定
@ConfigurationProperties(prefix = "myphone")
public class Phone {
private String band;
private Integer price;
public Phone() {
}
public Phone(String band, Integer price) {
this.band = band;
this.price = price;
}
public String getBand() {
return band;
}
public void setBand(String band) {
this.band = band;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
@Override
public String toString() {
return "Phone{" +
"band='" + band + '\'' +
", price=" + price +
'}';
}
}
@SpringBootApplication注解的作用:
这一个注解的作用相当于以下三个注解的作用:
1、@SpringBootConfiguration:标志这就是一个配置类
2、@ComponentScan:进行指定需要进行扫描的包(其中的value属性进行设置)
3、@EnableAutoConfiguration:这个注解又可以分为以下两个注解:
1) AutoConfigurationPackage:自动配置包?指定默认的加载包的规则
@Import({Registrar.class}) //进行加载Registrar这个类
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
//通过导入的Registrar对象将MainApplication(SpringBoot的入口类)这个包及其以下的组件进行注册导入
2.@Import({AutoConfigurationImportSelector.class}) : 将AutoConfigurationImportSelector这个类进行创建组件交予Spring的IOC容器进行管理
//查看源码,发现是通过selectImports方法进行选择性的导入
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
//这个方法主要的方法就是
// AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = //this.getAutoConfigurationEntry(annotationMetadata);
//以下是getAutoConfigurationEntry方法的方法体
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
//不难发现这个方法都是围绕者List<String> configurations进行操作的,所以重点就是知道如何获取这个List集合,也就是List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);这段代码
//以下是getCandidateConfigurations的方法体
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;
}
//通过代码可以知道是通过SpringFactoriesLoader这个类中的loadFactoryNames方法进行获取List<String>集合
//以下是loadFactoryNames()方法的方法体
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
//通过代码可以发现是通过loadSpringFactories()方法进行加载List<String>
//以下是loadSpringFactories()方法的代码:
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryImplementationName = var9[var11];
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
//可以看到是通过Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");代码进行加载文件
//在所有的第三方依赖中,最重要的是spring-boot-autoconfigure-2.3.4.RELEASE.jar下的spring.factories文件
我们进行查看spring-boot-autoconfigure-2.3.4.RELEASE.jar这个jar包下的spring.factories文件
以下的组件都会在SpringBoot工程启动的时候自动进行全部加载
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration
有这么多的组件,为什么我们自己的工程中没有这么多的组件?
这就有赖于SpringBoot的按需加载 (通过条件@conditional及其派生注解进行设置 ) ,用到什么就进行加载什么.
总结:
1. SpringBoot在启动的时候先进行加载自动配置类
1. 在加载自动配置类之后,每个配置类会按条件进行生效,默认都会开启属性绑定(@EnableConfigurationProperties),将这个配置类和xxxx.properties文件进行绑定,由于xxxx.properties文件是和全局配置文件进行绑定在一起的,所以可以通过修改全局配置文件(application.properties)文件进行修改配置类中进行创建的组件的值
1. 生效的配置类就会给IOC容器中添加自己类符合条件中的组件
1. 当用户自定义了组件的时候,SpringBoot会使用用户自定义的组件(用户自定义的优先),只有当用户没有进行自定义组件的时候,才会默认加载SpringBoot中配置类中符合条件的组件
如果想要自定义SpringBoot有两种方案:
第一种方案:通过自己编写一个配置类,在配置类中通过向IOC容器中进行添加自己想要自定义的组件(SpringBoot在启动的时候发现用户有自定义该类型的组件,就不会在进行创建这个类型的组件)
第二种方案:通过修改全局配置文件(application.properties)进行修改需要修改的组件中的属性值进行自定义
如何自己分析SpringBoot中加载了什么AutoConfiguration自动配置类:
通过在application.properties文件中设置 debug=true 就可以看到详细的信息
LomBok插件的作用:
作用1:在编译的时候生成setter方法、getter方法、toString方法、全有参构造、无参构造、Equals方法和HashCode方法
实力代码:
//通过lombok插件生成getterAndSetter方法,toString方法,HashCode方法和Equals方法
@Data //生成getter方法和setter方法
@ToString //生成ToString方法
@AllArgsConstructor //生成全参数的构造方法
@NoArgsConstructor //生成无参构造
@EqualsAndHashCode //重写HashCode方法阿赫Equals方法
public class Pet {
private String name;
}
作用2:在进行日志的输出
示例代码:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.littleshark.SpringBoot")
@Slf4j //在这个类中插入一个方法log进行日志的输出
public class Application {
public static void main(String[] args) {
//进行启动这个SpringBoot项目
//这个ConfigurableApplicationContext就是一个Ioc容器
ConfigurableApplicationContext run = SpringApplication.run(Application.class, args);
String[] beanDefinitionNames = run.getBeanDefinitionNames();//获取默认的组件的名字
for (String name : beanDefinitionNames) {
System.out.println(name);
}
boolean b1 = run.containsBean("cat1");
boolean b = run.containsBean("user1");
log.info("slf4jTest"); //在日志中进行输出slf4jTest 通知等级为info
System.out.println(b&&b1);
System.out.println("通过xml方式进行创建的组件:"+ run.containsBean("test"));
}
}
代码的结果:
devtools的使用
#devtools工具需要的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
这个热部署的快捷键为 ctrl+F9 ,在以后更新资源的时候,就不用在点重新开始了
SpringBoot的核心技术(核心功能):
yaml ——标记语言
语法规则:
1.区分大小写
2.key: value (需要注意,key: 和value之间会有一个空格的举例)
3.使用缩进标识层级关系
4.缩进不允许使用table键,只允许使用空格键(在IDEA中可以放心使用table键)
5.缩进的空格数不重要,重要的是同一层需要在同一列上对其
6.#标识注释
7.yaml中字符串不需要使用单引号或者双引号,但是如果使用了需要知道代表什么, ' ' 会将里面的字符串进行转义(\n转化为字符串的 \n ,将其进行转义) " "不会将里面的字符串进行转义( \n还是表示为换行 ,保留原理的功能)
实例代码:
user1:
name: 张三
age: 28
map:
pet1:
name: 胖胖
age: 3
pet2:
name: 小狗
age: 1
# list: [456,123,789]
list:
- 456
- 123
- 789
birthday: 2023/4/25 #通过 / 进行分隔时间
@ConfigurationProperties("user1")
@Component
@ToString
@Data
public class User {
private String name;
private Integer age;
private Map<String,Pet> map;
private List<Integer> list;
private Date birthday;
}
静态资源的加载:
在资源前面进行添加前缀:(使用场景,在需要登录的情况下才能加载资源(通过拦截器进行拦截),如果没有进行登录,后果就是不能访问到静态资源,样式就会出现问题,可以将静态资源前面进行添加前缀,将包含这个前缀的资源进行放行)
spring:
mvc:
static-path-pattern: /little/** #在资源路径前面添加前缀,也就是说,在获取静态资源的时候,需要通过工程路径+/little/+资源名称
实例:
SpringBoot项目中,默认进行存储静态资源的包分别为:/static、/public、/META-INF/resources、/resources
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
我们可以在全局配置文件中进行修改默认存放静态资源的包名:
spring:
mvc:
static-path-pattern: /little/** #在资源路径前面添加前缀,也就是说,在获取静态资源的时候,需要通过工程路径+/little/+资源名称
web:
resources:
static-locations: classpath:/little/
# private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
禁用所有的静态资源:
spring:
web:
resources:
add-mappings: false
这样设置之后,不论静态资源在哪儿,都不能进行访问到
欢迎页的设置:
有两种方式就进行设置欢迎页:
1、通过写一个index文件,将这个文件放到静态资源路径下,就可以直接将这个页面作为欢迎页面
使用这种方式进行设置的时候需要注意,不能在静态资源的前面添加前缀,否则这种方法就会失效(可以进行自定义静态资源的包)
2、通过写一个控制器进行指定欢迎页面
自定义网站图标功能(自定义Favicon):
直接将名字叫做favicon.icon的图片放到静态资源路径下就可以自动将这个文件作为网站的小图标
注意:这种方式同样存在一个问题,不能添加静态资源的前缀,添加之后则不会生效。
SpringBoot使用Restful风格:
@Bean
@ConditionalOnMissingBean({HiddenHttpMethodFilter.class})
@ConditionalOnProperty(
prefix = "spring.mvc.hiddenmethod.filter",
name = {"enabled"}
)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
//查看源代码可以知道,如果我们自己配置了HiddenHttpMethod这个组件,SpringBoot就不会在进行配置了,如果我们没有在全局配置文件中进行配置开启restful风格,默认是没有开启的。
开启restful风格:
Spring:
mvc:
hiddenmethod:
filter:
enabled: true
SpringMVC中请求处理最为重要的方法:
分析DiapatcherServlet类就需要分析这个类。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = HttpMethod.GET.matches(method);
if (isGet || HttpMethod.HEAD.matches(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
SpringMVC中,控制器的注解中可以进行解析的参数类型:(查看源码org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java)
SpringMVC中部分注解:
矩阵变量:
矩阵变量是和路径放在一起的,例如:
/boss/1;age=20,handsome=true/ 其中1;age=20,handsome=truez这个是一个整体
他的作用:
矩阵URI或矩阵变量为您提供了一种新的方式来处理可变数量的URI参数,并能够处理使用HTTP GET传递给应用程序的数据量日益增加的复杂性。
矩阵变量可以实现在禁用cookie的情况下使用session对象
在可以使用cookie请求下如何使用session:
session --> session的id -->cookie
当需要获取session中的值的时候,cookie中会存放session对象的id,服务器通过session对象的id进行获取唯一的session对象,从而获取数据。
在禁用了cookie之后,获取session中的值的时候,我们可以通过使用矩阵变量的方式,在请求中添加session对象的id(/zzz/id=6;sessionId=123456)服务器通过矩阵变量中的session的id进行获取唯一的Session对象。
在SpringBoot中默认是禁用矩阵变量的:
//UrlPathHelper是用来处理所有请求路径的
public class UrlPathHelper {
public static final String PATH_ATTRIBUTE = UrlPathHelper.class.getName() + ".PATH";
static final boolean servlet4Present = ClassUtils.hasMethod(HttpServletRequest.class, "getHttpServletMapping", new Class[0]);
private static final String WEBSPHERE_URI_ATTRIBUTE = "com.ibm.websphere.servlet.uri_non_decoded";
private static final Log logger = LogFactory.getLog(UrlPathHelper.class);
@Nullable
static volatile Boolean websphereComplianceFlag;
private boolean alwaysUseFullPath = false;
private boolean urlDecode = true;
private boolean removeSemicolonContent = true;
private String defaultEncoding = "ISO-8859-1";
private boolean readOnly = false;
public static final UrlPathHelper defaultInstance = new UrlPathHelper();
public static final UrlPathHelper rawPathInstance;
//其中removeSemicolonContent翻译为移除分号内容,默认为true,但是,矩阵变量就是通过分号进行连接的,所以,如果需要使用矩阵变量,需要将这个值进行修改为false
进行自定义我们的UrlPathHelper中的属性:
通过@Configuration注解和继承WebMvcConfigurer接口,再从写默认的configurePathMatch方法,在重写这个方法的时候进行自定义UrlPathHelper类就可以了。
实例代码:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper helper=new UrlPathHelper();
helper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(helper);
}
}
SpringMVC处理请求的步骤:
1、第一步通过HandlerMapping进行查找能够处理这个请求的handler(controller)
2、为当前的Handler寻找一个适配器HandlerAdapter;RequestMappingHandlerAdapter
3、最后通过适配器进行调用Handler(控制器)进行处理请求。
//这个代码是在DiapatcherServlet类中的doDispatcher()方法中的代码
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
HandlerAdapter的种类:
SpringMVC中可以存放的原生SerlvetAPI的参数有:
//这是在ServletRequestMethodArgumentResolver类中的方法,用于解析原生的Servlet API参数
public boolean supportsParameter(MethodParameter parameter) {
Class<?> paramType = parameter.getParameterType();
return WebRequest.class.isAssignableFrom(paramType) || ServletRequest.class.isAssignableFrom(paramType) || MultipartRequest.class.isAssignableFrom(paramType) || HttpSession.class.isAssignableFrom(paramType) || pushBuilder != null && pushBuilder.isAssignableFrom(paramType) || Principal.class.isAssignableFrom(paramType) && !parameter.hasParameterAnnotations() || InputStream.class.isAssignableFrom(paramType) || Reader.class.isAssignableFrom(paramType) || HttpMethod.class == paramType || Locale.class == paramType || TimeZone.class == paramType || ZoneId.class == paramType;
}
SpringMVC中存放复杂的参数:
/**
*向Request域对象中进行存放数据的五种方法:分别通过Map、Model、ModelMap、HttpServletRequest、ModelAndView(返回值类型必须是ModelAndView)
*/
@GetMapping("/params")
public String test(Map<String,Object> map , Model model , HttpServletRequest request , ModelMap modelMap){
map.put("map","this is test");
model.addAttribute("model","model");
request.setAttribute("HttpServletRequest","request");
modelMap.addAttribute("modelMap","modelMap");
return "forward:/test";
}
SpringMVC在处理请求的时候,可以通过级联复制的方式对对象中的对象属性进行赋值:
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>欢迎您!</h1>
<form action="/info" method="post" style="size: auto">
姓名:<input type="text" name="name">
<br>
<br>
年龄:<input type="text" name="age">
<br>
<br>
生日:<input type="text" name="birth">
<br>
<br>
宠物姓名:<input type="text" name="pet.name"> 通过级联赋值的方式对User对象中的Pet对象中的name属性进行赋值
<br>
<br>
宠物年龄:<input type="text" name="pet.age"> 通过级联赋值的方式对User对象中的Pet对象的age属性进行赋值
<br>
<br>
<input type="submit" value="提交信息"/>
</form>
</body>
</html>
//可以直接通过包装类进行获取整个对象
//因为是使用的Post请求进行提交的信息,请求会存在请求体,如果在控制器中放入一个对象,方法体中的内容会通过和参数对象的属性名与之匹配,匹配成功就将方法体中的值放入到参数对象的对应的属性中
@PostMapping("/info")
public String info(User user ,Model model){
model.addAttribute("user",user);
return "forward:/success";
}
我们通一通过WebMvcConfiguration定制化SpringMvc的功能:
@Configuration
public class MyConfiguration {
//通过WebMvcConfigurer进行定制化SpringMVC的功能
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
//通过WebMvcConfigurer进行开启矩阵变量
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper=new UrlPathHelper();
//RemoveSemicolonContent属性翻译为将分号后面的内容进行移除,如果需要使用矩阵变量(通过分号进行连接),需要设置为false
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
//通过WebMvcConfigurer进行添加转化器Converter(使用场景,需要将请求中的字符串对我们自定义的一个对象进行赋值)
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new Converter<String, Pet>() {
@Override
public Pet convert(String source) {
String[] pet = source.split(",");
return new Pet(pet[0],Integer.parseInt(pet[1]));
}
});
}
};
}
}
自定义Converter(转化器)的场景实例:直接通过一个字符串,将这个字符串和我们自定义的对象进行绑定(信息注入)
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>欢迎您!</h1>
<form action="/info" method="post" style="size: auto">
姓名:<input type="text" name="name">
<br>
<br>
年龄:<input type="text" name="age">
<br>
<br>
生日:<input type="text" name="birth">
<br>
<br>
<!--宠物姓名:<input type="text" name="pet.name">
<br>
<br>
宠物年龄:<input type="text" name="pet.age">
<br>
<br>-->
输入宠物的信息:<input type="text" name="pet"><span>名字和年龄通过逗号进行分割</span>
<input type="submit" value="提交信息"/>
</form>
</body>
</html>
SpringBoot中的Json响应:
因为我们通过Maven导入了Web的starter,他的父类以来中包含了Jackson
<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>${jackson-bom.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
所以,如果我们需要向前端响应Json数据,可以通过@ResponseBody注解进行直接响应
@ResponseBody
@RequestMapping("/user")
public User user(){
return new User("zhansan",25,new Date() ,new Pet("cat",2));
}
这就是一个json对象
返回值解析器有哪些:(用于处理响应的数据)
通过代码进行查找合适的处理器用于处理响应:(所在类:HandlerMethodReturnValueHandlerComposite.class)
@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
boolean isAsyncValue = this.isAsyncReturnValue(value, returnType);
Iterator var4 = this.returnValueHandlers.iterator();
HandlerMethodReturnValueHandler handler;
do {
do {
if (!var4.hasNext()) {
return null;
}
handler = (HandlerMethodReturnValueHandler)var4.next();
} while(isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler));
} while(!handler.supportsReturnType(returnType));//通过supportsReturnType方法进行确实是否支持这个属性
return handler;
}
//这是一个HandlerMethodReturnValueHandler接口,里面有两种抽象方法,这个类型就是seletHandler方法的返回值类型
public interface HandlerMethodReturnValueHandler {
boolean supportsReturnType(MethodParameter returnType);
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
}
1、先进行判断是否支持这种类型的返回值(通过supportsReturnType方法进行判断)
//通过selectHandler进行选择处理器
@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
2、如果支持,就通过HandlerMethodReturnaValueHandler的实现类中的handleReturnValue方法进行调用处理器进行处理
内容协商:
更具客户端的接收能力不同,返回的数据类型就不同。
内容协商的原理:
-
判断请求头中是否已经明确了媒体类型(MediaType)
-
获取客户端支持接收的类型(通过请求头中的Access:字段进行获取)
-
通过ContentNegotiationManager类(内容协商管理器)默认是基于请求头的策略
-
如果是基于请求头的策略,就会通过HeaderContentNegotiationStrategy类中的resolveMediaTypes()方法进行获取客户端可以接受的类型
-
源码如下:
-
@Override public List<MediaType> resolveMediaTypes(NativeWebRequest request) throws HttpMediaTypeNotAcceptableException { String[] headerValueArray = request.getHeaderValues(HttpHeaders.ACCEPT);//获取请求头中的Accept字段的信息 if (headerValueArray == null) { return MEDIA_TYPE_ALL_LIST; } List<String> headerValues = Arrays.asList(headerValueArray); try { List<MediaType> mediaTypes = MediaType.parseMediaTypes(headerValues); MediaType.sortBySpecificityAndQuality(mediaTypes); return !CollectionUtils.isEmpty(mediaTypes) ? mediaTypes : MEDIA_TYPE_ALL_LIST; } catch (InvalidMediaTypeException ex) { throw new HttpMediaTypeNotAcceptableException( "Could not parse 'Accept' header " + headerValues + ": " + ex.getMessage()); } }
-
-
遍历SpringBoot中默认的HttpMessageConverter对象,确定有哪些HeepMessageConverter对象能够将服务器的响应内容进行处理为客户端支持的内容
-
找到所有能处理响应内容的HttpMessageConverter对象,将他们进行统计起来
-
在能够处理的HttpMessageConverter对象中找出能够响应到客户端的最佳匹配(需要客户端支持这种类型,如果客户端发送的Access信息中存在权重,会将权重最为参考的点(再将所有的HttpMessageConverter进行排序的时候进行使用))
-
通过最佳匹配的Converter将需要响应的数据进行转化
HttpMessageConverter类的作用:
- HttpMessageConverter的规范:
-
在SpringBoot中都有哪些HttpMessageConverter:
开启浏览器参数方式内容协商功能:
为了方便与浏览器进行协商,开启基于请求参数方式内容协商功能(默认是通过请求头中的Access字段进行色设置响应的类型)
如何开启:
spring:
mvc:
contentnegotiation:
favor-parameter: true #开启基于请求参数的内容协商
# add-mappings: false 将所有的静态资源进行禁止
# private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
在开启了基于请求参数的内容协商策略之后,可以通过在请求后面添加format进行指定响应体是通过什么方式进行响应(源码中的解释:Whether a request parameter ("format" by default) should be used to determine the requested media type.)
实例:
如果需要返回的响应的数据类型为xml,需要添加进行转化的jar包:
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.13.3</version>
</dependency>
自定义HttpMessageConverter:
我们进行定制SpringMVc的操作都是在一个配置类中完成的:WebMvcConfigurer
如果我们是要进行拓展我们的HttpMessageConverter,就需要进行编写WebMvcConfigurer类中extendMessageConverters(翻译为拓展消息转化器)这个方法
注意WebMvcConfigurer类中的configureMessageConverters方法是将默认的全部消息转化器全部删除后再进行添加。
自定义HttpMessageConverter类的代码:
/**
* 自定义的HttpMessageConverter,处理User类型的数据
*/
public class MyMessageConverter implements HttpMessageConverter<User> {
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
//判断数据是否为User类型
//return clazz.isAssignableFrom(User.class);
return false;
}
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
//判断数据是否为User类型
return clazz.isAssignableFrom(User.class);
}
@Override //通过这个方法进行获取服务器支持的处理的类型
public List<MediaType> getSupportedMediaTypes() {
return MediaType.parseMediaTypes("application/x-shark");
}
@Override
public User read(Class<? extends User> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
@Override
public void write(User user, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
String s= user.getName()+";"+user.getAge()+";"+user.getBirth()+";"+user.getAge()+";"+user.getPet()+";";
//将处理后的信息进行写出去
OutputStream body = outputMessage.getBody();
body.write(s.getBytes(StandardCharsets.UTF_8));
}
}
将自定义的HttpMessageConverter进行添加到拓展到存放有默认消息转化器中:(在WebMvcConfigurer组件中)
@Override //在默认的消息转化器的基础山进行添加自定义的消息转化器
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
//拓展消息转化器(需要提前编写好自定义的消息转化器这个类实现HttpMessageConverter接口)
converters.add(new MyMessageConverter());
}
//extendMessageConverters方法是进行拓展消息转化器
//configMessageConverters方法是将默认的消息转化器进行删除后在进行添加消息转化器
在这里需要注意:
- 如果我们发送的请求中的Access字段中包含有我们自定义的消息转化器的类型(也就是这里的application/x-shark),这种方式能够进行访问,因为是通过默认的请求头协商策略进行查找的。
- 如果我们通过参数的方式进行访问,例如:localhost:8080/user/format=application/x-shark 或者localhost:8080/user/format=x-shark进行访问,返回的响应码会为406,为什么呢? 因为我们使用的是参数协商策略,然而我们并没有在参数协商策略中进行添加我们自定义的消息转化器,所以不能访问。
如何将我们自定义的消息转化器进行添加到参数协商策略中:
在SpringMvc的配置组件(WebMvcConfigurer)中进行重写configureCOntentNegotiation方法
/**
* 自定义参数协商策略(因为我们自定义了消息转化器,需要域format参数的值和我们自定义的消息转化器产生映射关系)
* @param configurer
*/
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
Map<String, MediaType> map=new HashMap<>();
map.put("json",MediaType.APPLICATION_JSON);
map.put("xml",MediaType.APPLICATION_XML);
//进行我们自定义的映射
map.put("shark",MediaType.parseMediaType("application/x-shark"));
//指定我们的参数内容协商策略,需要注意,如果我们自定义了协商策略,SpringBoot中的默认的协商策略就会被覆盖掉
//也就是说,现在我们传入的只有一个参数协商管理器,我们就只能通过参数的方式获取客户端支持的数据格式
//如果我们想要再根据客户端中的请求头中的Access字段中的值进行获取客户端支持的数据格式,我们需要再手动进行
// 添加基于请求头的内容协商管理器
ContentNegotiationStrategy paramStrategy=new ParameterContentNegotiationStrategy(map);//基于参数的内容协商管理器
HeaderContentNegotiationStrategy headerStrategy = new HeaderContentNegotiationStrategy();//基于请求头的内容协商管理器
//ContentNegotiationStrategy翻译为内容协商策略
configurer.strategies(List.of(paramStrategy,headerStrategy));
//strategies翻译为策略
}
这样就能访问了
视图:Thymeleaf
在SpringBoot项目中添加Thymeleaf:
<!--引入Thymeleaf的启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
当我们添加了Thymeleaf的启动器之后,SpringBoot就会通过ThymeleafAutoConfiguration这个自动配置类将Thymeleaf配置好。
自动配置的策略:
- 所有的Thymeleaf的配置都在ThymeleafProperties类中进行设置(这个类绑定了)
- 配置好了SpringTemplateEngin(Spring的模板引擎)
- 配置好了ThymeleafViewResolver(Thymeleaf的视图解析器)
- 我们只需要进行开发页面
//通过源码可以看出,如果我们需要进行自定义我们的Thymeleaf,需要在全局配置文件中通过spring.thymeleaf进行设置
@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";//默认的后缀
也就是说,我们需要将我们编写的Html文件放到Resource/templates/路径下
Thymeleaf测试:
代码如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>hello</title>
</head>
<body>
<h1 th:text="${msg}">hello</h1> <!--将请求域中的信息进行取出,并将其替换标签中的文本内容-->
<br>
<br>
<h2><a href="http://www.baidu.com" th:href="${href}">点击跳转,使用${}的方式进行获取哦</a></h2>
<!--th:href的作用是:将域中的数据进行取出后,再将href的值进行修改为取出的值-->
<br>
<br>
<br>
<h2><a href="http://www.baidu.com" th:href="@{href}">点击跳转,使用@{}的方式进行获取</a> </h2>
</body>
</html>
@Controller
public class ViewController {
@RequestMapping("/hello")
public String hello(Model model){
//在请求域中进行存放数据
model.addAttribute("msg","hello Word");
model.addAttribute("href","https://www.youdao.com");
return "hello";
}
}
以下图片是访问之后的源码:
可以看出,使用${}的方式是真正将域对象中的数据进行取出,再将其与th后面的属性的属性属性值进行修改(使用${}的方式进行获取域对象中的数据)
使用@{}的方式是将href拼接到href地址中(使用@{}的方式进行拼接地址)
Thymeleaf的行内写法:
行内写法的作用:不需要依赖标签,可以直接通过Thymeleaf进行获取信息之后显示出来
使用场景:
当我们需要修改的文字没有属于任何一个标签,不像可以通过th:text进行修改里面的值
有标签的情况,我们可以通过 th:text 进行修改标签中的text的值
<span>test</span>
如果没有标签的情况,例如
Join
上面的Join就是没有在任何标签中,我们如何进行修改呢?
我们通过Thymeleaf的行内写法进行修改
语法规则:
[[Thymeleaf代码]]
示例代码:
[[${session.user.username}]]
通过Thymeleaf将域对象中的数据进行遍历:
<tbody>
<tr th:each="user,state:${users}"><!--在遍历一个集合或者数组的时候,可以在添加一个参数用作记录这个元素在集合中的状态-->
<td th:text="${state.count}">X</td> <!--count表示为计数-->
<td th:text="${user.username}">Trident</td>
<td th:text="${user.password}">Internet
Explorer 4.0</td>
</tr>
</tbody>
拦截器的使用(interceptor):
-
编写一个类实现HandlerInterceptor接口
-
代码如下
-
public class LoginInterceptor implements HandlerInterceptor { /** * 在控制器方法执行前进行执行 * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //判断用户是否登录 if (request.getSession().getAttribute("user")!=null){ return true; } //将登陆信息存放到请求域中 request.setAttribute("msg","请先登录"); //通过请求转发到登录页面 request.getRequestDispatcher("/").forward(request,response); return false; } /** * 在控制器方法执行之后进行执行 * @param request * @param response * @param handler * @param modelAndView * @throws Exception */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } /** * 在图片渲染之后执行 * @param request * @param response * @param handler * @param ex * @throws Exception */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } }
-
-
在SpringBoot项目的配置类(WebMvcConfigurer)中进行注册拦截器
-
代码如下:
-
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { //将拦截器进行注册 registry.addInterceptor(new LoginInterceptor()) .addPathPatterns("/**")//将拦截路径设置为所有路径,静态资源也会被拦截 .excludePathPatterns("/","/login","/css/**","/js/**","/fonts/**","/images/**"); //将静态资原进行放行,将登录页面进行放行 } }
-
-
指定拦截规则(如果拦截路径为/**,就会将静态资源也进行拦截)
拦截器的触发原理:
只有PreHandle方式是按顺序执行的,postHandle方式和afterCompletion方法都是倒序执行的
文件上传的代码:(基本格式就是这样)
文件上传中,html文件的写法:
<!--文件上传的固定写法,提交方式需要是post,enctype的属性值需要是multiple/form-data-->
<form role="form" th:action="@{/upload}" method="post" enctype="multipart/form-data">
<!--上传文件的固定写法,提交方式为post,enctype的值需要是multiple/form-data-->
<div class="form-group">
<label for="exampleInputEmail1">邮箱</label>
<input type="email" name="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
</div>
<div class="form-group">
<label for="exampleInputPassword1">姓名</label>
<input type="text" name="username" class="form-control" id="exampleInputPassword1" placeholder="Password">
</div>
<div class="form-group">
<label for="exampleInputFile">头像</label>
<input type="file" id="exampleInputFile" name="headerImg"><!--上传一张图片-->
<p class="help-block">Example block-level help text here.</p>
</div>
<div class="form-group">
<label for="exampleInputFile">展示自己</label>
<input type="file" multiple name="photos"><!--上传多个文件-->
<p class="help-block">Example block-level help text here.</p>
</div>
<div class="checkbox">
<label>
<input type="checkbox"> Check me out
</label>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
@Slf4j
@Controller
public class FormController {
@GetMapping("/form_layouts")
public String form_layouts(){
return "form/form_layouts";
}
@PostMapping("/upload")
//获取请求体中的数据和文件
public String upload(@RequestParam("email") String email,
@RequestParam("username") String username,
@RequestParam("headerImg")MultipartFile headerImg,
@RequestParam("photos") MultipartFile[] photos) throws IOException {
//将获取到的信息进行输出,在开发中可以不要
log.info(email);
log.info(username);
log.info(headerImg.toString());
log.info(String.valueOf(photos.length));
//将文件保存到磁盘中
if (!headerImg.isEmpty()){
//获取上传文件的原文件名
String originalFilename = headerImg.getOriginalFilename();
headerImg.transferTo(new File("D:\\SpringBoot2InIDEATest02\\boot-test-admin\\src\\main\\resources\\uploadFile\\"+originalFilename));
}
if (photos.length>0){
for (MultipartFile photo : photos) {
if (!photo.isEmpty()){
String originalFilename = photo.getOriginalFilename();
photo.transferTo(new File("D:\\SpringBoot2InIDEATest02\\boot-test-admin\\src\\main\\resources\\uploadFile\\"+originalFilename));
}
}
}
//提交成功之后,返回主页
return "redirect:/index.html";
}
}
文件上传的时候,会存在默认的文件大小限制:
我们可以通过在全局配置文件中进行修改其中的默认值:
spring:
servlet:
multipart:
max-file-size: 10MB #单个文件上传大小的限制,单位MB
max-request-size: 100MB #多个文件上传大小的限制,单位MB
SpringBoot的错误处理机制:
我们可以直接将错误页面放到static包下或者templates包下,SpringBoot再出现错误之后就会直接跳转到错误页面
例如🐰如果出现了请求码为5开头的,例如502,505等就会找到5xx.html页面
如果出现404的请求码,就会找到404.html页面
如果像5xx.html这样的名称,再出现开头为5的错误请求码的时候,就会将这个页面作为错误页面
SpringBoot中如何处理异常:
1、通过自定义异常处理器(使用@ControllerAdvice注解和@ExceptionHandler注解进行处理):
示例代码:
@Slf4j
@ControllerAdvice //@ControllerAdvice注解的作用:这是一个增强的@Component注解,可以处理整个web工程中controller中的异常
public class GlobalExceptionHandler {
@ExceptionHandler({NullPointerException.class,ArithmeticException.class})//添加需要处理的异常的类型
//如果出现该类型的异常,就会执行以下的方法,返回一个视图名称
public String exception(Exception e){
log.error("错误信息为:"+e);
return "/";
}
2、通过@ResponseStatus和自定义异常进行处理异常:
@ResponseStatus注解的作用:将设置响应码和信息
@ResponseStatus(value = HttpStatus.FORBIDDEN ,reason = "Too Many Users") //设置响应的状态码和信息
public class UserTooManyException extends RuntimeException{//自定义一个异常
public UserTooManyException() {
}
public UserTooManyException(String message) {
super(message);
}
}
3、自定义异常解析器(实现接口HandlerExceptionResolver接口,通过@Component注解和@Order注解进行指定优先等级),可以通过将他的优先等级提高用来作为全局异常处理规则
示例代码:
@Order(Ordered.HIGHEST_PRECEDENCE) //指定异常处理器的优先等级
//为什么要指定优先等级,因为在SpringBoot底层会存在两个默认的异常解析器,第二个默认解析器会将所有的异常进行默认处理,所以,如果我们需要自己定义的异常解析器生效,就必须要制定优先等级
@Component //作用:将这个类表示为组件
/**
* 自定义我们自己的异常解析器
*/
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
try {
//这个代码的作用是通过Spring向tomcat服务器发送一个错误的信号,这一次请求就不会再进行运行了,优tomcat服务器发送/errot请求,SpringBoot中的BasicExceptionController视图解析器进行解析再通过ErrorViewResolver继续跳转到对应的错误视图(如果没有自定义错误视图,就会显示默认的错误视图)
response.sendError(520,"这是一个自定义的错误");
} catch (IOException e) {
e.printStackTrace();
}
return new ModelAndView();
}
}
如果我们没有对我们自定义的异常解析器进行指定优先等级,他就会排在最后,不会轮到她进行处理我们的异常,但是,如果我们进行指定了优先等级,在这里我们指定的是最高等级,所以,就会出现和上面图类型的情形(其中CustomerHandlerExceptionResolver是自定义的异常解析器)
Web原生组件注入(Servlet、listener、Filter):
向SpringBoot中注入原生的Servlet、Listener、Filter程序:
第一种方式,通过使用@ServletComponentScan和相应的注解进行注入Servlet、Listener、Filter
-
1、需要在SpringBoot启动类中添加加载Servlet注解的扫描注解,也就是@ServletComponentScan( ) 通过这个注解中的basepackages属性进行指定需要扫描的路径,如果不进行设置,默认就是当前SpringBoot启动类所在的包以及这个包的子包(也就是SpringBoot启动类的默认扫描范围)
-
2、通过编写我们需要注入的Servlet程序(需要继承Httpservlet类),在这个我们自定义的Servlet类中进行添加@WebServlet(添加监听器使用@WebListener,添加过滤器使用@WebFilter)注解,可以通过@WebServlet注解中的 urlPatterns属性值进行设置这个Servlet程序处理的路径。
实例代码:
//这是在SpringBoot的启动类中的代码
@ServletComponentScan(basePackages = "com.littleshark.admin.admin") //可以进行指定包进行扫描带有WebServlet(Servlet程序)的组件,将其进行加载
@SpringBootApplication
public class BootTestAdminApplication {
public static void main(String[] args) {
SpringApplication.run(BootTestAdminApplication.class, args);
}
}
//这是在我们自定义的Servlet中的代码
@WebServlet(urlPatterns = "/my")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过Servlet向页面中输入信息
resp.getWriter().write("zhangsan666");
}
}
//过滤器的代码:
@Slf4j
@WebFilter(urlPatterns = {"/css/*","/fonts/*"})
public class MyFilter extends HttpFilter {
@Override
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("进行过滤");
chain.doFilter(request,response);
}
@Override
public void init() throws ServletException {
log.info("进行初始化");
}
@Override
public void destroy() {
log.info("进行销毁");
}
}
//监听器的代码:
@Slf4j
@WebListener
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("项目初始化完成");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
log.info("项目已销毁");
}
}
第二种添加Servlet、Listener、Filter的方法:(推荐)
通过配置类在Spring的IOC容器中添加存放ServletRegistrationBean、ServletListenerRegistrationBean、FilterRegistrationBean进行实现注册Servlet、Listener、Filter
示例代码:
@Configuration //标志这是一个配置类
public class WebMvcConfig implements WebMvcConfigurer {
//实现WebMvcConfigurer表示可以自定义SpringMvc中的任意操作
@Override
public void addInterceptors(InterceptorRegistry registry) {
//将拦截器进行注册
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")//将拦截路径设置为所有路径,静态资源也会被拦截
.excludePathPatterns("/","/login","/css/**","/js/**","/fonts/**","/images/**");
//将静态资原进行放行,将登录页面进行放行
}
/**
* 在SpringIOC容器中添加ServletRegistrationBean组件,在ServletRegistrationBean组件中添加Servlet程序
* id值为方法名 servletRegistrationBean
* @return
*/
@Bean //表示会将这个方法的返回值放入Spring的IOC容器中
public ServletRegistrationBean servletRegistrationBean(){
MyServlet myServlet = new MyServlet();
//ServletRegistrationBean组件中添加Servlet,以及对应的路径
return new ServletRegistrationBean(myServlet,"/my","/zhangsan");
}
/**
* 在Spring的IOC容器中添加ServletListenerRegistrationBean组件,id值为servletListenerRegistrationBean
* @return
*/
@Bean //表示会将这个方法的返回值放入Spring的IOC容器中
public ServletListenerRegistrationBean servletListenerRegistrationBean(){
MyListener myListener = new MyListener();
//在ServletListenerRegistrationBean组件中添加监听器(不需要进行设置url,监听器是对整个生效)
return new ServletListenerRegistrationBean(myListener);
}
/**
* 在IOC容器中添加FilterRegistrationBean组件,id为filterRegistrationBean
* @return
*/
@Bean //表示会将这个方法的返回值放入Spring的IOC容器中
public FilterRegistrationBean filterRegistrationBean(){
MyFilter myFilter = new MyFilter();
//将过滤器添加到FilterRegistrationBean组件中,可以在后面添加需要进行过滤的Servlet
//例如:FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean(myFilter,servletRegistrationBean());
//表示这个过滤器会过滤servletRegistrationBean()方法中产生的Servlet
FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean(myFilter);
//进行添加过滤的路径
filterRegistrationBean.setUrlPatterns(Arrays.asList("/css/*","/my","/zhangsan"));
return filterRegistrationBean;
}
}
这种方法推荐使用。
为什么我们自定义的Servlet在访问其路径的时候没有被我们设置的拦截器进行拦截:
首先:我们需要知道,在我们没有注册我们默认的Servlet程序的shihou,SpringBoot项目中已经默认为我们配置好了一个Servlet程序(DispatcherServlet类)。
Spring是如何将DispatcherServlet进行配置的:
- 容器中通过DispathcerAutoConfiguration自动配置类进行配置,将DispathcerServlet的属性绑定到WebMvcProperties,对应到全局配置文件中的前缀为spring-mvc.
- 通过ServletRegistrationBean
将DispathcerServlet配置进来 - 默认映射的路径为 / 所有请求。
在这里,我们清楚了我们注册的Servlet和DispatcherServlet是同一个等级的Servlet,在Tomcat中,如果有多个Servlet都能处理同一个请求,原则为 精确选取原则(也就是通过Servlet中的映射的路径与请求的路径进行比较,选取最为精确的一个)
什么是精确选取原则:
举个例子:
请求路径为: /my/1
Servlet1的映射路径为:/my/ (my目录下的所有文件)
Servlet2的映射路径为:/my/1
因为Servlet1和Servlet2都能进行处理这个请求,所以就会进行精确选取原则,自然而然就选择到了Servlet2进行处理这个请求。
如果请求路径为:/my/2
这时候只有Servlet1能处理这个请求,所以只会有Servlet1进行处理这个请求。
为什么访问自定义的Servlet映射的路径不会被拦截器进行拦截原因:
因为我们发送的请求为我们自定义Servlet的映射路径,在这里,我们一共有两个Servlet,一个是我们自定义的Servlet,一个是DispathcerServlet,他们都能处理这个请求,所以就会通过精确选取原则进行选取映射路径和请求路径更相匹配的Servlet进行处理,自然就选到了我们自定义的Servlet进行处理这个请求,所以我们不会走通过DispatcherServlet-->Spring流程-->Tomcat处理这条线路,我们是直接通过Servlet在通过Tomcat进行处理,Servlet-->Tomcat处理,所以不会被拦截器进行拦截(在DispathcerServlet中配置的东西都不会生效,过滤器、监听器)
数据库连接连接:
创建步骤:
- 1、添加jdbc的启动器
<!--添加spring-boot-starter-data-jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
-
2、添加Mysql的驱动
-
<!--添加mysql的驱动,在SpringBoot底层会自动配置version--> <!--因为默认的SpringBoot的版本仲裁的版本是8.0.29版本,需要和自己的数据库版本进行匹配--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> 进行修改默认的mysql驱动版本的方式: 1、在maven引入mysql驱动的时候进行指定版本(根据maven的就近依赖原则) 实例: <!--添加mysql的驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.27</version> </dependency> 2、因为默认的版本是在当前pom.xml的父类中进行编写的,我们可以将其进行修改 <properties> <java.version>17</java.version> <mysql.version>8.0.27</mysql.version> </properties>
进行自定义数据库连接池:(在SpringBoot中引入的spring-boot-starter-data-jdbc中默认的数据库连接池为:Hikari数据库连接池)
//进行默认设置的数据库连接池(在没有时使用)
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
HikariDataSource dataSource(DataSourceProperties properties) {
HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
如果我们需要进行自定义数据库连接池,例如使用druid数据源有两种方式进行设置:
- 第一种方式:通过自定义的方式进行设置
- 第二种方式:通过寻找对应的starter进行自动设置
通过手动的方式进行设置我们的druid数据库连接池:
-
1、先将druid的依赖进行引入
<!--将druid数据库连接池进行引入--> <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.11</version> </dependency>
-
2、编写一个配置类进行配置数据库连接需要的属性
示例代码:
@Configuration //标志这是一个配置类 public class DataSourcesConfiguration { //因为只有在springIOC容器中没有DataSource对象的时候,才会使用默认的DataSource,所以,我们只需要向容器中存放一个 //数据库连接处对象就可以了 @ConfigurationProperties(prefix = "spring.datasource") //通过配置文件进行对druid进行初始化 @Bean public DataSource druidDataSource(){ //创建一个druid数据库连接池 DruidDataSource druidDataSource = new DruidDataSource(); return druidDataSource; } /** * 开启druid中的监控页面功能(通过注册一个Servlet进行实现) * //如果需要使用监控功能,还需要将druid中的filter属性进行行设置进行实现功能(这里通过yaml文件进行设置) * @return */ @Bean public ServletRegistrationBean statViewServlet(){ StatViewServlet statViewServlet = new StatViewServlet(); return new ServletRegistrationBean<StatViewServlet>(statViewServlet,"/druid/*"); } //通过druid进行关联Web应用(添加一个过滤器) @Bean public FilterRegistrationBean webStatFilter(){ WebStatFilter webStatFilter = new WebStatFilter(); FilterRegistrationBean<WebStatFilter> webStatFilterFilterRegistrationBean = new FilterRegistrationBean<>(webStatFilter); webStatFilterFilterRegistrationBean.setUrlPatterns(List.of("/")); webStatFilterFilterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); return webStatFilterFilterRegistrationBean; } }
spring:
datasource:
url: jdbc:mysql://localhost:3306/springtest #进行设置数据库连接池的rul
username: root #进行设置数据库连接处的用户名
password: 208262 #进行设置数据库连接池的密码
Filters: "stat,wall" #开启内置的监控页面和防火墙
第二种方式:通过引入starter的方式进行设置:
-
1、直接将starter进行引入
-
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.17</version> </dependency> 注意:通过starter的方式就不需要在进行导入druid的jar了
分析druid的自动配置:
druid的拓展配置项的前缀为:spring-datasource-druid
实例:
spring:
datasource:
druid:
filters: "stat.wall"
-
2、进行编写配置
-
spring: datasource: url: jdbc:mysql://localhost:3306/springtest #进行设置数据库连接池的rul username: root #进行设置数据库连接处的用户名 password: 208262 #进行设置数据库连接池的密码 druid: stat-view-servlet: #配置监控页功能的 enabled: true #将监控页面开启 login-username: admin #登录名称 login-password: 123456 #登录的密码 web-stat-filter: #监控web enabled: true #开启web监控 filters: stat,wall #使用stat(监控)和wall(防火墙) driver-class-name: com.mysql.cj.jdbc.Driver # 具体的还可以在根据官方文档进行设置
bruid启动器的配置:https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter
SpringBoot整合Mybatis:
-
1、先将mybatis的启动器进行引入
-
<!--将mybatis的启动器进行引入--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version> </dependency>
通过查看mybatisAutoConfiguration自动配置类,我们可以知道,我们在之后可以通过修改以mybatis为前缀的属性进行自定义我们的mybatis
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })//只有到容器中存在SqlSessionfactory组件和SqlSessionFactoryBean组件的时候进行加载这个自动配置类
@ConditionalOnSingleCandidate(DataSource.class)//只有当存在一个数据库连接池的时候进行加载这个类
@EnableConfigurationProperties(MybatisProperties.class) //加载和这个自动配置类向绑定properties文件
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class }) //在DataSourceAutoConfiguration自动配置类和MybatisLanguageDriverAutoConfiguration自动配置类完成之后在进行加载该自动配置类
public class MybatisAutoConfiguration implements InitializingBean {}
@ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX) //将这个类和MybatisProperties.MYBATIS_PIX进行绑定,前提是需要将这个类作为组件
public class MybatisProperties {
public static final String MYBATIS_PREFIX = "mybatis";//通过修改前缀为mybatis的属性进行自定义我们的mybatis
}
Mybatis的启动类为我们配置了什么:
- 1、配置好了Mybatis的全局配置文件(通过下xml方式中的mybatis-config.xml文件)
- 2、SqlSessionFactory
- 3、SqlSession 通过SqlSessionTemplate进行配置
- 4、Mapper接口 (只要我们编写的Mybatis的Mapper接口中有标识注解@Mapper就会被导入的AutoConfigurationMapperScannerRegistrat组件进行扫描到)
使用mybatis的步骤:
可以通过mybatis的逆向工程 进行获取mapper和pojo等
在使用mybatis的时候,可以通过两种方式进行使用:
-
第一种方式:通过xml文件的方式进行使用
-
第二种方式:通过注解的方式进行使用
实例代码:
//在Mapper接口中的每一个方法种添加对应需要执行的注解(例如需要查询就添加@Servlet注解),在注解种进行编写Sql语句(编写的方式和在mapper映射文件中的方式一样),通过这样就可以不用创建mapper映射文件 @Select("select * from t_user where id=#{id}") User selectByPrimaryKey(Integer id);
-
第三种方式:混合模式,既可以有mapper映射文件,可以通过注解的方式进行
如果嫌在每一个Mapper接口中标注@Mapper注解,可以在SpringBoot的启动类上使用@MapperScan注解进行指定包进行扫描Mapper接口
@MapperScan(basePackages = "com.littleshark.admin.admin.mapper")
@ServletComponentScan(basePackages = "com.littleshark.admin.admin") //可以进行指定包进行扫描带有WebServlet(Servlet程序)的组件,将其进行加载
@SpringBootApplication
public class BootTestAdminApplication {
public static void main(String[] args) {
SpringApplication.run(BootTestAdminApplication.class, args);
}
}
SpringBoot2.4版本之后,自动导入的Junit5中,会将JUnit Vintage(支持Junit4和Junit3版本)的版块进行移除
JUnit 5’s Vintage Engine Removed from spring-boot-starter-test
这是SpringBoot官方的说法
如果需要在SpringBoot2.4版本之后继续支持Junit4等,需要自动将Junit Vintage模块进行添加进入
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
在Junit5中,它可以支持Spring的任意功能,例如自动注入,事务等(@Autowired,@Transactional....),但是如果需要使用的Spring中的IOC容器等,就需要使用@SpringBootTest注解或者@ExtendWith注解(让一个有@SpringBootTest注解的测试类伴随这个测试类进行启动)
Junit5在开发中常用的注解:
Junit5的用户使用手册地址:https://junit.org/junit5/docs/current/user-guide/
Junit5中常用的注解的测试代码如下:
package com.littleshark.admin.admin;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest //@SpringBootTest注解的作用:将Spring进行伴随启动,可以获取存入Ioc的组件
@DisplayName("Junit5Test") //这个注解的作用是类似于取名字
public class Junit5Test {
@Test //标志这是一个测试方法
void testBeforeEach(){
System.out.println("testBeforeEach测试方法执行了");
}
@BeforeEach //@BeforeEach注解的作用:在每一个测试方法执行之前进行执行该方法
void beforeEachMethod(){
System.out.println("测试的方法要开始了!");
}
@AfterEach //@AfterEach注解的作用:在每一个测试方法结束之后进行执行该方法
void afterEachMethod(){
System.out.println("测试的方法结束了!");
}
@AfterAll
static //@AfterAll注解的作用:在所有的测试方法都结束之后进行执行的方法,注意,需要通过static进行标注
void afterAllMethod(){
System.out.println("所有的测试方法都已经结束了!");
}
@BeforeAll
static //@BeforeAll注解的作用:在所有的测试方法执行之前进行执行,注意,需要通过static关键字进行标注
void beforeAllMethod(){
System.out.println("所有的测试方法都要开始了!");
}
@Disabled //@Disabled注解的作用:表示这个一个不能使用运行的测试方法,就等同于将这个方法进行删除
@Test
void testDisabled(){
System.out.println("测试Disabled方法!");
}
@Timeout(value = 2) //@Timeout注解的租用:设置超时时间,一旦超时就抛出异常,默认单位为秒
@Test
void testTimeOut(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@RepeatedTest(3) //@RepeatedTest注解的作用:重复执行该测试方法多少次,可以不需要在添加@Test注解
void testRepeatedTestMethod(){
System.out.println("3");
}
}
Junit5中的断言机制:
是在org.junit.jupiter.api.Assertions中的静态方法
断言的用法实例:
package com.littleshark.admin.admin;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class TestAssert {
@DisplayName("测试Assertions中的assertEquals方法")
@Test
void testAssertEquals(){
Assertions.assertEquals(1,2,"通过Equals方法进行比较,期望的1不等于实际的2");
System.out.println("程序顺利运行");
}
@DisplayName("测试Assertions中的assertSame方法")
@Test
void testAssertSame(){
Assertions.assertSame(1,1,"通过==进行比较,期望的1等于实际的1");
System.out.println("程序顺利运行!");
}
@DisplayName("测试Assertions中的assertNull方法")
@Test
void testAssertNUll(){
Assertions.assertNull(null);//因为因为传入的是null,所以会顺利通过
Assertions.assertNull(new Object(),"这个实际的对象不是一个null");
System.out.println("程序顺利运行!");
}
@DisplayName("测试Assertions中的assertThrows方法")
@Test
void testAssertThrows(){
Assertions.assertThrows(ArithmeticException.class,()-> {
int i = 10 / 0;
},"这个程序居然没有出现异常!");
System.out.println("这个程序中出现了对应的异常!");
}
@DisplayName("测试Assertions中的assertAll方法,组合断言")
@Test
void test(){
Assertions.assertAll("这是一个组合断言",
()->{Assertions.assertNull(null,"这个对象不是一个null") ;},
()->{Assertions.assertEquals(1,1,"预期的1不等于实际的数字");}
);
System.out.println("所有的断言都顺利执行了!");
}
}
断言一旦失败,就会终止测试方法的执行,并且抛出一个异常。
Junit5中的假设assumptions:
assumptions的作用:
再假设不成立就会终止测试方法的执行,直接跳过这个测试方法
assumptions和assert的区别;
assert在断言失败之后会终止测试的运行,并且抛出一个异常
assumptions在假设失败之后,只会终止测试的运行,直接跳过这个测试方法
实例代码:
package com.littleshark.admin.admin;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class TestAssumptions {
@DisplayName("测试假设机制,前置条件")
@Test
void testAssumptions(){
Assumptions.assumeTrue(false,"假设失败!");
System.out.println("假设成功");
}
}
跳过的图标:
Junit5中的参数测试:
通过注解@ParameterizedTest进行标注的测试方法,可以不需要在添加@Test注解
package com.littleshark.admin.admin;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
@DisplayName("参数测试")
public class TestParam {
@ParameterizedTest
@MethodSource("getStrings")
//如果是通过MethodSource的方式获取参数,需要注意填写的方法必须是静态方法,并且返回值类型必须是Stream(流的形式)作为返回值
//会可使用是获取参数的注解有
// @ValueSource
// @NullSource等
void test(String s){
System.out.println(s);
}
//如果通过
static Stream getStrings(){
return Stream.of("little","shark","is","kkk");
}
}
SpringBoot中的Actuator(指标监控):
使用步骤:
-
1、将actuator的依赖进行引入
-
<!--将Actuator依赖进行引入,用于指标监控--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
-
2、将端点进行暴露出来
-
# 所有的关于指标监控(actuator)的设置都在management中 management: endpoints: enabled-by-default: false #将所有的端点进行隐藏,默认是开启的(避免敏感端点暴露) web: exposure: include: '*' #以web方式暴露所有端点 endpoint: #进行设置每一个端点的具体配置 health: enabled: true show-details: always #让健康信息显示更多信息 info: enabled: true #开启info端点 metrics: enabled: true #开启监控指标端点
这样设置之后,就可以进行i使用指标监控功能了
实例:
常用的端点:
最常用的端点:
自定义一个Health检查组件:
package com.littleshark.admin.admin.health;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.Status;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component //将健康检查组件放入Spring的IOC容器中
public class MyHealthIndicator extends AbstractHealthIndicator {
//这个类的名字需要含有HealthIndicator,在页面中显示的health组件的名字是将HealthIndicator去掉之后剩下的内容(在这里就是My)。
/**
* 检查健康状态的方法
* @param builder
* @throws Exception
*/
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
Map<String,String> map=new HashMap<>();
if (1==1){
builder.status(Status.UP);//Up表示为正常运行
builder.withDetail("OK","程序正常运行");
map.put("ms","程序正常运行");
}else {
builder.status(Status.OUT_OF_SERVICE);//服务器不工作了
map.put("ms","状态不正确");
builder.withDetail("errorCode","100");
}
//将map集合中的信息进行保存到builder中
builder.withDetails(map);
}
}
定义显示的Info信息:
-
第一种方式:在SpringBoot的全局配置文件中进行设置
使用这种方式可能会失效
info: springName: LittleSharkTest version: 1.0.0 #将pom.xml文件中的内容的信息作为值的方式,使用@@进行获取或者通过${}进行获取(推荐使用${}的方式进行获取) pomgroupId: ${project.name} #获取pom.xml文件中的artifactId属性(对应的存在层级关系,maven的根标签为project,指的是project下的artifactId中的属性值) #pomname: @project.name@ #获取pom.xml文件中的根标签下的name标签中的属性
-
第二种方式:通过编写一个组件进行设置actuator中info中的信息
package com.littleshark.admin.admin.actuator.info;
import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.stereotype.Component;
@Component
public class MyInfoContributor implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
builder.withDetail("StringName","Littleshark");
}
}
SpringBoot中的高级特性:Profile环境切换:
可以通过切换激活某一个环境,从而使用不同的配置文件,得到特定的配置。
默认的配置文件总是会加载的。
使用方法:
首先,需要明白如何创建不同环境的配置文件,创建环境配置文件的文件名为application-env.yaml,这里举一个例子:如果需要创建一个测试类的配置文件,就可以创建为application-test.yaml的配置文件进行自定义,需要注意,默认的配置文件application.yaml文件和application.properties文件始终都会进行加载。
如果激活某一个特定的环境:通过默认的全局配置文件进行设置
如果在环境配置文件中的配置属性和默认配置文件中的配置属性相重名,以特定的环境配置文件中设置的为主
实例:
外部配置源:
SpringBoot的启动流程:
本文作者:just1t
本文链接:https://www.cnblogs.com/just1t/p/16928390.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步