Java零基础——SpringBoot篇

SSM
Springboot
分布式微服务

1.Spring的发展

回顾:Spring是一个开源框架,2003年兴起的一个轻量级的Java 开发框架,作者:Rod Johnson。Spring是为了解决企业级应用开发的复杂性而创建的,简化开发。

1.1 Spring1.x时代
在Spring1.x时代,都是通过xml文件配置bean,随着项目的不断扩大,需要将xml配置分放到不同的配置文件中,需要频繁的在java类和xml配置文件中切换。

1.2 Spring2.x时代
随着JDK 1.5带来的注解支持,Spring2.x可以使用注解对Bean进行申明和注入,大大的减少了xml配置文件,同时也大大简化了项目的开发。

那么,问题来了,究竟是应该使用xml还是注解呢?

1.3 注解还是XML
在spring早期版本中,由于当时的JDK并不支持注解,因此只能使用XML的配置,很快,随着JDK升级到JDK5之后,它加入了注解的新特性,这样注解就被广泛地使用起来, 于是spring内部也分为两派,一派是使用XML的,一派是使用注解的,为了简化开发,在spring2.X之后的版本也引入了注解,不过是少量的注解,如@Component @Service等,但是功能还是不强大,因此对于srping的开发,大部分情况下还是使用XML为主,随着注解的增加,尤其是Servlet3.0


@WebServlet

@WebFilter

@WebListener

之后,WEB容器可以脱离web.xml的部署,使用得WEB容器完全可以基于注解开发,对于spring3和spring4的版本注解功能越来越强大。对于XML的依赖起来越少,到了4.0完全可以脱离XML, 所以在spring中使用注解开发占据了主流地位,近年来。微服务的流行,越来越多的企业要求快速开发,所以spring Boot更加兴旺了。

应用的基本配置用xml,比如:数据源、资源文件等;

业务开发用注解,比如:Service中注入bean等;

1.4 Spring3.x到Spring4.x
从Spring3.x开始提供了Java配置方式,使用Java配置方式可以更好的理解你配置的Bean,现在我们就处于这个时代,并且Spring4.x和Springboot都推荐使用java配置的方式。

2.Spring Boot和微服务的介绍

2.1 SpringBoot的简介
Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot 致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。

https://spring.io/projects/spring-boot

https://docs.spring.io/spring-boot/docs/current/reference/html/

2.2 Spring Boot的优点
约定大于配置

创建独立的spring应用程序。

嵌入的tomcat jetty 或者undertow 不用部署WAR文件。

允许通过Maven来根据需要获取starter

尽可能的使用自动配置spring

提供生产就绪功能,如指标,健康检查和外部配置properties yaml yml

完全没有代码生成,对XML没有要求配置[不用]

2.2.1 特性理解
为基于 Spring 的开发提供更快的入门体验

开箱即用,没有代码生成,也无需 XML 配置。同时也可以修改默认值来满足特定的需求。

提供了一些大型项目中常见的非功能特性,如嵌入式服务器、安全、指标,健康检测、外部配置等。

Spring Boot 并不是对 Spring 功能上的增强,而是提供了一种快速使用 Spring 的方式。

2.2.2 传统开发模式
所有的功能打包在一个 WAR包里,基本没有外部依赖(除了容器),部署在一个JEE容器(Tomcat,JBoss,WebLogic)里,包含了 DO/DAO,Service,UI等所有逻辑。

2.2.2.1 优点:
l 开发简单,集中式管理

l 基本不会重复开发

l 功能都在本地,没有分布式的管理和调用消耗

2.2.2.2 缺点:
l 效率低:开发都在同一个项目改代码,相互等待,冲突不断

l 维护难:代码功功能耦合在一起,新人不知道何从下手

l 不灵活:构建时间长,任何小修改都要重构整个项目,耗时

l 稳定性差:一个微小的问题,都可能导致整个应用挂掉

l 扩展性不够:无法满足高并发下的业务需求

l 对服务器的性能要求要统一,要高

2.2.3 微服务开发
微服务:架构风格(服务微化)

微服务是指开发一个单个小型的但有业务功能的服务,每个服务都有自己的处理和轻量通信机制,可以部署在单个或多个服务器上,微服务也指一种松耦合的,有一定有界上下文的面向服务的架构

目的:有效的拆分应用,实现敏捷开发和部署

2.2.3.1 优点
l 每个微服务都很小,这样能聚焦一个指定的业务功能或业务需求

l 微服务能够被小团队开发,这个小团队2-5人就可以完成了

l 微服务是松耦合的,是有功能,有意义的服务,开发阶段或部署阶段都是独立的

l 微服务可以使用不同的语言开发

l 微服务能部署在中低端配置的服务器上

l 很容易和第三方集成

l 每个服务都有自己的存储能力,单独的库,也可以有统一的库

2.2.3.2 缺点
l 微服务会带来过多的操作

l 可能有双倍的努力

l 分布式系统可能复杂难管理

l 分布跟踪部署难

l 当服务数量增加时,管理复杂度增加

3.Spring Boot 入门程序

3.1 环境准备
①JDK1.8

②Maven3.6+

③IDEA2020.1

④SpringBoot2.x

⑤Spring5.x

3.2 新建项目
3.3 在项目里面创建模块
这里我们选择创建Module来完成第一个Spring Boot项目
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.4 项目目录说明
在这里插入图片描述

3.5 Pom.xml文件分析

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <!--继承了springBoot的父项目-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <!-- 我们自己的GAV坐标-->
    <groupId>com.bjpowernode</groupId>
    <artifactId>01-spring-boot-hello</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <!--项目名称-->
    <name>spring-boot-hello</name>
    <!--项目描述-->
    <description>Demo project for Spring Boot</description>
    <!--版本控制-->
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <!--依赖-->
    <dependencies>
        <!--web的依赖整合了Mvc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--热部署的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!-- 配置文件拓展依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <!--lombok工具依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--springBoot测试依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!--构建-->
    <build>
        <!--打包插件-->
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

3.6 创建IndexController(在启动类同级或者子包下面)

package com.bjpowernode.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexController {


    @GetMapping("hello")
    public String hello() {
        return "hello Spring Boot";
    }
}
 

3.7 启动
在这里插入图片描述

3.8 测试访问
http://localhost:8080/hello

3.9 打jar包启动测试
在这里插入图片描述

在target目录下找到jar包并且在文件夹中打开
在这里插入图片描述
在这里插入图片描述

测试访问

http://localhost:8080/hello

3.10 彩蛋
启动时查看控制台的输出会发现有一个banner图案,这个banner图案是可以自定义的
在这里插入图片描述

3.10.1 修改为自己的banner
在src/main/resources目录下面创建一个banner.txt文件,并且输入想要的内容即可

这里提供一个字体生产网站 https://www.bootschool.net/ascii 可以随意创建
在这里插入图片描述

3.10.2 启动查看
在这里插入图片描述

4.常用注解【spring的java配置】

4.1 回顾spring和java的注解
4.1.1 类上的注解
@Controller

控制器

@RestController=@Controller+@ResponseBody

返回json的控制器

@Service

标记服务接口

@Respority

标记仓库接口

@Component

标记组件

@RequestMapping

请求映射 (也可在方法上)

作用在类上的常用注解

4.1.2 方法上的注解
@RequestMapping

请求映射

@GetMapping

GET请求

@PostMapping

POST请求

@DeleteMapping

DELETE请求

@PutMapping

PUT请求

@PatchMapping

PATCH请求

@ResponseBody

返回JSON对象

4.1.3 参数上的注解
@RequestBody

入参是JSON对象

@PathVariable

将路径上面的参数映射到入参里面

@RequestParam

将请求参数绑定到你控制器的方法参数上

4.1.4 属性上的注解
@Autowried

自动注入(首选按照类型) byType byName

@Resource

自动注入(首选按照名字)byName byType

4.2 相关注解说明
4.2.1 @Configuration
作用于类上,相当于一个xml配置文件;

|–application-dao.xml

4.2.2 @Bean
作用于方法上,相当于xml配置中的

4.2.2.1 创建实体类测试注解用法

package com.bjpowernode.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String name;
    private String address;
}

4.2.2.2 创建配置类

package com.bjpowernode.config;

import com.bjpowernode.domain.User;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfig1 {

    @Bean(value = "user1")
    public User user1() {
        return new User(1, "小明", "武汉");
    }

    @Bean(value = "user2")
    public User user2() {
        return new User(1, "小明", "武汉");
    }

    @Bean(value = "user3")
    public User user3(@Qualifier("user1") User user) {
        return new User(1, "小明", "武汉");
    }
}

4.2.3 @Qualifier注解
qualifier的意思是合格者,通过这个标示,表明了哪个实现类才是我们所需要的,我们修改调用代码,添加@Qualifier注解,需要注意的是@Qualifier的参数名称必须为我们之前定义@Bean注解的名称之一

4.2.4 @Primary 主候选的
当IOC容器里面有多个同类型的对象时,就会发生冲突,标注了该注解的就作为主候选对象

4.2.5 @Import注解
在创建配置文件之后可以引入其它的配置文件

|–

4.2.6 @ComponentScan(“com.bjpowernode”)配置扫描
|–<context:component-scan base-package=“com.bjpowernode.*.mapper”/>

5.Spring Boot热部署

5.1 什么是热部署
spring为开发者提供了一个名为spring-boot-devtools的模块来使springboot应用支持热部署,提高开发的效率,修改代码后无需重启应用

5.2 添加依赖

org.springframework.boot spring-boot-devtools runtime true

5.3 配置idea的启动面板
如果不配置面板,那么可直接使用ctrl+F9去刷新,配置 以后,当我们修改代码,光标失去idea的焦点以后,就出触发自动部署
在这里插入图片描述

6.手动创建springboot项目

6.1 创建maven项目
在这里插入图片描述在这里插入图片描述

6.2 修改pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!--继承springboot的项目-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath/>
    </parent>
    <groupId>com.powernode</groupId>
    <artifactId>02-springboot-hello</artifactId>
    <version>1.0</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--spring boot web项目的启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--热部署工具-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--写配置配置提示的包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <!--简化类的构造器和get set-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--测试用-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
 

6.3 创建启动类
在这里插入图片描述在这里插入图片描述

6.4 创建测试类
在这里插入图片描述
在这里插入图片描述

6.5 创建static,templates
6.6 创建application.properties

7. Spring Boot的自动配置原理以及启动分析(难点)

1,默认的包扫描

启动类所在的包及其子包

2,依赖的分析

7.1 pom的依赖分析

<!--继承了springBoot的父项目-->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.3</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

点进去spring-boot-starter-parent以后这依赖管理里面写和很从版本

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>2.5.3</version>
</parent>

这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;以后我们导入依赖默认是不需要写版本;但是如果导入的包没有在依赖中管理着就需要手动配置版本了

7.2 启动器 spring-boot-starter

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter</artifactId>
  <version>2.5.3</version>
  <scope>compile</scope>
</dependency>

springboot-boot-starter-xxx:就是spring-boot的场景启动器

<!--web的依赖整合了Mvc-->
<!-- 引入了spring-boot-starter-web以后,springboot就帮我们导入了web模块运行的所有组件 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ,也可以自己自定义 starter;

7.3 原理分析
7.3.1 注解功能划分
在这里插入图片描述

7.3.2 如何自动扫描(默认扫描启动类所在的包以下面的及子包)
@Import(AutoConfigurationPackages.Registrar.class)

在Registrar里面,找到register()方法
在这里插入图片描述

7.3.3 如何加载自动配置类
找到@Import(AutoConfigurationImportSelector.class)

7.3.3.1 在这个类里面的getAutoConfigurationEntry()方法
在这里插入图片描述

7.3.3.2 进入getCandidateConfigurations()方法查看究竟
在这里插入图片描述

这个方法spring的加载工厂去筛选所有引入(link)EnableAutoConfiguration的配置类

EnableAutoConfiguration是Key 返回的List是value

7.3.3.3 接着进入loadFactoryNames()方法

7.3.3.4 查看MATE-INF/spring.factories文件

最终我们从候选方法中获取到了需要自动配置的全限定类名的集合,我们再回到一开始的加载候选的方法

7.3.3.5 最后回到getAutoConfigurationEntry()方法里面往下执行
在这里插入图片描述

7.3.3.6 剔除掉不需要的自动配置类(pom.xml中没有加入依赖的)
在这里插入图片描述

至此自动加载配置类的初探就结束了

7.4 选讲如何加载前端控制器(DispatcherServlet)
7.4.1 在ssm里面,我们需要手动去创建DispatcherServlet对象,然后注入到Servlet容器中

<servlet>

      <servlet-name>dispatcherServlet</servlet-name>

      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

      <init-param>

          <param-name>contextConfigLocation</param-name>

          <param-value>

              classpath:spring-context.xml

          </param-value>

      </init-param>

      <load-on-startup>1</load-on-startup>

  </servlet>

  <servlet-mapping>

      <servlet-name>dispatcherServlet</servlet-name>

      <url-pattern>/</url-pattern>

  </servlet-mapping>

7.4.2 再SpringBoot中只要我们加了Web的starter,就默认做好了
7.4.2.1 查看DispatcherServletAutoConfiguration这个自动配置类
在这里插入图片描述
在这里插入图片描述

现在深刻理解了SpringBoot的 约定大于配置 这一句话了吧

8.Spring Boot的run方法到底执行了什么

在这里插入图片描述
在这里插入图片描述

9.Spring Boot给我们提供了哪些自动配置类呢?

https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-systems.starters
在这里插入图片描述

如果你需要使用,可以直接添加对应的starter的依赖,那么只需要自定一些参数即可,因为已经有默认配置了,但是如果你需要的组件没有starter,那么久需要自己写配置类了

10.Spring Boot的配置文件语法【重中之重】

10.1 首先引入依赖

<!-- 配置文件拓展依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

10.2 创建Hero 类
@Data // lombok的注解,生成get和set方法
@Component // 标记为spring的一个组件
@ConfigurationProperties(prefix = “hero”) // 使用hero前缀去ioc容器里面读取配置文件
public class Hero {

private Integer id;
private Integer age;
private String name;
private Date birth;
private String[] hobby;
private List<String> list;
private Set<String> set;
private Map<String, String> map;

}

10.3 properties方式
hero.id=2
hero.name=CXS
hero.age=18
hero.birth=2012/12/31
hero.hobby=LOL,DNF,CF
hero.list=C#,Python,PS
hero.set=football,basketball,swim
hero.map.k1=v1
hero.map.k2=v2

10.4 Yml方式
hero:
id: 2
age: 18
name: 超人
birth: 2012/12/31
hobby:
- LOL
- DNF
- CF
list:
- JAVA
- JS
- C++
set:
- 足球
- 篮球
- 排球
map:
k1: v1
k2: v2

10.5 测试
这里我们得知当properties配置和yml配置都存在是 proeprties的优先级更高
在这里插入图片描述

10.6 配置文件占位符
在这里插入图片描述

10.7 配置文件中读取IOC容器里的值
在这里插入图片描述

10.8 两种配置文件的用法说明
1,如果properties里面配置了就不会去yml里面去取值,如果没有配置就会去yml里面取

2,两种配置文件是互补的存在

10.9 练习作业
在Hero中添加一个属性

private List user;

如何通过配置文件注入

11.@Value读取配置文件

11.1 创建Hero2类
@Data // lombok的注解,生成get和set方法
@Component // 标记为spring的一个组件
public class Hero2 {

@Value("${hero.id}")
private Integer id;
@Value("${hero.age}")
private Integer age;
@Value("${hero.name}")
private String name;
@Value("${hero.birth}")
private Date birth;

// @Value(“ h e r o . h o b b y " ) p r i v a t e S t r i n g [ ] h o b b y ; / / @ V a l u e ( " {hero.hobby}") private String[] hobby; // @Value(" hero.hobby")privateString[]hobby;//@Value("{hero.list}”)
private List list;
// @Value(“ h e r o . s e t " ) p r i v a t e S e t < S t r i n g > s e t ; / / @ V a l u e ( " {hero.set}") private Set<String> set; // @Value(" hero.set")privateSet<String>set;//@Value("{hero.map}”)
private Map<String, String> map;
}

11.2 Yml文件
hero:
id: 2
age: 18
name: 小白
birth: 2012/12/31
hobby:
- LOL
- DNF
- CF
list:
- JAVA
- JS
- C++
set:
- 足球
- 篮球
- 排球
map:
k1: v1
k2: v2

11.3 总结说明
1,@Value只能注入普通的属性[也就是基本数据类型和String,Date] 其它的复杂类型是不能取到值的[如果yaml配置是array:LOL,DNF]这样的配置是可以取

2,如果属性是使用驼峰命名法则不能使用属性名注入,要使用@Value(“${hero.class-name}”)来取值

不能使用@Value(“${hero.className}”)来取值

11.4 @Value和@ConfigurationProperties取值比较
在这里插入图片描述

12.注解验证

12.1 引入依赖
Springboot2.3.x以后,需要单独引入依赖,之前在web-starter里面包含

<!--引入注解验证的依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

12.2 修改Hero类
在这里插入图片描述

12.3 修改application.yml文件
在这里插入图片描述

12.4 测试
在这里插入图片描述

12.5 常用的验证注解
@NotNull --不能为null,但可以空着不写 (name:)

@NotEmpty --不能为空,也不能为null,但可以是空格 “ ”

@NotBlank --不能为空,也不能为null,也不能为空格

@Min 最大值

@Max 最小值

@Size(min = 1, max = 6) 长度限制

@Range(min = 1,max = 2) 范围限制

@Pattern(regexp"[0,1]{1}") 正则限制
在这里插入图片描述

13.@PropertySource和@ImportResource的使用

13.1 为什么要用@PropertiesSource
上面的注入,所有的配置都是写在appliaction.properties或application.yml文件里,那么如果不想写在这里面怎么处理呢,使用@PropertySource可以解决

13.2 注入优先级的问题
所在的配置都是优先注入appliaction.properties或application.yml里面的数据

如果要不一样,必须修改配置文件引入的前缀

13.3 创建Hero3类
@Data
@Component // 标记为spring的一个组件
@PropertySource(value = {“classpath:hero.properties”}) // properties配置文件的指定
@ConfigurationProperties(prefix = “hero”) // 使用hero前缀去ioc容器里面读取配置文件
public class Hero3 {

private Integer id;
private String name;
private Integer age;
private Date birth;
private String[] hobby;
private List<String> list;
private Set<String> set;
private Map<String, String> map;
private String className;

}

13.4 创建Hero.properties配置文件
hero.name=“测试自己的配置文件”
hero.className=“班级名称”

13.5 测试
在这里插入图片描述

13.6 为什么要用@ImportResource
从上面所有的配置中可以看出我们没有使用以前的spring的xml的配置方法,如果还是要使用spring里面的xml的配置方式怎么办理,使用@ImportResource

13.7 创建Hero4类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Hero4 {
private Integer id;
private String name;
}

13.8 创建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="hero" class="com.bjpowernode.domain.Hero4">
        <property name="id" value="1"/>
        <property name="name" value="后羿"/>
    </bean>
</beans>

13.9 启动类添加@ImportResource注解
在这里插入图片描述

13.10 测试
在这里插入图片描述

14.Profile配置文件详解

14.1 为什么要使用profiles
在开发中,一般有两种环境

    1,生产环境 [项目上线,客户在使用中,就是生产环境]

    2,开发环境 [就是开发环境,自己开发测试的环境]

有时候开发环境和生产环境的配置方法是不一样的,那么如何快速的切换呢,这里就要使用profiles文件

14.2 创建application-dev.yml
14.3 创建application-pro.yml
14.4 修改application.yml
在application.yml的主配置文件中,激活哪个配置文件,就会使用该配置文件进行运行
在这里插入图片描述

14.5 启动测试
在这里插入图片描述

14.6 打jar包部署运行测试
打jar包运行不会去看3.9章节

java -jar 01-spring-boot-hello-0.0.1-SNAPSHOT.jar --spring.profiles.active=pro
在这里插入图片描述

15.配置文件加载优先级和外部配置文件

15.1 项目内部配置文件
spring boot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件

其中同一目标下的properties文件的优先级大于yml文件

15.1.1 配置文件可以放的位置和优先级
classpath:/ --优先级4

classpath:/config/ --优先级3

file:./ --优先级2

file:./config/ --优先级1
在这里插入图片描述

15.1.2 查看ConfigDataEnvironment
在这里插入图片描述

15.1.3 测试注意
在测试的时候,需要修改pom的编译路径,确保把所有的配置文件都编译以后再测试

<build>
    <!-- 将所有的配置文件都编译-->
    <resources>
        <resource>
            <directory>D:\workspace\SpringBoot-Code\02-spring-boot-config</directory>
            <includes>
                <include>**/*.yml</include>
                <include>application.yml</include>
            </includes>
        </resource>
    </resources>

    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <excludes>
                    <exclude>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                    </exclude>
                </excludes>
            </configuration>
        </plugin>
    </plugins>
</build>

15.2 外部的配置文件

在D盘放一个application.yml文件 端口指定为8009

打包后使用命令行运行并且指定

java -jar 02-spring-boot-config-0.0.1-SNAPSHOT.jar --spring.config.location=D:/application.yml
在这里插入图片描述

15.2.1 使用命令行参数
也可以使用命令行参数指定(文档一行写不下,你们写的时候不要回车啊)

java -jar 02-spring-boot-config-0.0.1-SNAPSHOT.jar --server.port=8888 --server.servlet.context-path=/bjpowernode

16.自动配置原理以及 @Conditional派生注解

16.1 配置文件到底怎么写什么?怎么写?
https://docs.spring.io/spring-boot/docs/2.5.3/reference/htmlsingle/#application-properties

16.2 自动配置
自7.3.3以后,我们就了解到了Spring Boot在启动的时候:

l 去扫描加载了所有引入依赖的jar包下面的MATE-INF/spring.factories文件,

l 然后通过EnableAutoConfiguration为key,下面所有自动配置类的全限定类名作为value,(List)

l 经过筛选排除掉不符合要求的(pom中没有添加依赖的配置类)

l 最后把(List:符合条件的自配配置类的全限定类名)添加到IOC容器去管理,从而实现了自动配置原理

16.3 以HttpEncodingAutoConfiguration为例来理解自动装配
根据当前不同的条件判断,决定这个配置类是否生效?

一但这个配置类生效;这个配置类就会给容器中添加各种组件;这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;

//表示这是一个配置类
@Configuration(proxyBeanMethods = false)
//开启自动配置属性,指定ServerProperties配置文件
@EnableConfigurationProperties(ServerProperties.class)
//spring的底层注解,根据条件判断当前类是否生效
//判断当前项目环境是否是一个web环境
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
//判断当前环境是否有CharacterEncodingFilter类
@ConditionalOnClass(CharacterEncodingFilter.class)
//判断我们自己配置的yml文件里面是否有server.servlet.encoding.enabled属性,如果没有就自动生效
@ConditionalOnProperty(prefix = “server.servlet.encoding”, value = “enabled”, matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

//这个属性和下面的有参构造器绑定在了一起,配置文件映射成功
private final Encoding properties;

public HttpEncodingAutoConfiguration(ServerProperties properties) {
    this.properties = properties.getServlet().getEncoding();
}

@Bean //创建一个CharacterEncodingFilter对象
@ConditionalOnMissingBean //前提条件是容器里面没有这个对象
public CharacterEncodingFilter characterEncodingFilter() {
    CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
    filter.setEncoding(this.properties.getCharset().name());
    filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
    filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
    return filter;
}

}

16.4 总结

  • SpringBoot启动会加载大量的自动配置类

  • 看我们需要的功能有没有SpringBoot默认写好的自动配置类;

  • 我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件有,我们就不需要再来配置了)

  • 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可

以在配置文件中指定这些属性的值;

- xxxxAutoConfigurartion:自动配置类;给容器中添加组件

- xxxxProperties:封装配置文件中的默认配置

16.5 @Conditional派生注解
作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置类里面的所有内容才生效;(条件之间是并且的关系)
在这里插入图片描述

16.6 如何查看自动配置类生效
我们可以通过启用debug=true属性(在配置文件配置);来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;
在这里插入图片描述
在这里插入图片描述

17.整合logback

17.1 概述
在搭建新的系统时候必不可少的是需要日志的,日志的作用就不用多说了吧,可以用来调试程序,记录程序运行的状态,最重要的是可以用来排查线上的问题。

那我们该如何在项目中使用日志呢?

SpringBoot内部集成了LogBack日志依赖,SpringBoot默认使用LogBack记录日志信息,默认根据base.xml配置内容来输出到控制台和文件之中,不过这些默认的配置不能达到企业级项目的要求

17.2 创建模块
在这里插入图片描述

17.3 创建logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration  scan="true" scanPeriod="10 seconds">

    <!--<include resource="org/springframework/boot/logging/logback/base.xml" />-->

    <contextName>logback</contextName>
    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
    <property name="log.path" value="D:/mylogs/" />

    <!-- 彩色日志 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>


    <!--输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>info</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>


    <!--输出到文件-->

    <!-- 时间滚动输出 level为 DEBUG 日志 -->
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_debug.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志归档 -->
            <fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录debug级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>debug</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 INFO 日志 -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_info.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 WARN 日志 -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_warn.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>


    <!-- 时间滚动输出 level为 ERROR 日志 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_error.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--
        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、
        以及指定<appender><logger>仅有一个name属性,
        一个可选的level和一个可选的addtivity属性。
        name:用来指定受此logger约束的某一个包或者具体的某一个类。
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
              还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
              如果未设置此属性,那么当前logger将会继承上级的级别。
        addtivity:是否向上级logger传递打印信息。默认是true。
    -->
    <!--<logger name="org.springframework.web" level="info"/>-->
    <!--<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>-->
    <!--
        使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
        第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
        第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
     -->


    <!--
        root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
        不能设置为INHERITED或者同义词NULL。默认是DEBUG
        可以包含零个或多个元素,标识这个appender将会添加到这个logger。
    -->

    <!--开发环境:打印控制台-->
    <springProfile name="dev">
        <logger name="com.nmys.view" level="debug"/>
    </springProfile>

    <root level="info">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="DEBUG_FILE" />
        <appender-ref ref="INFO_FILE" />
        <appender-ref ref="WARN_FILE" />
        <appender-ref ref="ERROR_FILE" />
    </root>

    <!--生产环境:输出到文件-->
    <!--<springProfile name="pro">-->
    <!--<root level="info">-->
    <!--<appender-ref ref="CONSOLE" />-->
    <!--<appender-ref ref="DEBUG_FILE" />-->
    <!--<appender-ref ref="INFO_FILE" />-->
    <!--<appender-ref ref="ERROR_FILE" />-->
    <!--<appender-ref ref="WARN_FILE" />-->
    <!--</root>-->
    <!--</springProfile>-->

</configuration>

17.4 修改启动类测试
在这里插入图片描述

17.5 查看本地日志
在这里插入图片描述

18.AOP开发

18.1 概述
aop是spring的两大功能模块之一,功能非常强大,为解耦提供了非常优秀的解决方案。SpringBoot集成aop是非常方便的,下面使用aop来拦截业务组件的方法

Aop的作用:在不修改源代码的情况下,对类里面的方法进行增强

(前置,后置,环绕,异常)

18.2 使用方法
18.3 创建项目并添加maven依赖

org.springframework.boot
spring-boot-starter-aop

18.4 创建Man测试类
/**

  • 将此类加入IOC管理

  • AOP作用的类一定要加入IOC容器中
    */
    @Component
    public class Man {

    /**

    • 吃饭的方法
    • @param foodsName
    • @return
      */
      public String eat(String foodsName) {
      System.out.println(“吃” + foodsName);
      return foodsName + “很好吃”;
      }
      }

18.5 创建切面

/**
 * 切面类加入IOC容器管理
 * 添加切面的标识
 */
@Component
@Aspect
public class ManAspect {


    /**
     * 切入点
     */
    public static final String POINT_CUT = "execution(* com.bjpowernode.test.Man.*(..))";

    /**
     * 前置通知
     */
    @Before(value = POINT_CUT)
    public void before() {
        System.out.println("吃饭前洗手");
    }


    /**
     * 后置通知
     */
    @After(value = POINT_CUT)
    public void after() {
        System.out.println("饭后甜点");
    }


    /**
     * 环绕通知
     *
     * @param joinPoint
     * @return
     */
    @Around(value = POINT_CUT)
    public Object around(ProceedingJoinPoint joinPoint) {
        Object result = null;
        System.out.println("执行目标方法之前");

        try {
            // 执行目标方法
            result = joinPoint.proceed();
            System.out.println("执行目标方法之后");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return result;
    }

    /**
     * 异常通知
     *
     * @param ex
     */
    @AfterThrowing(value = POINT_CUT, throwing = "ex")
    public void afterThrowing(Throwable ex) {
        System.out.println("异常了" + ex.getMessage());
    }

}

18.6 测试
在这里插入图片描述

18.7 代理方式的切换
从springBoot2.x以后,切换代理方式需要在配置文件中配置,使用注解切换的方式失效了

修改application.yml文件的切换方式代理方式

spring:
aop:
proxy-target-class: true # false表示使用JDK代理 true表示使用CGLIB代理,SpringBoot2.x以后默认使用CGLIB代理

19.WEB静态资源访问规则

19.1 springboot访问静态资源的几种方式
查看WebMvcAutoConfiguration里面的静态类WebMvcAutoConfigurationAdapter

关于资源管的方法addResourceHandlers

点进去看一下静态资源可以存放的位置

如果这四个目录下面都有相同的文件,那么访问的优先级为:

META-INF/resources>resources>static>public

19.2 自定义静态资源访问方式
19.2.1 自定义方式1配置文件方式yml
spring:
web:
resources:
static-locations: classpath:/mystatic/ # 静态资源存放的目录
mvc:
static-path-pattern: /static/** # 访问mvc的路径映射
在这里插入图片描述

19.2.2 Java类方式
/**

  • 自己写配置类去实现WebMvc的配置,并且重写
    */
    @Configuration
    public class MyWebMvcResourceHandler implements WebMvcConfigurer {

    /**

    • 重写静态资源配置的方法
    • @param registry
      */
      @Override
      public void addResourceHandlers(ResourceHandlerRegistry registry) {
      registry.addResourceHandler(“/static/**”)
      .addResourceLocations(“classpath:/mystatic/”);
      }
      }

19.3 webjars的访问规则
19.3.1 什么是webjars
WebJars是打包到JAR(Java Archive)文件中的客户端Web库(例如jQuery和Bootstrap)。

在基于JVM的Web应用程序中显式轻松地管理客户端依赖项

使用基于JVM的构建工具(例如Maven,Gradle,sbt,…)来下载客户端依赖项

了解您正在使用的客户端依赖项

传递依赖关系会自动解析,并可选择通过RequireJS加载

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

19.3.2 引入依赖

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

19.3.3 启动访问
http://localhost:8080/webjars/jquery/3.6.0/jquery.js
在这里插入图片描述

20.Thymeleaf模板的使用

20.1 Thymeleaf概述
简单说, Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替代 JSP 。相较与其他的模板引擎,它有如下三个极吸引人的特点:

1、Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。

2、Thymeleaf 开箱即用的特性。它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、该jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。

3、Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能

20.2 创建项目添加thymeleaf的依赖
在这里插入图片描述

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

20.3 Spring Boot项目Thymeleaf模板页面存放位置
查看Thymeleaf的自动配置类
在这里插入图片描述
在这里插入图片描述

当然我们也可以自己修改他的位置,只需要在yml文件中修改即可,一般不做修改
在这里插入图片描述

20.4 通过Controller跳转到Thymeleaf的页面
20.4.1 在指定位置下创建hello.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>hello</title>
</head>
<body>
<h1>hello Thymeleaf</h1>
<h1>我是classpath:/templates/hello.html</h1>
</body>
</html>

20.4.2 创建RouteController类

@Controller
public class RouteController {

    @GetMapping("hello")
    public String hello(){
        return "hello";
    }

}

20.4.3 测试访问
http://localhost:8080/hello

20.5 Thymeleaf的相关语法
官网:https://www.thymeleaf.org/

表达式

l ${…} 取作用域里面的值 request session applicationContext

l #{…} 取IOC容器中的值

l @{…} URL表达式 th:href=”@{/test(name=’abc’,pwd=’123’)}”

l th:text 标签中取字面值

l th:each 遍历

表达式基本对象

l #locale 本地环境

l #httpServletRequest HttpServletRquest对象

l #httpSession HttpSession对象

l #servletContext servletContext对象

常用工具对象

l #numbers 格式化数字对象的实用方法

l #strings 字符串对象的实用方法:包含startsWith,将/附加等

l #dates java.util的实用方法。对象:日期格式、组件提取等

l #objects:实用方法的对象。

l #bools:布尔评价的实用方法。

l #arrays:数组的实用方法。

l #lists:list集合。

l #sets:set集合。

l #maps:map集合。

l #aggregates:实用程序方法用于创建聚集在数组或集合.

l #ids:实用程序方法来处理可能重复的id属性(例如,由于迭代)。

20.6 Thymeleaf读取Model里面的对象
20.6.1 创建Hero类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Hero {
private Integer id;
private String name;
private String sex;
private Integer age;
private String country;
private String phone;
private Date birth;
private Double salary;
}

20.6.2 在RouteController增加一个方法跳转
@GetMapping(“helloHero”)
public String helloHero(Model model) {
Hero hero = new Hero(1, “后羿”, “男”, 18, “中国”, “110”, new Date(), 3150D);
model.addAttribute(“hero”, hero);
return “showHero”;
}

20.6.3 创建showHero页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>英雄面板</h1>
<span>英雄id</span> <span th:text="${hero.id}"></span> <br>
<span>英雄名字</span> <span th:text="${hero.name}"></span> <br>
<span>英雄性别</span> <span th:text="${hero.sex}"></span> <br>
<span>英雄年龄</span> <span th:text="${hero.age}"></span> <br>
<span>英雄年龄</span> <span th:text="${#numbers.formatDecimal(hero.age,0,2)}"></span> <br>
<span>英雄国家</span> <span th:text="${hero.country}"></span> <br>
<span>英雄电话</span> <span th:text="${hero.phone}"></span> <br>
<span>英雄生日</span> <span th:text="${hero.birth}"></span> <br>
<span>英雄生日</span> <span th:text="${#dates.format(hero.birth,'yyyy-MM-dd')}"></span> <br>
<span>英雄存款</span> <span th:text="${hero.salary}"></span> <br>
</body>
</html>

20.6.4 测试访问

http://localhost:8080/helloHero

20.7 Thymeleaf读取Model里面的集合
20.7.1 在RouteController增加一个方法跳转

@GetMapping("helloHeroList")
public String helloHeroList(Model model) {
    ArrayList<Hero> heroes = new ArrayList<>();
    for (int i = 1; i <= 3; i++) {
        heroes.add(new Hero(i, "后裔" + i, "男", 18 + i, "华夏", "110" + i, new Date(), 3150D + i));
    }
    model.addAttribute("heros", heroes);
    return "showHeroList";
}

20.7.2 创建showHeroList页面

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

<div th:each="hero: ${heros}">
    <div>
        <span>英雄id</span> <span th:text="${hero.id}"></span> <br>
        <span>英雄名字</span> <span th:text="${hero.name}"></span> <br>
        <span>英雄性别</span> <span th:text="${hero.sex}"></span> <br>
        <span>英雄年龄</span> <span th:text="${hero.age}"></span> <br>
        <span>英雄年龄</span> <span th:text="${#numbers.formatDecimal(hero.age,0,2)}"></span> <br>
        <span>英雄国家</span> <span th:text="${hero.country}"></span> <br>
        <span>英雄电话</span> <span th:text="${hero.phone}"></span> <br>
        <span>英雄生日</span> <span th:text="${hero.birth}"></span> <br>
        <span>英雄生日</span> <span th:text="${#dates.format(hero.birth,'yyyy-MM-dd')}"></span> <br>
        <span>英雄存款</span> <span th:text="${hero.salary}"></span> <br>
    </div>
    <hr>
</div>
</body>
</html>

20.7.3 测试访问

http://localhost:8080/helloHeroList

20.8 ThymeleafObjects的使用
20.8.1 在RouteController增加一个方法跳转

@GetMapping("thymeleafObject")
public String thymeleafObject(Model model, HttpServletRequest request){
    model.addAttribute("name","超人");
    request.setAttribute("age",22);
    HttpSession session = request.getSession();
    session.setAttribute("address","武汉");
    request.getServletContext().setAttribute("hobby","编码");
    return "showObj";
}

20.8.2 创建showObj页面

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

<div>
    model: <span th:text="${name}"></span>
    <hr>
    request: <span th:text="${#httpServletRequest.getAttribute('age')}"></span>
    <hr>
    session: <span th:text="${#httpSession.getAttribute('address')}"></span>
    <hr>
    servletContext: <span th:text="${#servletContext.getAttribute('hobby')}"> </span>
    <hr>
    <div>
        <span th:text="${#locale.getCountry()}"></span>
        <span th:text="${#locale.getLanguage()}"></span>
    </div>
</div>

</body>
</html>

20.8.3 测试访问

http://localhost:8080/thymeleafObject
在这里插入图片描述

20.9 Thymeleaf在js中取值

<script>
    // 字符串需要引号
    let name = "[[${name}]]"
    // 数字类型不需要引号
    let age = [[${age}]]
    console.log(name)
    console.log(age)
</script>

20.10 Thymeleaf链接接传值
20.10.1 创建一个按钮
点击传值

20.10.2 在RouteController增加一个方法
@GetMapping(“testGetParam”)
@ResponseBody
public String testGetParam(String name,String pwd){
System.out.println(name);
System.out.println(pwd);
return “ok”;
}

21.SpringBoot自动管理MVC分析

https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.developing-web-applications.spring-mvc.auto-configuration
在这里插入图片描述

21.1 查看WebMvcAutoConfiguration及其静态内部类
Mvc帮我们做了哪些事情?

1.(请求分发 --dispatcherServlet)

2.适配器 --requestMappingHandlerAdapter

3.消息转换 --MessageConverter

4.视图解析 --(ContentNegotiatingViewResolver)

5.格式化 --addFormatters

6…

21.2 具体查看视图解析
在ContentNegotiatingViewResolver内容视图协商解析器中初始化servletContext的时候,把加载的所有视图解析器收集了起来
在这里插入图片描述

这里总结出:只要IOC容器里面实现了viewResolver接口的,都可以被收集起来
在这里插入图片描述

21.3 具体查看文件上传下载
MultipartAutoConfiguration中帮我们自动配置了
在这里插入图片描述

MultipartProperties配置文件中可以设定参数,可以的yml文件里面配置
在这里插入图片描述

21.4 具体查看格式化【接收页面参数并转化】
在WebMvcAutoConfiguration中的addFormatters
在这里插入图片描述

我们可以看到默认配置了很多转换规则
在这里插入图片描述

我们也可以配置文件中自己配置

spring:
mvc:
format:
date-time: yyyy-MM-dd HH:mm:ss

版本说明

format.date ----java.utils.Date

format.date-time —java.time.LocalDateTime

21.5 欢迎页面自动配置
在这里插入图片描述
在这里插入图片描述

22.扩展MVC的组件【了解】

创建一个配置类实现WebMvcConfigurer重写之前的方法即可实现自定义拓展

22.1 自定义视图解析器【熟悉】
这样我们就不需要写controller

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {


    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // 转发的控制器注册
        registry.addViewController("/test")
                .setViewName("test");
        // 重定向的控制器注册
        registry.addRedirectViewController("/tobaidu", "https://www.baidu.com");
    }
}

22.2 自定义拦截器【掌握】
22.2.1 创建自己的拦截器

public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        // 返回true 就是放行 返回false就是拦截
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
}

22.2.2 注册到webMvc管理

/**
 * 注册自己的拦截器
 * @param registry
 */
@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new MyInterceptor())
            .addPathPatterns("/**") // 拦截的路径
            .excludePathPatterns("/hello"); // 放行的路径
}

23.注册Web三大组件【重点】

Servlet

|–@WebServlet

|–web.xml

Filter

|–@WebFilter

|–web.xml

Listener

|–@WebListener

|–web.xml

首先查看注册组件的结构

23.1 注册自己的Servlet
我们可以模仿DispatcherServlet的注册方式

23.1.1 创建UserServlet

@Component
public class UserServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("这是我自己的servlet");
        PrintWriter writer = resp.getWriter();
        writer.write("hello");
        writer.flush();
        writer.close();
    }
}

23.1.2 在配置类注册自己的servlet

@Configuration
public class MyWebConfig {

    @Autowired
    private UserServlet userServlet;

    /**
     * 注册自己的servlet
     *
     * @return
     */
    @Bean
    public ServletRegistrationBean<UserServlet> userServletServletRegistrationBean() {
        ServletRegistrationBean<UserServlet> registrationBean = new ServletRegistrationBean<>();
        registrationBean.setServlet(userServlet);
        registrationBean.addUrlMappings("/user");
        return registrationBean;
    }
}

23.2 注册自己的Filter

23.2.1 创建MyFilter

@Component
public class MyFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("我自己的过滤器");
        chain.doFilter(request,response);
    }
}

23.2.2 在配置类里注册自己的过滤器

@Autowired
private MyFilter myFilter;

@Bean
public FilterRegistrationBean<MyFilter> myFilterFilterRegistrationBean(){
    FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
    registrationBean.setFilter(myFilter);
    // 所有的请求都走过滤器   /不会过滤页面,只会过滤路径   /*会过滤路径和页面
    registrationBean.setUrlPatterns(Arrays.asList("/*"));
    return registrationBean;
}

23.3 注册自己的Listener

23.3.1 创建MyListener

@Component
public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("MyListener init");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("MyListener Destroy");
    }
}

23.3.2 在配置类里面注册自己的监听器

@Autowired
private MyListener myListener;

@Bean
public ServletListenerRegistrationBean<MyListener> myListenerServletListenerRegistrationBean(){
    ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>();
    registrationBean.setListener(myListener);
    return registrationBean;
}

24.数据源配置和自动管理【重中之中】

24.1 创建项目选择依赖
在这里插入图片描述

24.2 创建数据库
在这里插入图片描述

24.3 使用DriverManagerDataSource
24.3.1 修改配置文件
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
type: org.springframework.jdbc.datasource.DriverManagerDataSource # spring自带的数据源
url: jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8
username: root
password: root

24.3.2 测试
在这里插入图片描述

24.4 使用Druid数据源【自己配置】
24.4.1 添加durid的依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.6</version>
</dependency>

24.4.2 添加MyDruidProperties配置文件类

@Data
@AllArgsConstructor
@NoArgsConstructor
@ConfigurationProperties(prefix = "my.druid")
public class MyDruidProperties {

    private String url;
    private String driverClassName;
    private String username;
    private String password;
    /**
     * 初始化链接数
     */
    private Integer initialSize;
    /**
     * 最大链接活跃数
     */
    private Integer maxActive;
    /**
     * 最小链接数
     */
    private Integer minIdle;
    /**
     * 检查的sql语句
     */
    private String validationQuery;

    private StatView statView;

    /**
     * 监控配置
     */
    @Data
    static class StatView {
        /**
         * 监控登陆用户名
         */
        private String loginUsername;
        /**
         * 监控登陆密码
         */
        private String loginPassword;
        /**
         * 白名单
         */
        private String allow;
        /**
         * 黑名单
         */
        private String deny;
        /**
         * 映射路径
         */
        private String[] urlMapping;
    }
}

24.4.3 添加MyDruidAutoConfiguration自动配置类

@Configuration // 配置类
@EnableConfigurationProperties(MyDruidProperties.class) // 指定配置类
@ConditionalOnClass(DataSource.class) // 必须要有这个类才生效
public class MyDruidAutoConfiguration {


    @Autowired
    private MyDruidProperties myDruidProperties;

    /**
     * 创建数据源
     *
     * @return
     */
    @Bean(initMethod = "init", destroyMethod = "close")
    public DruidDataSource druidDataSource() {
        if (!StringUtils.hasText(myDruidProperties.getUrl())) {
            throw new IllegalArgumentException("URL 不能为空");
        }
        DruidDataSource druidDataSource = new DruidDataSource();
        // 设置参数
        druidDataSource.setUrl(myDruidProperties.getUrl());
        druidDataSource.setUsername(myDruidProperties.getUsername());
        druidDataSource.setPassword(myDruidProperties.getPassword());
        druidDataSource.setDriverClassName(myDruidProperties.getDriverClassName());
        druidDataSource.setMaxActive(myDruidProperties.getMaxActive());
        druidDataSource.setInitialSize(myDruidProperties.getInitialSize());
        druidDataSource.setMinIdle(myDruidProperties.getMinIdle());
        druidDataSource.setValidationQuery(myDruidProperties.getValidationQuery());
        return druidDataSource;
    }


    /**
     * 注册servlet
     *
     * @return
     */
    @Bean
    public ServletRegistrationBean<StatViewServlet> statViewServletServletRegistrationBean() {
        StatViewServlet statViewServlet = new StatViewServlet();
        ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>();
        registrationBean.setServlet(statViewServlet);
        // 设置参数
        registrationBean.addInitParameter("loginUsername", myDruidProperties.getStatView().getLoginUsername());
        registrationBean.addInitParameter("loginPassword", myDruidProperties.getStatView().getLoginPassword());
        registrationBean.addInitParameter("allow", myDruidProperties.getStatView().getAllow());
        registrationBean.addInitParameter("deny", myDruidProperties.getStatView().getDeny());
        registrationBean.addUrlMappings(myDruidProperties.getStatView().getUrlMapping());
        return registrationBean;
    }
}

24.4.4 修改yml配置文件

my:
    druid:
        url: jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8
        username: root
        password: root
        driver-class-name: com.mysql.cj.jdbc.Driver
        initial-size: 2
        max-active: 10
        min-idle: 3
        validation-query: select 'x'
        stat-view:
            login-username: admin
            login-password: admin
            allow:
            deny:
            url-mapping:
                - /druid/*
                - /druid2/*

24.4.5 测试访问

http://localhost:8080/druid

24.5 使用Druid数据源【官方starter】

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.6</version>
</dependency>

24.5.1 修改配置文件

spring:
    datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/test?useSSL=false&serverTimezone=GMT%2B8
        username: root
        password: root
        type: com.alibaba.druid.pool.DruidDataSource
        druid:
            max-active: 10
            min-idle: 2
            validation-query: select 'x'
            stat-view-servlet:
                login-username: admin
                enabled: true  #启用监控页
                login-password: admin
                allow:
                deny:
                url-pattern: /druid/*

25.集成mybatis【重点】

25.1 创建数据库并且新增测试数据
在这里插入图片描述

25.2 创建新模块并添加依赖

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

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.2.6</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

25.3 根据数据库创建User对象(逆向工程)

25.4 修改yml配置文件
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test?useSSL=false&serverTimezone=GMT%2B8
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
druid:
max-active: 10
min-idle: 2
validation-query: select ‘x’
stat-view-servlet:
login-username: admin
enabled: true #启用监控页
login-password: admin
allow:
deny:
url-pattern: /druid/*
mybatis:
mapper-locations: classpath:mapper/*.xml # mapper.xml文件位置
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # sql日志输出

25.5 修改启动类
在这里插入图片描述

25.6 测试查询
在这里插入图片描述

25.7 使用注解的方式

/**
 * 在mapper接口的方法上使用注解的方式
 * @Select
 * @Update
 * @Insert
 * @Delete
 *
 * @return
 */

@Select(“select * from user”)
List selectAllUser();
在这里插入图片描述

25.8 配置PageHelper插件分页(第一种,不推荐)
25.8.1 依赖pageHelper

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.2.1</version>
</dependency>

25.8.2 创建mybatis-cfg.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>
</configuration>

25.8.3 修改application.yml文件
mybatis:
mapper-locations: classpath:mapper/*.xml # mapper.xml文件位置
config-location: classpath:mybatis-cfg.xml # 指定配置文件

25.8.4 测试分页
在这里插入图片描述

25.9 配置PageHelper插件分页(第二种,推荐)
25.9.1 依赖pageHelper的starter

<!--        <dependency>-->
<!--            <groupId>com.github.pagehelper</groupId>-->
<!--            <artifactId>pagehelper</artifactId>-->
<!--            <version>5.2.1</version>-->
<!--        </dependency>-->

        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>

25.9.2 删除mybatis-cfg.xml文件后修改yml文件

mybatis:
    configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  # sql日志输出
    mapper-locations: classpath:mapper/*.xml  # mapper.xml文件位置
#    config-location: classpath:mybatis-cfg.xml # 指定配置文件

25.9.3 测试查询分页
在这里插入图片描述

25.10 事务管理
和spring里面一样的,但是在boot里面只要在XXXXServiceImpl上Transactionl

@Override
@Transactional(rollbackFor = RuntimeException.class, propagation = Propagation.REQUIRED)
public int addUser(User user) {
int i = userMapper.insert(user);
int a = 10 / 0;
return i;
}

25.11 boot和mybatis的集成的总结
1,创建项目导依赖

2,配置数据源[修改yml]

3,配置mybatis[修改yml]

4,配置mapper接口扫描

5,使用

26.使用外部tomcat【了解】

Springboot项目里面默认不支持jsp 它是使用模板引擎[thymeleaf]

Springboot不支持jsp的原因是因为内置的tomcat不支持jsp

26.1 创建项目,选择打包方式为war包
在这里插入图片描述

26.2 选择依赖
在这里插入图片描述

26.3 配置pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>
<!--加入内嵌入tomcat对jsp的支持-->
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>
<!-- servlet 依赖 -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <scope>provided</scope>
</dependency>
<!--jstl的依赖 -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.1.2</version>
</dependency>
<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>

26.4 添加IDEA配置
在这里插入图片描述
在这里插入图片描述

26.5 配置外部tomcat
在这里插入图片描述
在这里插入图片描述

26.6 创建controller
@Controller
public class TestController {

@GetMapping("test")
public String test(){
    return "test";
}

}

26.7 创建页面
在这里插入图片描述

26.8 修改配置文件
spring:
mvc:
view:
prefix: /WEB-INF/view/
suffix: .jsp

26.9 启动访问
http://localhost:8080/test

27.集成swagger【熟悉】

27.1 问题描述
随着互联网技术的发展,现在的网站架构基本都由原来的后端渲染,变成了:前端渲染、前后端分离的形态,而且前端技术和后端技术在各自的道路上越走越远。 前端和后端的唯一联系,变成了API接口;API文档变成了前后端开发人员联系的纽带,变得越来越重要,swagger就是一款让你更好的书写API文档的框架,而且swagger可以完全模拟http请求,入参出参和实际情况差别几乎为零。

没有API文档工具之前,大家都是手写API文档的(维护起来相当困难),在什么地方书写的都有,有在confluence上写的,有在对应的项目目录下readme.md上写的,每个公司都有每个公司的玩法,无所谓好坏。但是能称之为“框架”的,估计也只有swagger了
在这里插入图片描述

27.2 使用步骤
27.2.1 创建项目加入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--swagger starter-->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

27.2.2 创建SwaggerProperties信息配置类

@Data
@AllArgsConstructor
@NoArgsConstructor
@ConfigurationProperties(prefix = "swagger3")
public class SwaggerProperties {

    /**
     * 扫描的包
     * 给这个包下面的接口创建文档
     */
    private String basePackage;
    /**
     * 作者姓名
     */
    private String name;
    /**
     * 作者主页链接
     */
    private String url;
    /**
     * 作者邮箱
     */
    private String email;
    /**
     * 版本号
     */
    private String version;
    /**
     * 分组名称
     */
    private String groupName;
    /**
     * 文档标题
     */
    private String title;
    /**
     * 文档描述
     */
    private String description;
    /**
     * 组织地址
     */
    private String termsOfServiceUrl;
    /**
     * 许可证
     */
    private String license;
    /**
     * 许可链接
     */
    private String licenseUrl;

}

27.2.3 创建SwaggerAutoConfiguration自动配置类

@Configuration
@EnableOpenApi // 开启swagger的功能  旧版本是EnableSwagger2
@EnableConfigurationProperties(SwaggerProperties.class)
public class SwaggerAutoConfiguration {

    @Autowired
    private SwaggerProperties swaggerProperties;

    @Bean
    public Docket docket() {
        return new Docket(DocumentationType.OAS_30)
                .apiInfo(getApiInfo())
                .groupName(swaggerProperties.getGroupName())
                .select()
                .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))
                .build();
    }


    private ApiInfo getApiInfo() {
        Contact contact = new Contact(swaggerProperties.getName(), swaggerProperties.getUrl(), swaggerProperties.getEmail());
        return new ApiInfo(swaggerProperties.getTitle(),
                swaggerProperties.getDescription(),
                swaggerProperties.getVersion(),
                swaggerProperties.getTermsOfServiceUrl(),
                contact,
                swaggerProperties.getLicense(),
                swaggerProperties.getLicenseUrl(),
                new ArrayList<>()
        );
    }
}

27.2.4 修改yml文件

swagger3:
    base-package: com.bjpowernode.controller
    name: cxs
    url: https://gitee.com/smiledouble
    email: 775610843@qq.com
    version: 1.0
    group-name: cxs
    title: "测试"
    description: "测试swagger文档"
    terms-of-service-url: https://gitee.com/smiledouble
    license: cxs
    license-url: https://gitee.com/smiledouble
spring:
    jackson:
        date-format: yyyy-MM-dd HH:mm:ss
        time-zone: GMT+8
    mvc:
        format:
            date-time: yyyy-MM-dd HH:mm:ss

27.2.5 创建Hero类

@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("英雄对象")  // 描述实体类
public class Hero {

    @ApiModelProperty(value = "英雄的id")
    private Integer id;
    @ApiModelProperty(value = "英雄的名称")
    private String name;
    @ApiModelProperty(value = "英雄的地址")
    private String address;
    @ApiModelProperty(value = "英雄的生日")
    private Date birth;
    @ApiModelProperty(value = "英雄的爱好")
    private List<String> hobby;
    @ApiModelProperty(value = "英雄的map")
    private Map<String, String> map;
}

27.2.6 创建Controller

@RestController
@Api(tags = "英雄的管理接口")
public class HeroController {


    @GetMapping("getHero/{id}")
    @ApiOperation("根据id获取英雄")
    @ApiImplicitParam(name = "id", value = "英雄编号(必填)", required = true, dataType = "Integer", paramType = "path")
    public Hero getHeroById(@PathVariable("id") Integer id) {
        HashMap<String, String> map = new HashMap<>();
        map.put("技能", "射箭");
        return new Hero(id, "后裔", "峡谷", new Date(), Arrays.asList("打猎"), map);
    }


    @PostMapping("addHero")
    @ApiOperation("添加英雄")
    public Map<String, Object> addHero(@RequestBody Hero hero) {
        System.out.println(hero);
        HashMap<String, Object> map = new HashMap<>();
        map.put("code", 200);
        map.put("msg", "OK");
        return map;
    }

    @DeleteMapping("delHero")
    @ApiOperation("根据id删除一个英雄")
    @ApiImplicitParam(name = "id", value = "英雄编号", required = true, paramType = "query", dataType = "Integer")
    public Map<String, Object> delHero(@RequestParam Integer id) {
        System.out.println(id);
        HashMap<String, Object> map = new HashMap<>();
        map.put("code", 200);
        map.put("msg", "OK");
        return map;
    }
}

27.2.7 测试访问文档页面

http://localhost:8080/swagger-ui/index.html

27.2.8 测试接口
在这里插入图片描述

27.2.9 补充注解说明
https://gumutianqi1.gitbooks.io/specification-doc/content/tools-doc/spring-boot-swagger2-guide.html
在这里插入图片描述

28.Spring Boot异步

同步:

异步:

java里面这病异步就是多线程

springboot里面的异步,就是为开发者提供了种快速使用多线程的方式

New Thread().start();

28.1 概述
28.1.1 什么是异步调用?
异步调用是相对于同步调用而言的,同步调用是指程序按预定顺序一步步执行,每一步必须等到上一步执行完后才能执行,异步调用则无需等待上一步程序执行完即可执行。

28.1.2 如何实现异步调用?
多线程,这是很多人第一眼想到的关键词,没错,多线程就是一种实现异步调用的方式。

在非spring目项目中我们要实现异步调用的就是使用多线程方式,可以自己实现Runable接口或者集成Thread类,或者使用jdk1.5以上提供了的Executors线程池。

StrngBoot中则提供了很方便的方式执行异步调用。

28.1.3 异步接口的使用场景
耗时比较长,任务比较多的接口。比方说,文件下载,大文件下载比较耗时,这个时候就可以使用异步接口。还有就是对用户接下来操作没有影响的写库之类

28.2 最佳实践
28.2.1 创建项目选择依赖
在这里插入图片描述

28.2.2 创建Controller接口测试

@RestController
public class AsyncController {

    @GetMapping("doAsync")
    public Map<String,Object> doAsync(){
        Map<String,Object> map=new HashMap<>();
        Long startMills=System.currentTimeMillis();
        task1();
        task2();
        task3();
        Long endMills=System.currentTimeMillis();
        map.put("code",200);
        map.put("msg","异步调用成功,耗时"+(endMills-startMills));
        return map;
    }


    @Async
    public void task1(){
        try {
            long start = System.currentTimeMillis();
            Thread.sleep(1000);
            long end = System.currentTimeMillis();
            System.out.println("task1耗时:" + (end - start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Async
    public void task2(){
        try {
            long start = System.currentTimeMillis();
            Thread.sleep(2000);
            long end = System.currentTimeMillis();
            System.out.println("task2耗时:" + (end - start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Async
    public void task3(){
        try {
            long start = System.currentTimeMillis();
            Thread.sleep(3000);
            long end = System.currentTimeMillis();
            System.out.println("task3耗时:" + (end - start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

28.2.3 修改启动类开启异步功能
在这里插入图片描述

28.2.4 访问测试
http://localhost:8080/doAsync

发现测试结果并没有异步
在这里插入图片描述

28.2.5 异步并没有执行?
难道是代码写错了?反复检查了好几遍,并没有发现什么明显错误,想起spring对@Transactional注解时也有类似问题,spring扫描时具有@Transactional注解方法的类时,是生成一个代理类,由代理类去开启关闭事务,而在同一个类中,方法调用是在类体内执行的,spring无法截获这个方法调用。

豁然开朗,将异步任务单独放到一个类中,调整代码入下

28.2.6 添加异步任务类

@Component
public class AsyncTask {

    @Async
    public void task1(){
        try {
            long start = System.currentTimeMillis();
            Thread.sleep(1000);
            long end = System.currentTimeMillis();
            System.out.println("task1耗时:" + (end - start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Async
    public void task2(){
        try {
            long start = System.currentTimeMillis();
            Thread.sleep(2000);
            long end = System.currentTimeMillis();
            System.out.println("task2耗时:" + (end - start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Async
    public void task3(){
        try {
            long start = System.currentTimeMillis();
            Thread.sleep(3000);
            long end = System.currentTimeMillis();
            System.out.println("task3耗时:" + (end - start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

28.2.7 修改Controller接口测试

@RestController
public class AsyncController {

    @Autowired
    private AsyncTask asyncTask;

    @GetMapping("doAsync")
    public Map<String,Object> doAsync(){
        Map<String,Object> map=new HashMap<>();
        Long startMills=System.currentTimeMillis();
        asyncTask.task1();
        asyncTask.task2();
        asyncTask.task3();
        Long endMills=System.currentTimeMillis();
        map.put("code",200);
        map.put("msg","异步调用成功,耗时"+(endMills-startMills));
        return map;
    }
}

28.2.8 再次测试
在这里插入图片描述

29.Spring Boot定时任务

需求:领导说,每天晚上12把前一天的销售统计报表发给我

写一个任务

1,从数据库里面取数据进行处理

2,写一个定时任务 每天12点之前执行

3,从数据库里面查询数据处理完成之后以邮件的形式发送给领导

29.1 概述

  • sprignBoot定时任务是与quartz整合,不需要添加任何的依赖

  • 在springBoot的启动类上添加@EnableScheduling注解开启定时调度

  • 在需要定时调度的方法上添加@Scheduled这个注解即可,其中可以指定cron表达式和其他的定时方式

29.2 最佳实践
29.2.1 开启定时任务
在这里插入图片描述

29.2.2 执行任务

@Component
public class MyTask {

    /**
     * 这个方法必须是无参无返回值的
     * @Scheduled里面有两种用法
     * 一种是固定速率
     *   fixedDelay = 2000 规定延迟两秒执行一次
     *   fixedRate = 2000  固定过多少秒执行一次
     *   initialDelay = 2000,fixedRate = 5000  第一次延迟两秒执行,后面按照fixedRate的规则执行
     * 一种是cron表达式  https://www.matools.com/cron/
     */
    @Scheduled(cron = "0/3 * * * * ?") // 每三秒执行一次
    public void myTask(){
        System.out.println(new Date());
    }
}

30.Spring Boot邮件发送

30.1 概述
SpringBoot实现邮件功能是非常的方便快捷的,因为SpringBoot默认有starter实现了Mail。

发送邮件应该是网站的必备功能之一,什么注册验证,忘记密码或者是给用户发送营销信息。

最早期的时候我们会使用JavaMail相关api来写发送邮件的相关代码,后来spring退出了JavaMailSender更加简化了邮件发送的过程,在之后springboot对此进行了封装就有了现在的spring-boot-starter-mail。

30.2 最佳实践
先去qq邮箱设置smtp开启,并获得授权码

邮箱->设置->账户->POP3/SMTP服务:开启服务后会获得授权码
在这里插入图片描述

30.2.1 创建项目引入依赖(mail)
在这里插入图片描述

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

30.2.2 修改yml配置文件

spring:
    mail:
        host: smtp.qq.com  #配置服务器qq:smtp.qq.com,网易163:smtp.163.com
        password: dxyjutiafqktbdgd  #授权码,邮箱->设置->账户->POP3/SMTP服务:开启服务后会获得权码
        username: 775610843@qq.com
        default-encoding: UTF-8

30.2.3 编写测试发送邮件

@SpringBootTest
class SpringBootEmailApplicationTests {

    @Autowired
    private JavaMailSender javaMailSender;

    @Test
    void contextLoads() {
        System.out.println(javaMailSender);
    }

    /**
     * 发送基本内容
     */
    @Test
    void testSend() {
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        // 发件人邮箱
        simpleMailMessage.setFrom("775610843@qq.com");
        // 收件人邮箱
        simpleMailMessage.setTo("2270415677@qq.com");
        // 邮件主题
        simpleMailMessage.setSubject("这是一个测试邮件");
        // 邮件内容
        simpleMailMessage.setText("测试内容");
        javaMailSender.send(simpleMailMessage);
    }


    /**
     * 测试发送复杂内容,例如图片和附件等
     */
    @Test
    void testSend2() throws MessagingException {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        // 创建一个邮件工具,可以发送附件
        MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage,true,"utf-8");
        mimeMessageHelper.setFrom("775610843@qq.com");
        mimeMessageHelper.setTo("2270415677@qq.com");
        mimeMessage.setSubject("这是一个携带了图片和附件的邮件");
        //拼接内容参数
        StringBuilder sb = new StringBuilder();
        sb.append("<html> <body> <h1 style='color:red'>springboot 测试邮件发送复杂格式o</h1>");
        sb.append("<p style='color:blue,font-size:16px'>哈哈哈</p>");
        sb.append("<p style='text-align:center'>居中</p>");
        sb.append("<img src='cid:picture'/> </body></html>");  //如果要插入图片src='cid:picture'
        //设置内容,可以被html解析
        mimeMessageHelper.setText(sb.toString(), true);
        // 从本地磁盘中读取到图片 站位到内容中去
        mimeMessageHelper.addInline("picture",new File("C:\\Users\\cxsxjw\\Pictures\\Saved Pictures\\abc.jpg"));
        // 添加附件
        mimeMessageHelper.addAttachment("测试文件.xls",new File("D:\\测试文件.xls"));
        javaMailSender.send(mimeMessage);
    }
} 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/196679.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS 数据持久化 Preferences 如何在页面中对数据进行读写

背景介绍 最近在了解并跟着官方文档尝试做一个鸿蒙app 小demo的过程中对在app中保存数据遇到些问题 特此记录下来 这里的数据持久化以 Preferences为例子展开 废话不多说 这里直接上节目(官方提供的文档示例:) 以Stage模型为例 1.明确preferences的类型 import data_prefer…

四川劳动保障杂志社四川劳动保障编辑部四川劳动保障杂志2023年第10期目录

主题报道 四川抢抓“金九银十”招聘季多措并举稳就业促就业 举措频“上新” 金秋送岗忙 张玉芳; 2-5 法眼《四川劳动保障》投稿&#xff1a;cnqikantg126.com 筑牢长期护理保险基金安全防线 李科仲;赖晓薇; 6-7 调研 提升职业技能培训工作的举措 寇爵; 8-9 城乡…

虚拟机虚拟化原理

目录 什么是虚拟化广义虚拟化狭义虚拟化 虚拟化指令集敏感指令集虚拟化指令集的工作模式监视器对敏感指令的处理过程&#xff1a; 虚拟化类型全虚拟化类虚拟化硬件辅助虚拟化 虚拟化架构裸金属架构宿主机模式架构 什么是虚拟化 虚拟化就是通过模仿下层原有的功能模块创造接口来…

电压调整型脉宽调制控制集成电路芯片D7500,工作电压范围7V ~ 40V,输出电流(Max)可达200mA,具有欠压锁定功能

D7500/D7500F SMPS 控制器电路&#xff0c;是一块电压调整型脉宽调制控制集成电路。内部包含5V 基准电压电路、两个误差放大器、触发电路、控制输出电路、脉宽调制比较 器、死区时间比较器及一个 振荡器。该电路可转换频率1kHz至300kHz&#xff0c; 基准电压(Vref)的精确度提…

echarts 水波图

echarts 水波图 安装 npm install echarts --save npm install echarts-liquidfill --save引入 import * as echarts from echarts; import echarts-liquidfill;html <div id"chart1" ref"chart1" class"chart1"></div>css .cha…

DehazeNet: An End-to-End System for Single Image Haze Removal

来源&#xff1a;2016 IEEE journal Cai B, Xu X, Jia K, et al. Dehazenet: An end-to-end system for single image haze removal[J]. IEEE transactions on image processing, 2016, 25(11): 5187-5198. GitHub - caibolun/DehazeNet: DehazeNet: An End-to-End System for …

企业客户服务怎么做?6个有效方法献上!

毋庸置疑&#xff0c;赢得客户的青睐是维系企业经济长青的基础。想要客户满意&#xff0c;得到最佳的客户评价&#xff0c;企业就需要为客户提供超出他们期望的服务。客户服务(Customer Service)是企业成功的关键环节之一&#xff0c;它不仅仅是满足客户需求的过程&#xff0c;…

全新付费进群系统源码 完整版教程

首先准备域名和服务器 安装环境&#xff1a;Nginx1.18 MySQL 5.6 php7.2 安装扩展sg11 伪静态thikphp 后台域名/admin账号admin密码123456 代理域名/daili账号admin密码123456 一、环境配置 二、建站上传源代码解压 上传数据库配置数据库信息 三、登入管理后台 后台域名/ad…

NI自动化测试系统用电必备攻略,电源规划大揭秘

就像使用电脑之前需接通电源一样&#xff0c;自动化测试系统的电源选择也是首当其冲的问题&#xff0c;只不是这个问题更复杂。 比如&#xff0c;应考虑地理位置因素&#xff0c;因为不同国家或地区的公共电网所提供的线路功率有所不同。在电源布局和设备选型方面&#xff0c;有…

大语言模型(LLMs)在 Amazon SageMaker 上的动手实践(一)

本期文章&#xff0c;我们将通过三个动手实验从浅到深地解读和演示大语言模型&#xff08;LLMs&#xff09;&#xff0c;如何结合 Amazon SageMaker 的模型部署、模型编译优化、模型分布式训练等。 实验一&#xff1a;使用 Amazon SageMaker 构建基于开源 GPT-J 模型的对话机器…

14.Tomcat和HTTP协议-[一篇通]

文章目录 1.HTTP 协议1.1HTTP 是什么1.2理解 "应用层协议"1.3理解 HTTP 协议的工作过程1.4HTTP 协议格式1.4.1抓包工具的使用(Fiddler)1.4.2抓包工具的原理1.4.3抓包结果1.4.4协议格式总结 1.5HTTP 请求 (Request)1.5.1认识 URL1.5.1.1URL 基本格式1.5.1.2关于 URL e…

前缀和——238. 除自身以外数组的乘积

文章目录 &#x1f377;1. 题目&#x1f378;2. 算法原理&#x1f365;解法一&#xff1a;暴力求解&#x1f365;解法二&#xff1a;前缀和&#xff08;积&#xff09; &#x1f379;3. 代码实现 &#x1f377;1. 题目 题目链接&#xff1a;238. 除自身以外数组的乘积 - 力扣&a…

【测试开发】第五节.测试——自动化测试(Selenium工具)

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;Java测试开发 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01; 前言 一、…

csdn博客编写技巧

随便记录一下csdn博客编写时候用的到技巧&#xff0c;以作备忘。 1. 表格 1.1 Markdown-Table-Generator 这个是csdn编辑器中&#xff0c;工具栏自带的表格用法。主要优点是比较直观&#xff0c;缺点是无法设置表格中行列的宽高。 用法&#xff1a; | 表头一 | 表头二 | |-…

SpringSecurity+JWT

一.简介 Spring Security 是 Spring家族中的一个安全管理框架。相比与另外一个安全框架Shiro&#xff0c;它提供了更丰富的功能&#xff0c;社区资源也比Shiro丰富。 认证&#xff1a;验证当前访问系统的是不是本系统的用户&#xff0c;并且要确认具体是哪个用户​ 授权&…

扩散模型,快速入门和基于python实现的一个简单例子(复制可直接运行)

提示&#xff1a;内容丰富&#xff0c;收藏本文&#xff0c;以免忘记哦 文章目录 一、扩散模型二、一个简单的迭代式扩散模型的例子温度扩散模型python代码实现差分近似模拟拉普拉斯算子 三、扩散模型和深度学习进行结合简介用python和torch的代码实现 四、扩散模型与生成模型第…

JVM GC算法

一, 垃圾回收分类: 按线程数分&#xff0c;可以分为串行垃圾回收器和并行垃圾回收器。 按工作模式分&#xff0c;可以分为并发垃圾回收器和独占式垃圾回收器 按碎片处理方式分&#xff0c;可以分为压缩式垃圾回收器和非压缩式垃圾回收器按工作的内存区间分&#xff0c;又可分为…

C语言盐水的故事(ZZULIOJ1214:盐水的故事)

题目描述 挂盐水的时候&#xff0c;如果滴起来有规律&#xff0c;先是滴一滴&#xff0c;停一下&#xff1b;然后滴二滴&#xff0c;停一 下&#xff1b;再滴三滴&#xff0c;停一下...&#xff0c;现在有一个问题&#xff1a;这瓶盐水一共有VUL毫升&#xff0c;每一滴是D毫升&…

基于springBoot+mysql实现的竞赛管理系统

基于springBootmysql实现的竞赛管理系统&#xff0c;演示地址:系统登录 - 软件学院比赛管理系统 管理员账号&#xff1a;1&#xff0c;密码:1 包括比赛管理&#xff0c;队伍管理&#xff0c;教师管理&#xff0c;经费管理&#xff0c;学生管理&#xff0c;比赛结果&#xff0c;…

目前工资最高的几家外包公司汇总!(2023最新版)

最近&#xff0c;很多小伙伴问&#xff1a;只有外包的 offer 能去吗&#xff1f; 大环境不行&#xff0c;面试太少了&#xff0c;很多本科生想进外包都没机会。 非常时期&#xff0c;不需要在意那么多&#xff0c;外包作为过渡也是没问题的&#xff0c;很多外包其实比小公司还…