文章目录
Spring Boot的了解以及快速入门
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。因为我们知道,Spring开发的时候,我们需要创建他的配置文件,并且还需要导入许多的坐标,并且可能会因为各个坐标之间的版本原因从而导致不兼容,从而出现报错等。正因为spring的配置相对繁琐,所以就产生了Spring Boot,它简化了Spring的配置,Spring Boot简化了配置,并且SpringBoot通过集成大量的框架使得依赖包的版本冲突,以及引用的不稳定性等问题得到了很好的解决。
参考资料:Spring Boot
关于Spring Boot的快速入门,可以参考这一篇文章:IDEA搭建Spring Boot
Spring Boot的配置文件
在Spring Boot的配置文件中,可以是xxx.properties,也可以是xxx.yml或者xxx.yaml。其中文件名一般是application.其中在propertes配置文件中的格式应该如下所示:
service.port=8080
而在yml或者yaml中的格式为:
# port是在server下一层,所以需要换行,并且需要空出几格,类似于文件目录以树型结构的形式呈现出来是一样的道理
server:
port: 8080 # 键和值之间需要有空格隔开,否则就会发生报错的
所以在yml或者yaml中的格式要求为:
值得一提的是,在同一个目录下面给,优先级是:properties > yml > yaml,所以如果三个配置文件中设置了相同的属性的时候,那么会选择优先级较高的配置文件。例如如果三个配置文件都分别设置了端口值,那么Spring Boot就会选择优先级高的application.properties的文件的值。
在yml中,如果需要设置对象的属性,那么它的格式和上面设置server.port的格式是类似的,例如我们需要设置person这个属性中name以及age的属性的时候,那么对应的配置格式应该是:
person:
name: zhangshan # 键和值之间同样需要有空格间隔开
age: 20 # 因为name和age都是person的属性,所以是在同一层,因此age和name是左边对齐的
如果需要设置设置数组的元素的值,那么需要以下面的格式进行定义:
array:
- zhangshan # 以一个符号开始,然后空格,之后再写它的元素值
- lisi
如果值被单引号或者双引号括起来的时候,那么这时候两者的形式是不同的。单引号括起来的字符串中如果含有特殊字符,那么它是不会进行转义的,即它是原样输出的,但是如果是双引号括起来的字符串,那么它是能够对特殊字符进行转义的。
同样的,我们可以在配置文件中利用spring表达式${xxx}
来引用xxx属性的值。
所以如果我们需要获取xxx.yml配置文件中的属性的值的时候,我们可以有3种方式:
- 利用@Value注解,通过在对应的成员上方写上
@Value("${xxx}")
,这样就可以利用spring表达式,将获取到配置文件中xxx属性的值了,然后再赋值给修饰的成员。但是,如果是这样写@Value("xxx")
,这样就是直接给修饰的成员赋值xxx,作用等同于成员名=xxx**。 - 利用
@Autowired注解,从spring容器中取出Environment对象,通过调用方法getProperty("xxx"),就会获取到了配置文件中xxx属性的值
了。值得注意的是,这个Environment对象是一个接口,是在org.springframework下面的。 - 利用注解@ConfigurationProperties
测试代码为:
application.yml代码:
server:
port: 8081
# 在yml中表示对象的时候,那么先定义一个父对象,然后再设置父对象的属性的值
person:
name: zhangshan
age: 20
# 表示数组的时候,那么先定义数组的名字,然后再下一行,先用一个`-`开始,再空一格空格,后面就是它的元素值
array:
- aaa
- bbb
- ccc
# 单值形式的字符串,如果是一个单引号的字符串,那么就是原样输出,不会转义特殊字符
# 如果是双引号的字符串,那么他会转义特殊字符。例如
# 'Hello \n world' ----> 原样输出
# "Hello \n world" ----> 转义特殊字符\n,所以会换行打印,输出
# Hello
# world
msg1: 'Hello \n world'
msg2: "Hello \n world"
# 如果需要引用某一个属性的值的时候,需要利用${}表达式,其中花括号就是我们需要引用的属性名
msg3: ${msg1}
对应的测试类:
@Controller //将当前这个类添加到bean容器中
public class HelloController {
@Value("msg1") //这样写的话,是将字符串msg1赋值给msg1,效果等于String msg1 = "msg1";
private String msg1;
@Value("${msg2}") //将配置文件中的属性msg2的值通过spring表达式获取,然后将它的值赋值给msg2
private String msg2;
@Value("${msg3}")
private String msg3;
@RequestMapping("/hello")
@ResponseBody //提示返回值适用于回写数据的,而不是用于页面跳转的
public String hello(){
System.out.println(msg1);
System.out.println("-----------------");
System.out.println(msg2);
System.out.println("-----------------");
System.out.println(msg3);
return "Hello !!! Spring Boot !!!";
}
}
当我们开始运行之后,在搜索框上面输入localhost:8080/hello
,(因为还在application.properties文件中设置了端口为8080),那么就会在控制台下打印下面的结果:
但是当我们利用希望获取配置文件中数组的值的时候,即如果执行@Value("${array}")
,这时候就会发生报错的,如下所示:
但是当我们将配置文件中的数组array改成这样写的时候,就可以正常运行了:array: aaa,bbb,ccc(注意值和属性名之间有空格间隔开)
。代码如下所示:
@Controller //将当前这个类添加到bean容器中
public class HelloController {
@Value("${array}") //将配置文件中属性为array的值赋值给array数组以及字符串msg4
private String[] array;
@Value("${array}")
private String msg4;
@RequestMapping("/hello")
@ResponseBody //提示返回值适用于回写数据的,而不是用于页面跳转的
public String hello(){
System.out.println(Arrays.asList(array) + ", " + array.length);
System.out.println(msg4);
return "Hello !!! Spring Boot !!!";
}
}
这时候,如果在搜索框输入localhost:8080/hello
,那么就会在控制台输出如下信息:
[aaa, bbb, ccc], 3
aaa,bbb,ccc
具体原因不是很理解,但是个人觉得是配置文件中的属性array的值就是一个字符串,然后再赋值给数组的时候,是根据分隔符,
进行分割,从而形成了长度为3的字符串数组,因为当我们将array属性的值改称为aaa.bbb.ccc的时候,那么这时候控制台中输出的数组长度就是1,元素的值就只有aaa.bbb.ccc。
同样的,如果我们希望利用注解@Value来获取people属性的值的时候,同样会发生上面的错误信息,提示Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'person' in value "${person}"
,因为@Value是用于注入普通的数据类型的,而没有办法注入Bean对象的。所以这时候我们只能注入person下面的属性值,即@Value("${person.name}")
等形式是可以成功注入的。
当我们利用@Autowired
注解的时候,我们可以从spring容器中取出Environment的Bean对象,然后通过调用getProperty(“xxx”),就可以获取到属性为xxx的值了。测试代码如下所示:
@Controller //将当前这个类添加到bean容器中
public class HelloController {
@Autowired
private Environment environment;
@RequestMapping("/test")
@ResponseBody
public String test(){
String msg1 = environment.getProperty("msg1");
System.out.println(msg1);
System.out.println("---------------------");
String msg2 = environment.getProperty("msg2");
System.out.println(msg2);
System.out.println("---------------------");
return "通过从Bean对象中取出Environment对象,调用getProperty方法来获取配置文件中的属性值";
}
}
对应的结果为:
Hello \n world
---------------------
Hello
world
---------------------
同样的,如果我们需要获取数组等属性的值的时候,对应代码为:
@Controller //将当前这个类添加到bean容器中
public class HelloController {
@Autowired
private Environment environment;
@RequestMapping("/test")
@ResponseBody
public String test(){
Person person = environment.getProperty("person", Person.class); //尽管希望获取person属性,然后封装到Person类中,但是这时候返回的person为null
System.out.println(person);
System.out.println("---------------------");
String[] arrays = environment.getProperty("array", String[].class);//这时候的array属性的值在配置文件中为array: aaa,bbb,ccc
System.out.println(Arrays.asList(arrays));
return "通过从Bean对象中取出Environment对象,调用getProperty方法来获取配置文件中的属性值";
}
}
输出结果为:
null
---------------------
[aaa, bbb, ccc]
但是如果在配置文件中array的格式是按照这样写的时候:
array:
- aaa
- bbb
- ccc
那么这时候,即使是通过Environment对象调用getProperty(“array”,String[].class),也会发生报错,提示java.lang.IllegalArgumentException: Could not resolve placeholder 'array' in value "${array}"
.
利用注解@ConfigurationProperty(prefix = "xxx")
,这样就会将配置文件中的属性为xxx的元素赋值给它修饰的类,这样就可以将这个xxx属性中的成员的值赋值给这个类中相同名字的成员。然后再利用相关的注解,例如@Component,将这个类添加到Spring容器中,这样我们就可以直接利用@Autowired
来获取这个类了。例如上面配置文件中的person属性,无论是@Value
,还是通过Environment对象调用getProperty方法,都没有办法直接返回Person对象,而这种方式则可以。对应的代码为:
@Component //添加到Spring容器种
//配置文件中扫描person属性,这样就可以将它的子属性赋值给当前这个类中相同名字的成员
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private int age;
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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试代码:
@Controller //将当前这个类添加到bean容器中
public class HelloController {
@Autowired
private Person person;
@ResponseBody
@RequestMapping("/test2")
public String test2(){
System.out.println(person); //输出Person{name='zhangshan', age=20}
return "通过注解@ConfigurationProperties(prefix = 'xxxx')的方式来获取配置文件中的值";
}
}
在@ConfigurationProperties这一种方式中,和在Spring中获取请求参数的值方式类似。只是这里是要求配置文件中的名字要和对应的类成员名字相同,而获取请求参数的值中,则是需要参数的名字和类成员名字相同,才会将请求参数的数据封装到一个类中。可以参考这一个文章:Spring学习_day4~5
Spring Boot中的profile配置文件
profile配置文件主要是用于不同的环境中,动态进行配置的,例如在生产,开发或者测试的环境下,为了避免重复进行配置环境,这时候就需要profiles动态设置在什么环境下需要使用的是哪一个配置文件。
例如下面所示,我们创建以下profiles配置文件:
application-dev.properties:(格式为application-{profiles}.properties)
server.port=8081
application-pro.properties:
server.port=8089
application-test.properties:
server.port=8989
这时候我们还没有激活profile,也即还没有设置环境,那么这时候就会默认使用的是application.properties中设置的端口8080,并且提示没有设置环境。
但是一旦我们在applicaton.properties中设置了要激活哪一个profile配置文件的时候,那么端口号就变成了对应的文件中设置的值了。例如我们在application.properties中添加这一行spring.profiles.active=dev
,表示我们要激活的是application-dev.properties配置文件,这时候再次运行时,就提示了激活的是dev的profile配置文件。
同样的,我们也可以在创建的是application-dev.yml作为profile配置文件,然后再执行spring.profiles.active=dev
来激活这个profile配置文件。
但是这时候可以看到我们创建了许多个配置文件,这时候我们可以用一个yml文件来囊括这多个配置文件,这时候我们就只需要创建一个yml文件,就可以实现创建多个profile配置文件了。这时候我们只需要再yml文件中利用---
来进行分隔不同的profile配置文件即可。application.yml代码如下所示:
---
server:
port: 8081
spring:
profiles: dev # 表示这中间的配置是属于dev环境的
---
server:
port: 8082
spring:
profiles: pro # 表示这中间的配置是属于pro环境的
---
server:
port: 8083
spring:
profiles: test # # 表示这中间的配置是属于test环境的
---
然后再配置文件application.properties中执行spring.profiles.active
来激活哪一个profile环境即可。
但是这样还是要通过修改配置文件来激活profile环境,那么我们是否有不修改配置文件的方式来激活呢?当然是有的,我们可以通过下面的样子来进行配置:
点击Edit Configurations
,然后选中点击,之后就可以看到下图所示:
如果左边没有看到Spring Boot这个选项,那么我们需要点击上面的+
,然后找到Spring Boot即可。这时候我们可以看到右边的Environment下面有VM options以及Program arguments。这时候我们只要修改这2个中的一个,都可以实现激活profile。
其中VM options是通过JVM来激活的,对应的格式为-Dspring.profiles.active=xxx(不要忘记前面有-D)
,表示需要激活xxx的profile环境。而Program arguments的值则是--spring.profiles.active=xxx(不要忘记前面有--)
。
当然我们也可以生成这个项目的jar包之后,再输入命令行来配置环境,如下所示:
点击了Maven -> 找到对应Module -> 点击Lifecycle -> 点击package,然后就会再控制台中输出一系列的信息,我们重点看生成的对应jar包的位置即可。
然后再命令行的窗口中输出要运行对应的jar包,然后再输入--spring.profiles.active=xxx
来激活对应的profiles配置文件。如下所示:
Spring Boot内部配置文件的加载顺序
首先先说一下再Spring Boot内部中配置文件的加载顺序为:
- 项目目录下面的config包下的配置文件
- 项目目录下面的配置文件
- classpath下面的config包下的配置文件,也即resources包下的config包下的配置文件
- classpath下的配置文件,也即resources包下的配置文件
如图所示:
加载配置文件的信息,顺序如下所示,如果没有办法找到项目设置项目目录下面创建配置文件,也就是前2个配置文件,需要点击Project -> Project File即可,然后就可以开始创建对应的配置文件了。
而对于外部jar包配置文件的加载顺序,则可以参考官网上面,但是主要的顺序是:
- 命令行进行设置配置文件的信息,或者通过
--spring.config.locaton=xxx
来指定要读取对应路径下面的配置文件 - 这个maven导出的jar包外面的配置文件,而在这些外部配置文件中,同样遵循先加载config包下面的配置文件,然后再加载这个目录下面的配置文件。
- 这个maven对应的jar包内部的配置文件。
这样的话,当我们运行这个jar包的时候,就会根据上面的顺序进行加载配置文件,但是如果是在IDEA中运行项目的时候,那么它是根据这个jar包内部的配置文件进行加载的。
Spring Boot整合junit,mybatis以及redis
Spring Boot整合 junit
当我们创建好项目之后,这时候来到pom.xml文件,可以看到已经导入了test依赖,即如下所示:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
这时候我们就可以在test包下进行测试了。其中需要测试的步骤是:
- 在类的上方使用注解
@SpringBootTest(classes = 启动类.class)
,如果是在test包下面的项目名这个包下面,那么就不需要这个注解可以不需要设置classes属性的值 - 利用
@Autowired
导入需要测试的bean对象进行测试
Spring Boot整合mybatis
Spring Boot整合mybatis的基本步骤:
-
导入依赖,比如我们需要利用mybatis进行测试,所以需要导入数据库的联结对象以及mybatis-spring依赖,如下所示:
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <!--数据库--> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.21</version> </dependency>
-
配置数据源信息,只需要在application.properties或者创建application.yml,然后再配置文件中进行设置driver,url,username,password等信息即可。
-
配置mybatis的核心配置文件,同样是可以再application.properties或者application.yml中进行设置的,从而可以设置mybatis的核心配置文件的路径,映射文件的路径或者别名等属性。
# 配置数据库的基本信息 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/db1?serverTimezone=Asia/Shanghai username: root password: root # 配置mybatis mybatis: mapper-locations: classpath:mappers/*Mapper.xml # 配置映射文件的路径 # 配置别名,相当于<package location="xxx">,这样对应的别名就是对应的类名的缩写形式 type-aliases-package: com/example/springboot_redis/domain # config-location: 配置mybatis的核心配置文件的路径
-
创建实体类User,对应代码:
public class User { private int id; private String name; private String password; private String email; private String phone; 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 String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", password='" + password + '\'' + ", email='" + email + '\'' + ", phone='" + phone + '\'' + '}'; } }
-
创建对应的Mapper接口。这时候我们可以利用注解开发来操作mybatis,也可以通过xml来操作。如果我们是通过xml来操作mybatis,那么这时候我们通过利用代理来实现dao层的操作,并且需要创建对应的映射文件,需要在配置mybatis的时候,需要设置映射文件的路径,对应的代码为:
@Repository //可有可无的,只是在利用@Autowired注入的时候,IEDA中对应的变量下面显示红色的波浪线 @Mapper //这个注解是必须的,否则就会发生报错,这个作用相当于在SSM整合的过程中需要注入mapper的作用一样的,将扫描这个类,然后自动创建它的动态代理类,注入到spring容器中 public interface UserXmlMapper { List<User> findAll(); }
对应的映射文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.springboot_redis.mapper.UserXmlMapper"> <select id="findAll" resultType="user"> select * from user </select> </mapper>
如果是利用注解进行开发的话,那么这时候不需要创建对应映射文件,只是需要在Mapper接口中,对应的方法上面利用对应的注解,表示对应的操作,对应的代码为:
@Repository //可有可无 @Mapper //生成对应的mapper接口的动态代理对象,注入到spring容器中 public interface UserMapper { @Select("select * from user") List<User> findAll(); }
整合junit进行测试的代码为:
@SpringBootTest(classes = SpringbootRedisApplication.class) public class MybatisTest { @Autowired private UserXmlMapper userXmlMapper; //用xml来操作mybatis @Test public void test(){ List<User> userList = userXmlMapper.findAll(); for(User user : userList){ System.out.println(user); } } @Autowired private UserMapper userMapper; //用注解开发来操作mybatis @Test public void test2(){ List<User> userList = userMapper.findAll(); for(User user : userList){ System.out.println(user); } } }
值得注意的是,注解@SpringBootTest的属性classess的值是否省略,是看它的位置的。如下所示:
Spring Boot整合redis
Spring Boot整合redis的基本步骤为:
- 导入spring-boot-starter-data-redis依赖
- 配置redis的信息,例如默认情况下它的端口时6379,host默认是本地主机等
- 进行测试,但是前提是我们windows中已经安装了redis,对于安装redis的过程,请参考这篇文章:Redis安装(Windows环境下Redis安装)
测试类对应的代码为:
@SpringBootTest(classes = SpringbootRedisApplication.class)
public class RedisTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void setTest(){
redisTemplate.boundValueOps("name").set("zhangshan");
}
@Test
public void getTest(){
Object name = redisTemplate.boundValueOps("name").get();
System.out.println(name);
}
}
先在命令行窗口中运行了redis,然后再运行setTest方法,之后在运行getTest,这时候就会再控制台中打印出name对应的值zhangshan
.
安装redis的过程,请参考这篇文章:Redis安装(Windows环境下Redis安装)
测试类对应的代码为:
@SpringBootTest(classes = SpringbootRedisApplication.class)
public class RedisTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void setTest(){
redisTemplate.boundValueOps("name").set("zhangshan");
}
@Test
public void getTest(){
Object name = redisTemplate.boundValueOps("name").get();
System.out.println(name);
}
}
先在命令行窗口中运行了redis,然后再运行setTest方法,之后在运行getTest,这时候就会再控制台中打印出name对应的值zhangshan
.