学习春天の靴子(springBoot)

ps:以下笔记内容主要搬运自尚硅谷(雷神)的笔记

Chapter1—自动配置原理

1.1、依赖管理

  • 父项目做依赖管理
依赖管理    
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
</parent>

他的父项目
 <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.3.4.RELEASE</version>
  </parent>

几乎声明了所有开发中常用的依赖的版本号,自动版本仲裁机制
  • 开发导入starter场景启动器
1、见到很多 spring-boot-starter-* : *就某种场景
2、只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
3、SpringBoot所有支持的场景
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
4、见到的  *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
5、所有场景启动器最底层的依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter</artifactId>
  <version>2.3.4.RELEASE</version>
  <scope>compile</scope>
</dependency>
  • 可以修改默认版本号
1、查看spring-boot-dependencies里面规定当前依赖的版本 用的 key。
2、在当前项目里面重写配置
    <properties>
        <mysql.version>5.1.43</mysql.version>
    </properties>

1.2、自动配置

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <version>2.3.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
  • 自动配好SpringMVC

  • 引入SpringMVC全套组件

  • 自动配好SpringMVC常用组件(功能)

  • 自动配好Web常见功能,如:字符编码问题

  • SpringBoot帮我们配置好了所有web开发的常见场景

  • 默认的包结构

  • 主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来

  • 无需以前的包扫描配置

  • 想要改变扫描路径,@SpringBootApplication(scanBasePackages=“xxx”)

  • 或者@ComponentScan 指定扫描路径

@SpringBootApplication
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.atguigu.boot")

Chapter2—容器功能

2.1、组件添加

1、@Configuration

  • Full模式与Lite模式

  • `java
    #############################Configuration使用示例######################################################
    /**

    • 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
    • 2、配置类本身也是组件
    • 3、proxyBeanMethods:代理bean的方法
    • Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】
    • Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】
    • 组件依赖必须使用Full模式默认。其他默认是否Lite模式

      /
      @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
      public class MyConfig {

      /**

      • Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象
      • @return
        */
        @Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
        public User user01(){
        User zhangsan = new User(“zhangsan”, 18);
        //user组件依赖了Pet组件
        zhangsan.setPet(tomcatPet());
        return zhangsan;
        }

      @Bean(“tom”)
      public Pet tomcatPet(){
      return new Pet(“tomcat”);
      }
      }

################################@Configuration测试代码如下########################################
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(“com.atguigu.boot”)
public class MainApplication {

  public static void main(String[] args) {
      //1、返回我们IOC容器
      ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

      //2、查看容器里面的组件
      String[] names = run.getBeanDefinitionNames();
      for (String name : names) {
          System.out.println(name);
      }

      //3、从容器中获取组件

      Pet tom01 = run.getBean("tom", Pet.class);

      Pet tom02 = run.getBean("tom", Pet.class);

      System.out.println("组件:"+(tom01 == tom02));


      //4、com.atguigu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$51f1e1ca@1654a892
      MyConfig bean = run.getBean(MyConfig.class);
      System.out.println(bean);

      //如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。
      //保持组件单实例
      User user = bean.user01();
      User user1 = bean.user01();
      System.out.println(user == user1);


      User user01 = run.getBean("user01", User.class);
      Pet tom = run.getBean("tom", Pet.class);

      System.out.println("用户的宠物:"+(user01.getPet() == tom));



  }

}


```java
 * 4、@Import({User.class, DBHelper.class})
 *      给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名
 *
 *
 *
 */

@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
}

2、@Conditional

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

2.2、配置绑定

1、@ConfigurationProperties

/**
 * 只有在容器中的组件,才会拥有SpringBoot提供的强大功能
 */
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {

    private String brand;
    private Integer price;

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", price=" + price +
                '}';
    }
}

2.3、按需开启自动配置项

虽然我们127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration
按照条件装配规则(@Conditional),最终会按需配置。

总结

  • SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定

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

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

  • 定制化配置

  • 用户直接自己@Bean替换底层的组件

  • 用户去看这个组件是获取的配置文件什么值就去修改。

xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 —-> application.properties

Chapter3—配置文件

1、文件类型

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、示例

@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>

Chapter4—Web开发

1.1、模板抽取(thymeleaf)

  1. 首先,根据需求提取出模板网页
  2. 在模板网页中,利用th:fragment=”xxx”将模板”碎片化“
  3. 然后在需要的网页中使用th:insert=“[模板名称]::[碎片名]”或th:replace=“[模板名称]::[碎片名]”或th:include=“[模板名称]::[碎片名]”

1.2、拦截器配置

  1. 配置拦截器

  2. 将拦截器注册到容器中(其实是先配置到一个config配置类中,然后容器再通过调用 配置类 来进行 装配)

    必要时会指定拦截路径

1.2.1、拦截器原理(复习)

1、根据当前请求,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有 拦截器】

2、先来顺序执行 所有拦截器的 preHandle方法

  • 1、如果当前拦截器prehandler返回为true。则执行下一个拦截器的preHandle
  • 2、如果当前拦截器返回为false。直接 倒序执行所有已经执行了的拦截器的 afterCompletion;

3、如果任何一个拦截器返回false。直接跳出不执行目标方法

4、所有拦截器都返回True。执行目标方法

5、倒序执行所有拦截器的postHandle方法。

6、前面的步骤有任何异常都会直接倒序触发 afterCompletion

7、页面成功渲染完成以后,也会倒序触发 afterCompletion

1.3、文件上传

    /**
     * MultipartFile 自动封装上传过来的文件
     * @param email
     * @param username
     * @param headerImg
     * @param photos
     * @return
     */
    @PostMapping("/upload")
    public String upload(@RequestParam("email") String email,
                         @RequestParam("username") String username,
                         @RequestPart("headerImg") MultipartFile headerImg,
                         @RequestPart("photos") MultipartFile[] photos) throws IOException {

        log.info("上传的信息:email={},username={},headerImg={},photos={}",
                email,username,headerImg.getSize(),photos.length);

        if(!headerImg.isEmpty()){
            //保存到文件服务器,OSS服务器
            String originalFilename = headerImg.getOriginalFilename();
            headerImg.transferTo(new File("H:\\cache\\"+originalFilename));
        }

        if(photos.length > 0){
            for (MultipartFile photo : photos) {
                if(!photo.isEmpty()){
                    String originalFilename = photo.getOriginalFilename();
                    photo.transferTo(new File("H:\\cache\\"+originalFilename));
                }
            }
        }


        return "main";
    }

1.4、原生组件注入(Servlet、Filter、Listener)

该注解写在主程序类中

@ServletComponentScan(basePackages = “xxx”) :指定原生Servlet组件都放在那里


下列注解用来表示各个组件:

@WebServlet(urlPatterns = “/my”)

@WebFilter(urlPatterns={“/css/*“,“/images/*“})

@WebListener


1.4.1、利用RegistrationBean来注入组件

@Configuration
public class MyRegistConfig {

    @Bean
    public ServletRegistrationBean myServlet(){
        MyServlet myServlet = new MyServlet();

        return new ServletRegistrationBean(myServlet,"/my","/my02");//在注入的servlet,以及对应的映射路径
    }


    @Bean
    public FilterRegistrationBean myFilter(){

        MyFilter myFilter = new MyFilter();
//        return new FilterRegistrationBean(myFilter,myServlet());
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));
        return filterRegistrationBean;
    }

    @Bean
    public ServletListenerRegistrationBean myListener(){
        MySwervletContextListener mySwervletContextListener = new MySwervletContextListener();
        return new ServletListenerRegistrationBean(mySwervletContextListener);
    }
}

Chapter5—数据访问

导入JDBC场景

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>

导入数据库驱动

默认版本:<mysql.version>8.0.22</mysql.version>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
<!--            <version>5.1.49</version>-->
        </dependency>
想要修改版本
1、直接依赖引入具体版本(maven的就近依赖原则)
2、重新声明版本(maven的属性的就近优先原则)
    <properties>
        <java.version>1.8</java.version>
        <mysql.version>5.1.49</mysql.version>
    </properties>

另外,可以通过修改spring.jdbc来修改JdbcTemplate的相关值

测试:

@Slf4j
@SpringBootTest
class Boot05WebAdminApplicationTests {

    @Autowired
    JdbcTemplate jdbcTemplate;//!!!!!!!!!!!!!这里的自动注入可能会无法注入,解决方法在下面


    @Test
    void contextLoads() {

//        jdbcTemplate.queryForObject("select * from account_tbl")
//        jdbcTemplate.queryForList("select * from account_tbl",)
        Long aLong = jdbcTemplate.queryForObject("select count(*) from account_tbl", Long.class);
        log.info("记录总数:{}",aLong);
    }

}

解决JdbcTemplate无法自动注入的问题:

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
       <!-- <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.8.RELEASE</version>
            <scope>test</scope>
        </dependency>-->

只要不引入上面那个注释掉的依赖就可以了(我也不知道为什么,我给这个折磨了好一阵子了。。。)


使用Druid数据源

  1. 引入druid-starter

            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.17</version>
            </dependency>
    
  2. 能够进行自动配置的相关属性

    • 扩展配置项 spring.datasource.druid
    • DruidSpringAopConfiguration.class, 监控SpringBean的;配置项:spring.datasource.druid.aop-patterns

    • DruidStatViewServletConfiguration.class, 监控页的配置:spring.datasource.druid.stat-view-servlet;默认开启

    • DruidWebStatFilterConfiguration.class, web监控配置;spring.datasource.druid.web-stat-filter;默认开启

    • DruidFilterConfiguration.class}) 所有Druid自己filter的配置

使用mybatis

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>

使用yaml配置mybatis(替代原先的mybatis-congfig.xml全局配置文件)

# 配置mybatis规则
mybatis:
#  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true

 可以不写全局;配置文件,所有全局配置文件的配置都放在configuration配置项中即可

总的来说整合mybatis的操作和以前几乎一样

  • 导入mybatis官方starter
  • 编写mapper接口。标准@Mapper注解

  • 编写sql映射文件并绑定mapper接口

  • 在application.yaml中指定Mapper配置文件的位置,以及指定全局配置文件的信息 (建议;配置在mybatis.configuration

mybatis-plus(mybatisX)不用手写crud了!

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
  • MybatisPlusAutoConfiguration 配置类,MybatisPlusProperties 配置项绑定。mybatis-plus:xxx 就是对**mybatis-plus的定制**
  • SqlSessionFactory 自动配置好。底层是容器中默认的数据源

  • mapperLocations 自动配置好的。有默认值。**classpath*:/mapper/*/\.xml;任意包的类路径下的所有mapper文件夹下任意路径下的所有xml都是sql映射文件。 建议以后sql映射文件,放在 mapper下**

  • 容器中也自动配置好了 SqlSessionTemplate

  • @Mapper 标注的接口也会被自动扫描;建议直接 @MapperScan(“xxx”) 批量扫描就行

注意:

mybatis_plus 默认会使用 “id” 为主键字段,如果数据库的主键字段不是“id”的话,使用mybatis-plus中的 selectById ,getById 方法查询数据是查询不出来的。所以就会出现空指针…(折磨人,别问我为什么知道…)

解决方法:

在实体类的主键字段加上@TableId(value =“数据库你的主键字段”)注解即可