SpringBoot2核心技术
一、配置文件
1、文件类型
1.1、properties
同以前的properties用法
1.2、yaml
1.2.1、简介
YAML
是 “YAML Ain’t Markup Language”(YAML
不是一种标记语言)的递归缩写。在开发的这种语言时,YAML
的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)。
非常适合用来做以数据为中心的配置文件
1.2.2、基本语法
key
: value
;kv
之间有空格
大小写敏感
使用缩进表示层级关系
缩进不允许使用tab,只允许空格
缩进的空格数不重要,只要相同层级的元素左对齐即可
'#
'表示注释
字符串无需加引号,如果要加,''
与""
表示字符串内容 会被 转义/不转义
1.2.3、数据类型
字面量:单个的、不可再分的值。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
、queru
行内写法: k: [v1,v2,v3]
#或者
k:
- v1
- v2
- v3
1.2.4、示例
@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}]
2、配置提示
自定义的类和配置文件绑定一般没有提示
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<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>
二、Web开发
1、SpringMVC自动配置概览
大多场景我们都无需自定义配置
自动注册 Converter
,GenericConverter
,Formatter
静态index.html
页支持
自定义 Favicon
自动使用 ConfigurableWebBindingInitializer
,(DataBinder
负责将请求数据绑定到JavaBean
上
不用@EnableWebMvc
注解。使用 @Configuration
+ WebMvcConfigurer
自定义规则
声明 WebMvcRegistrations
改变默认底层组件
使用 @EnableWebMvc
+@Configuration
+DelegatingWebMvcConfiguration
全面接管SpringMVC
2、简单功能分析
2.1、静态资源访问
1、静态资源目录
只要静态资源放在类路径下: called /static (or /public or /resources or /META-INF/resources
访问 : 当前项目根路径/ + 静态资源名
原理: 静态映射/**。
请求进来,先去找Controller
看能不能处理。不能处理的所有请求又都交给静态资源处理器。静态资源也找不到则响应404
页面
改变默认的静态资源路径
spring:
mvc:
static-path-pattern: /res/**
resources:
static-locations: [classpath:/haha/]
2、静态资源访问前缀
默认无前缀
spring:
mvc:
static-path-pattern: /res/**
当前项目 + static-path-pattern
+ 静态资源名 = 静态资源文件夹下
3、webjar
自动映射 /webjars/**
https://www.webjars.org/
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.5.1</version>
</dependency>
访问地址:http://localhost:8080/webjars/jquery/3.5.1/jquery.js 后面地址要按照依赖里面的包路径
2.2、欢迎页支持
静态资源路径下 index.html
可以配置静态资源路径
但是不可以配置静态资源的访问前缀。否则导致 index.html
不能被默认访问
spring:
# mvc:
# static-path-pattern: /res/** 这个会导致welcome page功能失效
resources:
static-locations: [classpath:/haha/]
controller能处理/index
2.3、自定义 Favicon
favicon.ico
放在静态资源目录下即可
spring:
# mvc:
# static-path-pattern: /res/** 这个会导致 Favicon 功能失效
2.4、静态资源配置原理
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 {
}
给容器中配了什么?
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
}
配置文件的相关属性和xxx进行了绑定。`WebMvcProperties==spring.mvc`、`ResourceProperties==spring.resources`
三、请求参数处理
请求映射
1、rest
使用与原理
@xxxMapping;
Rest
风格支持(使用HTTP
请求方式动词来表示对资源的操作)
以前:/getUser
获取用户 /deleteUser
删除用户 /editUser
修改用户 /saveUser
保存用户
现在: /user
GET-
获取用户 DELETE-
删除用户 PUT-
修改用户 POST-
保存用户
核心Filter
;HiddenHttpMethodFilter
用法: 表单method=post
,隐藏域 _method=put
SpringBoot
中手动开启
扩展:如何把_method
这个名字换成我们自己喜欢的
@RequestMapping(value = "/user",method = RequestMethod.GET)
public String getUser(){
return "GET-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.POST)
public String saveUser(){
return "POST-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.PUT)
public String putUser(){
return "PUT-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.DELETE)
public String deleteUser(){
return "DELETE-张三";
}
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
//自定义filter
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
methodFilter.setMethodParam("_m");
return methodFilter;
}
Rest
原理(表单提交要使用REST
的时候)
表单提交会带上_method=PUT
请求过来被HiddenHttpMethodFilter
拦截
请求是否正常,并且是POST
获取到_method
的值
兼容以下请求;PUT.DELETE.PATCH
原生request(post)
,包装模式requesWrapper
重写了getMethod
方法,返回的是传入的值
过滤器链放行的时候用wrapper
。以后的方法调用getMethod
是调用requesWrapper
Rest
使用客户端工具,
如PostMan
直接发送Put
、delete
等方式请求,无需Filter
spring:
mvc:
hiddenmethod:
filter:
enabled: true #开启页面表单的Rest功能
2、请求映射原理
SpringMVC
功能分析都从 org.springframework.web.servlet.DispatcherServlet
→doDispatch()
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 找到当前请求使用哪个Handler(Controller的方法)处理
mappedHandler = getHandler(processedRequest);
//HandlerMapping:处理器映射。/xxx->>xxxx
RequestMappingHandlerMapping
:保存了所有@RequestMapping
和handler
的映射规则
所有的请求映射都在HandlerMapping中