Очень поверхностная вводная презентация по Spring Boot для первого года курса TU Delft Object Oriented Programming Project.

О чем это / Для кого это

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

Почему / для чего используется Spring?

Spring - самая популярная среда разработки приложений для корпоративной Java. Это expressjs эквивалент Java. Его можно использовать для создания как веб-служб, так и приложений. Он также часто используется для создания APIs, которые затем используются отдельными базами кода, которые, возможно, используют другой язык программирования.

В качестве примера рассмотрим прошлогоднюю программу OOPP, которая касалась создания приложения, позволяющего бронировать номера, а также заказывать еду.

Что такое API

Интерфейс прикладного программирования (API) - это вычислительный интерфейс, который определяет взаимодействие между несколькими программными посредниками. Он определяет виды вызовов или запросов, которые могут быть сделаны, как их делать, форматы данных, которые следует использовать, соглашения, которым нужно следовать, и т. Д. Он также может предоставлять механизмы расширения, чтобы пользователи могли расширять существующие функциональные возможности различными способами и в разной степени. API может быть полностью настраиваемым, специфичным для компонента или спроектированным на основе отраслевого стандарта для обеспечения взаимодействия. Благодаря скрытию информации API-интерфейсы обеспечивают модульное программирование, позволяя пользователям использовать интерфейс независимо от реализации.

TL;DR:

API - это программный посредник, который позволяет двум приложениям взаимодействовать друг с другом. Другими словами, API - это мессенджер, который доставляет ваш запрос провайдеру, у которого вы его запрашиваете, а затем доставляет ответ вам.

Что такое конечная точка API

Проще говоря, конечная точка API - это точка входа в канал связи, когда две системы взаимодействуют. Он относится к точкам взаимодействия между API и сервером. Конечная точка может рассматриваться как средство, с помощью которого API может получить доступ к ресурсам, которые им нужны с сервера для выполнения своей задачи. Конечная точка API - это, по сути, модное слово для URL-адреса сервера или службы.

Например, для тех из вас, кто создал веб-игру, конечной точкой является каждый URL-адрес, поддерживаемый вашим приложением (скажем, / и /game или /play).

Chocolatey: менеджер пакетов для Windows

Обязательно запускайте powershell с правами администратора, если хотите устанавливать пакеты. Исполняемый файл установки Choco можно найти здесь.

Что такое Spring Boot

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

Требования

В этом проекте я буду использовать Java 15, которая может отличаться от того, что будет использоваться в проекте.

  • Установить Gradle (choco install gradle)
  • Убедитесь, что вывод gradle -version (часть JVM) иjava -v указывает на одну и ту же версию Java. Если это не так, попробуйте переустановить Java SDK (choco install opensdk)или обновите файлы paths.

  • Убедитесь, что Intellij использует правильную версию Java SDK для проекта. Нажмите ctrl + shift + alt + s, чтобы открыть панель структуры проекта в Intellij (отметьте, что мы создаем проект).

Если вы используете другую версию Java, обязательно измените атрибут sourceCompatibility = ‘15’ в build.gradle на любую версию Java, которую вы установили (например, измените его на sourceCompatibility = ‘13’, если вы используете Java 13).

Структура приложения

Клиент будет создавать ЗАПРОСЫ на наш сервер, которые будут обрабатываться нашим уровнем API или контроллером в терминологии Spring. Этот уровень управляет всеми конечными точками нашего приложения и извлекает данные из запроса, прежде чем передать их следующему уровню.

Уровень обслуживания отвечает за любую бизнес-логику нашего приложения. В качестве примера рассмотрим сценарий, в котором у вас есть веб-сайт, и вы хотите разрешить пользователям создавать учетные записи, но никакие две учетные записи не должны иметь одинаковое имя пользователя. Пользователь отправит запрос на сервер с просьбой создать учетную запись вместе со своим именем пользователя (и учетными данными, но здесь это не важно). Контроллер получит запрос и деструктурирует имя пользователя перед вызовом соответствующего метода службы и передачей ему имени пользователя. Служба теперь отвечает за проверку того, существует ли уже имя пользователя в базе данных или нет. Обратите внимание, что взаимодействие с базой данных осуществляется на следующем уровне.

Уровень доступа к данным или репозиторий отвечает за взаимодействие с базой данных. На этом этапе генерируется типичный ответ и отправляется обратно пользователю (исключения могут привести к тому, что ответ будет сгенерирован на любом из трех уровней). Разделение приложения на слои чрезвычайно важно и имеет множество преимуществ.

  • Это увеличивает скорость разработки
  • Это делает код более чистым
  • Разные команды могут работать над разными слоями
  • Повышает отказоустойчивость приложения.

Справа вы можете увидеть класс Entity, который мы реализуем позже, класс Person с идентификатором и именем.

Файловая структура

Существует несколько различных способов структурирования такого приложения, один из которых я предпочитаю показан выше. Другой способ сделать это - создать папку Person, внутри которой будут находиться все остальные классы, которые я не буду использовать, поскольку я считаю, что это выглядит более запутанным.

Что такое Gradle

Gradle - это инструмент автоматизации сборки для многоязычной разработки программного обеспечения. Он контролирует процесс разработки в задачах от компиляции и упаковки до тестирования, развертывания и публикации. Поддерживаемые языки включают Java (Kotlin, Groovy, Scala), C / C ++, JavaScript.

Что такое почтальон

Postman - это масштабируемый инструмент тестирования API, который быстро интегрируется в конвейер CI / CD. Он начался в 2012 году как побочный проект Абхинава Астханы по упрощению рабочего процесса API при тестировании и разработке. API означает интерфейс прикладного программирования, который позволяет программным приложениям взаимодействовать друг с другом через вызовы API.

Скачать

Spring Initializr - это веб-инструмент, с помощью которого мы можем легко создать структуру проекта Spring Boot.

В качестве альтернативы есть инструмент командной строки, который сделает это за вас!

choco install spring-boot-cli

spring init Copy
    --build=gradle 
    -j 15 
    -d 'web,jpa,postgresql' 
    -a SpringPresentation 
    -n SpringPresentation
    -g '.'

Эта команда создаст проект с:

  • Gradle как его система сборки (по умолчанию это maven)
  • Java версии 15
  • Зависимости, упомянутые ранее (драйвер web, jpa и postgresql)
  • Идентификатор артефакта SpringPresentation
  • Название проекта SpringPresentation
  • Нет пакета

Если вы хотите использовать это, запустите spring help init для документации.

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

mkdir SpringPresentation | tar -xf SpringPresentation.zip -C SpringPresentation

Это создает новую папку SpringPresentation и извлекает из нее заархивированную папку, которую вы только что загрузили (при условии, что вы находитесь в правильном каталоге). Вы также можете запустить

idea64.exe ., чтобы запустить Intellij в вашем текущем каталоге.

Необязательно: если вы хотите реализовать весь проект, включая базу данных, убедитесь, что у вас установлен PostgtSQL (я установил его в Docker). Чтобы создать базу данных с помощью docker run:

docker run --name springboottestdb -e POSTGRES_PASSWORD=password -d -p 5432:5432 postgres:alpineCopy
    | docker exec -it 68627bf9417e bin/bash

Где 68627bf9417e - идентификатор вашего контейнера. Я не буду углубляться в это, поскольку это выходит за рамки данной статьи.

В качестве альтернативы вы можете использовать очень популярный механизм баз данных Java в оперативной памяти под названием H2, инструкции по которому будут выполнены в ближайшее время.

Зависимости

  • Spring Web: Разрешает создание приложений RESTful.
  • JPA: это упрощает создание приложений на основе Spring, использующих технологии доступа к данным.
  • Драйвер PostgreSQL

Кодирование

На этом этапе ваш пустой проект должен выглядеть так:

├── build.gradle
└── src
    ├── main
    │   ├── java
    │   │   └── SpringPresentation
    │   │       └── SpringPresentationApplication.java
    │   └── resources
    │       ├── application.properties
    │       ├── static
    │       └── templates
    └── test
        └── java
            └── SpringPresentation
                └── SpringPresentationApplicationTests.java

Мы начнем с редактирования файла src.main.resources.application.properties на это:

  • spring.datasource.url URL базы данных
  • spring.datasource.usernamePostgreSQL имя пользователя
  • spring.datasource.passwordPostgreSQL пароль
  • spring.jpa.hibernate.ddl-autoУказывает, как управлять базой данных при настройке (create-drop очищает базу данных при каждом запуске приложения, используется в целях тестирования)
  • spring.jpa.show-sql Регистрирует любые команды SQL.
  • spring.jpa.properties.hibernate.dialect Сообщает jpa, какой вид SQL мы используем
  • spring.jpa.properties.hibernate.format_sql Украшает выходные данные SQL

Эта конфигурация работает с моей настроенной базой данных PostgreSQL, но в случае, если вы хотите использовать базу данных H2 вместо этого, выполните следующие изменения в src.main.resources.application.properties:

  • Измените spring.datasource.url на jdbc:h2:mem:springboottestdb
  • Измените spring.datasource.username на sa (профиль по умолчанию) и оставьте пароль пустым.
  • Измените spring.jpa.properties.hibernate.dialect на org.hibernate.dialect.H2Dialect

И, наконец, перейдите к файлу build.gradle и замените runtimeOnly ‘org.postgresql:postgresql’ на runtimeOnly ‘com.h2database:h2’ (не забудьте пересобрать проект после этого шага)

Обратите внимание, что все остальное, упомянутое в этой статье, будет работать одинаково как в надлежащей базе данных PSQL, так и в базе данных H2.

Теперь мы создадим следующие 4 пакета в src.main.java.SpringPresentation:

  1. API
  2. Модели
  3. Репозитории
  4. Услуга

Теперь давайте создадим src.main.java.SpringPresentation.Models.Person. Добавьте личное поле long id;, а также String name;. Создайте геттеры, установщики, метод равенства, toString, а также 2 конструктора:
public Person() и public Person(String name).

Пока мы создали простой класс Java, теперь давайте превратим его в Spring Entity.
Перед public class Person добавьте следующие 2 аннотации:

  • @Entity(name = “Person”)
  • @Table(name = “people”)

Первый сообщает Spring, что это класс Entity, и указывает его имя. Имя по умолчанию - это имя класса (поэтому в нашем случае это не имеет значения), однако рекомендуется всегда указывать имя.
Второй определяет основную таблицу для аннотированной сущности.

На этом этапе вы можете заметить, что Intellij выдает ошибку при наведении курсора на имя таблицы
Cannot resolve table 'people'. Это потому, что нам еще предстоит настроить источник данных в Intellij. Нажмите
ctrl + shift + a и найдите create data source. Выберите PostgreSQL. Измените пользователя, пароль и базу данных на те, которые указаны в нашем application.properties. Нажмите «Применить» и «ОК». На этом этапе ошибка должна измениться на
Cannot resolve table 'people', это нормально, поскольку таблица не существует и еще не должна существовать, она будет создана автоматически после запуска приложения. Обратите внимание: если вы используете базу данных H2, вы можете пропустить этот шаг, поскольку таблица будет создана во время выполнения, ошибки все равно будут видны. Не волнуйся об этом; таблица существует и работает как задумано.

Вы должны увидеть еще одну ошибку в классе Person: Persistent entity 'Person' should have primary key , поскольку мы сказали Spring, что это таблица базы данных, которая должна иметь первичный ключ. Добавьте аннотацию @Id перед private long id;.

На этом этапе вы могли заметить что-то странное: мы не включили параметр id ни в один конструктор, так как же он когда-либо получит значение? Это не ошибка, мы хотим, чтобы любые идентификаторы генерировались базой данных, а не пользователем (представьте, если бы каждый раз, когда пользователь, который хотел создать учетную запись на веб-сайте, например, должен был включать уникальный идентификатор в свою форму; пользователь не имел бы возможности узнать, уникален ли его идентификатор). Обычный способ генерации идентификаторов базы данных - использование генератора последовательности.

Теперь мы определим наш генератор последовательности и назначим его нашему параметру id. Добавьте следующее перед объявлением идентификатора:

Давайте подробнее расскажем Spring о наших атрибутах. Мы можем указать имя, которое они будут иметь в базе данных (поскольку они являются столбцами), и несколько других вещей, например, могут ли они быть обновлены или иметь значение NULL. Поместите следующие 2 конфигурации перед объявлениями их соответствующих атрибутов.

Если мы теперь запустим приложение и обновим источник данных Intellij, мы увидим следующее:

Как мы видим, наша таблица базы данных создана, и ошибки с именами исчезли.

Далее мы будем создавать интерфейс репозитория. Создайте файл src.main.java.SpringPresentation.Repositories.PersonRepository. Сделайте наш интерфейс расширенным с
JpaRepository<Person, Long>. Первый параметр - это класс, с которым будет работать наш репозиторий, а второй указывает тип идентификатора этого класса. Этот интерфейс предоставляет нам некоторые базовые операции CRUD (создание, чтение, обновление, удаление). Давайте добавим метод updateNameById, который обновит имя человека с указанным идентификатором.

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

Строка, которую мы передали в аннотации, - это имя этого репозитория, которое в нашем случае необязательно. Как мы увидим позже, это необходимо, когда мы имеем дело с несколькими репозиториями.

Это все, что нам нужно в нашем интерфейсе репозитория, остальное обрабатывает JPA.

Переходим к нашему классу Сервис. Создайте файл src.main.java.SpringPresentation.Services.PersonSerivce. Как вы уже могли догадаться, мы добавим к нему аннотацию @Service

У нашего класса Service будет один атрибут: PersonRepository, который мы создали ранее. Идем дальше и создаем конструктор. Пришло время аннотировать это. Добавьте @Autowired над конструктором, это говорит Spring, что он должен использовать Dependency Injection. Наконец, внутри параметров нашего конструктора добавьте @Qualifier("PersonRepository"). Это гарантирует, что репозиторий с именем PersonRepository будет внедренным.

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

Имейте в виду, что наше приложение довольно простое. Фактически, в этот уровень включено 0 логических схем. В обычном приложении это должен быть самый сложный слой.

Наконец, давайте создадим контроллер src.main.java.SpringPresentation.Api.PersonController. Здесь есть еще несколько аннотаций. Прежде всего, давайте добавим следующее над объявлением класса:

@RestController // Tells Spring this is a REST controller
@RequestMapping("api/v1")

Вторая аннотация делает так, чтобы мы могли получить доступ к нашему API по адресу http://localhost:8080/api/v1/ вместо http://localhost:8080/. Это снова хорошая практика, поскольку часто в реальных проектах одновременно размещается множество версий своего API (из-за того, что обратная совместимость не является жизнеспособной).

Есть 4 аннотации, которые мы собираемся использовать в зависимости от того, какой тип HTTP-запроса мы хотим, чтобы наша конечная точка / метод поддерживала:

  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping

Все они имеют параметр path, который указывает относительный URL-адрес для http://localhost:8080/api/v1. Например, @GetMapping(path = "/example") создаст обработчик запроса GET для http://localhost:8080/api/v1/example.

Но как насчет использования данных, которые были включены в запрос? @PathVariable, @RequestBody сообщают Spring извлечь переменную из пути или тела запроса соответственно. В случае @PathVariable путь сопоставления должен включать имя переменной, заключенное в фигурные скобки, чтобы Spring знал, какой из них использовать. Это делается автоматически для @RequestBody.

Здесь особо не о чем говорить. Помните, что @RequestBody попытается извлечь один объект из тела запроса. Это означает, что, например, в нашем updateNameById методе не может быть одновременно id и person. Наконец, помните, что это попытается подогнать найденные данные к одному из определенных конструкторов, и у нас действительно есть конструктор public Person(String name).

На этом наше приложение в основном готово, пора протестировать наши конечные точки с помощью Postman!

Давайте сначала посмотрим, что происходит, когда мы отправляем запрос GET на http://localhost:8080/api/v1/

Как и ожидалось, мы получаем пустой массив, поскольку в нашей базе данных еще нет объектов. Давайте добавим! Помните, что сопоставление POST было на http://localhost:8080/api/v1/insert, и мы использовали @RequestBody для извлечения человека из запроса. Напомним, Spring будет автоматически пытаться уместить данные запроса в конструктор Person, что означает, что если мы отправим полезную нагрузку, содержащую атрибут с именем name, который имеет любое значение типа String, Spring создаст объект Person вне этого.

Оно работает! Мы даже получаем полный объект, возвращенный нам, как и ожидалось, и мы видим, что ему автоматически был присвоен идентификатор 1! Давайте снова попробуем нашу предыдущую конечную точку GET;

На этот раз мы получаем массив из одного элемента - человека, которого мы только что добавили! Поскольку теперь у нас есть объект в базе данных, давайте посмотрим, что произойдет, когда мы сделаем еще один GET на http://localhost:8080/api/v1/get/1

Помните, что для этой конечной точки мы использовали @PathParameter для получения идентификатора. Посмотрим, что произойдет, когда мы введем несуществующий идентификатор.

Мы получаем null вместо ошибки, что приятно. Помните, что этот метод вернул Необязательно. Пришло время проверить наше сопоставление PUT. Для этого нам снова нужно указать name, для примера давайте установим его на UPDATED и посмотрим, что произойдет.

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

У нас есть только удалить, так что время проверить и это. Нам просто нужно указать здесь переменную пути, и все готово.

Давайте повторно воспользуемся нашим первым запросом, чтобы убедиться, что в базе данных ничего не осталось.

Наконец, давайте убедимся, что наш Генератор последовательности работает правильно, добавив еще одну сущность в базу данных.

Как мы видим, у него идентификатор 2, что означает, что наш секвенсор работает правильно.

Поздравляю! Вы просто использовали почтальона вместо того, чтобы писать тесты, посмотрите, поможет ли вам это…

Мои учебные ресурсы

Если вы зашли так далеко, я хочу поблагодарить вас за то, что вы прочитали, и я надеюсь, что вы что-то поняли :)

Опять же, имейте в виду, что все это написано первокурсником, который еще не прошел курс. Не принимайте что-либо из этого как стопроцентно правильное или передовое, или даже как то, что вы обязательно будете использовать во время самого курса. Я научился некоторым основам Spring, в основном используя следующие источники (первые 2 сильно повлияли на пример приложения), поэтому обязательно изучите их все, особенно третий. Код для этого был размещен на моем github, ссылку на который вы можете найти ниже. Удачного кодирования;)

И последнее, но не менее важное: вы можете найти полный код этого проекта здесь.