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再出现错误之后就会直接跳转到错误页面
例如
标签:笔记,boot,autoconfigure,SpringBoot2,springframework,org,public,进行 From: https://www.cnblogs.com/just1t/p/16928390.html