在之前学过了Spring,Spring是简化Java开发,但是Spring还是有点麻烦,而Spring Boot就是简化Spring程序开发
Spring Boot翻译过来就是Sping的脚手架,盖房⼦的这个架⼦就是脚⼿架,脚⼿架的作⽤是砌筑砖墙,浇筑混凝⼟、⽅便墙⾯抹灰,装饰和粉刷 的,简单来说,就是使⽤脚⼿架可以更快速的盖房⼦
接下来可以对比一下Spring Boot和 之前学的Servlet操作难易程度
1.创建maven项目
2在pom.xml中引入相关的依赖
3.创建一些特定的目录来存放静态网页文件之类的
4.写代码
5.打包
6.部署
在之前的博客系统中,其实遇到了很多的问题和重复的步骤,这也是Servlet的几个缺陷
1 在添加一些jar包时,需要跟别的一些配置匹配,比如Tomcat的版本号和JDK的版本和mysql的版本,这需要我们在导入ja包之前明确你具体要的版本对应的上才可以
2.tomcat是外置的Web容器,在启动的时候,需要Tomcat带着我们的代码跑,每次修改完之后还要重新启动Tomcat来运行
3.路由配置很不方便,因为Servlet是一个类对应着一个二级路径,这导致我们需要创建很多类,容易搞混
最主要的是在Servlet层面,很多冗杂且重复的代码都要大量编写,但是在Spring Boot中是不需要的,它本身就通过注解的方式来帮我们进行处理
1 Spring Boot本身就提供了启动添加依赖的功能,可以用于快速去集成框架,也不用去考虑版本是否对应…
2 他自己就内置了Tomcat容器,所以当你只是运行项目的时候,就会启动Tomcat,直接运行和部署项目
3.可以完全抛弃繁琐的 XML,使⽤注解和配置的⽅式进⾏开发
4.调试项⽬更加⽅便,⽆需配置 Tomcat;
5 发布项⽬更加⽅便,⽆需配置 Tomcat;
6. 添加路由更加⽅便,⽆需每个访问地址都添加⼀个类
了解了Servlet和Spring Boot的区别,我们要学框架的目的更明显,为了提高开发的速度,框架的学习是接下来要重点关注的.
Sring Boot创建可以分为两种,
一种是通过IDEA来进行创建
第二个就通过Web创建
由于博主使用的是社区版,所以需要同第三方插件来创建
1.先下载 Spring Assistant 插件
注意:
第⼀次打开 Spring Boot 项⽬需要加载很久,因为当前 Spring Boot 框架并没有在⾃⼰的本地仓库
为了加速 Spring Boot 项⽬的下载,在打开项⽬之前,请先确认⾃⼰的 Maven 已经配置为国内源:
这里的Override的勾选的意思解释一下:
当你通过xml去下载依赖的时候,会在你配置的国内源或者国外源的配置文件下去寻找,如果你没有的话,你需要去拷贝一份放在该目录下面,如果你有的话,可能是国外源导致下载的特别慢甚至中断,这个时候你可以去配置国内源
alimaven
aliyun maven
http://maven.aliyun.com/nexus/content/groups/public/
central
第二个路径就是存储我们之前下载到本地的jar包,但是有一个问题就是,假设在下载某个jar包的时候,网络突然中断了,这个时候该jar只下载了一部分,但是在导入依赖的时候,先去本地仓库去找这个jar包,结果发现存在这个jar,就直接拿去用了(实际上是个半成品),那么到时候运行项目的时候就出问题了,所以需要把这个本地仓库下载的jar都删了重新下是最好的选择
勾选Override的目的覆盖默认的配置文件,而是在我们选的路径下去寻找仓库配置
我们在pom.xml中看见,这里的依赖实际上只有关于spring boot的,那些依赖是添加在spring boot框架里了
不使⽤ Idea 也可以创建 Spring Boot 项⽬,我们可以使⽤ Spring 官⽅提供的⽹⻚版来创建 Spring Boot 项⽬。
⽹⻚版创建项⽬先访问:https://start.spring.io,如下图所示:
点击⽣成按钮会下载⼀个 Spring Boot 的 zip 包,解压 zip 之后⽬录如下:
当然我这里是,没解压,只是演示一下,到时候解压完成用IDEA来打开就好了
我们学习 JavaEE 就是⽤来实现 Web 项⽬或接⼝的,⽽之前是 Spring 其实是⼀个普通 Java 项⽬,没 办法直接和浏览器进⾏互动,所以接下来我们要⽤ Spring Boot 来实现和浏览器及⽤户的交互。
但是有一点很重要,如果你没注意就不会打印你想要的结果
关于注入的位置是很重要的一点,把注入类放到启动类的同一级或者子集中,这也恰恰说明spring boot的另一个特点就是:
约定大于配置
对⽐ Spring 的项⽬我们也可以看到这⼀特点,⽐如在 Spring 中也是要配置 Bean 的扫描路径的,⽽ Spring Boot 则不需要,Spring 配置如下:
但是spring boot不需要的原因是已经约定好了,而你也必须遵守它的约定才行.
总结:
整个项目的重要数据都在配置文件中配置的,比如:
那有人就会说为啥不把这个数据库的连接写到代码中去呢???
因为写到代码里面去是不容易修改的,因为运维工程师本身把项目放到linux中去部署项目,并且让项目在服务器上稳定运行的.
1.运维人员大部分不懂Java代码,不一定会修改Java代码
2.开发人员编译的包是jar包格式,生成的class文件,是不允许修改的,除非你放到配置文件里面去才能进行修改
这也就是为什么要把这些重要信息放到配置文件中而不是代码中,这也是为了运维人员能操作和更方便的去修改
知道了为什么要有配置文件这个东西并且和它的重要性,接下来我们可以去修改配置文件里面的内容试试水,在修改之前,我们先去了解一下它的格式
配置文件格式主要是分为两种格式:
这就好像连锁店⾥⾯的统⼀服装⼀样,有两种不同的款式,properties 类型的配置⽂件就属于⽼款“服 饰”,也是创建 Spring Boot 项⽬时默认的⽂件格式(主要是由于仓库⾥还有库存),⽽ yml 属于新版 款式,如果⽤户了解情况直接指定要新款服饰,那么就直接发给他。
实际上在一个项目中.yml和properties两种配置文件是可以共存的,也就表明一个项目是可以不止拥有一种配置文件
当 properties 和 yml ⼀起存在⼀个项 ⽬中时,如果配置⽂件中出现了同样的配置,⽐如 properties 和 yml 中都配置了“server.port”,那 么这个时候会以 properties 中的配置为主,也就是 .properties 配置⽂件的优先级最⾼,但加载完 .properties ⽂件之后,也会加载 .yml ⽂件的配置信息
当在两个配置文件中都设置相同的属性的时候,还是有限以老版的properties的配置信息为主
我这里修改的端口号被占用了,也就说明是尝试在使用这个properties配置,但是yml那边同样去修改端口号是没反应的,所以也就证实了这一点.
IDEA 社区版安装 Spring Assistant 插件之后,就可以正常创建 Spring Boot 项⽬了,并且 yml 的配置 ⽂件就有提示了。但默认情况下是不⽀持 properties 格式的⽇志提示的,这个时候需要安装了 Spring Tools 插件才会有相应的提示。
properties 配置⽂件是最早期的配置⽂件格式,也是创建 Spring Boot 项⽬默认的配置⽂件
基本语法:
properties 是以键值的形式配置的,key 和 value 之间是以“=”连接的,如:
/# 配置项⽬端⼝号
server.port=8084
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/testdb?
characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
" # "是注释信息
还有一种就是 yml它本身就天生支持中文的,但是properties是不支持的,需要修改一下properties
记住,这里配置encoding不仅仅是当前项目,还有setting for new projects关于新项目的配置
在项目中想要读取配置稳健的信息,需要使用 @Value 注解来实现
@Value 注解使⽤“${}”的格式读取,如下代码所示
你要想一次性读取多个就不是@Value了,后面会介绍,暂时你可以用的多个@Value可以读取多个信息
porperties的缺点分析
在pro[erties中会有很多这种冗余信息,实际上在yml中是可以简化的
yml 是⼀个可读性⾼,易于理解,⽤来表达数据序列化的格式。它的语法和其他⾼级语⾔类似,并且可 以简单表达清单(数组)、散列表,标量等数据形态。它使⽤空⽩符号缩进和⼤量依赖外观的特⾊
特别适合⽤来表达或编辑数据结构、各种配置⽂件等。
yml 最⼤的优势是可以跨语⾔,不⽌是 Java 中可以使⽤ golang、python 都可以使⽤ yaml 作为配置⽂件。
yml 是树形结构的配置⽂件,它的基础语法是“key: value”,注意 key 和 value 之间使⽤英⽂冒汗加空 格的⽅式组成的,其中的空格不可省略
这样一来就很简化代码,他和json是比较像的,注意的是yml的格式 如果你不需要树形那种多层次,那你也不要忘记" : " 和空格
yml 读取配置的⽅式和 properties 相同,使⽤ @Value 注解即可,实现代码如下:
这里配置的是一些不同的数据类型
# 字符串
string.value: Hello
# 布尔值,true或false
boolean.value: true
boolean.value1: false
# 整数
int.value: 10
int.value1: 0b1010_0111_0100_1010_1110 # ⼆进制
# 浮点数
float.value: 3.14159
float.value1: 314159e-5 # 科学计数法
# Null,~代表null
null.value: ~
扩展知识:
尝试在 application.yml 中配置如下信息:
string:
str1: Hello \n Spring Boot.
str2: 'Hello \n Spring Boot.'
str3: "Hello \n Spring Boot."
@Component
public class ReadYml {
@Value("${string.str1}")
private String str1;
@Value("${string.str2}")
private String str2;
@Value("${string.str3}")
private String str3;
@PostConstruct
public void postConstruct() {
System.out.println("string.str1:" + str1);
System.out.println("string.str2:" + str2);
System.out.println("string.str3:" + str3);
}
}
假设我们创建一个Stduent类,然后再配置信息中去配置这个Studnet
或者这种写法:
那么这里通过@Value注解是不能读取对象的
这里创建Student,加上了 Date注解,它本身就是属于我们的lombok框架的,这样打印学生类会通过tostring()方法来打印
如果想要去获取对象,还需要在实例类上面再加一个注解叫做 @ConfugurationProperties注解,它的作用就是读取配置文件中对象
但是还是不够,要在项目启动的时候就要读取,所以需要把这个类也注册到spring boot项目中,还需要再加入一个五大类注解之一
这样就可以用他了,之前加了Component,他已经是一个组件了,你完全可以通过注入类的方式来使用他了
当想读取student2的时候,你只需要将student换成student2就好了
配置⽂件也可以配置 list 集合
数据量不大是可以考考虑行内的写法,易读性可以的,接近于json格式集合的读取和对象⼀样,也是使⽤ @ConfigurationProperties 来读取的,具体实现如下:
dbtypes就是集合的名字,里面的属性是name
然后我们创建一个类,还是加@ConfugurationProperties注解,你可以加上prefix,不加的话就是默认这个,然后这个类中按照
private List name这种格式
这个name 和 dbtypes一定要相对应
然后我们在打印类中中就直接去注入类 (ListConfig)
readList就是ListConfig类,这里getName就是获取注入类的名字也就是name属性
这里配置集合和获取集合是比较麻烦的
扩展
通过这个PropertySource注解可以去读取某个配置文件,这对我们还是有用出的
Spring Boot的日志是很重要的,最容易理解的就是 程序员可以通过日志去快读定位和排除问题
除了发现和定位问题之外,我们还可以通过⽇志实现以下功能:
以上这些都是⽇志提供的⾮常实⽤的功能。
日志它本身还可以去记录用户的登录,这样我们可以在短时间内查询到某一个用户是否是正常登录还是恶意破解(暴力破解)
而且记录下程序的执行时间,可以更快的帮我们优化程序
日志真实使用案列:
关键节点上的关键数据⽇志记录举例:例如,⽐如咱们的教务系统,在注册时候不⽌要在教务系统添加 ⼀条⽤户记录,同时也会给⽐特论坛添加⼀条⼀模⼀样的⽤户记录,这样做的⽬的是为了实现⼀次注 册,多处使⽤的⽬的。不需要⽤户在两边系统注册了,等于在程序中以极低的成本实现的⽤户数据的同 步,但这样设计有⼀个致命的问题,⽤户在教务系统注册信息的时候,如果论坛挂了,那么⽤户的注册 ⾏为就会失败?因为⽤户在注册的时候需要同步注册到论坛系统,但论坛现在挂了,这个时候怎么办 呢?
最简单的解决⽅案,教务系统在注册的时候,不管论坛是否注册成功,都给⽤户返回成功,那这个时候 如果论坛注册失败了怎么办?⾮常简单,如果注册失败了,记录⼀下⽇志,等论坛恢复正常之后,把⽇ 志给论坛的管理⼈员,让他⼿动将注册失败的⽤户同步到论坛系统,这样就最低成本的解决了问题。这 就是⽇志的重要作⽤。
这样的案列就体现出日志的重要性了
那么日志该怎么用???
Spring Boot 项⽬在启动的时候默认就有⽇志输出,如下图所示:
这就是控制台打印的日志信息
1.首先,Spring Boot框架就内置日志框架供我们使用(不然我们无法去输出日志)
2.控制台的日志是无法永久存储的,下一次项目运行后,该日志就被覆盖了
这是spring boot默认打印的日志,程序员要是想自定义的去打印日志该怎么办呢???
实现步骤:
如何去获取日志对象呢???
注意了,这里Logger 和 LoggerFactory的归属类都是 Slf4j
那么 SLF4J它本身就是一个日志框架
其实这里面涉及到一个设计模式叫做 : 门面设计
就是实际上我们使用的是SLF4J,其实内部还是通过logback来实现的
那么SLF4J就是一个门面,这样的设计好处有利于调用者不需要去关注内部发生,或者如果logback出了问题,门面不需要改动,我们只需要去将logback换成JUL或者log4j 1/2 这种,底层的改动不需要被人知道或者做出变化
一开始的时候我们去运行项目,打印的还是默认的日志,我们创建了日志对象并且传入的是UserController类型之后,只有当你去游览器访问到这个sayhi方法的之后,自定义日志才会打印出来
png)
我们先去通过日志工厂传入类类型,然后创建logger对象,然后通过log引用去调用日志级别即可
我先说个扩展知识:
在代码中,我加了两个注解,其中RequestMapping就是设置路由地址的,大家都很清楚,但是这个@ResponseBody这个注解,我注释的是返回一个非静态页面是实际上有点抽象
关于ResponseBody这个注解,是这样的,如果你加了这个注解,你的返回值就是作为responsebody的正文显示到游览器的页面上,如果你不加这个注解,你的返回值就是作为某一个html跳转路径来将进行跳转
扩展知识说完了
接下来就是基于上面的打印结果来进行分析
很明显在代码明明要求打印五条信息,但是在控制台只打印了三条,这是因为在不改变spring boot的日志默认级别的时候,只去打印该默认级别和以上的日志信息.
⽽⽇志分级⼤概的道理也是⼀样的,有了⽇志级别之后就可以过滤⾃⼰想看到的信息了,⽐如设置⽇志 级别为 error,那么就可以只看程序的报错⽇志了,对于普通的调试⽇志和业务⽇志就可以忽略了,从 ⽽节省开发者的信息筛选时间
首先这种重要配置是需要在配置文件中进行的
上面也说了.局部日志级别是 > 全局日志级别的,当你局部的级别和全局有冲突的话,肯定是优先以局部为主
以上的⽇志都是输出在控制台上的,然⽽在⽣产环境上咱们需要将⽇志保存下来,以便出现问题之后追 溯问题,把⽇志保存下来的过程就叫做持久化。
实际上就是把日志保存到磁盘的某个位置上去(持久化存储)
lombok本身就是一个框架
里面有很多注解供我们使用,提升了很大的开发效率
每次都使⽤ LoggerFactory.getLogger(xxx.class) 很繁琐,且每个类都添加⼀遍,也很麻烦,这⾥讲⼀ 种更好⽤的⽇志输出⽅式,使⽤ lombok 来更简单的输出。
这里有添加一个扩展知识
在最初创建spring boot项目的时候,一开始我们就是可以添加框架进去的,但是呢后来在写代码写一半的时候发现突然需要添加的某一个忘记添加了,这个时候如何去添加呢???
就拿这个lombok为例来说
其实是需要下载一个叫做 Eidt Starters的插件,下载完之后,在pom.xml文件中右键generate点击这个插件就可以去中途添加了
扩展知识结束之后,继续lombok
lombok它本身的很多注解就是供我们去简化开发
针对每次都要去创建log对象然后再去打印日志就很麻烦,只需要在该类上加上一个@Slf4j注解就可以了
注意:使⽤ @Slf4j 注解,在程序中使⽤ log 对象即可输⼊⽇志,并且只能使⽤ log 对象才能输出,这 是 lombok 提供的对象名
因为不需要去手动创建log对象,后面默认的对象名就是log
为什么呢???
这就需要去解释一下lombok的工作原理
lombok 能够打印⽇志的密码就在 target ⽬录⾥⾯,target 为项⽬最终执⾏的代码,查看 target ⽬录如 下:
那么最初我们是在.java源码上加的@Slf4j注解,但是呢通过看到变异之后的字节码才反应过来,实际上编译器在编译的时候是将注解转换成了该注解表示的代码
lombok的工作原理
包括了 @Slf4j注解 — 创建日志对象(对象名就是log)
⽇志是程序中的重要组成部分,使⽤⽇志可以快速的发现和定位问题,Spring Boot 内容了⽇志框架, 默认情况下使⽤的是 info ⽇志级别将⽇志输出到控制台的,我们可以通过 lombok 提供的 @Slf4j 注解 和 log 对象快速的打印⾃定义⽇志,⽇志包含 6 个级别:
trace:微量,少许的意思,级别最低;
info:普通的打印信息;
debug:需要调试时候的关键信息打印;
warn:警告,不影响使⽤,但需要注意的问题;
error:错误信息,级别较⾼的错误⽇志信息;
fatal:致命的,因为代码异常导致程序退出执⾏的事件
⽇志级别依次提升,⽽⽇志界别越⾼,收到的⽇志信息也就越少,我们可以通过配置⽇志的保存名称或 保存⽬录来将⽇志永久地保存下来