Первая часть здесь             В этой части мы создадим работоспособный микросервис, придерживаясь правильной архитектуры, которая обеспечивает качества, важные для промышленного проекта: гибкость, простота внесения доработок и исправления ошибок, масштабируемость.             Запросы от клиента через транспортный слой попадают в слой сервисов. Сервисы при помощи классов DAO-слоя посылают запросы к базе данных. Совершив необходимые операции, классы сервисного слоя передают их результат в транспортный слой, где формируется ответ на обработанный запрос. Иногда, операции сервисного слоя инициируются не по запросу, а по таймеру при помощи планировщика заданий.             Spring – это стандартный framework для создания backend-сервисов на языке Java. Spring Boot - это расширение Spring, которое позволяет быстро подключать типовые функции приложения (web-сервер, подключение к базе данных, безопасность и т.д.) при помощи «стартеров». Подключите библиотеки Spring Boot в проект, отредактировав файл build.gradle:             Плагины облегчают жизнь, гарантируя использование неконфликтующих между собой версий библиотек Spring Boot. Стартер spring-boot-starter-web создаст и запустит для нас готовый к эксплуатации web-сервер.     Затем необходимо задекларировать и стартовать Spring Boot приложение в файле Main.java:             При старте приложения мы увидим в журнале сообщений на консоли, как стартует web-сервер Tomcat:             Обратите внимание, приложение не завершается, как это было раньше. Оно работает как сервис - web-сервер ожидает запросов на порту 8080.             В большинстве запросов к сервисам передаются какие-то данные. Например, если мы хотим создать пользователя, то скорее всего нам надо передать в запросе на его создание хотя бы имя. Стандартом передачи данных в REST запросах являются Data Transfer Objects (DTO).              Предположим, функциональность нашего приложения будет связана с пользователями. Тогда первым делом надо написать обработчик запросов на их создание, а значит нам нужно создать соответствующий DTO-класс, чтобы передавать данные о новых пользователях. Добавьте новый java-package, где будут размещаться DTO-классы, назовите его web.dto: Добавьте новый класс CreateUserDto в пакет web.dto:             Стандартом для написания web-сервисов является REST-архитектура. Она крайне проста – сервис получает http-запросы, обрабатывает их и отправляет ответы. Занимаются этим REST-контроллеры приложения.             На данном этапе у нас есть работающий web-сервер и описано, как будут передаваться данные для создания пользователя. Пришла пора написать первый REST-контроллер, который будет обрабатывать запросы на создание новых пользователей. Создайте класс WebController в java-пакете web: Создайте в проекте папку http-test, а в ней создайте файл test.http: Запустите приложение, а затем тестовый POST-запрос в файле test.http             В результате запуска запроса вы должны увидеть ответ Response code: 200 – это значит, что запрос выполнился успешно. В консоли приложения будет выведено сообщение: Create user request received: {name='JohnDoe'} – это значит, что запрос «дошел» до приложения. Но на данном этапе мы пока не можем ничего сделать – нам негде хранить пользователей.             Наше приложение уже умеет получать запросы на создание пользователей. Но, прежде чем приступить к обработке запроса, было бы неплохо проверить пришедшие данные на корректность. Предположим, мы хотим, чтобы в имени пользователя было от 5 до 25 символов и присутствовали только буквы латинского алфавита. Добавьте стартер валидации в файл build.gradle: Добавьте правила валидации на поле name в классе CreateUserDto: Добавьте проверку входного параметра метода createUser в классе WebController:             Запустите приложение и попробуйте послать тестовые запросы в файле http.test с разными вариантами значения поля name. Убедитесь, что при допустимых значениях код ответа равен 200 (успех), иначе – 400 (некорректный запрос).             Итак, наше приложение умеет получать запросы на создание пользователя и проверяет полученные данные на корректность. Пора каким-то образом сохранить нового пользователя в базе данных. Но прежде создадим класс модели пользователя.             Создайте java-пакет model, а в нем java-класс UserInfo, для операций над сущностью пользователя:                Внимательный читатель может заметить, что класс UserInfo очень похож на класс CreateUserDto. Неудивительно – если честно, я создал его копированием, удалив аннотации и поправив комментарии. Зачем в приложении два почти одинаковых класса?                CreateUserDto – это класс транспортного слоя для передачи данных, а UserInfo – это класс для оперирования сущностью пользователя на уровне бизнес-логики. Их одинаковость – это временное состояние. В дальнейшем, по мере появления новых требований к транспорту, может меняться класс CreateUserDto, а по мере появления нового бизнес-функционала будет дополнятся класс UserInfo. Иногда эти изменения синхронны, иногда – нет, и классы начнут все больше отличаться.                Транспортные классы отделены в транспортный слой от остального приложения – это признак хорошей архитектуры. В данном случае транспортный слой находится в пакете web. Зачем это нужно?                Представьте, что мы написали отличный менеджер пользователей, но в какой-то момент весь проект включили в платформу, где уже есть соглашение о том, как передаются данные о пользователях, и вам надо работать по указанному протоколу. Например, в целевой платформе вместо HTTP используется обмен сообщениями при помощи Kafka, или вместо ключа name в их системах ходят запросы с ключом userName.                При этом требования к работоспособности по старому протоколу тоже остаются в силе, например, «на время переезда» или «на время внедрения новой платформы». Это состояние может продлиться месяцы, а то и годы.                 Если транспортные классы вашего приложения «проникли» куда-то за пределы транспортной логики, то придется переписывать все приложение. Придется иметь несколько версий приложения: «старую» и «новую», и дорабатывать их параллельно. А это уже не просто дублирование кода – это грозит дублированием всего процесса ведения доработок: постановка, разработка, тестирование.                Но если вы «выдержали» архитектуру, то в вашем приложении просто появится новый транспортный сервис, а бизнес-логику можно будет переиспользовать. Как это делается, будет продемонстрировано позже.                На этом этапе у нас уже есть модель сущности пользователя, которого мы хотим сохранить, но пока нет базы данных для этого. Воспользуемся библиотекой Liquibase для создания базы данных.                 В промышленных приложениях используют СУБД PostgreSQL, Oracle или MS SQL Server, но мы воспользуемся H2, которая отлично подходит для учебных целей и может создать эфемерную базу данных в оперативной памяти при каждом запуске приложения. Подключите стартер JDBC, библиотеку Liqubase и библиотеку H2 в файле build.gradle:                Создайте файл application.yml в каталоге resources, указав параметры подключения к базе данных:                В каталоге resources создайте каталог db, а в нем файл changelog.xml, по которому liquibase создаст для нас таблицу user_info:                Создайте java-пакет configuration, а в нем класс DataBaseConfiguration, который обеспечит для приложения возможность отправлять запросы к базе данных: Если все сделано правильно, то в журнале сообщений при старте приложения будет запись: ChangeSet db/changelog.xml::user::dev ran successfully                Это означает, что в памяти была создана база данных user_db, а в ней таблица user_info, в которой мы будем сохранять данные о пользователях.                Благодаря Liquibase наше приложение обеспечено базой данных с необходимой нам таблицей user_info. Пришла пора научиться записывать туда данные. Делается это при помощи Data Access Object (DAO) – специализированного класса, который принято выносить в отдельный DAO-слой приложения.                Создайте java-пакет dao и в нем класс UserInfoDao, который будет отвечать за отправку запросов к таблице user_info:                DAO-классу UserInfoDao необходим вспомогательный класс, отвечающий за преобразование записи из таблицы БД в java-класс UserInfo. В пакете dao создайте пакет mapper и в нем класс UserInfoRowMapper:                Мы описали DAO-класс, теперь надо добавить конфигурацию, по которой Spring Boot создаст при старте приложения “bean” – экземпляр этого класса. В java-пакете configuration создайте класс DaoConfiguration: Добавьте в класс WebController использование класса UserInfoDao для работы с БД: Дополните тестовый файл test.http новыми запросами:                Выполните запросы последовательно. Если все сделано правильно, будут получены ответы с кодом 200. Наше приложение теперь умеет: сохранять информацию о пользователе, возвращать ее по запросу, удалять информацию о пользователе.                 Приложение работает, но имеет пока скрытую архитектурную проблему – обращение к DAO-классу происходит напрямую из транспортного слоя.                  Предположим, мы хотим избежать появления пользователей с именами типа «administrator», «root» или «system». Или, прежде чем посылать запросы на создание и удаление пользователя, неплохо было бы проверить его наличие в БД.                  Писать эту логику в транспортном слое нельзя – при появлении нового транспорта, этот фрагмент кода придется дублировать.  Добавлять эту проверку в UserInfoDao тоже не стоит потому что: Нарушается принцип единой ответственности, класс начинает терять свою специализацию «работа с таблицей user_info» DAO-классы – это тоже, в известном смысле, «деталь» приложения, которую, возможно, придется заменить или дополнить при переходе на новую СУБД. Это будет сложнее сделать, если код утяжелен какой-то дополнительной логикой, кроме отсылки SQL-запроса.                 Для написания подобной «бизнес-логики» правильно будет создать отдельный «сервисный» слой – это смысловое ядро приложения, вокруг которого крутятся сравнительно легко заменяемые «детали»: транспорт, база данных, клиенты других сервисов т.д.                Добавьте java-пакет service и создайте в нем класс UserInfoService, который будет отвечать за бизнес-операции над сущностью пользователя:                Замените использование dao-объекта на использование сервисного класса в WebController: Запустите последовательно три тестовых запроса. Если все сделано правильно, будут получены ответы с кодом 200. Обратите внимание на записи в консоли приложения: Create user request received: {name='JohnDoe'}User created by user info: {name='JohnDoe'}Get user info request received userName=JohnDoeDelete user info request received userName=JohnDoeUser with name JohnDoe deleted                 Они могут быт очень полезными при диагностике неполадок. Общие рекомендации по логгированию такие:  Информационное сообщение сразу при получении запроса с выводом содержимого запроса. Информационное сообщение об успешности операции перед выходом из метода в сервисном классе. Сообщение об ошибке сразу после catch. Не забудьте показать само исключение. Сообщение об ошибке перед throw, если не было catch Отладочные сообщения в сложных алгоритмах Продолжение следует