SpringBoot简介

我们都知道Spring框架功能很强大,但是就算是一个很简单的项目,我们也要配置很多东西。由于Spring的配置过于繁杂,因此就诞生了Spring Boot框架,它的作用很简单,就是帮我们自动配置。Spring Boot框架的核心就是自动配置,只要存在相应的jar包,Spring就帮我们自动配置。如果默认配置不能满足需求,我们还可以替换掉自动配置类,使用我们自己的配置。另外,Spring Boot还集成了嵌入式的Web服务器,系统监控等很多有用的功能,能够让我们快速构建企业及应用程序。简而言之,SpringBoot就是简化了原本Spring的各种繁杂的配置,让我们能够很轻易地创建Spring应用,让我们可以享受约定大于配置的乐趣。

特性理解:

  • 为基于 Spring 的开发提供更快的入门体验
  • 开箱即用,没有代码生成,也无需 XML 配置。同时也可以修改默认值来满足特定的需求。
  • 提供了一些大型项目中常见的非功能特性,如嵌入式服务器、安全、指标,健康检测、外部配置等。
  • Spring Boot 并不是对 Spring 功能上的增强,而是提供了一种快速使用 Spring 的方式。
  • 嵌入的 Tomcat,无需部署 WAR 文件

官网地址如下:

http://projects.spring.io/spring-boot/

SpringBoot2.0官方文档地址如下:

https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/htmlsingle/

SpringBoot2.0 API文档地址如下:

https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/api/


第一个SpringBoot应用

在IDEA上我们可以使用Maven来创建SpringBoot工程,也可以用Spring Initializr来SpringBoot工程。我这里介绍的是使用Spring Initializr来SpringBoot工程。如下:
初识SpringBoot
初识SpringBoot
初识SpringBoot
初识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);
    }
}

启动时控制台的输出内容:
初识SpringBoot

使用PostMan进行访问,可以看到正常返回了内容:
初识SpringBoot

这样我们的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进行访问:
初识SpringBoot

可以看到,端口已经变成了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进行访问:
初识SpringBoot

我们还可以在配置文件里,自定义一些配置,例如定义一个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进行访问,返回结果如下:
初识SpringBoot

我们还可以在配置文件里引用其他属性的值,例如:

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进行访问,返回结果如下:
初识SpringBoot

有没有觉得写@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进行访问,返回结果如下:
初识SpringBoot

使用这种方式,我们就不需要逐个去写@Value注解了,通过@ConfigurationProperties注解将某个前缀下的属性值封装到一个类里即可。

我们都知道线上环境总是和开发环境的配置信息有些区别,所以有时候我们需要有多个配置文件,那么如何在不同环境下选择不同的配置文件呢?例如,我这里创建了三个配置文件:
初识SpringBoot

其中开发环境的配置文件: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里配置的值:
初识SpringBoot

这就是如何在不同的环境下,使用不同的配置文件。


数据库操作

在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数据库里是空的,没有任何表格:
初识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表格:
初识SpringBoot

表格结构如下:
初识SpringBoot


下面我们来做一个简单的小例题,设计如下RESTful API,实现相应的功能:

请求类型 请求路径 功能
GET /students 获取学生列表
POST /students/add 添加一个学生
GET /students/id 通过id查询一个学生
PUT /students/id 通过id更新一个学生的信息
DELETE /students/id 通过id删除一个学生

首先在表格里填充一些数据:
初识SpringBoot

编写一个接口类,继承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访问,返回结果如下:
初识SpringBoot

可以看到,数据正常的返回了。而且实现代码也很简单,我们并没有在代码中写任何的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访问,返回结果如下:
初识SpringBoot

数据库新增的内容如下:
初识SpringBoot

查询学生:

/**
 * 通过id查询一个学生
 */
@GetMapping(value = "/students/{id}")
public Student studentFindOne(@PathVariable("id") Integer id){
    return studentRepository.findById(id).get();
}

重启SpringBoot,使用PostMan访问,返回结果如下:
初识SpringBoot

更新学生信息:

/**
 * 通过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访问,返回结果如下:
初识SpringBoot

删除学生信息:

/**
 * 通过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信息就被删除了:
初识SpringBoot

在接口类中,我们可以自定义一些方法,以此作为扩展。例如,自定义一个按照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访问,返回结果如下:
初识SpringBoot


事务管理

涉及数据库的操作,就必定少不了事务,而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);
    }
}