Spring Boot简介
我们都知道Spring框架功能很强大,但是就算是一个很简单的项目,我们也要配置很多东西。由于Spring的配置过于繁杂,因此就诞生了Spring Boot框架,它的作用很简单,就是帮我们自动配置。Spring Boot框架的核心就是自动配置,只要存在相应的jar包,Spring就帮我们自动配置。如果默认配置不能满足需求,我们还可以替换掉自动配置类,使用我们自己的配置。另外,Spring Boot还集成了嵌入式的Web服务器,系统监控等很多有用的功能,能够让我们快速构建企业及应用程序。简而言之,SpringBoot就是简化了原本Spring的各种繁杂的配置,让我们能够很轻易地创建Spring应用,让我们可以享受约定大于配置的乐趣。
特性理解:
- 为基于 Spring 的开发提供更快的入门体验
- 开箱即用,没有代码生成,也无需 XML 配置。同时也可以修改默认值来满足特定的需求。
- 提供了一些大型项目中常见的非功能特性,如嵌入式服务器、安全、指标,健康检测、外部配置等。
- Spring Boot 并不是对 Spring 功能上的增强,而是提供了一种快速使用 Spring 的方式。
- 嵌入的 Tomcat,无需部署 WAR 文件
官网地址如下:
SpringBoot2.0官方文档地址如下:
https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/htmlsingle/
SpringBoot2.0 API文档地址如下:
第一个SpringBoot应用
在IDEA上我们可以使用Maven来创建SpringBoot工程,也可以用Spring Initializr来SpringBoot工程。我这里介绍的是使用Spring Initializr来SpringBoot工程。如下:
工程创建完成,自动生成的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>
<groupId>org.zero01.springboot</groupId>
<artifactId>springboot-01</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot-01</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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>
</plugin>
</plugins>
</build>
</project>
然后我们来创建一个控制器类,写一个简单的方法:
package org.zero01.springboot.springboot01;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@RequestMapping(value = "/hello",method = RequestMethod.GET)
public String say(){
return "Hello Spring Boot";
}
}
创建工程时,IDEA会自动帮我们生成一个SpringBoot的启动类,我们只需要直接运行这个类即可启动SpringBoot:
package org.zero01.springboot.springboot01;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Springboot01Application {
public static void main(String[] args) {
SpringApplication.run(Springboot01Application.class, args);
}
}
启动时控制台的输出内容:
使用PostMan进行访问,可以看到正常返回了内容:
这样我们的SpringBoot应用就创建好了,可以看到,整个过程我们并没有编辑任何的配置文件或属性文件。SpringBoot已经自动帮我们配置好了,而且由于集成了Tomcat,我们甚至都不需要在工程里配置Tomcat就能够直接启动。
除了使用IDEA启动之外,也可以直接使用Maven命令进行启动,进入到工程的主目录下,执行以下命令即可:
mvn spring-boot:run
项目属性配置
我们在创建工程的时候,IDEA会自动帮我们在resource目录下创建好属性配置文件:application.properties。默认情况下,这个属性配置文件是空的,我们可以在该文件中,配置一些信息,例如我要配置一下服务器的访问端口以及上下文的路径:
server.port=8081 // 配置服务器的访问端口
server.servlet.context-path=/springboot-01 // 上下文路径
配置完成之后,重新启动SpringBoot,然后再使用postman进行访问:
可以看到,端口已经变成了8081,而上下文路径变成了springboot-01。
除了可以使用属性文件进行配置之外,SpringBoot还支持使用yml文件来进行配置,yml的语法要简洁一些,并且层级也更加分明,IDEA对yml的语法支持也十分的好。接下来演示一下如何在yml文件里进行配置,首先在resource目录下创建一个application.yml文件,编辑文件内容如下:
server:
port: 8082
servlet:
context-path: /springboot-01
注:.properties文件与.yml文件只能有一个,也就是说使用.yml文件的话,就要把.properties文件删除,不然SpringBoot默认是加载.properties文件的。
同样的,配置完成之后,重新启动SpringBoot,然后再使用postman进行访问:
我们还可以在配置文件里,自定义一些配置,例如定义一个size和age的值:
server:
port: 8080
size: 1024
age: 18
然后在控制器里我们可以通过@Value注解来注入配置文件里自定义的属性值:
package org.zero01.springboot.springboot01;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
// 使用${}来获取属性值
@Value("${size}")
private String size;
@Value("${age}")
private int age; // 值的类型在代码中定义即可
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String say() {
return "配置文件里size的值为:" + size + ", 配置文件里age的值为:" + age;
}
}
重新启动SpringBoot,然后再使用postman进行访问,返回结果如下:
我们还可以在配置文件里引用其他属性的值,例如:
server:
port: 8080
size: 1024
age: 18
content: "size: ${size}, age: ${age}"
控制器代码修改如下:
package org.zero01.springboot.springboot01;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Value("${size}")
private String size;
@Value("${age}")
private int age;
@Value("${content}")
private String content;
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String say() {
return "配置文件里content的值为:" + content;
}
}
重新启动SpringBoot,然后再使用postman进行访问,返回结果如下:
有没有觉得写@Value很费劲,每一个属性都要写,如果我有很多个属性需要注入岂不是要写很多个@Value吗?当然不是,如果有很多个的话,我们可以使用另一个种方式进行注入。修改配置文件内容如下:
server:
port: 8080
girl:
cupSize: C
age: 18
sex: female
height: 160cm
weight: 90KG
在pom.xml里引入如下依赖:
<!-- 添加configuration-processor依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- json依赖是为了一会将对象转换成json进行输出 -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20171018</version>
</dependency>
创建一个pojo类,将配置文件中的属性封装起来:
package org.zero01.springboot.springboot01;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
// 引入配置文件中,前缀为girl的属性
@ConfigurationProperties(prefix = "girl")
public class GirlProperties {
private String cupSize;
private int age;
private String sex;
private String height;
private String weight;
... getter setter 略...
}
然后修改控制器代码如下:
package org.zero01.springboot.springboot01;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Autowired
private GirlProperties girlProperties;
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String say() {
return new JSONObject(girlProperties).toString();
}
}
重新启动SpringBoot,然后再使用postman进行访问,返回结果如下:
使用这种方式,我们就不需要逐个去写@Value注解了,通过@ConfigurationProperties注解将某个前缀下的属性值封装到一个类里即可。
我们都知道线上环境总是和开发环境的配置信息有些区别,所以有时候我们需要有多个配置文件,那么如何在不同环境下选择不同的配置文件呢?例如,我这里创建了三个配置文件:
其中开发环境的配置文件:application-dev.yml内容如下:
server:
port: 8080
girl:
cupSize: B
age: 18
sex: female
height: 160cm
weight: 90KG
线上环境的配置文件:application-product.yml内容如下:
server:
port: 80
girl:
cupSize: F
age: 18
sex: female
height: 165cm
weight: 85KG
然后是主配置文件application.yml内容如下:
spring:
profiles:
active: dev
当active的值为dev时表示使用application-dev.yml(开发环境的配置),为product时则表示使用application-product.yml(线上环境的配置),这里默认给的值是dev。
那么我们要怎么去改变active的值呢?总不能每次都去修改配置文件吧。这时候我们就需要使用到java命令了,首先我们进入到工程的主目录,使用maven命令将工程进行打包:
mvn package
注:IDEA的工程打包后会放在target目录下。
假设我们现在已经把jar包上传到了线上服务器上,并且这个服务器已经具备了java运行环境的。那么我们只需要使用以下命令即可启动该工程,并且可以通过传递--spring.profiles.active
参数来设置使用哪一个配置文件:
java -jar ./springboot-01-0.0.1-SNAPSHOT.jar --spring.profiles.active=product
使用postman进行访问,返回结果如下,可以看到是application-product.yml里配置的值:
这就是如何在不同的环境下,使用不同的配置文件。
数据库操作
在Spring Boot中,我们需要通过spring-boot-starter-data-jpa组件去访问数据库,这是一个JPA的实现,JPA(Java Persistence API)定义了一系列对象持久化的标准,目前实现这一规范的产品有Hibernate、TopLink等。spring-boot-starter-data-jpa里就是集成了Hibernate。
在pom.xml文件中,增加如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- mysql数据库连接器依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
在主配置文件中,配置数据源信息,如下示例:
spring:
profiles:
active: dev
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql:///springboot
username: root
password: your_password
jpa:
hibernate:
ddl-auto: update
show-sql: true
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
现在springboot数据库里是空的,没有任何表格:
然后我们来创建一个实体类,通过这个实体类可以生成数据库表格:
package org.zero01.springboot.springboot01;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
// 实体注释
@Entity
public class Student {
@Id // 声明为主键
@GeneratedValue(strategy = GenerationType.IDENTITY) // 指定主键为自动增长
private Integer sid;
private String sname;
private Integer age;
// 必须要有一个构造器
public Student(){}
... getter setter 略...
}
重新启动Spring Boot,可以看到数据库中自动生成了student表格:
表格结构如下:
下面我们来做一个简单的小例题,设计如下RESTful API,实现相应的功能:
请求类型 | 请求路径 | 功能 |
---|---|---|
GET | /students | 获取学生列表 |
POST | /students/add | 添加一个学生 |
GET | /students/id | 通过id查询一个学生 |
PUT | /students/id | 通过id更新一个学生的信息 |
DELETE | /students/id | 通过id删除一个学生 |
首先在表格里填充一些数据:
编写一个接口类,继承JpaRepository,如下示例:
package org.zero01.springboot.springboot01;
import org.springframework.data.jpa.repository.JpaRepository;
public interface StudentRepository extends JpaRepository<Student, Integer> {
}
然后编写一个控制器,先实现获取学生列表的API:
package org.zero01.springboot.springboot01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class StudentController {
@Autowired
private StudentRepository studentRepository;
/**
* 获取学生列表
* @return
*/
@GetMapping(value = "/students")
public List<Student> studentList(){
return studentRepository.findAll();
}
}
重启SpringBoot,使用PostMan访问,返回结果如下:
可以看到,数据正常的返回了。而且实现代码也很简单,我们并没有在代码中写任何的sql语句。
我们来接着实现其他方法,添加学生:
/**
* 添加学生
*
* @return
*/
@PostMapping(value = "/students/add")
public Student addStudent(@RequestParam("name") String sname,
@RequestParam("age") Integer age) {
Student student=new Student();
student.setSname(sname);
student.setAge(age);
return studentRepository.save(student);
}
重启SpringBoot,使用PostMan访问,返回结果如下:
数据库新增的内容如下:
查询学生:
/**
* 通过id查询一个学生
*/
@GetMapping(value = "/students/{id}")
public Student studentFindOne(@PathVariable("id") Integer id){
return studentRepository.findById(id).get();
}
重启SpringBoot,使用PostMan访问,返回结果如下:
更新学生信息:
/**
* 通过id更新一个学生的信息
*/
@PutMapping(value = "/students/{id}")
public Student studentUpdate(@PathVariable("id") Integer id,
@RequestParam("name") String sname,
@RequestParam("age") Integer age) {
Student student = new Student();
student.setSid(id);
student.setSname(sname);
student.setAge(age);
return studentRepository.save(student);
}
重启SpringBoot,使用PostMan访问,返回结果如下:
删除学生信息:
/**
* 通过id删除一个学生
*/
@DeleteMapping(value = "/students/{id}")
public void delStu(@PathVariable("id") Integer id){
studentRepository.deleteById(id);
}
重启SpringBoot,使用PostMan访问http://127.0.0.1:8080/students/1
,id为1的student信息就被删除了:
在接口类中,我们可以自定义一些方法,以此作为扩展。例如,自定义一个按照age字段查询的方法:
package org.zero01.springboot.springboot01;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface StudentRepository extends JpaRepository<Student, Integer> {
/**
* 通过年龄来查询学生信息
* @return
*/
public List<Student> findByAge(Integer age);
}
注:方法名称要遵循特定的格式,不能随便写。按照age查询就是findByAge,按照sname查询就是findBySname,以此类推,删除方法也是如此。
在控制器中,增加如下方法:
/**
* 通过年龄来查询学生列表
*/
@GetMapping(value = "/students/age/{age}")
public List<Student> studentsListByAge(@PathVariable("age") Integer age){
return studentRepository.findByAge(age);
}
重启SpringBoot,使用PostMan访问,返回结果如下:
事务管理
涉及数据库的操作,就必定少不了事务,而Spring Boot中的事务管理和SpringMVC里是一样的都是使用@Transactional注解即可。只不过区别就在于我们不需要像SpringMVC那样在XML配置文件里配置了事务管理才能使用该注解,在Spring Boot直接就可以使用了。示例:
package org.zero01.springboot.springboot01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class StudentService {
@Autowired
private StudentRepository studentRepository;
@Transactional
public void insertTow(){
Student studentA = new Student();
studentA.setSname("stuA");
studentA.setAge(21);
studentRepository.save(studentA);
Student studentB = new Student();
studentB.setSname("stuB");
studentB.setAge(23);
studentRepository.save(studentB);
}
}