从0到1,教你整合一下SpringBoot2的基础内容

努力学习的旭旭多多妹 2021-12-22 17:09:22

从0到1,教你整合一下SpringBoot2的基础内容

一、配置

1.配置maven文件中的conf下的setting.xml文件

修改setting.xml文件中的镜像

<mirrors>
      <mirror>
        <id>nexus-aliyun</id>
        <mirrorOf>central</mirrorOf>
        <name>Nexus aliyun</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>
      </mirror>
  </mirrors>
 
  <profiles>
         <profile>
              <id>jdk-1.8</id>
              <activation>
                <activeByDefault>true</activeByDefault>
                <jdk>1.8</jdk>
              </activation>
              <properties>
                <maven.compiler.source>1.8</maven.compiler.source>
                <maven.compiler.target>1.8</maven.compiler.target>
                <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
              </properties>
         </profile>
  </profiles>

+++

二、创建maven工程

1.pom.xml文件中添加

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
    </parent>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

    </dependencies>

2.在com.test.boot包下创建MainApplication主程序

package com.test.boot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/*
 * 主程序类
 * */
@SpringBootApplication  //这是springboot应用注解
public class MainApplication {
    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }
}

3.在com.test.boot.controller包下创建HelloController类

package com.test.boot.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

//@ResponseBody
//@Controller
@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String handle01() {
        return "Hello,Spring Boot 2!!!";
    }
}

4.在MainApplication测试

5.创建application.properties配置文件,可以在该文件下面修改配置(比如修改端口号,连接数据库等操作)

server.port=8888

6.简化部署,将项目打包成jar包,直接通过cmd方式运行即可

注意点:

  • 取消掉cmd的快速编辑模式
 <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

+++

三、自动配置原理

一、依赖管理

  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>

几乎声明了所有开发中常用的依赖的版本号,自动版本仲裁机制
  1. 开启了start场景启动器
1.所有场景启动器最底层的依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter</artifactId>
  <version>2.3.4.RELEASE</version>
  <scope>compile</scope>
</dependency>
2.只要引入了starter,这个场景的所有常规依赖我们都自动引入
  1. 可以修改默认引入的版本号
在pom.xml中添加
  <properties>
        <mysql.version>5.1.43</mysql.version>
  </properties>

+++

二、自动配置

  1. 自动配置好tomcat,SpringMvc所有组件和Web中的一些字符编码问题

  2. 开启自动扫描

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

    2.不需要再另外添加扫描配置语句

    +++

    3.==如果类不在主程序所在的包及其子包里面就需要改变包的扫描路径==

    方式一:@SpringBootApplication(scanBasePackages="com.test")
    方式二:@ComponentScan 指定扫描路径
    

    +++

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

+++

四、@Configuration注解

一、创建Pet和User类

二、在MyConfig类中添加@Configuration注解

步骤:

  1. 在MyConfig类中添加@Configuration注解
  2. 给容器中添加组件,组件注释用@Bean //给容器中添加组件,方法名user01相当于id,返回类型相当于组件类型,返回值就是在组件中的实例
  3. 在主程序类MainApplication中进行测试

+++

  1. 配置类里面用@Bean标注在方法上面给容器注册组件,默认也是单例的

@Bean的作用:

==//给容器中添加组件,方法名user01相当于id,返回类型相当于组件类型,返回值就是在组件中的实例==

  1. 配置类本身也是组件

  2. proxyBeanMethods:

代理bean的方法

  1. Full(proxyBeanMethods = true)

    1. ==解释:==外部调用bean对象时,从容器中调用每次调用的是同一个bean对象

    2. ==应用场景:==配置类组件之间==存在依赖关系时==方法会被调用到之前的单实例组件

  2. Lite(proxyBeanMethods = false) 外部调用bean对象时

    1. ==解释:==每次都要重新new一个新的bean对象

    2. ==应用场景:==配置类组件之间==不存在依赖关系时==用Lite模式加速容器的启动过程减少判断

三、MyConfig类代码

package com.test.boot.config;

import com.test.boot.bean.Pet;
import com.test.boot.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/*
 * 1.配置类里面用@Bean标注在方法上面给容器注册组件,默认也是单例的
 * 2.配置类本身也是组件
 * 3.proxyBeanMethods:代理bean的方法
 *  Full(proxyBeanMethods = true)   外部调用bean对象时
 *  从容器中调用每次调用的是同一个bean对象
 *  Lite(proxyBeanMethods = false)  外部调用bean对象时
 *  每次都要重新new一个新的bean对象
 *
 * */
@Configuration(proxyBeanMethods = false) //配置类等同于spring的配置文件
public class MyConfig {

    /**
     * 无论外部对配置类中的组件注册方法调用多少次获取的都是之前注册容器中的单实例对象
     *
     * @return
     */

    //给容器中添加组件,方法名user01相当于id,返回类型相当于组件类型,返回值就是在组件中的实例
    @Bean
    public User user01() {
        //User组件依赖l了Pet组件
        User zhangsan = new User("zhangsan", 18);
        zhangsan.setPet(tomcatPet());
        return zhangsan;
    }

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

四、主程序类MainApplication代码

//        3.从容器中获取组件
        Pet tom01 = run.getBean("tom", Pet.class);
        Pet tom02 = run.getBean("tom", Pet.class);
        System.out.println("组件:" + (tom01 == tom02));

        MyConfig bean = run.getBean(MyConfig.class);
        System.out.println(bean);

        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));

+++

五、@Import注解

一、作用:

@Import({User.class, DBHelper.class})给容器中自动创建出这两个类型的组件

默认组件的名字就是全类名

二、用法:

@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = true) //配置类等同于spring的配置文件
public class MyConfig {
    ...
}

p9看完

六、@Conditional注解

一、@ConditionalOnBean(name = "tom")

  1. @ConditionalOnBean(name = "tom")放在一个组件上面

如果容器中有tom这个组件再执行user01这个方法,没有就不执行

@ConditionalOnBean(name = "tom")
    @Bean
   public User user01() {
        //User组件依赖l了Pet组件
        User zhangsan = new User("zhangsan", 18);
        zhangsan.setPet(tomcatPet());
        return zhangsan;
    }
  1. @ConditionalOnBean(name = "tom")放在方法上面

如果容器中有组件tom就执行Myconfig类中的方法,没有就不执行

@ConditionalOnBean(name = "tom")
public class MyConfig {
    ...
}
  1. @ConditionalOnMissingBean(name = "tom")放在方法上面

如果容器没有组件tom就执行Myconfig类中的方法,否则就不执行

@ConditionalOnMissingBean(name = "tom")
public class MyConfig {
    ...
}

+++

七、@ImportResource注解

==作用:==

导入beans.xml文件中的bean组件

1.MyConfig类代码

@ImportResource("classpath:beans.xml")
public class MyConfig {
    ...
}

2.beans.xml文件代码

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="haha" class="com.test.boot.bean.User">
        <property name="name" value="zhangsan"></property>
        <property name="age" value="18"></property>
    </bean>

    <bean id="hehe" class="com.test.boot.bean.Pet">
        <property name="name" value="tomcat"></property>
    </bean>
</beans>

3.MainApplication类代码

package com.test.boot;

import ch.qos.logback.core.db.DBHelper;
import com.test.boot.bean.Pet;
import com.test.boot.bean.User;
import com.test.boot.config.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

/*
 * 主程序类
 * */
@SpringBootApplication  //这是springboot应用注解
public class MainApplication {
    public static void main(String[] args) {
//        1.返回IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);


        System.out.println("===========");
        boolean haha = run.containsBean("haha");
        boolean hehe = run.containsBean("hehe");
        System.out.println(haha);
        System.out.println(hehe);
    }
}

八、配置绑定

作用:用java读取到properties配置文件中的内容,并把它封装到javabean中方便使用

绑定方法

一、第一种方法:

@EnableConfigurationProperties + @ConfigurationProperties

==步骤:==

1.在MyConfig类中添加注解@EnableConfigurationProperties(Car.class)

@EnableConfigurationProperties==作用:==

* 1、开启Car配置绑定功能
* 2、把Car这个组件自动注册到容器中

2.在Car类中添加注解@ConfigurationProperties(prefix = "mycar")

MyConfig类

@EnableConfigurationProperties(Car.class)
public class MyConfig {
    ...
}

Car类

package com.test.boot.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/4 15:02
 */


//@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 +
                '}';
    }
}

二、第二种方法

@Component + @ConfigurationProperties

package com.test.boot.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/4 15:02
 */


@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 +
                '}';
    }
}

九、SpringBootApplication注解

1、@SpringBootConfiguration

@Configuration。代表当前是一个配置类

2、@ComponentScan

指定扫描哪些注解

3、@EnableAutoConfiguration

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}

==4.源码没看:ps(p13~p15):实在是太困了而且听起来也很抽象所以没看了后面会补上的。。。。==

十、Lombok简化开发

用法:加在类上面

一、@ToString

作用:相当于toString方法

二、@Data

作用:相当于getter和setter方法

三、@AllArgsConstructor和@NoArgsConstructor

作用:相当于有参构造函数和无参构造函数

四、@EqualsAndHashCode

作用:重写equals方法和hashCode方法

五、@Slf4j

作用:打印日志,放在控制层controller上面

十一、dev-tools

作用:项目或者页面修改以后(ctrl+F9)重新启动

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

十二、配置文件

1.文件类型

1.1properties

同之前的用法

1.2yaml

1.简介:

YAML 是 "YAML Ain't Markup Language"(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种标记语言)。

非常适合用来做以数据为中心的配置文件

1.2基本语法

  • key: value;kv之间有空格
  • 缩进不允许使用tab,只允许空格
  • '#'表示注释
  • 单引号会将\n作为字符串输出(单引号会转义)
  • 双引号会将\n作为换行输出(双引号不会转义)
  1. String userName:

    userName: "zhangsan \n 李四"
    
  2. Boolean boos:

    boos: true
    
  3. Date birth:

    birth: 2021/10/4
    
  4. Integer age:

    age: 18
    
  5. String[] interests:

     第一种:
     #interests: [篮球,足球]
     第二种:
      interests:
        - 篮球
        - 足球
        - 18
    
  6. List animal :

      animal: [阿猫,阿狗]
    
  7. Map<String, Object> score:

      score: {english: 80,math: 90}
    
  8. Set salarys:

      salarys:
        - 9999.98
        - 9999.99
    
  9. Map<String, List> allPets:

      allPets:
        sick:
          - {name: 阿狗,weight: 99.99}
          - name: 阿猫
            weight: 88.88
          - name: 阿虫
            weight: 77.77
        health:
          - {name: 阿花,weight: 199.99}
          - {name: 阿明,weight: 199.99}
    
  10. Pet pet:

      pet:
        name: 阿狗
        weight: 99.99
    

1.3整体代码:

person:
  userName: "zhangsan \n 李四"
#  单引号会将\n作为字符串输出(单引号会转义)
#  双引号会将\n作为换行输出(双引号不会转义)
  boos: true
  birth: 2021/10/4
  age: 18
  #interests: [篮球,足球]
  interests:
    - 篮球
    - 足球
    - 18
  animal: [阿猫,阿狗]
#  score:
#    english: 80
#    math: 90
  score: {english: 80,math: 90}
  salarys:
    - 9999.98
    - 9999.99
  pet:
    name: 阿狗
    weight: 99.99
  allPets:
    sick:
      - {name: 阿狗,weight: 99.99}
      - name: 阿猫
        weight: 88.88
      - name: 阿虫
        weight: 77.77
    health:
      - {name: 阿花,weight: 199.99}
      - {name: 阿明,weight: 199.99}
#spring:
#  banner:
#    location:

十三、web开发简单功能分析

1.1静态资源访问

1.1静态资源目录

静态资源放在类路径下:/static or /public or /resources or /META-INF/resources

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

访问:当前路径名/+静态资源名 eg:http://localhost:8080/res/timg.jpg

==请求进来时先去找Controller控制层看能不能处理,不能处理就将请求交给静态资源处理器,如果静态资源处理器也找不到请求就响应404页面==

1.2改变默认的静态资源路径

spring:
  mvc:
    static-path-pattern: /res/**

  web:
    resources:
      static-locations: classpath:/haha

第一种:http://localhost:8080/res/timg.jpg

第二种:在资源包resources下面新建haha包,将timg.jpg图片存入进去,则只能访问哈哈包下面的静态资源

1.2欢迎页支持

1.静态资源路径下 index.html

  • 可以配置静态资源路径
  • 但是不能配置静态资源的访问前缀
spring:
#  mvc:
#    static-path-pattern: /res/**

  web:
    resources:
      static-locations: classpath:/haha
  • controller能够处理/Index

1.3自定义Favicon(小图标)

  • 将favicon.ico放在静态资源下即可
  • 不能够配置静态资源访问前缀
spring:
#  mvc:
#    static-path-pattern: /res/**    这个会导致favicon小图标失效

==1.4源码分析没看看不懂,等后面有了应用之后再看(p25~p28)==

1.5普通参数注解

1.1@PathVariable(获取路径变量)

解释:

获取路径当中变量的值

eg:

<a href="car/3/owner/lisi">car/{id}/owner/{username}</a>

1.2@RequestHeader(获取请求头)

解释:

获取请求头的信息

1.3@RequestParam(获取请求参数)

解释:

获取请求路径中设置的参数的值

<a href="car/3/owner/lisi?age=18&inters=basketball&inters=game">car/{id}/owner/{username}</a>

1.4@CookieValue(获取Cookie值)

解释:

获取Cookie信息

1.5@RequestBody(获取请求体[Post])

解释:

获取请求体(比如:表单中的信息)

<form action="/save" method="post">
   测试@RequestBody获取数据 <br/>
   用户名:<input name="userName"/> <br>
   邮箱:<input name="email"/>
   <input type="submit" value="提交"/>
</form>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>大厂欢迎您!!!</h1>
<ul>
    <a href="car/3/owner/lisi?age=18&inters=basketball&inters=game">car/{id}/owner/{username}</a>
</ul>
<form action="/save" method="post">
    测试@RequestBody获取数据 <br/>
    用户名:<input name="userName"/> <br>
    邮箱:<input name="email"/>
    <input type="submit" value="提交"/>
</form>
</body>
</html>
ParameterTestController.java
package com.atguigu.boot.controller;

import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/5 21:45
 */
@RestController
public class ParameterTestController {

    @GetMapping("/car/{id}/owner/{username}")
    public Map<String, Object> getCar(@PathVariable("id") Integer id,
                                      @PathVariable("username") String name,
                                      @PathVariable Map<String, String> pv,
                                      @RequestHeader("User-Agent") String UserAgent,
                                      @RequestHeader Map<String, String> header,
                                      @RequestParam("age") Integer age,
                                      @RequestParam("inters") List<String> inters,
                                      @RequestParam Map<String, String> params,
                                      @CookieValue("_ga") String _ga,
                                      @CookieValue("_ga") Cookie cookie) {
        HashMap<String, Object> map = new HashMap<>();
//        map.put("id", id);
//        map.put("name", name);
//        map.put("pv", pv);
//        map.put("headers", header);
        map.put("age", age);
        map.put("inters", inters);
        map.put("params", params);
        map.put("_ga", _ga);
        System.out.println(cookie.getName() + "===>" + cookie.getValue());
        return map;
    }


    @PostMapping("/save")
    public Map postMethod(@RequestBody String content) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("content", content);
        return map;
    }
}

1.6@RequestAttribute(获取请求中的值)

解释:

获取请求request中的值

index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>大厂欢迎您!!!</h1>
<ul>
    <a href="car/3/owner/lisi?age=18&inters=basketball&inters=game">car/{id}/owner/{username}</a>
    <a href="/car/sell;low=18;brand=benci,baoma,aodi">@MatrixVariable(矩阵变量)</a>
    <a href="/car/sell;low=18;brand=benci;brand=baoma;brand=aodi">@MatrixVariable(矩阵变量)</a>
</ul>
<form action="/save" method="post">
    测试@RequestBody获取数据 <br/>
    用户名:<input name="userName"/> <br>
    邮箱:<input name="email"/>
    <input type="submit" value="提交"/>
</form>
</body>
</html>
RequestController.java
package com.atguigu.boot.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.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

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

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/6 15:26
 */
@Controller
public class RequestController {

    @GetMapping("/goto")
    public String goToPage(HttpServletRequest request) {
        request.setAttribute("msg", "成功了.....");
        request.setAttribute("code", 200);
        return "forward:/success";
    }

    @ResponseBody
    @GetMapping("/success")
    public Map success(@RequestAttribute("msg") String msg,
                       @RequestAttribute("code") Integer code,
                       HttpServletRequest request) {
        Object msg1 = request.getAttribute("msg");
        Map<String, Object> map = new HashMap<>();
        map.put("reqMethod_msg", msg1);
        map.put("annotation_msg", msg);
        map.put("annotation_code", code);
        return map;
    }
}

1.7@MatrixVariable(获取矩阵变量的值)

解释:

获取矩阵变量格式中的值

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>大厂欢迎您!!!</h1>
<ul>
    <a href="car/3/owner/lisi?age=18&inters=basketball&inters=game">car/{id}/owner/{username}</a>
    <a href="/car/sell;low=18;brand=benci,baoma,aodi">@MatrixVariable(矩阵变量)</a>
    <a href="/car/sell;low=18;brand=benci;brand=baoma;brand=aodi">@MatrixVariable(矩阵变量)</a>
    <a href="/boss/1;age=20/2;age=10">@MatrixVariable(矩阵变量)</a>
</ul>
<form action="/save" method="post">
    测试@RequestBody获取数据 <br/>
    用户名:<input name="userName"/> <br>
    邮箱:<input name="email"/>
    <input type="submit" value="提交"/>
</form>
</body>
</html>
RequestController.java
package com.atguigu.boot.controller;

import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/5 21:45
 */
@RestController
public class ParameterTestController {

    @GetMapping("/car/{id}/owner/{username}")
    public Map<String, Object> getCar(@PathVariable("id") Integer id,
                                      @PathVariable("username") String name,
                                      @PathVariable Map<String, String> pv,
                                      @RequestHeader("User-Agent") String UserAgent,
                                      @RequestHeader Map<String, String> header,
                                      @RequestParam("age") Integer age,
                                      @RequestParam("inters") List<String> inters,
                                      @RequestParam Map<String, String> params)
//                                      @CookieValue("_ga") String _ga,
//                                      @CookieValue("_ga") Cookie cookie) {
    {
        HashMap<String, Object> map = new HashMap<>();
        map.put("id", id);
        map.put("name", name);
        map.put("pv", pv);
        map.put("headers", header);
        map.put("age", age);
        map.put("inters", inters);
        map.put("params", params);
//        map.put("_ga", _ga);
//        System.out.println(cookie.getName() + "===>" + cookie.getValue());
        return map;
    }


    @PostMapping("/save")
    public Map postMethod(@RequestBody String content) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("content", content);
        return map;
    }

    // /car/sell;low=18;brand=benci;brand=baoma;brand=aodi
    @ResponseBody
    @GetMapping("/car/{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
    @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;
    }
}

十四、Thymeleaf

1.在pom.xml文件中引入starter

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

2.自动配置Thymeleaf策略

1、所有thymeleaf的配置值都在 ThymeleafProperties

2、配置好了 SpringTemplateEngine

3、配好了 ThymeleafViewResolver

4、我们只需要直接开发页面(Thymeleaf自动配置好了,并且设置好了前缀和后缀)

//将页面发在templates包下面,    
public static final String DEFAULT_PREFIX = "classpath:/templates/";

//返回的页面有了后缀
public static final String DEFAULT_SUFFIX = ".html";  //xxx.html

3.作用

1.使用Thymeleaf可以修改原先静态页面中的内容,但是要注意Thymeleaf的使用语法规则

4.例子

ViewController.java

package com.atguigu.boot.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/8 20:44
 */
@Controller
public class ViewController {

    @GetMapping("/baidu")
    public String baidu(Model model) {
        model.addAttribute("msg", "你好大厂我的梦想!!!");
        model.addAttribute("link", "https://www.bytedance.com/");
        return "success";
    }
}

success.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 th:text="${msg}">哈哈</h1>
<h2>
    <a href="www.baidu.com" th:href="${link}">去字节跳动</a>
    <a href="www.baidu.com" th:href="@{link}">去字节跳动</a>
</h2>
</body>
</html>

十五、后台登陆管理系统

1.创建项目

使用模板创建

2.静态资源处理

1.将静态资源放在resources下面的static包下面

3.其它的流程

1.创建controler包,创建IndexController类

2.在IndexController类写login页面跳转

    @GetMapping(value = {"/", "/login"})
    public String loginPage() {
        return "login";
    }

3.创建bean包,创建User类

package com.atguigu.admin.bean;

import lombok.Data;

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/10 20:06
 */
@Data
public class User {
    private String userName;
    private String password;

}

4.修改login.html,将路径映射到/login下,并且添加name="userName"和name="password"属性

<form class="form-signin" action="main.html" th:action="@{/login}" method="post">


<input type="text" name="userName" class="form-control" placeholder="User ID" autofocus>
<input type="password" name="password" class="form-control" placeholder="Password">

5.修改IndexController类

重定向路径到/main.html

==重定向的目的:==

重定向的作用是防止表单重复提交

并且添加逻辑将登陆成功的用户信息保存到session中,否则就跳转到登录页面login.html中

    //重定向防止表单重复提交
    @PostMapping("/login")
    public String main(User user, HttpSession session, Model model) {
        if (!StringUtils.isEmpty(user.getUserName()) && "123456".equals(user.getPassword())) {
            //把登录成功的用户保存起来
            session.setAttribute("loginUser", user);
            //登录成功就重定向到main.html页面
            //重定向的作用是防止表单重复提交
            return "redirect:/main.html";
        } else {
            model.addAttribute("msg", "账号密码错误");
            //回到登陆页面
            return "login";
        }
    }

6.重定向后的页面

设置逻辑如果登录成功就跳转到mian.html页面中否则就返回到login.html页面中

    @GetMapping("/main.html")
    public String mainPage(HttpSession session, Model model) {
        //是否登录    拦截器,过滤器
        Object loginUser = session.getAttribute("loginUser");
        if (loginUser != null) {
            return "main";
        } else {
            //回到登陆页面
            model.addAttribute("msg", "请重新登录");
            return "login";
        }
    }

4.代码:

IndexController类

package com.atguigu.admin.controller;

import com.atguigu.admin.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.thymeleaf.util.StringUtils;

import javax.jws.WebParam;
import javax.servlet.http.HttpSession;

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/10 19:45
 */
@Controller
public class IndexController {

    @GetMapping(value = {"/", "/login"})
    public String loginPage() {
        return "login";
    }

    //重定向防止表单重复提交
    @PostMapping("/login")
    public String main(User user, HttpSession session, Model model) {
        if (!StringUtils.isEmpty(user.getUserName()) && "123456".equals(user.getPassword())) {
            //把登录成功的用户保存起来
            session.setAttribute("loginUser", user);
            //登录成功就重定向到main.html页面
            //重定向的作用是防止表单重复提交
            return "redirect:/main.html";
        } else {
            model.addAttribute("msg", "账号密码错误");
            //回到登陆页面
            return "login";
        }
    }

    @GetMapping("/main.html")
    public String mainPage(HttpSession session, Model model) {
        //是否登录    拦截器,过滤器
        Object loginUser = session.getAttribute("loginUser");
        if (loginUser != null) {
            return "main";
        } else {
            //回到登陆页面
            model.addAttribute("msg", "请重新登录");
            return "login";
        }
    }
}

十六、拦截器

一、步骤:

1、编写一个拦截器实现HandlerInterceptor接口

2、拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors)

3、指定拦截规则【如果是拦截所有,静态资源也会被拦截】

1.创建LoginInterceptor类实现HandlerInterceptor接口

package com.atguigu.admin.interceptor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/14 17:36
 */
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestURI = request.getRequestURI();
        log.info("拦截的请求路径是{}", requestURI);
        
        HttpSession session = request.getSession();
        Object loginUser = session.getAttribute("loginUser");
        if (loginUser != null) {
            return true;
        }
        request.setAttribute("msg", "请先登录");
        request.getRequestDispatcher("/").forward(request, response);
        return false;
    }
}

2.创建AdminWebConfig类实现WebMvcConfigurer接口

package com.atguigu.admin.config;

import com.atguigu.admin.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/14 17:40
 */
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()) // 将拦截器注册到容器中
                .addPathPatterns("/**") // 添加拦截的路径
                .excludePathPatterns("/", "/login", "/css/**", "/fonts/**",
                        "/images/**", "/js/**"); // 添加放行的路径
    }
}

十七、文件上传

一、知识点

1.multiple多文件上传

<input type="file" name="photos" multiple>

2.在application.properties中修改文件上传的大小

spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=100MB

3.参数

//MultipartFile自动封装上传过来的文件
//@RequestPart获取上传的文件注解
@RequestPart("headerImg") MultipartFile headerImg,
@RequestPart("photos") MultipartFile[] photos)

4.页面表单上传文件

<form method="post" action="/upload" enctype="multipart/form-data">
   <input type="file" name="file"><br>
   <input type="submit" value="提交">
</form>

二、文件上传代码

1.创建FormTestController.java

package com.atguigu.admin.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/16 15:22
 */
@Slf4j
public class FormTestController {
    @GetMapping("/form_layouts")
    public String form_layouts() {
        return "form/form_layouts";
    }

    @PostMapping("/upload")
    public String upload(@RequestParam("email") String email,
                         @RequestParam("username") String username,
                         //MultipartFile自动封装上传过来的文件
                         //RequestPart获取上传的文件注解
                         @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()) {
            //保存到文件服务器
            String originalFilename = headerImg.getOriginalFilename();//获取到文件源文件名
            headerImg.transferTo(new File("..." + originalFilename));//将文件保存到指定的路径
        }
        if (photos.length > 0) {
            for (MultipartFile photo : photos) {
                if (!photo.isEmpty()) {
                    String originalFilename = photo.getOriginalFilename();//获取到文件源文件名
                    photo.transferTo(new File("..." + originalFilename));//将文件保存到指定的路径
                }
            }
        }
        return "main";
    }
}

十八、Web原生组件注入(Servlet、Filter、Listener)

1.使用Servlet原生API

1.Servlet

1.在Boot06WebAdminApplication.java中配置扫描Servlet的注解

@ServletComponentScan(basePackages = "com.atguigu.admin")

2.在MyServlet.java中配置Servlet组件

@WebServlet(urlPatterns = "/my")
public class MyServlet extends HttpServlet {
   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       resp.getWriter().write("66666");
   }
}

2.Filter

1.在MyFilter.java类中配置Filter组件

@WebFilter(urlPatterns = {"/css/*", "/images/*"})
@Slf4j
public class MyFilter implements Filter {

   @Override
   public void init(FilterConfig filterConfig) throws ServletException {
       log.info("MyFilter初始化完成");
   }

   @Override
   public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
       log.info("MyFilter工作");
       filterChain.doFilter(servletRequest, servletResponse);
   }

   @Override
   public void destroy() {
       log.info("MyFilter销毁");
   }
}

3.Listener

1.在MyServletContextListener中配置Listener组件

@WebListener
@Slf4j
public class MyServletContextListener implements ServletContextListener {
   @Override
   public void contextInitialized(ServletContextEvent sce) {
       log.info("MyServletContextListener监听到项目初始化完成");
   }

   @Override
   public void contextDestroyed(ServletContextEvent sce) {
       log.info("MyServletContextListener监听到项目项目销毁 ");

   }
}

2.使用RegistrationBean

1.在MyRegistConfig.java中配置ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean组件并注入到容器中

@Configuration
public class MyRegistConfig {

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

        return new ServletRegistrationBean(myServlet,"/my","/my02");
    }


    @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);
    }
}

十九、数据访问

1.Sql

1.导入JDBC场景

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

2.导入数据库驱动

<dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>8.0.26</version>
</dependency>

3.连接数据库

application.yaml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/jdbctest?characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: 12345678
    driver-class-name: com.mysql.cj.jdbc.Driver
#  jdbc:
#    template:
#      query-timeout: 0

4.测试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);
    }

}     

2.stater整合druid

1.导入依赖

<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.8</version>
        </dependency>

2.application.yaml配置功能

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/jdbctest?characterEncoding=UTF-8&serverTimezone=UTC

    username: root
    password: 12345678
    driver-class-name: com.mysql.cj.jdbc.Driver

    druid:
      aop-patterns: com.atguigu.admin.*  #监控SpringBean
      filters: stat,wall     # 底层开启功能,stat(sql监控),wall(防火墙)

      stat-view-servlet:   # 配置监控页功能
        enabled: true
        login-username: admin
        login-password: admin
        resetEnable: false

      web-stat-filter:  # 监控web
        enabled: true
        urlPattern: /*
        exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'


      filter:
        stat:    # 对上面filters里面的stat的详细配置
          slow-sql-millis: 1000
          logSlowSql: true
          enabled: true
        wall:
          enabled: true
          config:
            drop-table-allow: false

#  jdbc:
#    template:
#      query-timeout: 0

3.整合mybatis

一、配置模式

1.整体步骤:
  • 导入mybatis官方starter

  • 编写mapper接口。标准@Mapper注解

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

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

2.导入依赖
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>
3.application.yaml文件全局配置文件
#配置mybatis规则
mybatis:
#  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml
  configuration: // 指定ybatis中相关的全局配置项
    map-underscore-to-camel-case: true
4.编写AccountMapper.xml映射文件并且绑定mapper接口AccountMapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.admin.mapper.AccountMapper">
    <!--    public Account getAcct(Long id); -->
    <select id="getAcct" resultType="com.atguigu.admin.bean.Account">
        select * from  account_tbl where  id=#{id}  
    </select>
</mapper>
package com.atguigu.admin.mapper;

import com.atguigu.admin.bean.Account;
import org.apache.ibatis.annotations.Mapper;

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/17 17:29
 */
@Mapper
public interface AccountMapper {
    public Account getAcct(Long id);
}

5.编写service层AccountService文件
package com.atguigu.admin.service;

import com.atguigu.admin.bean.Account;
import com.atguigu.admin.mapper.AccountMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/17 17:40
 */
@Service
public class AccountService {
    @Autowired
    AccountMapper accountMapper;

    public Account getAcctById(Long id) {
        return accountMapper.getAcct(id);
    }
}
6.在indexController文件中测试
    @Autowired
    AccountService accountService;

    @ResponseBody
    @GetMapping("/acct")
    public Account getById(@RequestParam("id") Long id) {
        return accountService.getAcctById(id);
    }

p63看完

二、注解模式

1.相比于配置模式,不用单独去写CityMapper.xml文件

只用修改CityMapper.java接口即可

package com.atguigu.admin.mapper;

import com.atguigu.admin.bean.City;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Select;

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/21 16:04
 */
@Mapper
public interface CityMapper {
    @Select("select * from city where id=#{id}")
    public City getById(Long id);

    @Insert("insert into city('name','state','country') values(#{name},#{state},#{country})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    public void insert(City city);
}

三、混合模式

1.混合模式就是结合配置模式与注解模式,两种方式同时使用。

4.整合 MyBatis-Plus 完成CRUD

1.导入依赖

   <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
</dependency>

1.==只需要我们的Mapper类继承了 BaseMapper 就可以拥有CRUD能力,无需再重写CRUD代码==

2.TableController类

    @GetMapping("/user/delete/{id}")
    public String deleteUser(@PathVariable("id") Long id,
                             @RequestParam(value = "pn",defaultValue = "1")Integer pn,
                             RedirectAttributes ra){

        userService.removeById(id);

        ra.addAttribute("pn",pn);
        return "redirect:/dynamic_table";
    }


    @GetMapping("/dynamic_table")
    public String dynamic_table(@RequestParam(value="pn",defaultValue = "1") Integer pn,Model model){

        //构造分页参数
        Page<User> page = new Page<>(pn, 2);
        //调用page进行分页
        Page<User> userPage = userService.page(page, null);


//        userPage.getRecords()
//        userPage.getCurrent()
//        userPage.getPages()


        model.addAttribute("users",userPage);

        return "table/dynamic_table";
    }

二十、单元测试

一、JUnit5常用注解

二、断言机制

1.断言是测试方法中的核心部分,用来对测试需要满足的条件进行验证

2.断言用于检查业务逻辑返回的数据是否合理

3.所有的测试运行结束后,会有一个详细的报告

一、简单断言

方法说明
assertEquals判断两个对象或两个原始类型是否相等
assertNotEquals判断两个对象或两个原始类型是否不相等
assertSame判断两个对象引用是否指向同一个对象
assertNotSame判断两个对象引用是否指向不同的对象
assertTrue判断给定的布尔值是否为 true
assertFalse判断给定的布尔值是否为 false
assertNull判断给定的对象引用是否为 null
assertNotNull判断给定的对象引用是否不为 null
    @DisplayName("测试简单断言")
    @Test
    void testAssertions() {
        int cal = cal(2, 3);
        assertEquals(5, cal);
    }

    int cal(int i, int j) {
        return i + j;
    }

二、数组断言

==通过 assertArrayEquals 方法来判断两个对象或原始类型的数组是否相等==

@Test
@DisplayName("array assertion")
public void array() {
 assertArrayEquals(new int[]{1, 2}, new int[] {1, 2});
}

三、组合断言

assertAll 方法接受多个 org.junit.jupiter.api.Executable 函数式接口的实例作为要验证的断言,可以通过 lambda 表达式很容易的提供这些断言

@Test
@DisplayName("assert all")
public void all() {
 assertAll("Math",
    () -> assertEquals(2, 1 + 1),
    () -> assertTrue(1 > 0)
 );
}

四、异常断言

JUnit5提供了一种新的断言方式Assertions.assertThrows() ,配合函数式编程就可以进行使用

@Test
@DisplayName("异常测试")
public void exceptionTest() {
    ArithmeticException exception = Assertions.assertThrows(
           //扔出断言异常
            ArithmeticException.class, () -> System.out.println(1 % 0));

}

五、超时断言

Junit5还提供了Assertions.assertTimeout() 为测试方法设置了超时时间

@Test
@DisplayName("超时测试")
public void timeoutTest() {
    //如果测试方法时间超过1s将会异常
    Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(500));
}

六、快速失败

通过 fail 方法直接使得测试失败

@Test
@DisplayName("fail")
public void shouldFail() {
 fail("This should fail");
}

三、前置条件

JUnit 5 中的前置条件(assumptions【假设】)类似于断言,不同之处在于不满足的断言会使得测试方法失败,而不满足的前置条件只会使得测试方法的执行终止

@Test
@DisplayName("前置条件测试")
public void simpleAssume() {
    assumeTrue(false,"假设失败方法不可以执行");
}

四、嵌套测试

JUnit 5 可以通过 Java 中的内部类和@Nested 注解实现嵌套测试,从而可以更好的把相关的测试方法组织在一起。在内部类中可以使用@BeforeEach @AfterEach 注解,而且嵌套的层次没有限制。

@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());
            }
        }
    }
}

六、参数化测试

参数化测试是JUnit5很重要的一个新特性,它使得用不同的参数多次运行测试成为了可能,也为我们的单元测试带来许多便利。

@ValueSource: 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型

@NullSource: 表示为参数化测试提供一个null的入参

@EnumSource: 表示为参数化测试提供一个枚举入参

@CsvFileSource:表示读取指定CSV文件内容作为参数化测试入参

@MethodSource:表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)

@ParameterizedTest
@ValueSource(strings = {"one", "two", "three"})
@DisplayName("参数化测试1")
public void parameterizedTest1(String string) {
    System.out.println(string);
    Assertions.assertTrue(StringUtils.isNotBlank(string));
}


@ParameterizedTest
@MethodSource("method")    //指定方法名
@DisplayName("方法来源参数")
public void testWithExplicitLocalMethodSource(String name) {
    System.out.println(name);
    Assertions.assertNotNull(name);
}

static Stream<String> method() {
    return Stream.of("apple", "banana");
}

二十一、指标监控

一、SpringBoot Actuator

1.简介

未来每一个微服务在云上部署以后,我们都需要对其进行监控、追踪、审计、控制等。SpringBoot就抽取了Actuator场景,使得我们每个微服务快速引用即可获得生产级别的应用监控、审计等功能。

2.在pom.xml文件中配置

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

3.在application.yaml中配置

#management是所有actuator的配置
management:
  endpoints:
    enabled-by-default: true  #默认开启全部监控端点
    web:
      exposure:
        include: '*' #以web方式暴露

二、Actuator Endpoint

1.最常用的EndPoint

最常用的Endpoint

  • Health:监控状况

  • Metrics:运行时指标

  • Loggers:日志记录

2.在application.yaml中配置

#开启指定的监控(自定义)
  endpoint:
    health:
      show-details: always    #总是显示详细信息。可显示每个模块的状态信息 

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

三、管理Endpoints

1、开启与禁用Endpoints

1.默认开启全部EndPoints

配置模式:

endpointName为要开启的变量名

management.endpoint.endpointName.enabled = true

eg:

management:
 endpoint:
   beans:
     enabled: true
2.禁用所有的Endpoint然后手动开启指定的Endpoint
management:
  endpoints:
    enabled-by-default: false
  endpoint:
    beans:
      enabled: true
    health:
      enabled: true

二十二、原理解析

一、Profile功能

为了方便多环境适配,springboot简化了profile功能。

1.application-profile功能

1.配置默认的文件application.properties,任何时候都会加载

2.配置指定的文件 application-{env}.yaml

3.指定环境配置文件激活:

spring.profiles.active=prod #指定激活的环境

==注意:==

  • 默认配置与环境配置同时生效,但是如果默认的与指定的有相同的属性则默认的会被指定的覆盖掉
  • 同名配置项,profile配置优先

2、@Profile条件装配功能

在指定的类上面添加@Profile("prod"),prod为激活的环境,其它的类就不会被加载

package com.atguigu.boot.bean;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/23 12:51
 */
@Component
@ConfigurationProperties("person")
@Data
@Profile("prod")
public class Person {

    private String name;
    private Integer age;
}

数")
public void testWithExplicitLocalMethodSource(String name) {
System.out.println(name);
Assertions.assertNotNull(name);
}

static Stream method() {
return Stream.of("apple", "banana");
}




## 二十一、指标监控

### 一、SpringBoot Actuator

#### 1.简介

未来每一个微服务在云上部署以后,我们都需要对其进行监控、追踪、审计、控制等。SpringBoot就抽取了Actuator场景,使得我们每个微服务快速引用即可获得生产级别的应用监控、审计等功能。

#### 2.在pom.xml文件中配置

~~~xml
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

3.在application.yaml中配置

#management是所有actuator的配置
management:
  endpoints:
    enabled-by-default: true  #默认开启全部监控端点
    web:
      exposure:
        include: '*' #以web方式暴露

二、Actuator Endpoint

1.最常用的EndPoint

最常用的Endpoint

  • Health:监控状况

  • Metrics:运行时指标

  • Loggers:日志记录

2.在application.yaml中配置

#开启指定的监控(自定义)
  endpoint:
    health:
      show-details: always    #总是显示详细信息。可显示每个模块的状态信息 

[外链图片转存中...(img-HNOK5Y3h-1635088496342)]

三、管理Endpoints

1、开启与禁用Endpoints

1.默认开启全部EndPoints

配置模式:

endpointName为要开启的变量名

management.endpoint.endpointName.enabled = true

eg:

management:
 endpoint:
   beans:
     enabled: true
2.禁用所有的Endpoint然后手动开启指定的Endpoint
management:
  endpoints:
    enabled-by-default: false
  endpoint:
    beans:
      enabled: true
    health:
      enabled: true

二十二、原理解析

一、Profile功能

为了方便多环境适配,springboot简化了profile功能。

1.application-profile功能

1.配置默认的文件application.properties,任何时候都会加载

2.配置指定的文件 application-{env}.yaml

3.指定环境配置文件激活:

spring.profiles.active=prod #指定激活的环境

==注意:==

  • 默认配置与环境配置同时生效,但是如果默认的与指定的有相同的属性则默认的会被指定的覆盖掉
  • 同名配置项,profile配置优先

2、@Profile条件装配功能

在指定的类上面添加@Profile("prod"),prod为激活的环境,其它的类就不会被加载

package com.atguigu.boot.bean;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

/**
 * @Author:xuxuduoduomei
 * @Date:2021/10/23 12:51
 */
@Component
@ConfigurationProperties("person")
@Data
@Profile("prod")
public class Person {

    private String name;
    private Integer age;
}

整理不易,请一键三连哦!!!大家一起加油冲💪💪💪

...全文
41 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

67,566

社区成员

发帖
与我相关
我的任务
社区描述
欢迎大家来到抱团内卷学习社区,在这里大家可以分享自己的学习笔记,求职心得,一起记录彼此的成长历程。社区群号:94108843,WX公众号:【兴趣使然的草帽路飞】
社区管理员
  • 路  飞
  • 一百个Chocolate
  • 灰小猿
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

最怕你一生碌碌无为,还安慰自己平凡可贵!

努力提高自己的知识储备,助力每一位冲刺大厂的小伙伴!

祝大家前程似锦,offer连连!

注意:每个月活跃积分最高的小伙伴,可以获得社区管理员权限哦!

试试用AI创作助手写篇文章吧