@RequestMapping:映射请求。
@ResponseBody:表明返回的是字符串,而不是跳转页面。
@RestController:轻量级的标注,为@ResponseBody和@RequestMapping的合体。
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.4.3version>
parent>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
@SpringBootApplication
public static void main(String[] args) {
SpringApplication.run(Example.class, args);
}
server.port=8080
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.4.3version>
parent>
1.spring-boot-starter-*表示各种类型的场景。
2.只要引入starter,这个场景的各种依赖我们都能自动引入。
3.SpringBoot支持的各种场景:https://docs.spring.io/spring-boot/docs/2.4.3/reference/html/using-spring-boot.html#using-boot-starter
4.见到的*-spring-boot-starter-*为第三方的场景。
1.引入Tomcat组件
2.自动配好Tomcat依赖
1.引入SpringMVC全套组件
2.自动配好SpringMVC常用组件
1.主程序下所在包下及其下的所有子包里面的组件都会被默认扫描,以前的包扫描不用配置。
2.若想扫描主程序之上的包则需要如下配置:@SpringBootApplication(scanBasePackages="xxx.xxx")或通过@Component("xxx.xxx")。
非常多的starter
引入哪个场景这个场景的自动配置才会开启
SpringBoot的所有自动配置功能都在spring-boot-autoConfigure包里
@Configuration
- 配置类组件之间没有依赖关系,使用lite模式,加快容器启动过程,减少判断。
- 配置类组件之间有依赖关系,会使用到之前的单实例组件,使用full模式,但容器启动会变慢。
@Import({User.class,DBHelper.class}):给容器中创建出这两个类型的组件,默认组件就是全类名。
@ImportResource:导入资源文件
把配置文件中的值绑定在容器中。
@Component
@ConfigurationProperties(preifx="myCar")
public class Car{
}
//注解@SpringBootApplication拆分
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
@SpringBootConfiguration:代表当前是一个配置类。
@ComponentScan:开启包扫描。
@EnableAutoConfiguration:
//@EnableAutoConfiguration的注解
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {}
@AutoConfigurationPackage:
@Import({Registrar.class})//给容器中导入一个组件
public @interface AutoConfigurationPackage {}
//利用Registrar给容器导入一系列组件
//将主程序所在的包下的所有组件都导进来
\META-INF\spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
......
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration
总结:
1.自己分析,引入场景对应的自动配置一般都生效了
2.配置文件中debug=true开启自动配置报告。Negative(不生效)\Positive(生效)
参照文档修改配置项
自定义加入或替换组件
自定义器xxxxCustomizer
简化Java Bean的开发。
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
Ctrl+F9:重新编译,自动重启,利于修改静态页面。
//引入依赖。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<optional>trueoptional>
dependency>
项目初始化向导,帮助开发SpringBoot项目。
常规的是properties文件,也可以使用yaml。yaml非常适合以数据为中心的配置文件,是轻量级的。但按照优先级,SpringBoot会最终加载properties中的配置。
k: v
行内写法: k: {k1: v1,k2: v2,k3: v3}
#或
k:
k1: v1
k2: v2
k3: v3
行内写法: k: [v1,v2,v3]
#或
k:
- v1
- v2
- v3
pom.xml在添加:
<dependencys>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
dependencys>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<proc>noneproc>
configuration>
plugin>
静态资源目录:只要静态资源放在类路径下的/static、/public、/resources、/META-INF/resources,访问当前项目根路径/+静态资源名。
原理:静态资源/**。请求进来,先去找Controller看能不能处理,不能处理的请求又交给静态资源处理器,静态资源找不到就404。
静态资源访问前缀:默认无前缀,可在配置文件中修改。当前项目+static-path-pattern+静态资源名=静态资源文件夹下找。
webjar:支持webjar。
将favicon.ico图标放在静态资源路径下即可以访问。
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {}
@Configuration(
proxyBeanMethods = false
)
@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {}
@GetMapping:用于处理请求方法的GET类型。
@PathVariable:获取路径变量上的参数。可以单个获取,也可以用Map
@RequestHeader:获取请求头信息。可以单个获取,也可以用Map
@RequestParam:获取请求参数。可以单个获取,也可以用Map
@CookieValue:获取Cookie中的值。可以单个获取,也可以用Cookie的方式整体获取。
@RequestBody:获取请求体【POST请求才有请求体】。
@RequestAttribute:获取请求域属性的值。
@MatrixVariable:获取矩阵变量的值。但是SpringBoot默认禁用了矩阵变量的功能,需要手动开启。原理:对于路径处理,都是用UrlPathHelper解析的。UrlPathHelper中的removeSemicolonContent属性是用来设置是否禁用分号内容【矩阵变量必须有路径变量才可以被解析】。
/cars/{path}?xxx=xxx?xxx=xxx queryString 查询字符串,使用@RequestParam的方式获取请求参数。
/cars/{path};xxx=xxx;yyy=aaa,bbb,ccc 矩阵变量,使用@MatrixVariable的方式获取参数。
面试题:当Cookie禁用了,session中的值怎么使用?
【session.set(a,b)--->jsessionid--->cookie--->每次发请求携带】
通过URL重写:/abc;jsessionid=xxx 把cookie的值用矩阵变量进行传递。
thymeleaf使用
<dependency>
<groupId>org.thymeleafgroupId>
<artifactId>thymeleafartifactId>
<version>3.0.12.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jdbcartifactId>
dependency>
自动配置的项:
因为官方不知道我们需要操作什么数据库,所有缺少数据库驱动,需要手动导入。
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.4version>
dependency>
配置模式
1.全局配置文件。
2.SqlSessionFactory:自动配置好了。
3.SqlSession:自动配置了SqlSessionTemplate组合了SqlSession。
4.@Import(AutoConfiguredMapperScannerRegisterar.class)
5.Mapper:只要我们写的操作Mybatis的接口标注了 @Mapper就会被自动扫描进来。【可以用 @MapperScan来扫描Mapper,代替@Mapper】
#配置mybatis规则
#Mapper接口绑定xml
mybatis:
config-location: #全局配置文件
mapper-location: #sql映射文件位置
注解模式
@Select:写查询语句。
@Insert:写插入语句。
@Options:写语句的属性项。
混合模式
什么是Mybatis-Plus:是一个Mybatis的增强工具,为简化开发提高效率而生。建议安装MybatisX插件。
引入mybatis-plus
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>Latest Versionversion>
dependency>
自动配置:
优点:
引入依赖:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
自动配置:
Redis环境搭建:
RedisTemplate与Lettuce:
application.yaml中配置spring.redis.host、spring.redis.port、spring.redis.password。
切换到jedis:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
dependency>
JUnit5:
注意:
SpringBoot整合JUnit后:
@DisplayName:为测试类或者测试方法展示名称。
@DisplayName("测试displayName方法")
@Test
void testDisplayName(){
System.out.println(1);
}
@BeforeEach:在每个测试单元测试之前执行。
@BeforeEach
void testBeforeEach(){
System.out.println("当前测试之前执行");
}
@AfterEach:在每个测试单元测试之后执行。
@BeforeEach
void testAfterEach(){
System.out.println("当前测试之后执行");
}
@BeforeAll:在所有测试单元测试之前执行。
//因为只执行一次,所有方法之前要加上static
@BeforeAll
static void testBeforeAll(){
System.out.println("所有测试之前执行");
}
@AfterAll:在所有测试单元测试之后执行。
//因为只执行一次,所有方法之前要加上static
@AfterAll
static void testAfterAll(){
System.out.println("所有测试之后执行");
}
@Tag:表示单元测试类别,相当于JUnit4的 @Categories。
@Disable:表示测试类或测试方法不执行,类似于JUnit4的 @Ignore。
@Timeout:表示测试方法运行如果超过了指定时间将会返回错误。
@RepeatedTest:测试重复测试的次数。
断言是测试中的核心部分,用来测试需要满足的条件进行验证。这些断言方法都是静态方法。用来检查业务逻辑返回的数据是否合理。所有测试运行结束后会有一个详细的测试报告。
断言失败后,后面的代码都不会执行。
断言有以下分类:
@Test
@DisplayName("测试简单断言")
void testSimpleAssertions(){
int cal=cal(2,3);
//可以自定义失败信息
assertEquals(5,cal,"业务逻辑计算失败");
}
int cal(int a,int b){
return a+b;
}
@Test
@DisplayName("测试组合断言")
void testAll(){
assertAll(
"testAll";
()->assertEquals(5,5,"结果不是5"),
()->assertTrue(true,true,"结果不为True"));
}
@Test
@DisplayName("测试异常断言")
void testException(){
assertThrows(
ArithmeticException.class,
()->{
int i=10/0;
},
"业务逻辑居然正常");
}
//结果为:测试通过
@Test
@DisplayName("测试超时断言")
void testTimeout(){
assertTimeout(
Duration.ofMillis(1000),
()->Thread.sleep(500)
);
}
@Test
@DisplayName("测试快速断言")
void testFail(){
fail("is should fail");
}
前置条件:assumption【假设】类似于断言,不同之处是在于不满足的断言会使得测试方法失效,而不满足的前置条件只会使得测试方法的执行终止。前置方法可以看作测试方法的前提,当该前提不满足时,没有继续的必要。
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.EmptyStackException;
import java.util.Stack;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@DisplayName("A stack")
class TestingAStackDemo {
Stack<Object> stack;
@Test
@DisplayName("is instantiated with new Stack()")
void isInstantiatedWithNew() {
new Stack<>();
}
@Nested
@DisplayName("when new")
class WhenNew {
@BeforeEach
void createNewStack() {
stack = new Stack<>();
}
@Test
@DisplayName("is empty")
void isEmpty() {
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("throws EmptyStackException when popped")
void throwsExceptionWhenPopped() {
assertThrows(EmptyStackException.class, stack::pop);
}
@Test
@DisplayName("throws EmptyStackException when peeked")
void throwsExceptionWhenPeeked() {
assertThrows(EmptyStackException.class, stack::peek);
}
@Nested
@DisplayName("after pushing an element")
class AfterPushing {
String anElement = "an element";
@BeforeEach
void pushAnElement() {
stack.push(anElement);
}
@Test
@DisplayName("it is no longer empty")
void isNotEmpty() {
assertFalse(stack.isEmpty());
}
@Test
@DisplayName("returns the element when popped and is empty")
void returnElementWhenPopped() {
assertEquals(anElement, stack.pop());
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("returns the element when peeked but remains not empty")
void returnElementWhenPeeked() {
assertEquals(anElement, stack.peek());
assertFalse(stack.isEmpty());
}
}
}
}
@ParamsterizedTest
@DisplayName("参数化测试1")
@ValueSource(ints={1,2,3,4,5})
void testParamsterizedTest1(int i){
System.out.println(i);
}
@ParamsterizedTest
@DisplayName("参数化测试2")
@MethodSource("stringProvider")
void testParamsterizedTest2(String i){
System.out.println(i);
}
static Stream<String> stringProvider(){
return Stream.of("apple","pear","cry");
}
参照JUnit官方文档:https://junit.org/junit5/docs/current/user-guide/#migrating-from-junit4
SpringBoot Actuator:SpringBoot抽取Actuator场景,使得我们每个微服务都可以快速应用应用监控、审计等功能。
导入starter:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
management:
endpoints:
enable-by-default: true #暴露所有端点信息
web:
exposure:
include: '*' #以web方式暴露
https://github.com/codecentric/spring-boot-admin
spring:
boot:
admin:
client:
url: http://localhost:8888 #此为监控端ip
instance:
prefer-ip: true #使用IP注册进来,默认值为false
application:
name: boot-01-admin #设置项目名
如果应用程序是Web应用程序,还可以使用以下:
最常用的Endpoint:
健康检查端点,用于云平台,定时检查应用的健康状况。我们就需要Health Endpoint为平台返回当前应用的一些列组件健康状况的集合。
注意:
#management.endpoints:对所有端点进行配置
#management.endpoint: 对某个端点进行配置
management:
endpoint:
health:
show-details: always
提供详细的、层级的、空间指标信息,这些信息可以被pull(主动推送)或push(被动获取)的方式获得。
由于某些端点比较敏感,所有有时候要按需开启端点,方法如下:
management:
endpoints:
enable-by-default: false #关闭所有端点信息
web:
exposure:
include: '*' #以web方式暴露
endpoint:
health:
show-details: always
enable: true
info:
enable: true
beans:
enable: true
metrics:
enable: true
//继承AbstractHealthIndicator抽象类
@Component
public class MyComHealthIndicator extends AbstractHealthIndicator{
@Override
protect void doHealthCheck(Health.Builder builder) throws Exception{
//mongodb.进行连接测试
//存储详细数据
Map<String,Object> map=new HashMap<>();
//进行检查业务逻辑
if(1=1){
// builder.up(); //方式一:健康
builder.status(Stauts.UP); //方式二:取具体的状态Stauts.UP
map.put("count",1);
map.put("ms",100);
}else{
// builder.down();
builder.status(Stauts.OUT_OF_SERVICE); //方式二:取具体的状态Stauts.OUT_OF_SERVICE
map.put("err","连接超时");
map.put("ms",300);
}
//withDetail()放键值对
//withDetails()放Map
builder.withDetail("code",100)
.withDetails(map);
}
}
info:
##在application.yaml写死
appName: boot-gul
version: 2.0.2
#使用@@获取maven的pom文件的值
mavenProjectName: @project.artifactId@
mavenProjectVersion: @project.version@
//实现InfoContributor接口
@Component
public class AppInfoInfoContributor implements InfoContributor{
@Override
public void contribute(Info.Builder builder){
builder.withDetail("msg","hello")
.withDetails(Collections.singletonMap("time","20200000"));
}
}
class MyService{
Counter counter;
public Myservice(MeterRegistry meterRegistry){
counter=meterRegistry.counter("myService.method.running.counter");
}
public void hello(){
counter.increament();
}
}
@Compoment
@Endpoint(id="myservice")
public class DockerEndpoint{
@ReadOperation
public Map getDockerInfo(){
return Collection.singletonMap("info","docker start...");
}
@WriteOpertion
public void restartDocker(){
System.out.println("docker stop...");
}
}
@Profile可以在类上或方法上使用。
@Profile("prod")
public class prodEnv(){
//...
}
在默认配置的application.properties中配置分组。
spring.profiles.group.myprod[0]=prod0
spring.profiles.group.myprod[1]=prod1
spring.profiles.active=myprod
常用:Java属性文件、yaml文件、环境变量、命令行参数。
1.Default properties (specified by setting SpringApplication.setDefaultProperties).
2.@PropertySource annotations on your @Configuration classes. Please note that such property sources are not added to the Environment until the application context is being refreshed. This is too late to configure certain properties such as logging.* and spring.main.* which are read before refresh begins.
【3.Config data (such as application.properties files)】配置文件application.properties、application.yaml
4.A RandomValuePropertySource that has properties only in random.*.
5.OS environment variables.
6.Java System properties (System.getProperties()).
7.JNDI attributes from java:comp/env.
8.ServletContext init parameters.
9.ServletConfig init parameters.
10.Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).
【11.Command line arguments.】命令行参数
13.@TestPropertySource annotations on your tests.
14.Devtools global settings properties in the $HOME/.config/spring-boot directory when devtools is active.
至上而下查找,后面的会覆盖前面的。
【2.6.2总结:指定环境优先,外部配置优先】
学习过程中难免会接触到一些源码的解析,但也可以整体把握好SpringBoot的基本应用,回头再来理解好源码。这样便于减少枯燥,保持学习兴趣。后续的SpringBoot一些核心技术的学习还包括虚拟化技术、安全控制、缓存技术、消息中间件、对象存储、定时调度、异步任务、分布式系统等。以及SpringBoot的响应式编程,包括响应式编程基础、Weflux开发web应用、响应式访问持久层、响应式安全开发和响应式原理。