Spring的诞生是为了简化 Java 程序的开发的,Spring Boot 的诞生是为了简化 Spring 程序开发的.
Spring Boot 是所有基于 Spring 开发的项目的起点 . Spring Boot 的设计是为了让你尽可能快的跑起来 Spring 应用程序并且尽可能减少你的配置文件 . Spring Boot是在Spring的基础上面搭设的框架,目的是为了简化Spring项目的搭设和开发过程 .
- 快速集成框架,Spring Boot 提供了启动添加依赖的功能, 于秒级集成各种框架 ;
- 内置运算容器, 需配置 Tomcat 等 Web 容器,直接运行和部署程序 ;
- 快速部署项目,⽆需外部容器即可启动并运⾏项⽬ ;
- 可以完全抛弃繁琐的 XML,使用注解和配置的⽅式进⾏开发 ;
- ⽀持更多的监控的指标,可以更好的了解项⽬的运⾏情况 .
Step1:安装 Spring Boot Helper 插件.
Step2:新建一个Spring Boot项目.
Lombok是一个Java库,能自动插入编辑器并构建工具,简化Java开发 . 通过添加注解的方式,不需要为类编写getter或equals方法,同时可以自动化日志变量 .
spring为开发者提供了一个名为spring-boot-devtools的模块来使Spring Boot应用支持热部署,提高开发者的开发效率,无需手动重启Spring Boot应用 .
spring web 包含web应用开发时,用到spring框架时所需的核心类,包括自动载入webapplicationcontext特性的类、struts与jsf集成类、文件上传的支持类、filter类和大量工具辅助类 .
这是整体的项目结构 :
Step3:编写代码
新建TestController类并编写代码 :
添加maven框架支持 :
Step4:删除掉无用的maven插件文件.
Step5:运行项目,检验结果正确性
可以手动修改端口号 :
Step1:直接新建一个Spring Boot项目.
会得到一个压缩包 :
Step2:解压文件,放置在你需要放置的目录下,并使用IDEA打开项目.
这里我放在C盘下. (顺便改了个名)
Step3:删除无用的maven插件文件并编写代码[参考3.1]
Step4:运行项目,检验结果正确性
成功 !!!
Spring中Boot有一个核心的要点 : 约定大于配置 !
比如 , 如果我们希望TestController能够被项目识别到 , 它必须和Demo1Application放在同一目录下 .
其中 , Demo1Application含有注解@SpringBootApplication .
再比如 , 如果希望配置文件生效 , 配置文件必须以application开头 .
整个项目中所有重要的数据都是在配置文件中配置的, 如:
主要有2种 :
.properties
.yml
properties 配置文件是最早期的配置文件格式,也是创建 Spring Boot 项目默认的配置文件.
使用@value注解实现.
@Value 注解使用“${}”的格式读取,如下代码所示 :
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
//读取系统配置项
@Value("${server.port}")
private Integer port;
//读取用户配置项
@Value("${mykey.key1}")
private String mykey;
@RequestMapping("/say")
public String say() {
return "我喜欢" + mykey + "当前端口号是" + port;
}
}
注意 : 如果想正确识别中文 , 一定要修改字符集配置 , 如下图所示 :
yml 是 YAML 是缩写,它的全称 Yet Another Markup Language 翻译成中文就是"另一种标记语言".
大小写敏感
使用缩进表示层级关系
缩进不允许使用tab,只允许空格
缩进的空格数不重要,只要相同层级的元素左对齐即可
'#'表示注释
对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
纯量(scalars):单个的、不可再分的值
一级目录
多级目录
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Value("${mykey}")
private String kunkey;
//读取系统配置项
@Value("${server.port}")
private Integer port;
//读取用户配置项
@RequestMapping("/say")
public String say() {
return "我喜欢" + kunkey + "当前端口号是" + port;
}
}
运行结果 :
如果我们在properties和yml中出现了相同名称的自定义配置呢 ? 比如如下这种情况 :
仍然进行读取 :
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Value("${mykey.key1}")
private String same;
@RequestMapping("/say")
public String say() {
return "我喜欢" + same;
}
}
运行结果 :
这说明properties的优先级高于yml .
前面谈到yml支持多种数据类型 , 下面一一介绍 :
先举一例 :
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Value("${string.value}")
private String str;
@RequestMapping("/say")
public String say() {
return str;
}
}
application.yml
string.value: Hello
运行结果 :
同时支持的数据类型还有 :
# 字符串
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: ~
student:
id: 1
name: zhangsan
age: 20
或者是使用行内写法 :
student: {id: 1,name: zhangsan,age: 18}
这个时候就不能用 @Value 来读取配置中的对象了,此时要使用另一个注解
@ConfigurationProperties 来读取,具体实现如下:
package com.example.demo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "student")
@Component
public class Student {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
@RestController
public class StudentInfoRead {
@Autowired
private Student student;
@PostConstruct
public void readStudentInfo() {
System.out.println(student);
}
@RequestMapping("/say")
public Student say() {
return student;
}
}
运行结果 :
解释 :
总结 :
参考文章 :
原始写法
mylist1:
talent:
- sing
- jump
- rap
- basketball
行内写法
mylist2: {talent: [sing,jump,rap,basketball]}
创建一个实体类 :
package com.example.demo.model2;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@Getter
@Setter
@ConfigurationProperties(prefix = "mylist1")
@Component
public class MyList {
private List talent;
}
进行读取 :
package com.example.demo.model2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class readList {
@Autowired
private MyList talent; //talent是集合名称
@RequestMapping("/list")
public MyList func() {
return talent;
}
}
运行结果 :
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Value("${mykey.str1}")
private String str1;
@Value("${mykey.str2}")
private String str2;
@Value("${mykey.str3}")
private String str3;
@RequestMapping("/say")
public String say() {
System.out.println("str1 : " + str1);
System.out.println();
System.out.println("str2 : " + str2);
System.out.println();
System.out.println("str3 : " + str3);
return "测试yml的字符串修饰符问题!";
}
}
以数据库配置为例
application-dev.yml
server:
port: 8888
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/blog_system?chararcterEncoding=utf8
username: root
password: 12345678
mykey:
key1: dev
application-prod.yml
server:
port: 11111
spring:
datasource:
url: jdbc:mysql://yyyy:3306/blog_system?chararcterEncoding=utf8
username: root
password: 12345678
mykey:
key1: prod
application-test.yml
server:
port: 9999
spring:
datasource:
url: jdbc:mysql://xxxx:3306/blog_system?chararcterEncoding=utf8
username: root
password: 12345678
mykey:
key1: test
在主配置文件中设置环境 :
application.yml
spring:
profiles:
active: dev
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Value("${mykey.key1}")
private String key;
@RequestMapping("/say")
public String say() {
return "这是一个" + key + "的配置文件";
}
}
运行结果 :
同时可以查看端口号 :
可以实现在不同的IP地址访问同一数据库操作 .
日志是程序的重要组成部分,想象一下,如果程序报错了,不让你打开控制台看日志,那么你能找到报错的原因吗?
除了发现和定位问题之外,我们还可以通过日志实现以下功能 :
Spring Boot在启动的时候 , 也有默认的日志 , 比如这些 :
日志对象的打印方法有很多种,我们可以先使 info()来输出日志,代码如下所示:
package com.example.demo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
//1.得到日志对象
private Logger logger = LoggerFactory.getLogger(TestController.class);
@Value("${mykey.key1}")
private String key;
@RequestMapping("/say")
public String say() {
logger.info("------------这是我自己打印的日志------------");
return "这是一个" + key + "的配置文件";
}
}
运行结果 :
因为 Spring Boot 中内置了日志框架 Slf4j,所以咱们可以直接在程序中调用slf4j 来输出日志 .
以上的日志都是输出在控制台上的,然而在生产环境上咱们需要将日志保存下来,以便出现问题之后追溯问题,把日志保存下来的过程就叫做持久化.
介绍两种方法:
1.设置日志的名称;
2.设置日志的保存路径.
logging:
file:
name: springboot.log
启动项目 , 查看项目路径 :
再次运行项目 :
说明 :
logging:
file:
path: C:\\logtest
package com.example.demo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
//1.得到日志对象
private Logger log = LoggerFactory.getLogger(TestController.class);
@Value("${mykey.key1}")
private String key;
@RequestMapping("/say")
public String say() {
log.trace("Hi,i am trace.");
log.debug("Hi,i am debug.");
log.info("Hi,i am info.");
log.warn("Hi,i am warn.");
log.error("Hi,i am error.");
return key;
}
}
运行结果 :
大家可能会奇怪了 , 我的trace和debug的信息为什么没有在控制台输出呢 ? 这就涉及到日志级别问题了 .
日志级别顺序 :
他爹级别低 , IWEF级别高 . (仅用于助记)
越往上接收到的消息就越少,如设置了 warn 就只能收到 warn、error、fatal 级别的日志了 .
日志级别配置只需要在配置文件中设置“logging.level”配置项即可 :
#设置根路径的日志级别
logging:
level:
root: debug
运行效果如下 :
此时控制台的输出就包含了许多debug级别的日志了 .
访问网页 , 观察控制台输出 :
#设置自己项目目录文件的日志级别
logging:
level:
com:
example:
demo: error
项目结构如图所示 :
此时访问网页 , 只打印了一条日志 :
原来添加日志对象 :
package com.example.demo;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
//1.得到日志对象
private Logger log = LoggerFactory.getLogger(TestController.class);
@Value("${mykey.key1}")
private String key;
@RequestMapping("/say")
public String say() {
log.trace("Hi,i am trace.");
log.debug("Hi,i am debug.");
log.info("Hi,i am info.");
log.warn("Hi,i am warn.");
log.error("Hi,i am error.");
return key;
}
}
简化写法 :
package com.example.demo;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class TestController {
@Value("${mykey.key1}")
private String key;
@RequestMapping("/say")
public String say() {
log.trace("Hi,i am trace.");
log.debug("Hi,i am debug.");
log.info("Hi,i am info.");
log.warn("Hi,i am warn.");
log.error("Hi,i am error.");
return key;
}
}
查看字节码 , 你就知道@Slf4j在底层实现时做了怎样的替换 :
你会发现 , 代码中并没有出现@Slf4j , 取而代之的是这行代码 !
如果你无法导入@Slf4j , 需要手动添加依赖 , 方法如下 :
同时 , 你也可以安装此插件实现依赖引入 :
本节内容到此结束 !