目录
9.7、根据上述代码,我们可以同过配置禁止所有静态资源规则:
1、最佳实践-SpringBoot应用如何编写
- 引入场景依赖
- 官方文档
- 查看自动配置了哪些(选做)
- 自己分析,引入场景对应的自动配置一般都生效了
- 配置文件中debug=true开启自动配置报告。
- Negative(不生效)
- Positive(生效)
- 是否需要修改
- 参照文档修改配置项
- 官方文档
- 自己分析。xxxxProperties绑定了配置文件的哪些。
- 参照文档修改配置项
- 自定义加入或者替换组件
- @Bean、@Component…
- 自定义器 XXXXXCustomizer;
配置文件中debug=true开启自动配置报告:
- Positive matches 生效的
- Negative matches 不生效的
- Unconditional classes。
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:
-----------------AopAutoConfiguration matched:
- @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)
Negative matches:
-----------------ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)
Unconditional classes:
---------------------- org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
修改启动时的图像
- spring.banner.image.location = classpath.2.jpg
2、最佳实践-Lombok简化开发
Lombok用标签方式代替构造器、getter/setter、toString()等鸡肋代码。
spring boot已经管理Lombok。引入依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
IDEA中File->Settings->Plugins,搜索安装Lombok插件。
@NoArgsConstructor
//@AllArgsConstructor
@Data
@ToString
@EqualsAndHashCode
public class User {
private String name;
private Integer age;
private Pet pet;
public User(String name,Integer age){
this.name = name;
this.age = age;
}
}
简化日志开发
@Slf4j
@RestController
public class HelloController {
@RequestMapping("/hello")
public String handle01(@RequestParam("name") String name){
log.info("请求进来了....");
return "Hello, Spring Boot 2!"+"你好:"+name;
}
}
3、最佳实践-dev-tools
热部署,热更新,以后更新完代码后使用command + f9即可
在IDEA中,项目或者页面修改以后:comand +F9(Build Project)。
Restart:实际上这是自动重启,类似于手动点击重启按钮。
JRebel:付费,重新编译。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
4、最佳实践-Spring Initailizr
Spring Initailizr是创建Spring Boot工程向导。
在IDEA中,菜单栏New -> Project -> Spring Initailizr。
5、配置文件-yml的用法
同以前的properties用法
YAML 是 “YAML Ain’t Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)。
非常适合用来做以数据为中心的配置文件。
基本语法
- key: value;kv之间有空格
- 大小写敏感
- 使用缩进表示层级关系
- 缩进不允许使用tab,只允许空格
- 缩进的空格数不重要,只要相同层级的元素左对齐即可
- '#'表示注释
- 字符串无需加引号,如果要加,单引号’’表示字符串内容会被 转义 、双引号""表示字符串内容不转义
数据类型
- 字面量:单个的、不可再分的值。date、boolean、string、number、null
k: v
- 对象:键值对的集合。map、hash、set、object
#行内写法:
k: {k1:v1,k2:v2,k3:v3}
#或
k:
k1: v1
k2: v2
k3: v3
- 数组:一组按次序排列的值。array、list、queue
#行内写法:
k: [v1,v2,v3]
#或者
k:
- v1
- v2
- v3
实例
@Data
public class Person {
private String userName;
private Boolean boss;
private Date birth;
private Integer age;
private Pet pet;
private String[] interests;
private List<String> animal;
private Map<String, Object> score;
private Set<Double> salarys;
private Map<String, List<Pet>> allPets;
}
@Data
public class Pet {
private String name;
private Double weight;
}
用yaml表示以上对象
person:
userName: zhangsan
boss: false
birth: 2019/12/12 20:12:33
age: 18
pet:
name: tomcat
weight: 23.4
interests: [篮球,游泳]
animal:
- jerry
- mario
score:
english:
first: 30
second: 40
third: 50
math: [131,140,148]
chinese: {first: 128,second: 136}
salarys: [3999,4999.98,5999.99]
allPets:
sick:
- {name: tom}
- {name: jerry,weight: 47}
health: [{name: mario,weight: 47}]
6、配置文件-自定义类绑定的配置提示
自定义的类和配置文件绑定一般没有提示。若要提示,添加如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- 下面插件作用是工程打包时,不将spring-boot-configuration-processor打进包内,让其只在编码的时候有用 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
7、web场景-web开发简介
- 大多场景我们都无需自定义配置
- 内容协商视图解析器和BeanName视图解析器
- 静态资源(包括webjars)
- 自动注册 Converter,GenericConverter,Formatter
- 支持 HttpMessageConverters (后来我们配合内容协商理解原理)
- 自动注册 MessageCodesResolver (国际化用)
- 静态index.html 页支持
- 自定义 Favicon
- 自动使用 ConfigurableWebBindingInitializer (DataBinder负责将请求数据绑定到JavaBean上)
不用@EnableWebMvc注解。使用
@Configuration
+WebMvcConfigurer
自定义规则声明 WebMvcRegistrations 改变默认底层组件
使用 @EnableWebMvc+@Configuration+DelegatingWebMvcConfiguration 全面接管SpringMVC
8、web场景-静态资源规则与定制化
8.1、静态资源访问
- 存放位置:只要静态资源放在类路径下: /static ( /public 、 /resources 、 /META-INF/resources
- 访问 : 当前项目根路径/ + 静态资源名
- 原理: 静态映射/**
访问:http://localhost:8888/4.jpeg http://localhost:8888/1.jpeg。http://localhost:8888/2.jpeg
处理原理:请求进来,先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器,到静态资源路径下找。静态资源也找不到则响应404页面。
静态资源访问前缀
application.yml
spring:
mvc:
static-path-pattern: /res/**
- * 代表一层目录或目录下的一个文件
- ** 任意层目录任意文件
访问路径:当前项目 + static-path-pattern + 静态资源名 = 静态资源文件夹下找
http://localhost:8888/res/1.jpeg
也可以改变默认的静态资源路径,/static、
/public
、/resources
、/META-INF/resources
失效。只有/haha/下的资源有效
spring:
resources:
static-locations: [classpath:/haha/]
8.2、web场景-welcome与favicon功能
欢迎页支持
-
静态资源路径(resources路径)下 index.html。
- 可以配置静态资源路径
- 但是不可以配置静态资源的访问前缀。否则导致 index.html不能被默认访问
- controller能处理/index。
spring:
# mvc:
# static-path-pattern: /res/** 这个会导致welcome page功能失效
resources:
static-locations: [classpath:/haha/]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>欢迎你</title>
</head>
<body>
<h1>欢迎你</h1>
</body>
</html>
自定义Favicon
指网页标签上的小图标。
favicon.ico 放在静态资源目录下即可。
spring:
# mvc:
# static-path-pattern: /res/** 这个会导致 Favicon 功能失效
9、web场景-【源码分析】-静态资源原理
9.1、
- SpringBoot启动默认加载 xxxAutoConfiguration 类(自动配置类)
- SpringMVC功能的自动配置类
WebMvcAutoConfiguration
,生效
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
...
}
- 给容器中配置的内容:
- 注意@EnableConfigurationProperties 代表绑定配置文件
- 配置文件的相关属性的绑定:WebMvcProperties==spring.mvc、ResourceProperties==spring.resources
- WebMvcProperties和ResourceProperties注册到容器中
public class WebMvcAutoConfiguration { @Configuration(proxyBeanMethods = false) @Import(EnableWebMvcConfiguration.class) @EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class }) @Order(0) public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer { 有参构造器所有参数的值都会从容器中确定 public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) { this.mvcProperties = mvcProperties; this.beanFactory = beanFactory; this.messageConvertersProvider = messageConvertersProvider; this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable(); this.dispatcherServletPath = dispatcherServletPath; this.servletRegistrations = servletRegistrations; this.mvcProperties.checkConfiguration(); } } }@ConfigurationProperties(prefix = "spring.mvc") public class WebMvcProperties { }
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false) public class ResourceProperties { }
9.2、注意:
一个配置类只有一个有参构造器,那有参构造器所有参数的值都会默认从容器中确定。
则WebMvcAutoConfigurationAdapter会从容器中获取以下参数
- ResourceProperties resourceProperties:获取和spring.resources绑定的所有的值的对象
- WebMvcProperties mvcProperties :获取和spring.mvc绑定的所有的值的对象
- ListableBeanFactory beanFactory :Spring的beanFactory
- HttpMessageConverters :找到所有的HttpMessageConverters
- ResourceHandlerRegistrationCustomizer :找到 资源处理器的自定义器
- DispatcherServletPath
- ServletRegistrationBean 给应用注册Servlet、Filter…
9.3、资源处理的默认规则:
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
}
WebMvcAutoConfigurationAdapterl里的addResourceHandlers:
代表加载资源的路径。
- 拿到ResourceProperties配置文件里绑定的所有内容,即能获取addMappings属性,默认true。
- 如果addMappings属性设置为false,则直接返回,则不会走下面获取静态资源的代码,则静态资源无论放哪都不会被访问到。
- 当Cache 和 Cachecontrol 返回304给客户端,让客户端缓存该页面内容一段时间
- 当访问/webjars/**下面的所有请求时,她会到 classpath:/META-INF/resources/webjars/ 路径下找资源。
9.3、数据缓存设置:
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); return; } Duration cachePeriod = this.resourceProperties.getCache().getPeriod(); CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();}
resources: cache: period: 332536000
9.4、访问 /webjars
会自动到classpath:/META-INF/resources/webjars中找资源
http://localhost:8888/webjars/jquery/3.5.1/jquery.min.js
9.5、访问 /**
staticLoscations就是
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" };
9.6、欢迎页的处理规则:
handlerMapping:处理器映射器,保存了每一个handler能处理那些请求。
...
public class WebMvcAutoConfiguration {
...
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
...
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
return welcomePageHandlerMapping;
}
WelcomePageHandlerMapping
的构造方法如下:
WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders,
ApplicationContext applicationContext, Resource welcomePage, String staticPathPattern) {
if (welcomePage != null && "/**".equals(staticPathPattern)) {
//要用欢迎页功能,必须是/**
logger.info("Adding welcome page: " + welcomePage);
setRootViewName("forward:index.html");
}
else if (welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) {
//调用Controller /index
logger.info("Adding welcome page template: index");
setRootViewName("index");
}
}
要用欢迎页功能,必须将index.xml放到 /** 下。
这构造方法内的代码也解释了web场景-welcome与favicon功能中配置static-path-pattern
了,welcome页面和小图标失效的问题。
9.7、根据上述代码,我们可以同过配置禁止所有静态资源规则:
application.yaml中
spring:
resources:
add-mappings: false #禁用所有静态资源规则
9.8、静态资源规则:
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/"};
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
...
}}