- 创建一个maven工程
- 探究Hello World
- 主程序类、主入口类
- 使用Spring Initializer快速创建SpringBoot项目
- 配置文件的编写
- web开发
- 嵌入式 Servlet 容器
- Docker
- SpringBoot与数据访问
- SpringBoot启动原理以及监听
创建一个maven工程
- 创建 maven 工程
- 导入相关依赖jar包
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
<!-- Add typical dependencies for a web application -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
- 编写一个主程序,启动Spring Boot应用
//该类必须与Controller包同层
@SpringBootApplication
public class HelloWordMainApplication {
public static void main(String[] args) {
//启动Spring
SpringApplication.run(HelloWordMainApplication.class,args);
}
}
- 编写相关的 Controller 和 Service
@Controller
public class HelloController {
@ResponseBody
@RequestMapping("/hello")
public String hello(){
return "Hello World";
}
}
- 简化部署工作
<!-- 这个插件,可以把应用打包成一个可执行的jar包,放到 pom.xml 文件中 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<!--可以在maven中的生命周期里打成jar包,然后在cmd命令行中启动该jar包-->
cd Dessktop
java -jar spring-boot-01-helloword-1.0-SNAPSHOT.jar
<!--最终可以通过访问 http://localhost:8080/hello 直接访问后台,不需要项目名-->
探究Hello World
- POM文件(都可以点进去看)
<!--父项目-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/>
</parent>
<!--父项目还依赖另一个父项目,由该项目来中的 <properties> 属性来管理spring boot所有的依赖版本,也称为Spring Boot 的仲裁中心,因此以后导入依赖默认不需要写版本号(没有在里面管理就要写版本号) -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
- 依赖导入
- spring-boot-starter:Spring Boot 场景启动器,帮我们导入了web模块正常启动所依赖的组件
<!-- Spring Boot 将所有的功能场景都抽取出来,做成一个个的starters(启动器),只需要在项目里面引入这些starter相关场景的所有依赖都会导入进来。需要导入什么功能就导入什么场景启动器 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
主程序类、主入口类
- @SpringBootApplication:Spring Boot 应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot 就应该运行这个类的main方法来启动 SpringBoot 应用
- @SpringBootConfiguration:修饰@SpringBootApplication,是Spring Boot 的配置类,可以标记在某个类上,表示是一个 Spring Boot 配置类
- @Configuration:修饰@SpringBootConfiguratio,是Spring 配置类注解,该注解也是用 @Component 修饰的,表明是一个组件
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
- @EnableAutoConfiguration:开启自动配置功能,以前需要配置的东西Spring已经帮我们自动配置
//EnableAutoConfiguration中的修饰两个注解
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
- @AutoConfigurationPackage:自动配置包
- @Import({Registrar.class}):spring的底层注解,给容器中导入组件
- Registrar.class:将主配置类(@SpringBootApplication)所在包及所有子包所有组件扫描到Spring容器中,所以主配置类要放在与包同级
- @Import({Registrar.class}):spring的底层注解,给容器中导入组件
- @Import({AutoConfigurationImportSelector.class})
- AutoConfigurationImportSelector导入哪些组件的选择器,该类中会将需要导入的组件以全类名的方式封装在数组中返回,这些组件会被类加载器在spring.factories中将其添加到容器中,有了这些自动配置类,免去了手动编写注入功能组件等的工作。
//选择器
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;
}
- SpringBoot在启动时会从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效了,帮我们自动进行配置工作
- C:\Users\DELL.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.2.1.RELEASE\spring-boot-autoconfigure-2.2.1.RELEASE.jar!\META-INF\spring.factories
使用Spring Initializer快速创建SpringBoot项目
IDEA支持Spring项目的创建向导快速创建一个SpringBoot项目,选择所需要的模块,向导会联网创建SpringBoot项目
默认生成的SpringBoot项目
- 主程序已经写好了,我们只需要导入自己的逻辑
- resources文件夹目录结构
- static:保存所有的静态资源,像js、css、images
- templates:保存所有的模块页面(SpringBoot默认jar包使用嵌入式Tomcat,默认不支持JSP页面),但是可以使用模板引擎(freemarke、thymeleaf)
- application.properties:SpringBoot应用的配置文件,可以修改一些默认配置,像端口号
- 配置文件
- 配置文件名称是固定的(已是默认值,也可手动更改)
- application.properties
- application.yml
- 配置文件名称是固定的(已是默认值,也可手动更改)
- YAML:标记语言(A Markup Language)
- 以数据为中心进行配置,比xml、json等更适合做配置文件
#application.properties文件配置端口号
server.port=8081
#application.yml文件配置端口号
server:
port: 8081
配置文件的编写
YAML 语法
- 基本语法
- k:(空格)v :表示一对键值对(必须有空格)
- 以空格的缩进来控制层级关系,只要左对齐的一列数据,就都是同一层级的,同时属性和值也是大小写敏感的。
server:
port: 8081
path: /hello
值的写法:
- 字面量:普通的值(数字,字符串,布尔)
- k:v :字面量直接写入
- “” : 双引号不会转义字符串里面的特殊字符,特殊字符会作为本身表示的意思
- name: “zhangshan \n lisi”
- 输出:zhangsan \n lisi
- ‘’ : 单引号会转义特殊字符,特殊字符最终只是一个普通的字符串数据
- name: “zhangshan \n lisi”
- 输出:zhangsan 换行 lisi
- 对象、Map(属性和值)(键值对):k: v : 在下一行来写对象的属性和值的关系,注意缩进
- 分行写法:注意缩进
- 行内写法:大括号,里面键值对间有空格
#分行写法
friends:
lastName:zhangsan
age:20
#行内写法
friends: {lastName: zhangsan,age: 20}
- 数组:用 - 值表示数组中的元素
- 分行写法:注意缩进
- 行内写法:中括号,里面对象间有空格
#分行写法
pets:
- cat
- dog
- pig
#行内写法
pets: [cat,dog,pig]
配置文件值注入
配置文件:全局变量
person:
name: zhangsan
age: 20
pom.xml
- 导入配置文件处理器,以后编写配置文件就会有提示了
<!--配置数据源的jar包(配置文件处理器),将配置文件值注入对象-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.1.7.RELEASE</version>
<optional>true</optional>
</dependency>
JavaBean
- 将配置文件配置的每一个属性的值,映射到这个组件中
- @ConfigurationProperties(prefix = “person”):告诉springboot将本类中的所有属性和配置文件中相关的配置进行绑定
- prefix = “person”:这个是指配置文件中哪个下面的所有属性进行一一映射
- 同时只有是容器中的组件才能使用 @ConfigurationProperties(prefix = “person”),所有要加入注释 @Component
- @Value():标注一个属性,注入属性值
/**
* @author Ming
* @date 2019/11/14 - 22:48
* 将配置文件配置的每一个属性的值,映射到这个组件中
* @ConfigurationProperties(prefix = "person"):告诉springboot将本类中的所有属性和配置文件中相关的配置进行绑定
* prefix = "person":这个是指配置文件中哪个下面的所有属性进行一一映射
* 同时只有是容器中的组件才能使用 @ConfigurationProperties(prefix = "person"),所有要加入注释 @Component
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private Integer age;
//...getter和setter方法...
}
//也可以
@Component
public class Person {
@Email
@Value("${person.name}")
private String name;
@Value("#{11*5}")
private Integer age;
private Map<String,Object> map;
}
@Configurationproperties | @Value | |||
---|---|---|---|---|
功能 | 批量注入配置文件属性 | 只能注入一个属性值 | ||
松散绑定(eg:last-name) | 支持 | 不支持 | ||
SpEL | 不支持 | 支持 | ||
JSR303数据校验 | 支持 | 不支持 | ||
复杂类型封装 | 支持 | 不支持 |
@PropertySource和@ImportResource
@PropertySource:加载指定的配置文件
//person上的注解
@PropertySource(value = "classpath:person.properties")
//person.properties文件上的内容
person.name=李四person.properties
person.map.hhh='123'
person.map.k2=321
@ImportResource:导入Spring的配置文件,让配置文件里面的内容生效
//标注在主配置类上,让配置文件生效
@ImportResource(location={"classpath:beans.xml"})
SpringBoot推荐给容器中添加组件的方式:不推荐使用xml文件,而使用配置类(注解方式)
- 配置类==Spring配置文件
- 使用@Bean向容器中添加组件,id就是标注注解的类名称,返回啥就向容器中添加啥
/**
* @author Ming
* @date 2019/11/24 - 23:18
* @Configration:指明当前类是一个配置类,就是用来代替之前的Spring配置文件
* 在配置类中的@Bean就相当于<bean></bean>,且 id 等于类的名称,返回啥就向容器添加啥
*/
@Configuration
public class MyApplicationConfig {
@Bean
public HelloService helloService(){
System.out.println("配置类给Spring添加组件了......");
return new HelloService();
}
}
配置文件占位符
随机数:{random.int}、{random.uuid}、{random.int[1024,65536]}…
占位符获取之前配置的值,如果没有可以用冒号(:)指定默认值以防止报错
person.name=李四${random.uuid}
person.map.hhh='123'
person.map.k2=${person.name}
Profile
1、多Profile文件
- 我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml,默认使用application.properties的配置
- yml支持多文档块方式
- 可以用—分开文档块,然后用active来激活
server:
port: 8081
spring:
profile:
active:dev
---
server:
port: 8081
spring:
profiles:dev
---
server:
port: 8084
spring:
profiles: prod
- 激活指定Pofile
- 在配置文件的指定
- 命令行激活:在配置里的Program arguments行中:–spring.profiles.active=dev
- cmd命令行:java -jar jar包名称 --spring.profiles.active=dev
- 虚拟机参数写法:在 VM options中配置:-Dspring.profiles.active=dev
<!-- 在application.properties中指定,dev也就是{profile}的值 -->
spring.profiles.active=dev
<!-- 在 VM options中指定,dev也就是{profile}的值 -->
-Dspring.profiles.active=dev
配置文件加载位置
可识别位置(有优先级):高优先级会覆盖低优先级
- file:./config/
- file:./
- classpath:/config/
- classpath:/
可以通过spring.config.location来改变默认的配置文件位置
外部配置加载顺序
- 命令行参数
java -jar spring-boot-01-helloword-1.0-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc
- 1.来自java:comp/env的NDI属性
- 2.java系统属性(System.getProperties())
- 3.操作系统环境变量
- RandomValuePropertySource配置的random.*属性值
由jar包外向jar包内进行寻找
- 4.jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件
- 5.jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件
再来加载不带profile
-
6.jar包外部的application-{profile}.properties或application.yml(不带spring.profile)配置文件
-
7.jar包内部的application-{profile}.properties或application.yml(不带spring.profile)配置文件
-
8.@Configuration注解类上的@PropertySource
-
9.通过SpringApplication.setDefaultProperties指定的默认属性
web开发
自动配置原理
自动配置原理
- SpringBoot启动时加载自动配置类,开启了自动配置功能@EnableConfiguration
//扫描jar包类路径下META-INF/spring.factories,将扫描到的这些文件的内容整合成properties对象
//再从properties中获取到EnableConfiguration.class类(类名)对应的值
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加载器
public final class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap();
private SpringFactoriesLoader() {
}
# Auto Configure
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.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
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.ElasticsearchAutoConfiguration,\
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.ReactiveRestClientAutoConfiguration,\
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.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.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
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.groovy.template.GroovyTemplateAutoConfiguration,\
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.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.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
每一个 xxxxAutoConfiguration 类都是容器中的一个组件,都加入到容器中,用他们来做自动配置
@Configuration(
proxyBeanMethods = false
)//表示是一个配置类,以前编写的文件一样,也可以给容器中添加组件
@EnableConfigurationProperties({HttpProperties.class})//启动指定类的ConfigurationProperties功能,将配置文件中对应的值和HttpEncodingProperties绑定起来,并且把它加入到IOC容器中
@ConditionalOnWebApplication(
type = Type.SERVLET
)//Spring底层@Conditional注解,根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效
@ConditionalOnClass({CharacterEncodingFilter.class})//判断当前项目是否有这个配置类 CharacterEncodingFilter,SpringMVC中解决乱码问题的过滤器
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true
)//判断配置文件是否存在某个配置,如果不存在,判断也是成立的,即使不配置,也是默认生效的
public class HttpEncodingAutoConfiguration {
//已经和SpringBoot配置文件映射了
private final Encoding properties;
//只有一个有参构造器的情况下,参数的值会从容器中拿
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
@Bean//给容器中添加组件,组件的某些值需要从容器中拿
@ConditionalOnMissingBean//容器中没有这个组件
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
return filter;
}
所有在配置文件中能配置的属性值都是xxxxProperties类中封装着,配置文件能配什么就可以参照某个功能对应的这个属性类
@ConfigurationProperties(
prefix = "spring.http"
)//从配置文件中获取指定的值和bean属性进行绑定
public class HttpProperties {
使用精髓:
-
SpringBoot启动会自动加载大量的配置类
-
首先看我们所需要的功能有没有SpringBoot默认写好的自动配置类
-
有的话可以看这个自动配置类到底配置了哪些的组件(有的话就可以不用配了)
-
给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这些属性的值
自动配置类需要一定条件才能生效
xxxxAutoConfiguration:自动配置类,给容器中添加组件
xxxxProperties:封装配置文件中相关的属性值 -
可以通过debug=true 属性来查看自动配置类是否生效
日志框架
市面上的框架:JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j
日志门面(日志抽象层) | 日志实现 |
---|---|
JCL、SLF4j、jboss-logging | Log4j、JUL、Log4j2、Logback |
SpringBoot底层是Spring框架,Spring框架使用的是JCL。然而SpringBoot使用的是SLF4J和logback
日志配置
Logger logger = LoggerFactory.getLogger(getClass());
@Test
void contextLoads() {
//日志级别 由低到高trace<debug<info<warm<error
//可以调整输出级别就可以在这个级别和更高级别输出
//Spring默认级别是info级别
logger.trace("trace日志");
logger.debug("debug日志");
logger.info("info日志");
logger.warn("warm日志");
logger.error("error日志");
}
可以调节日志级别
#logging.level.+包名=级别名称
logging.level.com.springboot=trace
#在当前项目下生成springboot.log日志,不指定路径默认在根目录下
logging.file.name=D:/SpringBoot.log
#在项目当前磁盘根目录下创建也就是D盘
logging.path=/spring/log
#在控制台输出的格式,默认为时间+日志级别+线程Id+类名+信息
#logging.pattern.console=
#指定文件中日志输出格式
#logging.pattern.file=
SpringBoot对前端的支持
SpringBoot对静态资源的映射规则
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
}
//配置欢迎页映射
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));
return welcomePageHandlerMapping;
}
- 所有的 /webjars/** 都去classpath:/META-INF/resource/webjars/找资源
- webjars:以jar包的形式引入静态资源,引入需要在xml文件中引入
- http://localhost:8080/webjars/jquery/3.4.1/jquery.js
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.4.1</version>
</dependency>
- /**,访问当前项目的任何资源
"classpath:/META-INF/resources/"
"classpath:/resources/"
"classpath:/static/"
"classpath:/public/"
- 欢迎页:静态资源文件夹下的所有index.html。被“/**”映射
local- 放在resources/public文件下
- css等放在resources/static下
- 图标放在resources/resources下
- 也可在application.properties中配置spring.resources
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,classpath:/
SpringBoot模板引擎
- SpringBoot推荐是使用Thymeleaf模板引擎:语法简单,功能强大
<!-- 修改版本号,thymeleaf3.+,layout2.+ -->
<properties>
<java.version>1.8</java.version>
<!--<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>-->
<thymeleaf-layout-dialect.version>2.2.1</thymeleaf-layout-dialect.version>
</properties>
<!-- 映入版本starter,默认是2点多版本 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
- Thymeleaf 使用和用法
@ConfigurationProperties(
prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
private boolean checkTemplate = true;
private boolean checkTemplateLocation = true;
//前缀和后缀
private String prefix = "classpath:/templates/";
private String suffix = ".html";
private String mode = "HTML";
private Charset encoding;
private boolean cache;
private Integer templateResolverOrder;
private String[] viewNames;
private String[] excludedViewNames;
private boolean enableSpringElCompiler;
private boolean renderHiddenMarkersBeforeCheckboxes;
private boolean enabled;
private final ThymeleafProperties.Servlet servlet;
private final ThymeleafProperties.Reactive reactive;
@RequestMapping("/success")
public String success(){
//解析完访问classpath:/templates/success.html
//不能加ResponseBody,否则封装为字符串了
return "success";
}
- 1、导入 Thymeleaf 的命名空间
<html lang="en" xmlns:th="http://www.thymeleaf.org">
- 2、使用 Thymeleaf 语法
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--<h1>成功!</h1>-->
<div th:text="${hello}">如果没有后端,则显示这些内容</div>
</body>
</html>
- 3、语法规则
- th:text:改变元素里面的文本内容
- th:可以用其替换掉容易元素原先的值
- 4、表达式语法
Simple expressions: (表达式语法)
Variable Expressions:${...} 获取变量值,OGNL表达式
1.获取属性值、调用方法
2.使用内置的基本对象
3.内置的工具对象
Selection Variable Expressions: *{...} :和 ${} 功能一样
1、补充:配合 th:object 使用
<div th:object="${session.user}">
<p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
<p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
<p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
</div>
Message Expressions: #{...} :获取国际化内容
Link URL Expressions: @{...} :定义 url 链接
<!-- Will produce 'http://localhost:8080/gtvg/order/details?orderId=3' (plus rewriting) -->
<a href="details.html" th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a>
<!-- Will produce '/gtvg/order/details?orderId=3' (plus rewriting) -->
<a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a>
<!-- Will produce '/gtvg/order/3/details' (plus rewriting) -->
<a href="details.html" th:href="@{/order/{orderId}/details(orderId=${o.id})}">view</a>
Fragment Expressions: ~{...} :片段引用表达式
Literals (字面量)
Text literals: 'one text' , 'Another one!' ,…
Number literals: 0 , 34 , 3.0 , 12.3 ,…
Boolean literals: true , false
Null literal: null
Literal tokens: one , sometext , main ,…
Text operations:(文本操作)
String concatenation: +
Literal substitutions: |The name is ${name}|
Arithmetic operations: (数学运算)
Binary operators: + , - , * , / , %
Minus sign (unary operator): -
Boolean operations: (布尔运算)
Binary operators: and , or
Boolean negation (unary operator): ! , not
Comparisons and equality: (比较运算)
Comparators: > , < , >= , <= ( gt , lt , ge , le )
Equality operators: == , != ( eq , ne )
Conditional operators: (条件运算:比如三元运算符)
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
Special tokens: (特殊运算符)
No-Operation:_
SpringMVC自动配置
Spring Boot为Spring MVC提供了自动配置,可与大多数应用程序完美配合。
自动配置在Spring的默认值之上添加了以下功能:
- 包含ContentNegotiatingViewResolver和BeanNameViewResolver。
- 配置 ViewResolver(视图解析器,根据方法的返回值得到视图对象),视图对象决定如何渲染(转发?重定向?)
- ContentNegotiatingViewResolver :组合所有的视图解析器
- 如何定制和添加一个视图解析器,自动的将其组合进来。
- 支持提供静态资源,包括对WebJars的支持。
- 自动注册了 Converter,GenericConverter,Formatter豆类
- Converter:转换器,类型转换使用Converter
- Formatter:格式化器,如日期的转换
- 支持HttpMessageConverters
- 支持HttpMessageConverters:消息转换器,用于转换Http请求和响应的,如User对象转换为Json
- HttpMessageConverters 是从容器中确定的,从容器中获取所有的HTTP转换器,所以可以自己给容器添加,将自己的组件注册在容器中。
- 自动注册MessageCodesResolver
- MessageCodesResolver:定义错误代码生成规则
- 静态index.html支持:静态首页的访问
- 定制Favicon支持
- 自动使用ConfigurableWebBindingInitializer
- ConfigurableWebBindingInitializer:我们也可以配置一个来替换原有的
如果您想保留Spring Boot MVC功能,而只想添加其他MVC配置(拦截器,格式化程序,视图控制器等),则可以添加自己@Configuration的type类 WebMvcConfigurerAdapter,但不添加 @EnableWebMvc。如果您希望提供的自定义实例RequestMappingHandlerMapping,RequestMappingHandlerAdapter或者 ExceptionHandlerExceptionResolver可以声明一个WebMvcRegistrationsAdapter 提供此类组件的实例。
如果您想完全控制Spring MVC,可以使用添加自己的@Configuration 注释@EnableWebMvc。
如何修改SpringBoot的默认配置
- SpringBoot 在自动配置很多组件的时候,先看用户是否有自己配置的组件(@Bean、@Component),如果有就用用户自己配置的,如果没有就自动配置。如果有些组件可以有多个(视图解析器)的时候,SpringBoot将用户自己配置的和自身的组合起来
- 扩展SpringMVC(添加配置类方法)
- 编写一个配置类,该配置类(@Configuration),是WebMvcConfigurerAdapter类型,不能用 @EnableWebMvc 标注,添加了会使其他的MVC配置类失效
- 原理:
- WebMvcAutoConfiguration 是 SpringMVC 的自动配置类
- 在做其他配置时会导入@ImportWebMvcConfiguration.class
- 扩展SpringMVC(添加配置类方法)
//即保留了原有的自动配置,也能用我们的扩展
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
//即保留了原有的自动配置,也能用我们的扩展
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//浏览器发送 /hello 请求时来到 success.html
registry.addViewController("hello").setViewName("success");
}
@Bean
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter(){
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//super.addViewControllers(registry);
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
};
return adapter;
};
}
国际化开发编码
- 可编写一个配置类来代替原有的国际解析器
- 1、添加一个配置类来继承 LocaleResolver 接口
- 2、将该类添加到 MVC 的配置类中
public class MyLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
Locale locale = Locale.getDefault();
String l = httpServletRequest.getParameter("l");
if(StringUtils.isEmpty(l)){
String[] spilt = l.split("_");
locale = new Locale(spilt[0],spilt[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
=================================================
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
禁用thymeleaf缓存
- 1、在配置文件中配置相关信息
- 2、ctrl+F9
# 禁用模板引擎缓存
spring.thymeleaf.cache=false
拦截器进行登录检查
- 1、编写一个拦截器
- 2、将拦截器注册到MVC中
/**
* @author Ming
* @date 2020/1/12 - 15:52
*
* 登录的拦截检查,要实现HandlerInterceptor 接口
*/
public class MyHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object obj = request.getSession().getAttribute("loginUser");
if(obj==null){
//未登录,拦截,返回登录页面
request.setAttribute("msg","没有权限,请先登录!");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else{
return true;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
=======================
//MyMvcConfig类,重写方法
@Bean
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter(){
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//super.addViewControllers(registry);
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
registry.addViewController("/main.html").setViewName("main");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册拦截器,拦截所有请求,排除登录页面的请求,静态资源不需要排除
registry.addInterceptor(new MyHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/index.html","/","/user/login");
}
};
return adapter;
};
RestfulCRUD操作
- 1、RestfulCRUD和普通的CRUD区别
普通CRUD | RestfulCRUD | |
---|---|---|
查询 | getEmp | emp—GET |
添加 | addEmp?xxx | emp—POST |
修改 | updateEmp?id=xxx&xxx=xx | emp/{id}—PUT |
删除 | deleteEmp?id=xx | emp/{ID}—DELETE |
- 2、SpringBoot 错误处理机制
- 默认是一个页面,如果不是则返回 JSON 数据
- 默认给容器中添加了以下组件
- 1、DefaultErrorAttributes
- 2、BasicErrorAttributes:处理默认 /error 请求
- 3、ErrorPageCustomizer:定制错误的响应规则
- 4、DefaultErrorViewResolver:去哪个页面
@RequestMapping(
produces = {"text/html"}
)//产生 Html 数据,浏览器来到这个处理
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = this.getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
//去到哪个页面作为错误页面,包含页面地址和页面内容
ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
return modelAndView != null ? modelAndView : new ModelAndView("error", model);
}
@RequestMapping//产生 Json 数据,其他客户端用这个处理
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
HttpStatus status = this.getStatus(request);
if (status == HttpStatus.NO_CONTENT) {
return new ResponseEntity(status);
} else {
Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
return new ResponseEntity(body, status);
}
}
//DefaultErrorViewResolver:去哪个页面
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
ModelAndView modelAndView = this.resolve(String.valueOf(status.value()), model);
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);
}
return modelAndView;
}
private ModelAndView resolve(String viewName, Map<String, Object> model) {
//默认SpringBoot可以去到哪一个页面?error/404
String errorViewName = "error/" + viewName;
//模板引擎可以解析这个页面地址就用模板引擎解析
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);
//模板引擎可用和不可用调用不同的方法
return provider != null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model);
}
- 一旦出现 4xx 或者 5xx 之类的错误,ErrorPageCustomizer会生效(定制错误的响应规则),就会来到 error 请求,就会被 BasicErrorAttributes 处理
//响应页面
protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
Iterator var5 = this.errorViewResolvers.iterator();
ModelAndView modelAndView;
do {
if (!var5.hasNext()) {
return null;
}
ErrorViewResolver resolver = (ErrorViewResolver)var5.next();
modelAndView = resolver.resolveErrorView(request, status, model);
} while(modelAndView == null);
return modelAndView;
}
- 2、如何定制错误的页面
- 1、有模板引擎的情况下,在 templates 下建立一个子文件夹 error,在里面放置一个名字为 404.html(相应的状态码400、500…) 的页面即可。
- 2、如果没有匹配到可以在error文件夹下,可以放置一个4xx.html 和 5xx.html 去到没有被匹配到的(优先精确寻找状态码页面)
- 3、能取出的错误共享信息:时间戳(timestamp)、状态码(status)、错误提示(error)、异常对象(exception)、异常消息(message)、JSR303数据校验(errors)
- 3、如何定制错误的 Json 数据
- 需要将我们定制的数据携带出去
- 出现错误以后,会来到 /error 请求,会被BasicErrorController处理,相应出去可以获取的数据是由getErrorAttributes得到的(是AbstractError(ErrorController)规定的方法)
- 1、完全来编写一个ErrorController的实现类(或者编写AbstractErrorController的子类),放在容器中
- 2、页面上能用的数据,或者是json返回能用的数据都是通过errorAttributes.getAttributes()方法得到的
- 出现错误以后,会来到 /error 请求,会被BasicErrorController处理,相应出去可以获取的数据是由getErrorAttributes得到的(是AbstractError(ErrorController)规定的方法)
@ControllerAdvice
public class MyExceptionHandler {
/**
* 可达到自适应效果的错误请求处理
* @param e 错误
* @param request 原生的request
* @return 返回页面,模板引擎解析
*/
@ExceptionHandler(UserException.class)
public String handleException(Exception e, HttpServletRequest request){
Map<String ,Object> map = new HashMap<>(8);
map.put("data","放置的错误消息数据");
map.put("message",e.getMessage());
//设置状态码,然后转发
map.put("javax.servlet.error.status_code",500);
request.setAttribute("ext",map);
//转发到 /error
return "forward:/error";
}
}
============================================================
@ControllerAdvice
public class MyExceptionHandler {
/**
* 可达到自适应效果的错误请求处理
* @param e 错误
* @param request 原生的request
* @return 返回页面,模板引擎解析
*/
@ExceptionHandler(UserException.class)
public String handleException(Exception e, HttpServletRequest request){
Map<String ,Object> map = new HashMap<>(8);
map.put("data","放置的错误消息数据");
map.put("message",e.getMessage());
//设置状态码,然后转发
map.put("javax.servlet.error.status_code",500);
request.setAttribute("ext",map);
//转发到 /error
return "forward:/error";
}
}
嵌入式 Servlet 容器
注册三大组件
- 1、修改和定制一个Servlet容器的相关配置
- (1)、修改和server有关的配置(ServerProperties)
- (2)、编写一个EmbeddedServletContainerCustomizer:嵌入式的Servlet容器的定制器
@Bean
public WebServerFactoryCustomizer webServerFactoryCustomizer(){
return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
@Override
public void customize(ConfigurableWebServerFactory factory) {
factory.setPort(8082);
}
};
}
- 2、由于SpringBoot默认是以jar包方式启动嵌入式 Servlet 容器来启动SpringBoot的web应用,没有web.xml文件
- 注册三大组件用以下方式(Servlet、Filter、Listener)
- 1、ServletRegistrationBean
- 注册三大组件用以下方式(Servlet、Filter、Listener)
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Hello MyServlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Hello MyServlet");
}
}
/**
* 注册Servlet组件
* @return ServletRegistrationBean
*/
@Bean
public ServletRegistrationBean myServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet");
return registrationBean;
}
///
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("MyFilter process...");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
/**
* 注册拦截器
* @return FilterRegistrationBean
*/
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new MyFilter());
filterRegistrationBean.setUrlPatterns(Arrays.asList("/myServlet","/myFilter"));
return filterRegistrationBean;
}
///
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("contextInitialized...web应用启动");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("contextDestroyed...web应用销毁");
}
}
/**
* 注册监听器
* @return ServletListenerRegistrationBean
*/
@Bean
public ServletListenerRegistrationBean myListener(){
ServletListenerRegistrationBean<MyListener> listenerRegistrationBean = new ServletListenerRegistrationBean<>(new MyListener());
return listenerRegistrationBean;
}
使用其他Servlet容器
- SpringBoot支持的Servlet容器
- Jetty(长链接应用)
- Undertow(不支持jsp):高性能,非阻塞
- 切换其他服务器
- 1、在生成树(或者pom.xml文件)中去除服务器的相关依赖
- 2、导入相关依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!--引入其他的Servlet容器-->
<dependency>
<artifactId>spring-boot-starter-undertow</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
嵌入式Servlet容器自动配置原理
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
//导入BeanPostProcessorsRegistrar:Spring注解版;给容器中导入一些组件
//导入了EmbeddedServletContainerCustomizerBeanPostProcessor:
//后置处理器:bean初始化前后(创建完对象,还没赋值赋值)执行初始化工作
public class EmbeddedServletContainerAutoConfiguration {
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class })//判断当前是否引入了Tomcat依赖;
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)//判断当前容器没有用户自己定义EmbeddedServletContainerFactory:嵌入式的Servlet容器工厂;作用:创建嵌入式的Servlet容器
public static class EmbeddedTomcat {
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory();
}
}
/SpringBoot 2.0后
@Configuration(
proxyBeanMethods = false
)
@AutoConfigureOrder(-2147483648)
@ConditionalOnClass({ServletRequest.class})
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@EnableConfigurationProperties({ServerProperties.class})
@Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class})
public class ServletWebServerFactoryAutoConfiguration {
public ServletWebServerFactoryAutoConfiguration() {
}
-
步骤:
-
1)、SpringBoot根据导入的依赖情况,给容器中添加相应的EmbeddedServletContainerFactory【TomcatEmbeddedServletContainerFactory】
-
2)、容器中某个组件要创建对象就会惊动后置处理器;EmbeddedServletContainerCustomizerBeanPostProcessor;只要是嵌入式的Servlet容器工厂,后置处理器就工作;
-
3)、后置处理器,从容器中获取所有的EmbeddedServletContainerCustomizer,调用定制器的定制方法
-
自动配置原理(细)
EmbeddedServletContainerAutoConfiguration:嵌入式的Servlet容器自动配置?
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
//导入BeanPostProcessorsRegistrar:Spring注解版;给容器中导入一些组件
//导入了EmbeddedServletContainerCustomizerBeanPostProcessor:
//后置处理器:bean初始化前后(创建完对象,还没赋值赋值)执行初始化工作
public class EmbeddedServletContainerAutoConfiguration {
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class })//判断当前是否引入了Tomcat依赖;
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)//判断当前容器没有用户自己定义EmbeddedServletContainerFactory:嵌入式的Servlet容器工厂;作用:创建嵌入式的Servlet容器
public static class EmbeddedTomcat {
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory();
}
}
/**
* Nested configuration if Jetty is being used.
*/
@Configuration
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class,
WebAppContext.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedJetty {
@Bean
public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {
return new JettyEmbeddedServletContainerFactory();
}
}
/**
* Nested configuration if Undertow is being used.
*/
@Configuration
@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedUndertow {
@Bean
public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory() {
return new UndertowEmbeddedServletContainerFactory();
}
}
1)、EmbeddedServletContainerFactory(嵌入式Servlet容器工厂)
public interface EmbeddedServletContainerFactory {
//获取嵌入式的Servlet容器
EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers);
}
2)、EmbeddedServletContainer:(嵌入式的Servlet容器)
3)、以TomcatEmbeddedServletContainerFactory为例
@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers) {
//创建一个Tomcat
Tomcat tomcat = new Tomcat();
//配置Tomcat的基本环节
File baseDir = (this.baseDirectory != null ? this.baseDirectory
: createTempDir("tomcat"));
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
//将配置好的Tomcat传入进去,返回一个EmbeddedServletContainer;并且启动Tomcat服务器
return getTomcatEmbeddedServletContainer(tomcat);
}
4)、我们对嵌入式容器的配置修改是怎么生效?
ServerProperties、EmbeddedServletContainerCustomizer
EmbeddedServletContainerCustomizer:定制器帮我们修改了Servlet容器的配置?
怎么修改的原理?
5)、容器中导入了EmbeddedServletContainerCustomizerBeanPostProcessor
//初始化之前
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
//如果当前初始化的是一个ConfigurableEmbeddedServletContainer类型的组件
if (bean instanceof ConfigurableEmbeddedServletContainer) {
//
postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
}
return bean;
}
private void postProcessBeforeInitialization(
ConfigurableEmbeddedServletContainer bean) {
//获取所有的定制器,调用每一个定制器的customize方法来给Servlet容器进行属性赋值;
for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {
customizer.customize(bean);
}
}
private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {
if (this.customizers == null) {
// Look up does not include the parent context
this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
this.beanFactory
//从容器中获取所有这葛类型的组件:EmbeddedServletContainerCustomizer
//定制Servlet容器,给容器中可以添加一个EmbeddedServletContainerCustomizer类型的组件
.getBeansOfType(EmbeddedServletContainerCustomizer.class,
false, false)
.values());
Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
this.customizers = Collections.unmodifiableList(this.customizers);
}
return this.customizers;
}
ServerProperties也是定制器
步骤:
1)、SpringBoot根据导入的依赖情况,给容器中添加相应的EmbeddedServletContainerFactory【TomcatEmbeddedServletContainerFactory】
2)、容器中某个组件要创建对象就会惊动后置处理器;EmbeddedServletContainerCustomizerBeanPostProcessor;
只要是嵌入式的Servlet容器工厂,后置处理器就工作;
3)、后置处理器,从容器中获取所有的EmbeddedServletContainerCustomizer,调用定制器的定制方法
###5)、嵌入式Servlet容器启动原理;
什么时候创建嵌入式的Servlet容器工厂?什么时候获取嵌入式的Servlet容器并启动Tomcat;
获取嵌入式的Servlet容器工厂:
1)、SpringBoot应用启动运行run方法
2)、refreshContext(context);SpringBoot刷新IOC容器【创建IOC容器对象,并初始化容器,创建容器中的每一个组件】;如果是web应用创建AnnotationConfigEmbeddedWebApplicationContext,否则:AnnotationConfigApplicationContext
3)、refresh(context);刷新刚才创建好的ioc容器;
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
4)、 onRefresh(); web的ioc容器重写了onRefresh方法
5)、webioc容器会创建嵌入式的Servlet容器;createEmbeddedServletContainer();
6)、获取嵌入式的Servlet容器工厂:
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
从ioc容器中获取EmbeddedServletContainerFactory 组件;**TomcatEmbeddedServletContainerFactory**创建对象,后置处理器一看是这个对象,就获取所有的定制器来先定制Servlet容器的相关配置;
7)、使用容器工厂获取嵌入式的Servlet容器:this.embeddedServletContainer = containerFactory .getEmbeddedServletContainer(getSelfInitializer());
8)、嵌入式的Servlet容器创建对象并启动Servlet容器;
先启动嵌入式的Servlet容器,再将ioc容器中剩下没有创建出的对象获取出来;
IOC容器启动创建嵌入式的Servlet容器
使用外置的Servlet容器
-
嵌入式Servlet容器:应用打成可执行的jar
-
优点:简单、便携;
-
缺点:默认不支持JSP、优化定制比较复杂(使用定制器【ServerProperties、自定义EmbeddedServletContainerCustomizer】,自己编写嵌入式Servlet容器的创建工厂【EmbeddedServletContainerFactory】);
外置的Servlet容器:外面安装Tomcat—应用war包的方式打包;
步骤
1)、必须创建一个war项目;(利用idea创建好目录结构)
2)、将嵌入式的Tomcat指定为provided;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
3)、必须编写一个SpringBootServletInitializer的子类,并调用configure方法
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
//传入SpringBoot应用的主程序
return application.sources(SpringBoot04WebJspApplication.class);
}
}
4)、启动服务器就可以使用
Docker
1、简介
Docker是一个开源的应用容器引擎;是一个轻量级容器技术;
Docker支持将软件编译成一个镜像;然后在镜像中各种软件做好配置,将镜像发布出去,其他使用者可以直接使用这个镜像;
运行中的这个镜像称为容器,容器启动是非常快速的。
2、核心概念
docker主机(Host):安装了Docker程序的机器(Docker直接安装在操作系统之上);
docker客户端(Client):连接docker主机进行操作;
docker仓库(Registry):用来保存各种打包好的软件镜像;
docker镜像(Images):软件打包好的镜像;放在docker仓库中;
docker容器(Container):镜像启动后的实例称为一个容器;容器是独立运行的一个或一组应用
SpringBoot与数据访问
原生JDBC的使用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://116.62.46.122:3306/test?serverTimezone=GMT%2B8&useSSL=false
driver-class-name: com.mysql.jdbc.Driver
效果:
默认数据源;
数据源的相关配置都在DataSourceProperties里面;
自动配置原理:
org.springframework.boot.autoconfigure.jdbc:
1、参考DataSourceConfiguration,根据配置创建数据源,默认使用Tomcat连接池;可以使用spring.datasource.type指定自定义的数据源类型;
2、SpringBoot默认可以支持;
org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource、
3、自定义数据源类型
/**
* Generic DataSource configuration.
*/
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {
@Bean
public DataSource dataSource(DataSourceProperties properties) {
//使用DataSourceBuilder创建数据源,利用反射创建响应type的数据源,并且绑定相关属性
return properties.initializeDataSourceBuilder().build();
}
}
4、DataSourceInitializer:ApplicationListener;
作用:
1)、runSchemaScripts();运行建表语句;
2)、runDataScripts();运行插入数据的sql语句;
默认只需要将文件命名为:
schema-*.sql、data-*.sql
默认规则:schema.sql,schema-all.sql;
可以使用
schema:
- classpath:department.sql
指定位置
5、操作数据库:自动配置了JdbcTemplate操作数据库
整合Druid数据源
- 1、导入 Druid 依赖的jar包
<!-- 引入自定义数据源连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
- 2、配置相关的yml文件内容
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://116.62.46.122:3306/test?serverTimezone=GMT%2B8&useSSL=false
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
# 数据源其他配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,slf4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
- 3、配置Druid的配置文件,即可访问 Druid 的监控后台
配合拦截器的链接地址:http://localhost:8080/druid/
//导入druid数据源
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DruidDataSource druid(){
return new DruidDataSource();
}
//配置Druid的监控
// 1、配置一个管理后台的Servlet
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
Map<String,String> initParam = new HashMap<>(8);
//配置监控的参数,登录后台的账号密码(eg:用户名,密码等)
initParam.put("loginUsername","admin");
initParam.put("loginPassword","123456");
//默认是允许全部
// initParam.put("allow","localhost");
initParam.put("allow","");
servletRegistrationBean.setInitParameters(initParam);
return servletRegistrationBean;
}
//2、注册一个web监控的过滤器
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
Map<String,String> initParam = new HashMap<>(8);
//不拦截那些应用
initParam.put("exclusions","*.js,*.css,/druid/*");
filterRegistrationBean.setInitParameters(initParam);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
return filterRegistrationBean;
}
整合 mybatis
基础章
- 1、导入相关的场景启动器:改启动器为 mybatis 官方为配设 SpringBoot 做的
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
- 2、注入 Druid 数据源(参考上一部分):
- 3、编写相关的接口,加上 @Component 和 @Mapper
- 插入时,若想获得主键,可增加配置
//@Component 注解可加可不加
@Component
@Mapper //指定这是一个操作数据库的mapper
public interface UserMapper {
/**
* 根据 id 查询用户
* @param id 用户 id
* @return 返回用户
*/
@Select("select * from user where id=#{id}")
public User getUserById(Integer id);
/**
* 根据 id 删除用户
* @param id 用户 id
* @return 返回影响行数
*/
@Delete("delete from user where id=#{id}")
public int deleteUserById(Integer id);
/**
* 插入用户
* @param user 用户消息
* @return 返回影响行数
*/
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into user(name,age) values(#{name},#{age})")
public int insertUser(User user);
/**
* 根据用户 id 更新用户信息
* @param user 用户信息
* @return 返回值
*/
@Update("update user set name = #{name} , age=#{age} where id=#{id}")
public int updateUser(User user);
}
配置章
以配置类方式配置
- 若数据库采用蛇形命名法,而实体类用驼峰命名法,则需要更改映射规则,可以采用添加配置类形式
@Configuration
public class MyBatisConfig {
@Bean
public ConfigurationCustomizer configurationCustomizer(){
return new ConfigurationCustomizer() {
@Override
public void customize(org.apache.ibatis.session.Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true);
}
};
}
}
- 若一个一个类扫描太过麻烦,可在主配置类上添加配置注解 @MapperScan 来指定扫描哪个包下接口,然后改包下接口就可不加 @Mapper。( @MapperScan(“com.spring.mapper”))
@MapperScan(value = "com.springboot.mapper")
@SpringBootApplication
public class SpringBootDataMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDataMybatisApplication.class, args);
}
}
以配置文件方式配置
- 1、编写一个主配置文件,资料在GitHub 的 MyBatis页面查找
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
- 2、编写每个接口的映射,资料在GitHub 的 MyBatis页面查找
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.springboot.mapper.RoleMapper">
<select id="getRoleById" resultType="com.springboot.domain.Role">
select * from role where id = #{id}
</select>
<insert id="insertRole" keyProperty="id" useGeneratedKeys="true">
insert into role(role_name,role_introduction) values(#{roleName},#{roleIntroduction})
</insert>
</mapper>
- 3、在 application.yml 中添加 mybatis 配置文件的路径
mybatis:
config-location: classpath:mybatis/mybatis-config.xml #指定主配置类
mapper-locations: classpath:mybatis/mapper/*.xml #指定相关映射文件位置
整合 SpringBoot 的 JPA
- JPA也是 ORM 思想(object、relational、mapping)
- 1、导入场景启动器(创建项目时可添加),编写数据源
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
- 2、编写一个实体类,添加注解表示这是一个与表格对应的实体类
//使用JPA注解配置映射关系
@Entity //告诉JPA这是一个实体类
@Table(name = "user") //表示表名为user,没有标注默认是实体类名的小写
public class User {
@Id //标志这是一个主键
@GeneratedValue(strategy = GenerationType.IDENTITY) //表示这是一个自增主键
private Integer id;
@Column(name = "name",length = 50) // 和表的一列对应,长度为50
private String name;
@Column // 不加默认列名为属性名
private Integer age;
}
- 3、编写一个基本的操作接口(继承JpaRepository,不需要重写它的方法,泛型第一个表示对应的表格实体类,第二个表示主键类型)以及编写基本的配置(更新数据库和显示 sql 语句)
// 继承JpaRepository来实现对数据库的操作
public interface UserRepository extends JpaRepository<User,Integer> {
}
//
spring:
jpa:
hibernate:
ddl-auto: update # 表示如果更新或者创建表格时更新结构
show-sql: true #表示输出sql语句
- 4、编写 Controller ,使用 UserRepository 来实现基本增删查改(类似Hibernate)
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
UserRepository userRepository;
@GetMapping("/getUserById/{id}")
public User getUserById(@PathVariable("id") Integer id){
return userRepository.findById(id).get();
}
@GetMapping("/insertUser")
public User insertUser(User user){
return userRepository.save(user);
}
}
SpringBoot启动原理以及监听
SpringBoot 的 Application启动原理
几个重要的事件回调机制
配置在META-INF/spring.factories
ApplicationContextInitializer
SpringApplicationRunListener
只需要放在ioc容器中
ApplicationRunner
CommandLineRunner
启动流程:
1、创建SpringApplication对象
initialize(sources);
private void initialize(Object[] sources) {
//保存主配置类
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
//判断当前是否一个web应用
this.webEnvironment = deduceWebEnvironment();
//从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//从类路径下找到ETA-INF/spring.factories配置的所有ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//从多个配置类中找到有main方法的主配置类
this.mainApplicationClass = deduceMainApplicationClass();
}
2、运行run方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
//获取SpringApplicationRunListeners;从类路径下META-INF/spring.factories
SpringApplicationRunListeners listeners = getRunListeners(args);
//回调所有的获取SpringApplicationRunListener.starting()方法
listeners.starting();
try {
//封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成
Banner printedBanner = printBanner(environment);
//创建ApplicationContext;决定创建web的ioc还是普通的ioc
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
//准备上下文环境;将environment保存到ioc中;而且applyInitializers();
//applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法
//回调所有的SpringApplicationRunListener的contextPrepared();
//
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();
//s刷新容器;ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);Spring注解版
//扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
refreshContext(context);
//从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
//ApplicationRunner先回调,CommandLineRunner再回调
afterRefresh(context, applicationArguments);
//所有的SpringApplicationRunListener回调finished方法
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//整个SpringBoot应用启动完成以后返回启动的ioc容器;
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
SpringBoot事件监听
- 1、实现以下方法
- ApplicationContextInitializer
- SpringApplicationRunListener
- ApplicationRunner
- CommandLineRunner
public class HelloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("ApplicationContextInitializer...initialize..."+applicationContext);
}
}
///
public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {
//必须有的构造器
public HelloSpringApplicationRunListener(SpringApplication application, String[] args){
}
@Override
public void starting() {
System.out.println("SpringApplicationRunListener...starting...");
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
Object o = environment.getSystemProperties().get("os.name");
System.out.println("SpringApplicationRunListener...environmentPrepared.."+o);
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener...contextPrepared...");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener...contextLoaded...");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("SpringApplicationRunListener...failed...");
}
}
///
@Component
public class HelloApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner...run....");
}
}
//
@Component
public class HelloCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner...run..."+ Arrays.asList(args));
}
}
- 2、在resource目录下创建META-INF然后创建spring.factories文件,在其中指定ApplicationContextInitializer和SpringApplicationRunListener的全类名
org.springframework.context.ApplicationContextInitializer=\
com.springboot.listener.HelloApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=\
com.springboot.listener.HelloSpringApplicationRunListener
自定义场景启动器
starter:
1、这个场景需要使用到的依赖是什么?
2、如何编写自动配置
@Configuration //指定这个类是一个配置类
@ConditionalOnXXX //在指定条件成立的情况下自动配置类生效
@AutoConfigureAfter //指定自动配置类的顺序
@Bean //给容器中添加组件
@ConfigurationPropertie//结合相关xxxProperties类来绑定相关的配置
@EnableConfigurationProperties //让xxxProperties生效加入到容器中
自动配置类要能加载
将需要启动就加载的自动配置类,配置在META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
3、模式:
启动器只用来做依赖导入;
专门来写一个自动配置模块;
启动器依赖自动配置;别人只需要引入启动器(starter)
mybatis-spring-boot-starter;自定义启动器名-spring-boot-starter
步骤:
1)、启动器模块
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>test-spring-boot-autoconfigurer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>test-spring-boot-autoconfigurer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- 引入 spring-boot-starter,所有 starter 所需要的基本配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>
package com.springboot.starter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author Ming
* @date 2020/1/17 - 15:03
*/
@Component
@ConfigurationProperties(prefix = "springboot.hello")
public class HelloProperties {
private String prefix;
private String suffix;
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
}
package com.springboot.starter;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @author Ming
* @date 2020/1/17 - 15:02
*/
public class HelloService {
HelloProperties helloProperties;
public HelloProperties getHelloProperties() {
return helloProperties;
}
public void setHelloProperties(HelloProperties helloProperties) {
this.helloProperties = helloProperties;
}
public String sayHello(String name){
return helloProperties.getPrefix() + "-" + name + ": 这个是测试的语句" + helloProperties.getSuffix();
}
}
package com.springboot.starter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Ming
* @date 2020/1/17 - 15:08
*/
@Configuration
@ConditionalOnWebApplication //web应用才生效
@EnableConfigurationProperties(HelloProperties.class)
public class HelloServiceAutoConfiguration {
@Autowired
HelloProperties helloProperties;
@Bean
public HelloService helloService(){
HelloService helloService = new HelloService();
helloService.setHelloProperties(helloProperties);
return helloService;
}
}
2)在将两个模块添加导 Maven 仓库中
3)在其他工程的使用
- 在其他工程需要使用需要将场景启动器添加到依赖
<dependency>
<groupId>com.example</groupId>
<artifactId>test-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
- 可在 application.properties 文件中配置相关的属性值
springboot.hello.prefix=HEAD HELLO
springboot.hello.suffix=HELLO WORLD
- 然后在类里面即可直接注入
package com.springboot.controller;
import com.springboot.starter.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Ming
* @date 2020/1/17 - 15:20
*/
@RestController
@RequestMapping("/hello")
public class HelloController {
@Autowired
HelloService helloService;
@GetMapping("sayHello")
public String sayHello(){
return helloService.sayHello("haha");
}
}