SpringBoot2

尚硅谷雷丰阳

​ 视频地址:https://www.bilibili.com/video/BV19K4y1L7MT?p=1&spm_id_from=pageDriver

​ 笔记地址:https://www.yuque.com/leifengyang/wzypip/vrs7yn

正常翻笔记,且对照下面的补错

笔记有小错误或者需要记录但是没有记录的,都在下面

都是按照链接中笔记来补的,根据笔记目录来查找

03、了解自动配置原理

错别字使用【】标记

• 各种配置拥有默认值
	• 默认配置最终都是映射到某个类上,如:MultipartProperties
	• 配置文件的值最终会绑定 在底层中的【某】 个类上,这个类会在容器中创建对象

自动配置

小知识点

//这个属性的默认值为true,表示这个这个配置类(组件)中的bean都为单例模式(创建一次),为false表示为原型模式(每次创建)
@Configuration(proxyBeanMethods = true)
public class MyConfig {
    @Bean("user")
    public User user01(){
        User user = new User("张三", 18);
        /*
        更新:如果上面为false,这里会报错,但是不影响执行:
        Method annotated with @Bean is called directly in a @Configuration where proxyBeanMethods set to false.
        翻译:在@Configuration中直接调用带有@Bean注释的方法,其中proxyBeanMethods设置为false。
        */
        user.setPet(cat());
        return user;
    }
    @Bean("tomcat")
    public Pet cat(){
        return new Pet("tomcat");
    }
}

笔记内容

• 最佳实战
• 配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断 
• 配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式

Lite:@Configuration(proxyBeanMethods = false)

Full:@Configuration(proxyBeanMethods = true)

如果这个配置类中其他生产bean的方法不依赖当前bean,@Configuration(proxyBeanMethods = ) 配置为false

反之改为true

为true的缺点:

每次调用都需要去扫描容器,寻找这个bean。没有才会去创建

@Conditional

条件装配:满足Conditional指定的条件,则进行组件注入

@Configuration(proxyBeanMethods = false)
public class MyConfig {
    //Conditional派生出的一个方法,见名知义:存在这个bean就执行
    //与执行先后顺序有关,如果user01()先执行,无法创建user bean,如果cat()先执行,可以创建user bean
    @ConditionalOnBean(name = "tomcat") 
    @Bean("user")
    public User user01(){
        User user = new User("张三", 18);
        user.setPet(cat());
        return user;
    }
    @Bean("tomcat")
    public Pet cat(){
        return new Pet("tomcat");
    }
}

配置文件绑定

@ConfigurationProperties

笔记中没写释义,这里补充

第一种方式 @Component + @ConfigurationProperties

/**
 * 只有作为SpringBoot容器中的一份子,才能使用到SpringBoot中的内容 
 */
@Component
//根据配置文件(properties)中的前缀来匹配对应的属性
@ConfigurationProperties(prefix = "mycar")
public class Car {

    private String brand;
    private Integer price;

    //constructor/Setter/Getter
}

properties

 mycar.brand=BYD 
 mycar.price=100000
@EnableConfigurationProperties

第二种方式 @EnableConfigurationProperties + @ConfigurationProperties

##使用## 

在标注了**@ConfigurationProperties(prefix = "mycar")**之后,在**config**类上标注 **@EnableConfigurationProperties()**

参数为标注了 @ConfigurationProperties 所在的类,也就是需要绑定配置文件资源的那个类
  1. 这个注解会开启参数中指定的 xxx.class 的配置绑定功能
  2. 把这个 xxx.class 作为组件注册到容器中

自动配置原理

自动注册组件

@AutoConfigurationPackage //点进去
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration

    
//点Registrar 
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage 
    

/**
* @metadata:这个注解的元数据(比如:标注在哪?传的参数?)
* @registry:用来注册
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
    /*
    这里通过new PackageImports(metadata).getPackageNames() 获取了标注的位置,也就是@SpringBootApplication
    标注的位置(可以这么理解,因为都是一层一层传下来的)最终的位置是在@SpringBootApplication,然后根据
    这个类所在的包和其子包下的组件注册到容器中,且根据注解和配置文件自动配置 根据spring.factories所有包的这个文件
    */
    register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
总结:
  • SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration

  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties.class里面拿。xxxProperties.class和配置文件(properties)进行了绑定

  • 生效的配置类就会给容器中装配很多组件

  • 只要容器中有这些组件,相当于这些功能就有了

  • 定制化配置

    • 用户直接自己@Bean替换底层的组件
    • 用户去看这个组件是获取的配置文件什么值就去修改。

自动配置流程:

最后会按照 application.properties的配置覆盖 相同的配置

xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 ----> 包中自带的.properties ----> application.properties

要更改springboot原有的属性时,去点开autoConfiguration中对应的依赖包

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fb7DZOg5-1624634097826)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210615175636062.png)]

然后

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RQJ7Bv8F-1624634097828)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210615180123684.png)]

根据这个前缀去application.properties配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WTN4Pdzv-1624634097829)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210615180202362.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3dm3Ib7y-1624634097832)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210615180405411.png)]

按需配置

需要满足标注在类或者方法上的 @ConditionalOn… 的条件 //容器中有无这个组件来判断

导入的所有组件不一定生效,需要加入对应的依赖才能不被 @Conditional 拦截

文件上传

底层解析

有三个条件:

@Bean//作为组件注册到容器中
@ConditionalOnBean(MultipartResolver.class)  //容器中有这个类型组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)  
//容器中没有这个 DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME 名字的 multipartResolver 的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {
    //如果给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
    //SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
    // Detect if the user has created a MultipartResolver but named it incorrectly
    return resolver;
}

小结

​ 1.只要你传过来的 resolver 命名不为 DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME 这个方法返回的 resolver 就会的名字就会变成 DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME

​ 2. 后两个注解的大概意思是 必须有这个类型的组件,但是名字不能为 DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME

大概意思是为了遵守规范帮我重新命名?

yaml小知识点

# yaml表示以上对象
person:
  #String
  userName: zhangsan
  #Boolean 
  boss: false
  #Date
  birth: 2019/12/12 20:12:33
  #Integer 
  age: 18
  #对象
  pet: 
    name: tomcat
    weight: 23.4
  #数组
  interests: [篮球,游泳]
  #List 和 数组的方法都是互用的
  animal: 
    - jerry
    - mario
  # Map<String, Object>
  score:
    english: 
      first: 30
      second: 40
      third: 50
    math: [131,140,148]
    chinese: {first: 128,second: 136}
  #Set
  salarys: [3999,4999.98,5999.99]
  #Map<String, List<Pet>>
  allPets:
    sick:
      - {name: tom}
      - {name: jerry,weight: 47}
    health: [{name: mario,weight: 47}]

yaml中,双引号会转义,单引号不会

yaml的加载优先级比properties高,所以会被properties中相同的配置覆盖2、配置提示

idea配置提示

【@ConfigurationProperties(prefix = “mycar”)】

类中设置了properties前缀之后,在properties文件中会弹出提示

自定义的类和配置文件绑定一般没有提示,需要导入一个依赖。

<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>
                <!--这个配置是让maven打包的时候不把这依赖中的几个类打包进去,因为对业务没有作用-->
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-configuration-processor</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

静态文件目录修改

因为拦截静态资源和接收其他请求一样,都是 / **

所以会先到controller中去找处理这个请求的方法,如果处理不了再交到resources目录下的文件去匹配

spring:
  mvc:
    # 给静态资源加访问前缀  http://localhost:8080/res/a.png 
    static-path-pattern: /res/** # 这个配置会导致default welcome page 和 favicon.ico 失效
  web:
    resources:
      # 设置静态资源存放路径,只能访问到这些目录下的静态资源
      static-locations: [classpath:/haha/]

      # 如果是加入一个访问路径的话,需要把之前的默认目录也一起写入
      # static-locations: [classpath:/haha/,"classpath:/META-INF/resources/",
      #				"classpath:/resources/", "classpath:/static/", "classpath:/public/"]

欢迎页【首页】

只要把一个名为index的html页面放到自己定义或者默认的静态资源路径下,且没有配置静态资源访问前缀

classpath:
"classpath:/META-INF/resources/"
"classpath:/resources/"
"classpath:/static/"
"classpath:/public/"

才会自动被SpringBoot扫描到,作为首页展示

默认从上至下将扫描到的第一个静态资源目录下的index.html作为首页

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-06bBjMNa-1624634097833)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210621202829177.png)]

浏览器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JRy5OwLF-1624634097834)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210621202932108.png)]

favicon.ico

欢迎页 同理

webjars

所有/webjars/**请求, 都去classpath:/META-INF/resources/webjars/下面寻找资源

webjars: 以jar包的方式引入资源

webjars官网: https://www.webjars.org/

例如在项目中引入jQuery的webjar

<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>jquery</artifactId>
    <version>3.6.0</version>
</dependency>

一个webjars请求资源的例子: http://localhost:8081/webjars/jquery/3.6.0/jquery.js

2./**访问当前项目下的任何资源(静态资源文件夹)
"classpath:/META-INF/resources/",
"classpath:/resources/", 
"classpath:/static/", 
"classpath:/public/"
"/" : 当前项目的根路径

例如请求: http://localhost:8081/webjars-requirejs.js 将会去上述静态资源文件路径中寻找webjars-requirejs.js

RestFul风格

发送 GET/POST之外的 PUT和DELETE请求需要在 表单中method的值为POST,

并且需要隐藏一个属性:_method【可修改默认值】
<form action="/user" method="post">
    <input name="_method" type="hidden" value="put">
    <input type="submit" value="PUT-USER">
</form>
<form action="/user" method="post">
    <input name="_method" type="hidden" value="delete">
    <input type="submit" value="DELETE-USER">
</form>

//自定义filter
    @Bean
    public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
        HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
        methodFilter.setMethodParam("_m");
        return methodFilter;
    }
且配置文件中加入此配置

【只在处理表单请求的时候会开启这个过滤器,因为表单只能发送get/post。而客户端则可以直接发起其他请求】

因为源码中默认为false

image-20210621210244222

翻阅源码:

双shift搜索WebMvcAutoConfiguration 再一路点下去

这几个类是负责解析隐藏的请求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HSzmj64w-1624634097835)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210621205601427.png)]

/** Default method parameter: {@code _method}. */
public static final String DEFAULT_METHOD_PARAM = "_method";

参数注解

每一个参数注解怎么使用,点进去查看源码注释

@PathVariable【路径变量】
//测试参数注解
@GetMapping("/car/{id}/name/{username}")
public Map<String,Object> getCar(@PathVariable("id") Integer id,
                                 @PathVariable("username") String name,
                                 //这里标注@PathVariable之后会把 id 和 username作为kv存储到pv中
                                 @PathVariable Map<String,String> pv){
    Map<String,Object> map = new HashMap<>();
    map.put("id",id);
    map.put("name",name);
    map.put("pv",pv);
    return map;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HIdWhxbv-1624634097836)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210623201915850.png)]

@RequestHeader【请求头】
//测试参数注解
@GetMapping("/car/{id}/name/{username}")
public Map<String,Object> getCar(	//带key是获取单个
    @RequestHeader("Upgrade-Insecure-Requests") String uir,
    //无参数是获取所有
    @RequestHeader Map<String,String> headers){
    Map<String,Object> map = new HashMap<>();
    map.put("uir",uir);
    map.put("headers",headers);
    return map;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j7mxtzKj-1624634097836)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210623202811981.png)]

@RequestParam【请求参数】
//测试参数注解
@GetMapping("/car/{id}/name/{username}")
							 //带key是获取单个
public Map<String,Object> getCar(@RequestParam("id") String id,
                                 //相同的参数有多个
                                 @RequestParam("inters") List<String> inters,
                                 //无参数是获取所有
    						   @RequestParam Map<String,String> params){
    
    Map<String,Object> map = new HashMap<>();
    map.put("id",id);
    map.put("List",inters);
    //注意!这里获取到所有的参数中,list只能遍历出一个元素,因为map中key不可重复
    map.put("params",params);
    return map;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zpXOlhsH-1624634097836)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210623203710482.png)]

@CookieValue【cookie】
//测试参数注解
@GetMapping("/car/{id}/name/{username}")
							  //获取单个cookie信息
public Map<String,Object> getCar(@CookieValue("Idea-8296e76f") String Idea,
                                 //获取整个cookie的值
                                 @CookieValue("Idea-8296e76f") Cookie cookie){
    
    Map<String,Object> map = new HashMap<>();
    map.put("Idea",Idea);
    map.put("cookie",cookie);
    return map;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xDtt2kqF-1624634097837)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210623204457751.png)]

@RequestBody【请求体】
<form action="/save" method="post">
    <input type="hidden" name="username" value="zhangsan">
    <input type="hidden" name="password" value="123456">
    <input type="submit" value="提交">
</form>
@PostMapping("/save")
							//获取请求体,也就是表单提交的数据
public Map<String,Object> save(@RequestBody String content){
    Map<String,Object> map = new HashMap<>();
    map.put("content",content);
    return map;
}
@RequestAttribute【request中的参数】
package com.zsh.springboot.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

//请求域参数获取
@Controller
public class RequestParamTest {

    @GetMapping("/goto")
    //使用原生的request做演示给请求域中添加数据
    public String gotoPage(HttpServletRequest request){
        request.setAttribute("msg1","msg1");
        request.setAttribute("msg2","msg2");
        //转发到当前项目中的  /success请求
        return "forward:/success";
    }
    @ResponseBody
    @GetMapping("/success")			//获取request中的数据,这个不能直接获取全部数据
    public Map<String,Object> success(@RequestAttribute("msg1") String msg1,
                                      @RequestAttribute("msg2") String msg2,
                                      //使用原生request取出Attribute与注解对比演示
                                      HttpServletRequest request){
        Map<String,Object> map = new HashMap<>();
        String msg3 = (String) request.getAttribute("msg1");
        map.put("msg1",msg1);
        map.put("msg2",msg2);
        map.put("msg3",msg3);
        return map;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gOvYeA6P-1624634097837)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210623211017134.png)]

矩阵变量

语法

在请求后面使用 ; 然后 变量名=值 
localhost:8080/cars/sell;low=34
多个请求需要变量 / 后面继续写
localhost:8080//cars/sell;low=34;brand=byd,audi,yd
相同的变量名在controller中解释
localhost:8080/boss/1;age=20/2;age=20

controller处理

//1、语法: 请求路径:/cars/sell;low=34;brand=byd,audi,yd
//2、SpringBoot默认是禁用了矩阵变量的功能
//      手动开启:原理。对于路径的处理。UrlPathHelper进行解析。
//              removeSemicolonContent(移除分号内容)支持矩阵变量的
//3、矩阵变量必须有url路径变量才能被解析
@GetMapping("/cars/{path}")
public Map carsSell(@MatrixVariable("low") Integer low,
                    @MatrixVariable("brand") List<String> brand,
                    @PathVariable("path") String path){
    Map<String,Object> map = new HashMap<>();

    map.put("low",low);
    map.put("brand",brand);
    map.put("path",path);
    return map;
}

// /boss/1;age=20/2;age=10
//相同的矩阵变量名使用 pathVar 根据变量名前面的请求来区分
@GetMapping("/boss/{bossId}/{empId}")
public Map boss(@MatrixVariable(value = "age",pathVar = "bossId") Integer bossAge,
                @MatrixVariable(value = "age",pathVar = "empId") Integer empAge){
    Map<String,Object> map = new HashMap<>();

    map.put("bossAge",bossAge);
    map.put("empAge",empAge);
    return map;

}

@MatrixVariable(“brand”) List brand,
@PathVariable(“path”) String path){
Map<String,Object> map = new HashMap<>();

map.put("low",low);
map.put("brand",brand);
map.put("path",path);
return map;

}

// /boss/1;age=20/2;age=10
//相同的矩阵变量名使用 pathVar 根据变量名前面的请求来区分
@GetMapping("/boss/{bossId}/{empId}")
public Map boss(@MatrixVariable(value = “age”,pathVar = “bossId”) Integer bossAge,
@MatrixVariable(value = “age”,pathVar = “empId”) Integer empAge){
Map<String,Object> map = new HashMap<>();

map.put("bossAge",bossAge);
map.put("empAge",empAge);
return map;

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值