目录
[一、 spring core](#一、 spring core)
[1.0 Ioc简介](#1.0 Ioc简介)
[(3)spring IoC和DI](#(3)spring IoC和DI)
[2.0 详解Ioc](#2.0 详解Ioc)
[(2)Bean name规则](#(2)Bean name规则)
[3.0 DI](#3.0 DI)
[4.0 常见面试题](#4.0 常见面试题)
[(1)Autowired 和 @Resource的区别](#(1)Autowired 和 @Resource的区别)
[(2)Spring SpringBoot 和 Spring mvc的关系以及区别](#(2)Spring SpringBoot 和 Spring mvc的关系以及区别)
[1.0 简介](#1.0 简介)
[(2)配置文件说明 properties](#(2)配置文件说明 properties)
[(3)配置文件说明 yml /yaml](#(3)配置文件说明 yml /yaml)
[1.0 验证码案例](#1.0 验证码案例)
[2.0 问题:](#2.0 问题:)
[(1) 静态内部类](#(1) 静态内部类)
[1.0 简介](#1.0 简介)
[(8) 更简单的日志输出](#(8) 更简单的日志输出)
一、 spring core
1.0 Ioc简介
(1)Ioc简介
spring最原始的样子是什么样的:spring core
spring core是spring的核心模块 长下面这一个

spring是一个包含众多工具的IoC容器 (容器是一个抽象的概念 可以装很多东西)
IoC:控制反转 解释:反转 字面意思 反差 控制:字面意思 控制权 对象的控制权发生了发转
之前对象的控制权在 之前是谁使用在谁手上 之前是需要你手动创建对象
现在是spring控制 对象由spring帮你创建和注入
(2)Ioc的引入
传统程序开发的流程: 以造一辆车为例来了解一下IoC


如果这个时候需求发生变化呢?
例如 我希望的是用户说轮胎多少尺寸,然后得到多少相应尺寸的车子
相应的函数里面要设置好参数 都改为这样

传统方式的问题:一个函数改了代码参数 其他函数都得跟着改
当客户提出的五花八门的需求时,按照这种方式 改来改去 效率非常的低
Ioc的方式:

也就是外包的思想 具体的实现代码是这样的改变

创建car的时候 不自己new了 外包给framework framwork就是从外包公司拿过来的 最后造汽车只是组装一下各个零件
之后要增加新的需求 例如增添轮胎的颜色 就从轮胎里面加上新的代码就可以了
而不需要修改所有的代码 这样就是实现了解耦
上述的外包公司 我们在这里可以类比为spring 对象的控制权交给了spring
创建对象的过程叫做Ioc 拿来用的过程叫做注入DI
(3)spring IoC和DI
@component 表示是由spring来创建 管理它的对象(实例)
spring启动时会自动扫描这个类,创建它的对象并保存,你需要用的时候直接拿就行 不用手动创建
@Autowired 表示从spring当中获得对象 并给属性赋值

从spring容器中,获取BookDao这个类型的对象 并赋值给bookDao
compoent和autowired对应: 一个表示是存 一个表示是取
2.0 详解Ioc
(1)Bean简介
Bean:
Bean是spring容器(IOC容器)所管理的一个Java对象,它由spring创建 装配 初始化 生命周期管理以及销毁 简单来说不是你new出来的 是Spring给你造好 配好 管理好的对象
Bean的存储:
注解实现Bean的存储,指的是:通过在类、方法或者字段上添加特的Spring注解 将该类或对象自动注册为Spring容器管理的Bean

Application 应用 Context 上下文//表示一个容器
例如ApplicationContext 表示应用的上下文 可以表示Spring的运行环境
(2)Bean name规则
Bean name:
bean是spring容器创建 管理 装配的对象 而Bean name就是spring给这个对象在容器中起的"唯一标识符"
HelloController---->helloController BookDao---->bookDao USCcontroller--->USCcontroller
注意当前两个字母是大写的时候 类名和对象名是一致的
也可以直接指定 不用默认的

getBean:从spring容器中主动获取一个由spring创建兵管理的Bean实例
(3)三种不同语义的Bean获取方式

HelloController bean1 = context.getBean(HelloController.class)
//适合该对象类型只有一个 返回的是Object
HelloController bean2 = (HelloController) context.getBean("helloController") 注意强制转换
//需要精确通过Bean的名称获取 切不关心类型(或者类型在编译期间不可知)
HelloController bean3 =context.getBean("helloController",HelloController.class)
//需要按照名称精准定位Bean 要求编译器类型安全+运行时类型校验
//认识错误日志:
先看异常是什么 //控制台输出的就是错误日志

(4)注解
Controller注解
**上下文:**可以理解为容器 就是存东西的 表示前后的一种关系 绵绵潺潺的
service注解 Repository注解 Component注解 Configuration注解

这五个注解就是用来告诉spring管理对象 标了这五个注解 就会告诉spring创建一个对象放到里面
那么这五个注解有什么区别呢?

其他四个都是Component的衍生注解 那为什么要区分? 不同的含义
晋A 晋B 晋C
Controller 控制层 Service 业务逻辑层 Repository 数据层 configuration 配置层componet组件层 //实际应用过程中,这5个注解的边界并没有那么清晰

@Controller不可以和其他注解替换 控制层必须使用@Controller
其他几个注解可以替换 但是不建议 因为不同的注解表示的含义不同 可能造成不必要的麻烦

@Bean注解
方法前面加@Bean之前 类上要加五大注解 //@Bean要配合五大注解使用
Bean name默认为方法名 @Bean可以重命名 name和value是一样的 value又可以省略
@Bean在哪些场景使用:

扫描路径
spring的扫描路径默认是启动类所在的路径及其子路径 //看源码就可以发现
但是加了@ComponentScan之后 就以@componentscan括号里面的路径为扫描路径了
所以一般把启动类放在最外层
可以通过@ComponentScan来定义扫描的路径 @ComponentScan ("com.bit.ioc.component")
3.0 DI
(1)DI简介
Dependecy Injection 依赖注入
图片化的理解:

什么是依赖? 例如BookController需要正常工作 需要有bookService bookService需要正常工作 需要里面有bookDao
BookController依赖bookService bookDao依赖bookService 可以理解为里面的一些属性
依赖的核心是:A 类的功能实现,离不开 B 类的协助,A 就依赖 B。
DI :表示依赖注入
如何从spring中取到对象 并且赋值给它
你只要告诉spring容器 我需要xx对象 它就把xx对象直接送到你的手上
(2)依赖注入的方式
1.属性注入
@Autowired
private UserService userService;
在后面的代码里面就可以调用userService的方法 实现了依赖的注入
过程:
Autowired注解 在spring容器中,根据类型获取对象,并赋值
@Autowired帮助实现 spring看到@Autowired注解 知道你要给userService属性赋值
spring去自己的容器里面找userService属性类型的bean
spring把找到的UserService对象赋值给userService属性
DI测试: HelloController bean = context.getBean(HelloController.class); 打印结果是

既有do Controller又有do Service 在调用Controller的时候 userService方法也执行了 //context是spring的Ioc容器 *仓库
下面是有关的两个报错信息 错误日志是一段一段的 从下面往上面倒着看

缺陷:
bean 一个类型是可以有多个对象 当有多个对象 autowired注入的时候就是失败了
2.构造方法注入
private UserService userService ;
public HelloController(UserService userService) { this.userService = userService; }
如果只有一个构造方法 @Autowired可以省略
如果有存在多个构造方法:
spring帮我们管理对象的时候 默认调用的是无参的构造函数 也可以通过Autowired来指定默认的构造方法 //如果想要证明的话 自己可以测试 然后看错误日志 没得选的时候选唯一的 多选一的时候报错

3.setter方法注入
也需要加上@Autowired注解
@Autowired
public void serUserService (UserService) { this.userService = userService }
//多个的话 得分别标记上@Autowired 一个@Autowierd只对下面一行起作用 多个的时候一定要多@Autowired
4.三种方式优缺点分析
属性注入: 优 简洁方便 缺 只能在spring中使用 不能修饰final属性 private final UserService错误
解释:final 必须在 对象创建完成前 完成初始化,且初始化后不可修改。 //因为是类加载
这样就只能两种方式
声明时直接赋值 private final UserUservice us =new UserService( );
//我们写Autowired就是为了自动注入 现在自己new了 那加注解的意义何在?
在类的构造方法中赋值 private final UserService us;
public HelloController (UserService us) { this.us = us; } 在构造器中完成初始化
spring属性注入 实际发生在对象创建之后
构造函数注入(spring 4.x推荐): 优 可以注入final修饰的属性
注入的对象不会被修改 //没办法赋值了
通用性好(构造方法是JDK支持的)
依赖对象在使用前一定会被完全初始化 构造方法在类加载阶段就会执行
缺 注入多个对象时 代码会比较繁琐
setter注入(spring 3.x推荐) : 优 方便在创建对象之后 重新对该对象进行配置或者注入
缺 不能注入一个final修饰的属性
注入对象可能会被改变 因为setter方法可能会被多次调用 就有被
修改的风险
(3)Autowired存在的问题
当同一个类型有多个对象要怎么办? 因为Autowired是根据类型对应的 就会存在这样的情况
解决方式: idea编译器会有报错信息//最下面一行 说了两个解决方式 圈主的那个

一种是 加注解@Primary 来标明哪个是主要的
另一种是 加注解@Qualifier qualifier 修饰符 限定符 限定词 @Qualifier("s3") 限定了用s3
另另一种是 加注解@Resource @Resource("s3")
// 告诉 Spring"我要从容器 里找一个指定的'资源(Bean)',并注入到这个属性里" 就不用写@Autowired注解了
一般用另一种和另另一种 比较简便
//@Qualifer注解的另一种用法 这个就是用来指定名称的 可以加在属性上 也可以加在参数上
@Bean
public Student s2 ( @Qualifier("name2") String n ) 这样也可以区分
依赖注入 通常使用@Autowired和@Resource 对于参数通常使用@Qualifier
(4)Ioc和DI总结
context是spring的应用环境 是springIoc容器
beanFactory和Application的区别:
获取bean对象,是父类BeanFactory提供的功能 它有基础的访问容器的能力
ApplicationContext属于BeanFactory的子类,它除了继承了BeanFactory的所有功能外,还参加了对国际化支持,资源访问支持,以及事件传播等方面的支持
性能方面,ApplicationContext是一次性加载并初始化所有的Bean对象,而BeanFactory是需要哪个就去加载哪个 更加的轻量化(空间换时间)
4.0 常见面试题
(1)Autowired 和 @Resource的区别
@Autowired 是spring提供的注解 @Resource是jdk提供的注解
@Autowired 是依照类型注入 而@Resource是按照名称注入的 @Resource支持更多的参数设置
(2)Spring SpringBoot 和 Spring mvc的关系以及区别
spring 是框架 简化企业级应用程序的开发
主要功能是管理对象 以及对象之间的依赖关系 //面向切面编程 数据库事务管理 web框架支持

这个图片就是spring的部分 包含了Ioc和DI
springbootspringboot是对spring的一个封装 为了简化spring应用而开发出来的
中小型企业 没有成本研究自己的框架
springboot可以更加快速的搭建框架 降级开发成本 让开发人员更加专注于spring应用的开发
而无需关注一些xml配置和底层的实现
是基于spring进行开发
spring类似于火车 高铁,spring boot类似于12306 功能不局限于火车 引入一些第三方的工具 例如集成了tomcat 等
spring mvc
是spring的一个子框架 spring诞生之后 大家觉得很好用 于是按照mvc模式设置了一个mvc框架
主要用于开发web应用 和 网络接口
类似于火车站车票待售点

//以大楼为例子 也可以把spring理解为核心地基 钢筋结构 springboot为脚手架 springmvc是大楼门面和外部接待系统
(3)三种注入方式的优缺点
上面的第四点
(4)常见的注解有哪些 分别是什么作用?

ediayr笔记上面
二、SpringBoot配置文件
1.0 简介
(1)配置文件
电脑的配置文件 maven配置文件 ....... 配置文件一直在使用
配置文件的作用:
配置文件主要是为了解决硬编码带来的问题 把可能会发生改变的信息 放在一个集中的地方
当我们启动某个程序时 应用程序从配置文件中读取数据 并加载运行
硬编码:代码写死 例如每次打开某个软件 字数大小都是那样 但是不同的用户有不同的喜好
我们就可以把手机字体的大小放在配置文件中,当程序启动时,读取配置,以用户设置的字体大小来显示。
springboot的配置文件: 项目的启动端口 数据库的连接信息 第三方系统调用密钥等信息
(2)配置文件说明 properties
三种格式:Properties yml yaml-->yml是yaml的简写

默认的配置文件 application.properties 可以手动指定
如果同时存在properties和yml两个配置文件 两个文件同时生效
如果yml文件和properties设置内容冲突时 以properties为准
properties基本语法:
是以键值对的形式配置的 key和value之间是以 = 连接的 所有单词小写 单词之间用.分割
例: spring.datasource.username = root
properties的注释是一个#
配置数据库连接信息
@Value注解 : 把配置文件里面写好的配置值,直接 抓 到代码里面 不用在代码里硬写死
@Value(" {my.key } ") private String myKey ;
例:

@PostConstruct注解 初始化方法
public vodi init sout ( "mykey29"+mykey2)
spring创建完成某个bena 并把所有的属性(比如@Value注入的mykey)都赋值完成之后 会自动执行这个注解标记的方法 而且只执行一次
properties缺点分析:
properties配置文件中会有何怒都冗余的信息 例如:好几个开头都是spring.datasource
如何解决乱码问题:
改两个地方
file settings(表示改的是当前项目) 搜索encoding

能看到都改为utf-8
之前乱码的恢复不了了 但是之后不会出现乱码的问题了
new project setup(创建新项目的时候)

点开之后还是那个页面 还是都修改成utf-8
(3)配置文件说明 yml /yaml
yml基本语法:
yml的格式比较复杂 容易发生错误
空格不可以省略 port前面也有
相当于porperties .换为空格
当有共同前缀的时候 
例:
对齐的地方表示属于一级(类似于文件系统) url和username和password上一级是datasource datasource的上一级是spring
自定义key:

理解:如果是string格式 就是那个hello 而且这个hello是可以自己更改的

null是关键字 不可以把null放到配置文件里面 会报错
~表示null值 它相当于Java中的null 如果某个配置项没有值 可以显式写成~来表示空
读取:
简单解释一下代码 @Controller注解 让spring管理 自动创建对象
@PostConstruct自动初始化方法 这两个注解结合起来实现

配置对象:
@ConfigurationProperties(prefix = " ")注解:
把配置文件(yml/properties)里所有以person为前缀的配置项 一次性抄写到当前类的属性里 不用像@Value那样挨个读

配置集合:
//类的生命周期 实例化 依赖注入 初始化方法 使用 销毁

配置Map:
配置集合 配置map等 要放在对象里面
spring读不了孤立的集合/map 集合/map是归属某个对象的属性
例如公告栏上面只贴打球 跑步 看书 音乐(孤立的集合) 别人看到会问"这是谁的爱好?"
你必须贴好 这个是张三的爱好 把集合/map归类到张三这个对象下面
yml优缺点:
优点:可读性高 写法简单 易于理解
支持更多的数据类型 可以简单表达对象 数据 list map等数据形态
支持更多的编程语言 不止是Java中可以使用 在golang python ruby javaScrpit中也可以使用
缺点: 不适合写复杂的配置文件 不适合写稀疏的文件
对于格式有比较强的要求 (一个空格可能会引发一场血案)
三、验证码案例
1.0 验证码案例
(1)简介

//贴这个图片单纯无聊 感觉好看哈哈
验证码的实现方式很多 可以前端实现 也可以后端实现
网络上也有比较多的工具包 之前验证码是为了区分人与机器的 仙现在机器也能操作验证码了
很多厂商开始和电话合作 发送那种短信的验证码 (需要付费)
效果展示图:

(2)需求
如何实现:
验证码:随机字符串+干扰元素
字符串可以来个数字集 字符集 汉字集等 放在一个数组里面 干扰元素:可以是横线 可以是曲线
一张图片 里面放那个字符集 随机两个点 生成一些线段 贴上字符

滑动拼图验证码 只要是有个图片集 叠加 拿到坐标传递给后端 后端对比坐标
准备工作:
hutool工具 简介 | Hutool
在hutool上面 看不懂介绍 看不懂代码 先复制下来 放到ieda项目的test模块中 或者自己创建一个项目试一试
引入依赖 设置好版本号 在测试类里面尝试
定义接口:
1.返回验证码 后端返回一个验证码
请求URL : cpatcha / getCaptcha
响应:验证码图片内容
2.校验 验证码是否正确
请求URL :cpatcha/check 请求参数:captcha=xn8d
响应:true false
优化:
把图片验证码的大小放到配置文件中
http是无状态的 为了保存用户的信息 采用的是session和cookie+
写response写到最上面
2.0 问题:
(1) 静态内部类
静态内部类可以独立存在 而实例内部类必须依附于外部类的对象
假如我们要设计一个Person类,每个人都有一张身份证,身份证属于这个人,但是身份证本身就是一个独立的概念 不需要访问其他人的属性
(2)session
验证码的session的key写死了 那么多个用户请求验证码的时候是不是会有错? //并发的情况

知识准备:
session 存储用户信息的会话机制 之前也记录过 这个session像是图书馆的借阅记录 就是后端的记录机制 cookie是后端和前端沟通的桥梁,cookie是后端发给前端的
cookie通常不会直接存储session的数据 而是存储一个唯一标识符(Session ID) 因为HTTP是无状态的嘛 每次发送请求的时候 cookie会自动附带在HTTP的头部发送给服务器
当用户第一次访问服务器的时候,服务器会生成一个Session 并创建一个对应的Session ID
服务器通过Set-Cookie响应头 将这个Session ID发送给浏览器 浏览器将其保存为Cookie
后续每次请求,浏览器会自动在Cookie中带上这个SessionID 服务器根据接收到的Seesion ID 在内存或者数据库查找对应的Session数据 从而识别用户
过程:
1用户1获取验证码,后端获取的Session 为空,会创建一个对象 //这个对象包含session ID 对应一个session对象 这个对象里面是key value结构
2服务端进行返回 会把Seesion通过Set-Cookie返回
3客户端接收到响应 发现header有set-Cookie 就会把信息存储在客户端
4用户2发起请求 重复的上面的123步骤 此时得到如下结果

//这里分别用chrome浏览器和edge浏览器模拟不同的客户端
5用户1校验验证码 发送请求的时候 携带Cookie信息 Cookie里面的seesion ID信息获取到 session
tomcat本身就是一个线程池 支持多线程 当请求来的时候,这个请求从tomcat里面获取一个请求 下一个请求来的时候 再从tomcat里面获取一个请求 所以我们开发的时候 不用考虑多用户的场景 线程的安全性是服务器本身就保证了的
总结:多个用户请求验证码的时,即使Seesion的Key写死,也不会出错。因为每个用户有独立的Session对象 数据互不干扰 并发场景下,服务器通过多线程和Session的隔离机制 保证了安全性
例:下面是我们一个客户端发起多次请求 客户端自动匹配的多线程模式 看日志我们就能看到这些记录

四、spring日志
1.0 简介
(1)为什么学习日志
之前使用的代码System.out.print来打印日志
虽然感觉这个概念有点陌生 但是其实我们早已在不知不觉中用了好多次了
比如前端页面 出现问题的时候 我们去按F12 在控制台找错误在第几行代码 这个就是一个日志
比如程序突然崩溃 我们不会一行一行看代码哪里错了 而是去控制台看错误日志 这里错误日志就是日志的一部分..........
随着项目复杂度的上升,我们对打印的日志也有了更高的要求 而不仅仅是定位和排查问题
比如需要记录一下用户的操作记录 也可能需要日志来记录用户的一些喜好 把日志持久化,后续进行数据分析等 sout 不能很好的满足我们的需求 我们就需要使用一些专门的日志框架
通俗的例子:
sout时代 你只能在开发时看"订单已经创建""数据库连接成功 " 关掉DEA就没有了
专业的日志时代:记录下每个用户的下单时间 点的菜品 口味偏好(数据持久化 存在服务器)
运营人员月底分析日志:发现80%的用户点微辣 于是推出"微辣套餐促销"
如果某天气系统崩溃,运维查看错误日志,迅速定位到"数据库连接池满"并扩容
(2)日志的作用
除了之前的发现问题 分析问题 定位问题外 日志还有很多用途
系统监控 :监控每一个方法的运行时间 响应时间 运行点等等
数据采集:浏览量 访问量 排序(浏览时长排名等) 后续其他的算法人员 大模型人员根据这些数据分析用户喜好 然后做相关的喜好推荐
日志审计:网络安全越来越受到大家的关注 系统安全也成为一个重要的环节
安全审计也是系统中非常中非常重要的部分 通过系统日志分析,可以判断一些非法攻
击 非法调用 以及系统处理过程中的安全隐患
网络上面的任何行为都是有痕迹的
(3)springboot的日志

时间 日志级别 进程ID 应用名称 线程名称 类的路径 日志内容 .....
类的路径这里,有一套规范
如何打印idea这样的日志呢?
spring内置的日志框架: org.slf4j

日志框架(了解):
四个日志框架 (上面图片勾住的红色的内容)
区别是什么:了解即可

日志门面,日志实现
SLF4J:通用遥控器 可以用很多 其他的三个是日志实现 日志实现可以单独使用
充电线没有统一的时候 有很多种 现在的充电线统一好多了
SLF4J框架:
Simple Looging Facade Java --->Java简单日志门面

不引入日志门面有很多问题,这里不在一一赘述,引入日志门面框架之后,应用程序和日志框架(框架的具体实现)之间有了统一的API接口
此时应用程序只需要维护一套日志文件配置 SJF4J就是其他日志框架的门面,SLF4J可以理解为是提供日志服务的统一API接口,并不设计到具体的日志逻辑实现
常见的日志框架有很多:log4J logback等
外观模式:
门面模式又称做外观模式 重思想轻代,代码的实现有很多种
提供了一个统一的接口 用来访问子系统的一群接口
其主要特征是定义了一个高层接口 让子系统更容易调用

门面模式的实现:
两种角色 门面角色 系统对外的统一接口
子系统角色可以同时拥有一个或者多个子系统角色 每个子系统角色都不是一个单独的类,而是一个类的子集合 子系统角色并不知道门面角色的存在 对于子系统而言,门面角色只是另一个客户端而已
场景:进家开灯 出门关灯
实现:创建一个客户端Main 还有卧室类 厨房类 客厅类等等 这些子类都是实现light接口
FacadeLight类 希望用这个类来关闭所有的灯 里面创建了卧室对象厨房对象灯 里面的重写方法都调用了每个房间的开灯 客户端Main开灯直接调用FacadeLight类的方法就可以了
(4)日志级别
为什么要有日志级别分类:就像是老板想要管理公司 但是不能大大小小的事情都来找老板把
级别:FATAL ERROR WARN INFO DEBUG TRACE

翻译单词: fatal 致命 error 错误 warn 警告 info (information)信息 debug 调试 trace 追踪
如何打印不同级别的日志:
logger.inf0()

日志默认级别是info 低于info级别自动不打印
但是这个默认级别也是可以调整的
配置文件里面修改

这里的root是根目录的意思
哇咔咔 出来好多啊 满满的几屏幕 而且还在一直加 好多好多好多 哈哈哈 好玩

如果想要对单独某个文件的日志修改 跟在下面

(5)日志持久化
引入: 重启了项目之后 之前的日志没有了 这个时候怎么办?
日志不存 出事抓瞎 日志存了 有据可查
两种方式:
1配置日志文件名
logging.file.name= logger.springboot.log //yml格式就不演示了
//写好之后 记得刷新一下


file也可以配置路径: file : name: log/log.log

2配置日志的存储目录
logging.file.path

这样直接存储到电脑的硬盘上面了 甚至可以logger/log.log 此时logger是一个文件夹
优先级:

如果两种配置同时存在 以logging.file.name为主
(6)日志文件分割
日志是堆积的 长年累月 如果一个日志文件动不动几个G 容易打不开
//这里如果可以规定 日志文件超过xxx可以分割
默认的是超过10M



也可以指定划分的文件的名称
file-name-pattern:&{LOG_FILE}.%d{yyyy-MM-dd}.%i.gz %d表示日期 yyyy-MM-dd表示日期的格式


通常情况下 运维人员负责清理日志
(7)配置日志格式

%clr(表达式){ 颜色 } 设置输入日志的颜色
%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}} ⽇期和时间--精确到毫 秒
%5p 显⽰⽇志级别ERROR,MARN,INFO,DEBUG,TRACE.
%t 线程名. %c 类的全限定名. %M method. %L 为⾏号. %thread 线程名称. %m 或者
%msg 显⽰输出消息. %n 换⾏符
%5 若字符⻓度⼩于5,则右边⽤空格填充. %-5 若字符⻓度⼩于5,则左边⽤空格填充. %.15 若
字符⻓度超过15,截去多余字符. %15.15 若字符⻓度⼩于15,则右边⽤空格填充. 若字符⻓度超
过15,截去多余字符
(8) 更简单的日志输出
lombook给我提供了一种更简单的方式
使用@slf4j注解输出日志
过程:
添加lombok依赖: //这样实现了使用注解打印日志

加上这个注解 自动生成log对象 我们直接使用就可以了 这种做法也是spring的特点--->注解