Статьи

Spring Boot Tutorial

1. Введение

Если вы всегда хотели работать с веб-платформой, которая позволяет быстро приступить к разработке API-интерфейса без необходимости настройки веб-серверов, сбора всех проводных зависимостей, установки различных инструментов, вы были наделены отличной средой, Spring Загрузочный. Главный девиз Spring Boot — соглашение по конфигурации .

На этом уроке мы изучим, как легко настроить проект Spring Boot, и создадим несколько служб RESTful, которые взаимодействуют с базой данных менее чем за 20 минут! Именно так все просто с Spring Boot. Spring Boot позволяет нам создавать производственные Spring-приложения, которые вы можете «просто запустить». Лучшая часть загрузочного приложения Spring состоит в том, что оно требует очень небольшой настройки.

2. Создание проекта Spring Boot с Maven

Мы будем использовать один из многих архетипов Maven для создания примера проекта для нашего примера. Чтобы создать проект, выполните следующую команду в каталоге, который вы будете использовать в качестве рабочей области:

1
mvn archetype:generate -DgroupId=com.javacodegeeks.example -DartifactId=JCG-SpringBoot-example -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Если вы запускаете maven в первый раз, выполнение команды генерации займет несколько секунд, поскольку maven должен загрузить все необходимые плагины и артефакты, чтобы выполнить задачу генерации.

Создав проект, не стесняйтесь открывать его в своей любимой среде IDE. Следующим шагом является добавление соответствующих зависимостей Maven в проект. Мы будем работать с четырьмя зависимостями в нашем проекте:

  • spring-boot-starter-web : эта зависимость помечает этот проект как веб-проект и добавляет зависимости для создания контроллеров и создания веб-связанных классов.
  • spring-boot-starter-data-jpa : эта зависимость обеспечивает проект поддержкой JPA, где мы можем выполнять множество операций, связанных с базой данных.
  • h2 : H2 — это база данных в памяти, которую мы будем использовать для демонстрации операций с БД в этом уроке
  • spring-boot-starter-test : эта зависимость собирает все связанные с тестами JAR-файлы в проекте, такие как JUnit и Mockito .

Вот файл pom.xml с соответствующими зависимостями:

pom.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.5.10.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-data-jpa</artifactId>
  </dependency>
 
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
 
  <dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
  </dependency>
   
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
   
</dependencies>

Чтобы упаковать код в JAR, мы будем использовать spring-boot-maven-plugin который является отличным инструментом для управления упаковкой самого приложения в JAR или WAR. Вот как мы можем добавить в наш файл зависимостей:

pom.xml

1
2
3
4
5
6
7
8
<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
  </plugins>
</build>

Найти последние зависимости Maven от Maven Central .

Наконец, чтобы понять все JAR-файлы, которые добавляются в проект при добавлении этой зависимости, мы можем запустить простую команду Maven, которая позволяет нам видеть полное дерево зависимостей для проекта, когда мы добавляем в него некоторые зависимости. Вот команда, которую мы можем использовать:

Проверьте дерево зависимостей

1
mvn dependency:tree

Когда мы запустим эту команду, она покажет нам следующее дерево зависимостей:

Дерево зависимостей

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
[INFO] --------------------
[INFO] Building JCG-SpringBoot-example 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.10:tree (default-cli) @ JCG-SpringBoot-example ---
[INFO] com.javacodegeeks.example:JCG-SpringBoot-example:jar:1.0-SNAPSHOT
[INFO] +- org.springframework.boot:spring-boot-starter-data-jpa:jar:1.5.10.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:1.5.10.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot:jar:1.5.10.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-autoconfigure:jar:1.5.10.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:1.5.10.RELEASE:compile
[INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.1.11:compile
[INFO] |  |  |  |  \- ch.qos.logback:logback-core:jar:1.1.11:compile
[INFO] |  |  |  +- org.slf4j:jul-to-slf4j:jar:1.7.25:compile
[INFO] |  |  |  \- org.slf4j:log4j-over-slf4j:jar:1.7.25:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.17:runtime
[INFO] |  +- org.springframework.boot:spring-boot-starter-aop:jar:1.5.10.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-aop:jar:4.3.14.RELEASE:compile
[INFO] |  |  \- org.aspectj:aspectjweaver:jar:1.8.13:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-jdbc:jar:1.5.10.RELEASE:compile
[INFO] |  |  +- org.apache.tomcat:tomcat-jdbc:jar:8.5.27:compile
[INFO] |  |  |  \- org.apache.tomcat:tomcat-juli:jar:8.5.27:compile
[INFO] |  |  \- org.springframework:spring-jdbc:jar:4.3.14.RELEASE:compile
[INFO] |  +- org.hibernate:hibernate-core:jar:5.0.12.Final:compile
[INFO] |  |  +- org.jboss.logging:jboss-logging:jar:3.3.1.Final:compile
[INFO] |  |  +- org.hibernate.javax.persistence:hibernate-jpa-2.1-api:jar:1.0.0.Final:compile
[INFO] |  |  +- org.javassist:javassist:jar:3.21.0-GA:compile
[INFO] |  |  +- antlr:antlr:jar:2.7.7:compile
[INFO] |  |  +- org.jboss:jandex:jar:2.0.0.Final:compile
[INFO] |  |  +- dom4j:dom4j:jar:1.6.1:compile
[INFO] |  |  \- org.hibernate.common:hibernate-commons-annotations:jar:5.0.1.Final:compile
[INFO] |  +- org.hibernate:hibernate-entitymanager:jar:5.0.12.Final:compile
[INFO] |  +- javax.transaction:javax.transaction-api:jar:1.2:compile
[INFO] |  +- org.springframework.data:spring-data-jpa:jar:1.11.10.RELEASE:compile
[INFO] |  |  +- org.springframework.data:spring-data-commons:jar:1.13.10.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-orm:jar:4.3.14.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-context:jar:4.3.14.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-tx:jar:4.3.14.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-beans:jar:4.3.14.RELEASE:compile
[INFO] |  |  +- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] |  |  \- org.slf4j:jcl-over-slf4j:jar:1.7.25:compile
[INFO] |  \- org.springframework:spring-aspects:jar:4.3.14.RELEASE:compile
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:1.5.10.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-tomcat:jar:1.5.10.RELEASE:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:8.5.27:compile
[INFO] |  |  |  \- org.apache.tomcat:tomcat-annotations-api:jar:8.5.27:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-el:jar:8.5.27:compile
[INFO] |  |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.5.27:compile
[INFO] |  +- org.hibernate:hibernate-validator:jar:5.3.6.Final:compile
[INFO] |  |  +- javax.validation:validation-api:jar:1.1.0.Final:compile
[INFO] |  |  \- com.fasterxml:classmate:jar:1.3.4:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.8.10:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.0:compile
[INFO] |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.8.10:compile
[INFO] |  +- org.springframework:spring-web:jar:4.3.14.RELEASE:compile
[INFO] |  \- org.springframework:spring-webmvc:jar:4.3.14.RELEASE:compile
[INFO] |     \- org.springframework:spring-expression:jar:4.3.14.RELEASE:compile
[INFO] +- com.h2database:h2:jar:1.4.196:runtime
[INFO] \- org.springframework.boot:spring-boot-starter-test:jar:1.5.10.RELEASE:test
[INFO]    +- org.springframework.boot:spring-boot-test:jar:1.5.10.RELEASE:test
[INFO]    +- org.springframework.boot:spring-boot-test-autoconfigure:jar:1.5.10.RELEASE:test
[INFO]    +- com.jayway.jsonpath:json-path:jar:2.2.0:test
[INFO]    |  \- net.minidev:json-smart:jar:2.2.1:test
[INFO]    |     \- net.minidev:accessors-smart:jar:1.1:test
[INFO]    |        \- org.ow2.asm:asm:jar:5.0.3:test
[INFO]    +- junit:junit:jar:4.12:test
[INFO]    +- org.assertj:assertj-core:jar:2.6.0:test
[INFO]    +- org.mockito:mockito-core:jar:1.10.19:test
[INFO]    |  \- org.objenesis:objenesis:jar:2.1:test
[INFO]    +- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO]    +- org.hamcrest:hamcrest-library:jar:1.3:test
[INFO]    +- org.skyscreamer:jsonassert:jar:1.4.0:test
[INFO]    |  \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test
[INFO]    +- org.springframework:spring-core:jar:4.3.14.RELEASE:compile
[INFO]    \- org.springframework:spring-test:jar:4.3.14.RELEASE:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

Заметили что-то? Так много зависимостей было добавлено, просто добавив четыре зависимости в проект. Spring Boot сама собирает все связанные зависимости и ничего не оставляет для нас в этом вопросе. Самым большим преимуществом является то, что все эти зависимости гарантированно совместимы друг с другом .

3. Gradle-эквивалент для файла сборки

Хотя Maven — отличная система сборки, если вы предпочитаете Gradle, вот эквивалент Gradle для pom.xml сборки pom.xml :

build.gradle

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
buildscript {
    ext {
        springBootVersion = '1.5.10.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}
 
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
 
group = 'com.javacodegeeks.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
 
repositories {
    mavenCentral()
}
 
 
dependencies {
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('org.springframework.boot:spring-boot-starter-web')
    runtime('com.h2database:h2')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

Мы представили точно такие же зависимости и версии, чтобы предоставить точный эквивалент.

4. Структура проекта

Прежде чем мы продолжим работу и начнем работать над кодом для проекта, давайте представим здесь структуру projet, которая будет у нас после завершения добавления всего кода в проект:

Структура проекта Spring Boot

Мы разделили проект на несколько пакетов, чтобы следовать принципу разделения интересов, а код оставался модульным.

5. Определение сущности

Давайте посмотрим, как это можно сделать:

Person.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.javacodegeeks.example.model;
 
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
 
@Entity
public class Person {
 
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private int age;
 
    //standard getters and setters
     
    @Override
    public String toString() {
        return String.format("Person{id=%d, name='%s', age=%d}", id, name, age);
    }
}

Для краткости мы опускаем стандартные методы получения и установки, но их необходимо создавать, поскольку Джексон использует их во время сериализации и десериализации объекта.

Аннотация @Entity помечает этот POJO как объект, который будет управляться API-интерфейсами Spring Data, а его поля будут обрабатываться как столбцы таблицы (если не помечены как временные ).

Наконец, мы добавили пользовательскую реализацию для метода toString() чтобы мы могли печатать связанные данные при тестировании нашего приложения.

6. Определение репозитория JPA для доступа к базе данных H2

JPA предоставляет нам очень простой способ определения интерфейса репозитория JPA.

Прежде чем узнать, как определить репозиторий JPA, мы должны помнить, что каждый интерфейс JPA предназначен для взаимодействия только с одним объектом таблицы базы данных, когда задействованы функции, связанные с JPA. Мы это глубоко поймем, если взглянем на определение интерфейса:

PersonRepository.java

1
2
3
4
5
6
7
8
package com.javacodegeeks.example.repository;
 
import com.javacodegeeks.example.model.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
 
@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {  }

Хотя приведенное выше определение интерфейса пустое, у нас все же есть некоторые моменты, которые нам нужно понять:

  • Аннотация @Repository помечает этот интерфейс как Spring Bean, который инициализируется при запуске приложения. С этой аннотацией Spring позаботится о том, чтобы корректно управлять бросками взаимодействия с базой данных
  • Мы использовали Person в качестве параметра, чтобы показать, что этот интерфейс JPA будет управлять Person Entity
  • Наконец, мы также передали тип данных Long в качестве параметра. Это означает, что объект Person содержит уникальный идентификатор для типа Long .

7. Создание RESTful-контроллера

Контроллер RESTful, в котором мы предоставляем клиенту данные приложения. Мы будем использовать несколько HTTP-глаголов, таких как GET, POST, PUT и DELETE, для поддержки связанных с ними функций.

Для начала давайте определим класс PersonController который помечен как @RestController . Аннотация @RestController сигнализирует контейнеру Spring о том, что любые исключения, возникающие в этом классе, допустимы для передачи самому клиенту. Это другое поведение по сравнению с компонентом репозитория.

PersonController.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.javacodegeeks.example.controller;
 
import com.javacodegeeks.example.model.Person;
import com.javacodegeeks.example.repository.PersonRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
 
import java.util.List;
 
@RestController
public class PersonController {
 
    private final Logger LOG = LoggerFactory.getLogger(getClass().getName());
 
    private final PersonRepository personRepository;
 
    @Autowired
    public PersonController(PersonRepository personRepository) {
        this.personRepository = personRepository;
    }
 
    ...
}

Давайте предоставим некоторую мощность этому контроллеру, добавив конкретные API, которые выполняют реальные операции.

7.1 Вставка данных с помощью POST

Мы начнем с добавления API, с помощью которого мы можем добавлять данные в базу данных H2. Поскольку этот метод принимает объект Person в его @RequestBody , объект JSON for Person должен быть передан API в запросе.

PersonController.java

1
2
3
4
5
6
7
@RequestMapping(value = "", method = RequestMethod.POST)
public Person createPerson(@RequestBody Person person) {
    LOG.info("Saving Person: {}.", person);
    personRepository.save(person);
    LOG.info("Person saved: {}.", person);
    return person;
}

Мы использовали Personrepository компонент Personrepository для доступа к методу, который предварительно определен в интерфейсе JpaRepository мы определили ранее для работы с Person Entity.

В следующем разделе мы попробуем этот API в REST-клиенте Postman.

7.2 Построение GET API

Теперь, когда у нас есть API для вставки данных в базу данных, мы можем создать API для получения объекта Person с его идентификатором. Здесь personId передается как PathVariable :

PersonController.java

1
2
3
4
5
6
@RequestMapping(value = "/{personId}", method = RequestMethod.GET)
public Person getPerson(@PathVariable Long personId) {
    Person person = personRepository.findOne(personId);
    LOG.info("Got person from DB: {}.", person);
    return person;
}

Чтобы получить все данные, которые присутствуют в базе данных, мы сделаем еще один GET API для получения всех данных из базы данных:

PersonController.java

1
2
3
4
5
6
@RequestMapping(value = "/all", method = RequestMethod.GET)
public List<Person> getAllPerson() {
    List<Person> persons = personRepository.findAll();
    LOG.info("Getting all Data: {}.", persons);
    return persons;
}

Он просто использует метод findAll репозитория JPA, чтобы получить все данные Person в БД и собрать их в список.

7.3 Обновление данных с помощью PUT

Теперь мы позволим клиенту обновлять существующие данные из базы данных. Для этого мы снова используем метод save . Когда метод save видит, что объект JSON заполнен полем id , он сначала находит объект с этим идентификатором, а затем обновляет предоставленные поля.

PersonController.java

1
2
3
4
5
6
7
@RequestMapping(value = "", method = RequestMethod.PUT)
public Person editPerson(@RequestBody Person person) {
    LOG.info("Updating Person: {}.", person);
    personRepository.save(person);
    LOG.info("Person updated: {}.", person);
    return person;
}

7.4 Удаление данных с помощью DELETE

Теперь у нас будет последняя операция удаления данных, когда идентификатор человека передается как PathVariable :

PersonController.java

1
2
3
4
5
6
@RequestMapping(value = "/{personId}", method = RequestMethod.DELETE)
public void deletePerson(@PathVariable Long personId) {
    LOG.info("Deleting Person with ID {}.", personId);
    personRepository.delete(personId);
    LOG.info("Person deleted.");
}

8. Включение перехватчика запроса

Хотя в этом нет особой необходимости, в этом примере мы также включим перехватчик запросов. Перехватчик запросов позволяет нам что-то делать с объектом запроса до того, как он достигнет контроллера. Как только Контроллер выполнит запрос и вернет ответ, этот объект ответа снова пройдет через Перехватчик запросов. Давайте определим перехватчик запросов здесь:

JCGRequestInterceptor.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.javacodegeeks.example.interceptor;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
@Component
public class JCGRequestInterceptor extends HandlerInterceptorAdapter {
 
    private final Logger LOG = LoggerFactory.getLogger(getClass().getName());
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        LOG.info("Incoming request.");
        return super.preHandle(request, response, handler);
    }
 
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        LOG.info("Outgoing request.");
        super.postHandle(request, response, handler, modelAndView);
    }
}

9. Запуск проекта с Maven

Перед тем, как запустить проект, нам нужно также определить основной класс для проекта. Вот определение основного класса с компонентом Request Interceptor:

Запуск проекта

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
package com.javacodegeeks.example;
 
import com.javacodegeeks.example.interceptor.JCGRequestInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
 
@SpringBootApplication
public class BootApp {
 
    public static void main(String[] args) {
        SpringApplication.run(BootApp.class, args);
    }
 
    @Bean
    public JCGRequestInterceptor requestInterceptor() {
        return new JCGRequestInterceptor();
    }
}

Теперь, когда это сделано, мы можем запустить наш проект. С приложением maven легко запустить приложение, просто используйте следующую команду:

Запуск проекта

1
mvn spring-boot:run

Теперь, когда проект запущен, мы можем использовать инструмент Postman для доступа к API и посмотреть, работают ли они должным образом.

10. Доступ к API в Почтальоне

Мы начнем с вставки некоторых данных в базу данных H2 с помощью API POST мы создали:

Вставка данных в H2

Теперь мы можем получить этот объект Person с назначенным ему идентификатором JPA, т.е. 1:

Получить объект по идентификатору

Мы также можем попробовать API данных Get All, чтобы увидеть, возвращен этот объект или нет:

Получить все данные

Давайте обновим одно из полей созданного нами объекта:

Обновить данные

Наконец, мы пытаемся удалить данные, передав идентификатор в URL как PathVariable :

Удалить данные

11. Включение и запуск юнит-тестов

Любое приложение Spring не завершено без хотя бы одного модульного теста. В этом примере мы включим один тестовый блок, готовый к производству. Здесь это идет:

ControllerTests.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.javacodegeeks.example;
 
import com.javacodegeeks.example.controller.PersonController;
import com.javacodegeeks.example.repository.PersonRepository;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
 
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
@RunWith(SpringJUnit4ClassRunner.class)
public class ControllerTest {
 
    private MockMvc mockMvc;
 
    @InjectMocks
    private PersonController controller;
 
    @Mock
    private PersonRepository repository;
 
    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        controller = new PersonController(repository);
        mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
    }
 
    @Test
    public void getAllPerson_Pass() throws Exception {
        mockMvc.perform(
                get("/all"))
                .andExpect(status().is2xxSuccessful());
    }
}

Мы сделали несколько вещей в приведенном выше примере. Давайте разберемся по очереди:

  • Я пометил этот класс аннотацией @RunWith(SpringJUnit4ClassRunner.class) которая предоставляет тестовый пример с бегуном.
  • Когда мы используем Mockito, нам нужно включить его аннотации. Это делается с помощью initMocks(...) метода initMocks(...) .
  • Мы использовали метод mockMvc объекта mockMvc для проверки кода состояния, возвращаемого API-интерфейсом GET /all и сравнивали его с любым 2XX состояния 2XX .

Когда мы запустили этот тестовый пример в IntelliJ, мы увидели следующий вывод:

Запуск теста Spring Boot

Увидеть тест-кейс с зеленым на нем — отличное чувство, не так ли?

12. Использование Spring Boot CLI

Интерфейс командной строки Spring Boot — это программное обеспечение, которое мы можем использовать для запуска и тестирования приложений Spring Boot из командной строки. В Spring Boot CLI внутренне используются средства запуска Spring Boot и компоненты AutoConfiguration для сбора необходимых зависимостей и запуска приложения.

Чтобы начать использовать CLI, самый быстрый способ — загрузить ZIP-файл, перейти в каталог bin и проверить команду, как показано ниже:

Загрузка и использование Spring CLI

Чтобы использовать Spring CLI из любого места, добавьте этот JAR в вашу переменную PATH.

Теперь давайте быстро покажем, насколько мощным является Spring Boot CLI. CLI может использоваться для запуска и запуска отдельных скриптов на основе Groovy без предоставления каких-либо зависимостей. Мы сделаем один файл и назовем его «HelloWorld.groovy». Обратите внимание на расширение файла, так как необходимо, чтобы файл был только типа groovy. В файл мы поместим простой фрагмент кода:

HelloWorld.groovy

1
2
3
4
5
6
7
@RestController
class HelloWorld {
  @RequestMapping("/")
  String hello() {
    "Hello World!"
  }
}

Теперь перейдите в папку, где вы создали этот скрипт и выполните следующую команду:

HelloWorld.groovy

1
spring run HelloWorld.groovy

Эта команда запустит упомянутый скрипт Grovvy на порте по умолчанию 8080. Давайте попробуем посетить этот порт сейчас:

Hello World от CLI

Разве это не было легко? Обратите внимание, что при написании скрипта Groovy не было никаких зависимостей, конфигурации и операторов импорта. Это связано с тем, что эту ответственность несут основные компоненты Spring Boot, Groovy Compiler ( groovyc ) и Groovy Grape (Groovy’s JAR Dependency Manager).

13. Вывод

В этом уроке мы рассмотрели, как легко и быстро создать API промышленного уровня с помощью Spring Boot. Нам удалось создать несколько полнофункциональных API-интерфейсов, которые взаимодействовали с базой данных, а также выполняли тестовый модуль.

Мы попробовали API в RESTful-клиенте промышленного уровня Postman и увидели, что наши API отвечают на вызовы, как и ожидалось. База данных H2, которую мы использовали в этом уроке, очень легко заменить реальной базой данных, такой как MySQL, MongoDB или любой другой базой данных.

14. Загрузите исходный код

В этом примере мы рассмотрели, как начать работу с базовым проектом Spring Boot.

Скачать
Вы можете скачать полный исходный код этого примера здесь: JCG-SpringBoot-Example