Пишем свое первое приложение на Java и Spring Boot
Полезные ссылки:
Информация про Java Spring Boot
Платформа Java Spring Boot была впервые выпущена в 2004 году. С тех пор платформа постоянно обновляется и пополняется новыми функциями. На сегодняшний день платформа является наиболее продвинутым фреймворком для создания веб сайтов на основе языка Java.
C первых дней выпуска Spring был тепло встречен разработчиками Java, так как это был первый достойный конкурент технологии JavaBeans. JavaBeans, как и Spring, предоставляют набор различных решений для реализации веб проектов.
На основе Spring Boot вы можете создавать веб сайты различных жанров и возможностей. Вы можете создать простой одностаничник или крупный веб проект для какого-либо международного банка.
Spring содержит хорошо описанную документацию, а также множество готовых решений, что можно копировать и использовать в своих проектах.
Технология MVC
Spring реализует шаблон проектирования MVC. MVC расшифровывается как «model-view-controller» или же модель вид контроллер. Данный шаблон позволяет структурировать все файлы внутри проекта и делает чтобы каждый файл отвечал лишь за свою часть работы.
Рассмотрим простой запрос к веб сайту, написанному на Spring Boot. Когда пользователь переходит на какую-либо страницу сайта, то переход отслеживается в контроллере. Контроллер понимает по какому URL адресу перешёл пользователь и далее обращается к модели.
Модели могут обратиться к базе данных, получить оттуда какие-то значение, выполнить различные вычисления и далее вернуть эти данные обратно в контроллер. Далее контроллер передает все данные в шаблон, который как раз и показывается пользователю.
Шаблон в свою очередь представляет из себя простую HTML страницу с различными текстами, кнопками, картинками и прочим.
Таким образом, приложение делиться на три части, каждая из которых выполняет свою роль в проекте.
Создание проекта
Создать пустой шаблонный проект можно самому или же можно воспользоваться специальным сайтом для подготовки готового проекта. Если создавать пустой проект самому, то необходимо следовать официальной документации.
В случае использования сервиса Start Spring.io вы можете выбрать нужные для вас пакеты, после чего нажать на клавишу «Generate» для генерации и скачивания архивного проекта.
Чтобы открыть проект вы можете воспользоваться любой средой разработки, к примеру программой IntelliJ IDEA.
План курса
В ходе курса мы научимся писать сайты с использованием Java Spring Boot MVC. Мы рассмотрим все основные моменты при работе с данным фреймворком. За курс мы создадим множество шаблонов, рассмотрим работу с шаблонизаторами, рассмотрим работу с базой данных, а также создадим небольшой полноценный проект по типу веб-блога.
К концу курса у вас будет достаточно знаний чтобы начать разрабатывать сайты на основе Java Spring.
Перед изучением курса вам необходимо ознакомиться с языками для вёрстки сайта: HTML, CSS и JavaScript. Также вам необходимо обладать навыками работы с языком Java прежде чем изучать платформу Спринг. Все дополнительные курсы можно посмотреть на нашем ресурсе.
Исходный код
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.2.2.RELEASE
com.itproger
blog
0.0.1-SNAPSHOT
blog
Demo project for Spring Boot
11
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-devtools
runtime
true
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
org.springframework.boot
spring-boot-maven-plugin
Создаем свой Spring Boot Starter
Один из мощных механизмов Spring Boot — возможность использования «стартеров» для быстрой настройки нового проекта с предварительно сконфигурированными зависимостями.
https://www.youtube.com/watch?v=7qvwtlnxVH8\u0026list=PLMN3dELi3-VdVo8NGOYqaOLC2alq6ZmSh
Стартеры Spring Boot — это, предварительно упакованные наборы зависимостей и сконфигурированных бинов для обеспечения определённой функциональности. Например, доступа к базе данных или безопасности.
Возьмём мою библиотеку GodFather Telegram, которая позволяет создавать ботов для Telegram. Без стартера вам пришлось бы создать бинов 15: бин для принятия входящих событий от телеграма, бин для отправки сообщений, бин для построения сценария бота, множество инфраструктурных бинов. Без подробной документации не обойтись.
Стартер даёт возможность разработчику библиотеки произвести начальную конфигурацию и определить инфраструктурные бины. А пользователю библиотеки остаётся подключить зависимость и начинать писать бизнес-код, не думая о том, как получить сообщение от телеграма или как его отправить пользователю. Все эти бины сконфигурированы мной, как разработчиком стартера.
У клиентов стартера остаётся возможность переопределить внутренние бины, если сценарии использования выходят за рамки дефолтных настроек. Также разработчик стартера может вынести множество настроек в файл application.properties.
В этой статье мы рассмотрим, как создать собственный стартер Spring Boot. Обсудим некоторые лучшие практики и советы по созданию.
Создаем свой стартер
Написание стартера будем рассматривать на примере моей библиотеки для создания ботов GodFather Telegram.
Для начала определимся с groupId и artifactId. Все официальные стартеры придерживаются следующей схемы именования spring-boot-starter-*, где * это конкретный тип приложения.
Сторонние стартеры не должны начинаться с spring-boot, поскольку они зарезервированы для официальных стартеров от разработчиков Spring. Сторонний стартер обычно начинается с названия проекта. Например, мой стартер называется telegram-bot-spring-boot-starter.
Можно реализовать стартер как дополнительный maven-модуль основного проекта, или как отдельный проект. Я предпочитаю делать отдельный проект.
Поэтому создаём пустой SpringBoot проект. Убедитесь, что в pom.xml присутствуют следующие зависимости:
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-configuration-processor
true
Добавьте зависимости вашей библиотеки. В моём случае их три:
dev.struchkov.godfather.telegram
telegram-consumer-simple
${telegram.bot.version}
dev.struchkov.godfather.telegram
telegram-core-simple
${telegram.bot.version}
dev.struchkov.godfather.telegram
telegram-sender-simple
${telegram.bot.version}
Теперь создадим обычный класс конфигурации Spring с нужными бинами.
@Configuration
public class TelegramBotAutoconfiguration {
@Bean(AUTORESPONDER_EXECUTORS_SERVICE)
public ExecutorService executorService(
TelegramBotAutoresponderProperty autoresponderProperty
) {
return Executors.newFixedThreadPool(autoresponderProperty.getThreads());
}
… … … … …
@Bean
public TelegramService telegramService(TelegramConnect telegramConnect) {
return new TelegramServiceImpl(telegramConnect);
}
}
Смысла описывать всю конфигурацию нет, это просто бины необходимые для работы библиотеки.
Пока это ничем не примечательный модуль с обычным классом конфигурации, что делает его стартером? Стартером его сделает особый файл, создадим его.
В папке resources создаём папку META-INF, в ней папку spring, и в ней файл org.springframework.boot.autoconfigure.AutoConfiguration.imports.
Этот файл должен содержать перечисление конфигураций. В моём случае это одна конфигурация. Каждую конфигурацию указывайте с новой строки.
dev.struchkov.godfather.telegram.starter.config.TelegramBotAutoconfiguration
SpringBoot автоматически найдёт этот файл, возьмёт перечисленные конфигурации и создаст указанные в них бины, добавив их в контекст. Так класс конфигурации превращается в класс автоконфигурации. Вот и вся магия ????
Проперти классы
Если вашей библиотеке требуются какие-то конфигурационные переменные, стоит позволить передавать их через application.yml. Например, в моей библиотеке это информация данные для подключения к Telegram: токен и имя бота.
Для этого создайте класс и аннотируйте его @ConfigurationProperties или добавьте существующий через конфигурацию:
@Configuration
public class TelegramBotPropertyConfiguration {
@Bean
@ConfigurationProperties(«telegram.bot»)
public TelegramBotConfig telegramConfig() {
return new TelegramBotConfig();
}
}
А в pom.xml добавим зависимость, которая генерирует метаданные о классах приложения, аннотированных @ConfigurationProperties.
org.springframework.boot
spring-boot-configuration-processor
true
Этот процессор аннотаций создаст файл META-INF/spring-configuration-metadata.json, который содержит метаданные о параметрах конфигурации в классе TelegramBotConfig. Эти метаданные включают Javadoc о полях, поэтому убедитесь, что Javadoc понятен.
https://www.youtube.com/watch?v=MJCFm16x6NA\u0026list=PLMN3dELi3-VdVo8NGOYqaOLC2alq6ZmSh
В Idea плагин Spring Assistant будет читать метаданные и обеспечивать подсказки для этих свойств.
Так это будет выглядеть в Idea
Также мы можем добавить некоторые свойства вручную, создав файл META-INF/additional-spring-configuration-metadata.json:
{
«properties»: [
{
«name»: «telegram.bot.enable»,
«type»: «java.lang.Boolean»,
«description»: «Enables or disables Telegram Bot.»
}
]
}
Процессор аннотаций автоматически объединит содержимое этого файла с автоматически созданным файлом.
Conditionals
Добавим больше вариаций конфигураций стартеру. На данный момент при добавлении стартера поднимаются все бины. Но чаще всего нужны конкретные бины в зависимости от уже имеющихся бинов или указанных значений проперти.
Например, в моем случае нет смысла поднимать бины, если пользователь не указал переменные подключения к боту в application.yml, потому что всё завязано на них.
Для решения этой проблемы существуют аннотации @Conditional…
@ConditionalOnProperty
Воспользуемся аннотацией @ConditionalOnProperty, которая проверяет наличие заполнения конкретной проперти в application.yml.
@Bean
@ConfigurationProperties(«telegram.bot»)
@ConditionalOnProperty(prefix = «telegram.bot», name = «token»)
public TelegramBotConfig telegramConfig() {
return new TelegramBotConfig();
}
Бин TelegramBotConfig будет создаваться, только если указана проперти telegram.bot.token.
Используя параметр аннотации value, можно указать конкретные значения проперти. В моем случае важно само наличие токена.
@ConditionalOnBean
Также воспользуемся @ConditionalOnBean, которая создаёт бин, когда в BeanFactory присутствует указанный в @ConditionalOnBean бин.
@Bean
@ConditionalOnBean(TelegramBotConfig.class)
public TelegramDefaultConnect telegramDefaultConnect(TelegramBotConfig telegramConfig) {
return new TelegramDefaultConnect(telegramConfig);
}
@ConditionalOnMissingBean позволяет создавать бин, если указанный бин отсутствует в BeanFactory.
@ConditionalOnClass
Создаёт бин, только если указанный класс есть в classpath. И противоположный ему @ConditionalOnMissingClass.
Несколько классов автоконфигурации
При добавлении нескольких классов автоконфигурации и использовании аннотаций @ConditionalOnBean вы столкнётесь с неожиданным поведением — условие не будет отрабатывать и бин не будет создаваться.
Это происходит, потому что Spring берёт конфигурации в произвольном порядке, и может сначала попробовать поднять бин помеченный @ConditionalOnBean, хотя бин в условии будет создан позже. Порядок классов автоконфигураций в файле никак не влияет на порядок создания бинов.
Чтобы этого избежать, используйте аннотации @AutoConfigureAfter или @AutoConfigureBefore над классом конфигурации, которые явно задают порядок создания бинов.
Опциональные бины
Еще одним полезным классом является ObjectProvider, который позволяет передавать необязательные бины. Похоже на логику работы Optional.
@Bean
@ConfigurationProperties(«telegram.bot»)
@ConditionalOnProperty(prefix = «telegram.bot», name = «token»)
public TelegramBotConfig telegramConfig(
ObjectProvider proxyConfigProvider
) {
final TelegramBotConfig telegramBotConfig = new TelegramBotConfig();
final ProxyConfig proxyConfig = proxyConfigProvider.getIfAvailable();
if (proxyConfig != null) {
telegramBotConfig.setProxyConfig(proxyConfig);
}
return telegramBotConfig;
}
Бин ProxyConfig является опциональным. Если его не будет, мы всё равно хотим создать TelegramBotConfig. Если не использовать ObjectProvider, то приложение упадёт при старте, если бина ProxyConfig не будет.
Бины по умолчанию
Мы можем позволить пользователю переопределять наши бины, но предоставлять дефолтные бины. Для этого воспользуемся аннотацией @ConditionalOnMissingBean
@Bean
@ConditionalOnMissingBean(PersonSettingRepository.class)
public PersonSettingRepository personSettingRepository() {
return new PersonSettingLocalRepository();
}
Обратите внимание, что в @ConditionalOnMissingBean мы указываем тот же класс, что и возвращаем. Таким образом, если пользователь стартера определит бин PersonSettingRepository, то дефолтный бин из автоконфигурации не будет создан.
Улучшаем время запуска
Классы конфигурации тоже можно аннотировать @Conditional…. И для каждого класса автоконфигурации Spring Boot оценивает условия, указанные в аннотации @Conditional…, чтобы решить, загружать ли автоконфигурацию и все необходимые в ней бины. В зависимости от размера и количества стартеров в приложении Spring Boot, это может быть очень дорогой операцией и повлиять на время запуска.
https://www.youtube.com/watch?v=0QV9Wxz8_rM\u0026pp=ygVO0J_QuNGI0LXQvCDRgdCy0L7QtSDQv9C10YDQstC-0LUg0L_RgNC40LvQvtC20LXQvdC40LUg0L3QsCBKYXZhINC4IFNwcmluZyBCb290
Существует ещё один процессор аннотаций, который генерирует метаданные об условиях всех автоконфигураций. Spring Boot считывает эти метаданные во время запуска и отфильтровывает конфигурации, условия которых не выполняются, без необходимости проверять эти классы.
Чтобы метаданные генерировались, нужно добавить процессор аннотаций в стартовый модуль:
org.springframework.boot
spring-boot-autoconfigure-processor
true
Во время сборки метаданные будут сгенерированы в файл META-INF/spring-autoconfigure-metadata.properties, который будет выглядеть так:
dev.struchkov.godfather.telegram.starter.config.TelegramBotAutoconfiguration=
dev.struchkov.godfather.telegram.starter.config.TelegramBotAutoconfiguration.AutoConfigureAfter=dev.struchkov.godfather.telegram.starter.config.TelegramBotDataConfiguration
dev.struchkov.godfather.telegram.starter.config.TelegramBotAutoconfiguration.ConditionalOnBean=dev.struchkov.godfather.telegram.simple.core.TelegramConnectBot
dev.struchkov.godfather.telegram.starter.config.TelegramBotDataConfiguration=
dev.struchkov.godfather.telegram.starter.config.TelegramBotDataConfiguration.AutoConfigureAfter=dev.struchkov.godfather.telegram.starter.config.TelegramBotPropertyConfiguration
Использование стартера
Теперь, когда стартер готов, мы можем его добавить в наше другое приложение:
dev.struchkov.godfather.telegram
telegram-bot-spring-boot-starter
${godfather.telegram.version}
Теперь нам доступны все сконфигурированные бины.
Заключение
Выделить определённые функции в модуль стартер, чтобы использовать их в любом приложении Spring Boot, — дело нескольких простых шагов.
Создайте автоконфигурацию, сделайте её настраиваемой и добавьте процессоры аннотаций, чтобы автоматически генерировать метаданные для повышения производительности и удобства использования.
на Struchkov.Dev в Telegram Гайдлайн spring java junior
Введение в Spring Boot: создание простого REST API на Java
Рейтинг статьи Загрузка…
В этой статье мы напишем маленькое приложение на Spring Boot, которое предоставляет REST-сервисы. Архитектура приложения будет стандартна и включать несколько слоев: dao, (service отсутствует) и controller. Все шаги по построению приложения просты. Код приложения можно скачать на GitHub.
Spring Initializr
Заготовку любого проекта на Spring Boot удобно взять на https://start.spring.io/. Здесь мы придумываем имя группы и имя артифакта будущего проекта на Maven, выбираем dependency, которые нам точно понадобятся и генерируем проект. А потом импортируем его в Eclipse как Maven-проект.
Нам понадобятся зависимости WEB, JPA и H2.
Встроенную базу данных H2 прикрепляем потому, что ее проще использовать для демонстрационных целей: не придется устанавливать настоящую базу вроде MySQL, а также прописывать ее настройки.
Maven-зависимости
В результате получаем сгенерированный POM с такими зависимостями:
Хоть файл и сгенерирован, это не мешает нам добавлять в него новые зависимости при необходимости.
Слои (multi-layer architecture)
Импортированный проект выглядит так, плюс мы создали пакеты для моделей, dao и контроллеров (выделены красным):
Service-layer отсутствует потому, что приложение слишком простое, бизнес-логики тут нет.
Модель
Модель будет состоять из одного класса Person:
Person аннотирован как JPA-сущность, то есть при запуске приложения в базе данных будет создана таблица с таким именем и полями.
DAO-layer предназначен для работы с данными. У нас он состоит из одного бина PersonRepository.
Благодаря аннотации @Repository и интерфейсу JpaRepository DAO-layer предельно прост:
Мы создаем бин PersonRepository, аннотируя его с помощью @Repository. Полученный бин реализует все методы интерфейса, можно ничего не писать самостоятельно, если не нужны какие-то особые запросы к базе. А стандартные операции поиска, добавления и удаления тут все реализованы.
Service-layer опускаем, поскольку приложение простое. В контроллере будем использовать бин PersonRepository.
Контроллер
Здесь реализованы запросы поиска, добавления, редактирования и удаления Person.
- Класс аннотирован @RestController и указан основной путь к запросам этого контроллера- “/persons”.
- С помощью аннотации @Autowired бин personRepository инжектирован в поле контроллера – теперь его можно использовать.
Тут два метода для получения данных (аннотации @GetMapping) и три – для редактирования. Все методы аннотированны:
- @GetMapping – для GET-запросов, получения Person
- @PostMapping – для POST-запросов, т.е. добавления Person
- @PutMapping – для PUT-запросов, редактирования Person
- @DeleteMapping – для DELETE-запросов, удаления Person
Возвращаем обычно ResponseEntity
, это более гибкий вариант, чем вернуть просто Person, поскольку для ResponseEntity можно установить Http-статус ответа – ResponseEntity.ok() – это 200 или ResponseEntity.status(201).
В методе body() передается возвращаемая сущность – в вышеприведенных методах это Person (либо список Person). Под капотом она конвертируется в JSON благодаря тому, что у нас стоит аннотация @RestController. Для конвертации под капотом Spring Boot использует библиотеку Jackson – она включена благодаря Maven-зависимости spring-boot-starter-web.
Если надо возвратить JSON с описанием ошибки, выбрасываем исключение. Например, если запрос на редактирование содержит id несуществующего Person, то выбрасываем EntityNotFoundException. Как обрабатывать исключения и кастомизировать JSON с ошибкой, описано в следующей статье.
Запуск
Для запуска Spring Boot приложения запускаем main() этого класса:
При этом будет запущен веб-сервер, отдельно его устанавливать и запускать не надо – это одно из преимуществ Spring Boot приложения.
https://www.youtube.com/watch?v=0QV9Wxz8_rM\u0026pp=YAHIAQE%3D
Также не надо задавать пути для поиска бинов, они найдутся автоматически. Единственное, класс SpringBootRestApplication не надо перекладывать в подпакет, он должен быть на верхнем уровне иерархии, иначе с поиском бинов возникнут проблемы. Когда мы сгенерировали заготовку приложения, этот файл уже был именно там, где надо – перекладывать его не следует.
Тестирование
Осталось проверить, что методы контроллера работают. Составлять запросы будем с помощью бесплатного графического приложения Postman (но учтите, оно ресурсоемкое). Как писать тесты, рассмотрим в другой статье.
Добавление Person
Ответ, возвращается вновь добавленный Person с id=1:
Редактирование Person
Ответ, возвращается отредактированный Person с id=1 и name=’Jane’:
Получение Person
Ответ, возвращается Person:
Получение списка Person
Ответ, возвращается список, состоящий из одного элемента Person:
Удаление Person
Ответ, возвращается удаленный Person с id=1 и name=’Jane’:
Заключение
Мы написали маленькое приложение, предоставляющее REST-сервис. Как обрабатывать исключения описано в следующей части.
Spring Boot REST API: 5 комментариев
Есть ли статья по тестированию?
Будет в ближайшее время
Аесть статья, как кастомизировать response body таким образом, чтобы в нем можно было возвращать не все поля энтити? Например, я хочу исключить из респонза ID. Мне на ум приходит два варианта, оба убогие. 1.
В теории, я могу сделать ResponseEntity и исключить из переопределения toString нужное поле, но я не хочу возвращать стринг, я хочу вернуть именно json.
Есть возможность дефолтными методами это как-то сделать или необходимо только всякие манипуляции проводить с кастованием стрингов в жсон и обратно?
2. Кастомизировать Query, чтобы он возвращал только нужные поля. Но тогда возвращаемым значением будет Object, которые никак не получится кастовать к моему классу. Да и работать с таким значением невозможно.
1. Заботиться о преобразовании в объекта в JSON не надо, это на совести контроллера. Главное, чтобы у нас был объект с нужными полями. 2. Чтобы он был, надо использовать паттерн DTO – Data Transfer Object; то есть помимо объекта Person, создаете объект PersonDTO специально для передачи – он содержит ровно те поля, которые нужно отправить/принять на фронтенд.
В статье этого нет, т.к. случай рассмотрен примитивный. Но если бы было, возвращаемым значением метода getPerson()был бы:
Создание приложений с Spring Boot
Этот урок показывает пример того, как Spring Boot помогает вам ускорить и облегчить разработку приложений. Из учебных материалов вы увидите случаи использования Spring Boot. Если вы хотите создать проект на его основе, то посетите Spring Initializr, заполните онформацию о проекте, выберите опции и вы сможете загрузить файл сборки Maven, либо Gradle, либо как проект в виде zip-файла.
Что вы создадите
Вы создадите простое web-приложение с Spring Boot и добавите в него несколько полезных сервисов.
Что вам потребуется
- Примерно 15 минут свободного времени
- Любимый текстовый редактор или IDE
- JDK 6 и выше
- Gradle 1.11+ или Maven 3.0+
- Вы также можете импортировать код этого урока, а также просматривать web-страницы прямо из Spring Tool Suite (STS), собственно как и работать дальше из него.
Как проходить этот урок
Как и большинство уроков по Spring, вы можете начать с нуля и выполнять каждый шаг, либо пропустить базовые шаги, которые вам уже знакомы. В любом случае, вы в конечном итоге получите рабочий код.
Чтобы начать с нуля, перейдите в Настройка проекта.
Чтобы пропустить базовые шаги, выполните следующее:
- Загрузите и распакуйте архив с кодом этого урока, либо кнонируйте из репозитория с помощью Git: git clone https://github.com/spring-guides/gs-spring-boot.git
- Перейдите в каталог gs-spring-boot/initial
Когда вы закончите, можете сравнить получившийся результат с образцом в gs-spring-boot/complete .
Настройка проекта
Для начала вам необходимо настроить базовый скрипт сборки. Вы можете использовать любую систему сборки, которая вам нравится для сборки проетов Spring, но в этом уроке рассмотрим код для работы с Gradle и Maven. Если вы не знакомы ни с одним из них, ознакомьтесь с соответсвующими уроками Сборка Java-проекта с использованием Gradle или Сборка Java-проекта с использованием Maven.
Создание структуры каталогов
В выбранном вами каталоге проекта создайте следующую структуру каталогов; к примеру, командой mkdir -p src/main/java/hello для *nix систем:
Создание файла сборки Gradle
Ниже представлен начальный файл сборки Gradle. Файл pom.xml находится здесь. Если вы используете Spring Tool Suite (STS), то можете импортировать урок прямо из него.
Spring Boot gradle plugin предоставляет множество удобных возможностей:
- Он собирает все jar’ы в classpath и собирает единое, исполняемое “über-jar”, что делает более удобным выполнение и доставку вашего сервиса
- Он ищет public static void main() метод, как признак исполняемого класса
- Он предоставляет встроенное разрешение зависимостей, с определенными номерами версий для соответсвующих Spring Boot зависимостей. Вы можете переопределить на любые версии, какие захотите, но он будет по умолчанию для Boot выбранным набором версий
Узнайте, что вы можете делать с Spring Boot
Spring Boot предлагает быстрый путь для создания приложений. Он просматривает ваш classpath и бины, которые вы сконфигурировали, делает предположения о том, что нехватает и добавляет их. С Spring Boot вы можете сконцентрироваться больше на решении бизнес задач и меньше на инфраструктуру.
- Требуется Spring MVC? Некоторые определенные бины вам почти всегда необходимы и Spring Boot добавит для них автоматически. Spring MVC приложению также необходим сервлет контейнер, поэтому Spring Boot автоматически настроит встроенный Tomcat
- Требуется Jetty? Если так, то скорее всего вам не нужен Tomcat, а вместо него нужен встроенный Jetty. Spring Boot обработает эту задачу для вас
- Требуется Thymeleaf? Для этого несколько бинов должны всегда быть добавлены в контекст вашего приложения; Spring Boot добавит их для вас
Это лишь несколько примеров, которые предоставляет автоманическая настройка Spring Boot. В то же время, Spring Boot не заработает с вашими настройками.
Например, если Thymeleaf в вашем classpath, то Spring Boot добавит SpringTemplateEngine в ваш контекст приложения автоматически.
Но если вы определите свой собственный SpringTemplateEngine с вашими настройками, то Spring Boot не добавит его. Это останется под вашим контролем и потребует от вас немного усилий.
Создание простого web приложения
Теперь вы можете создать web контроллер для простого web приложения.
Класс помечен как @RestController , означая, что он готов к использованию Spring MVC для обработки запросов. RequestMapping соответствует / метода index() .
При вызове из браузера или использовании curl в командной строке, метод возвращает чистый текст. Т.к.
@RestController сочетает в себе @Controller и @ResponseBody , две аннотации в результате web запросов возвращают данные, а не представление.
Создание Application класса
Здесь вы создаете Application класс с компонентами:
- @Configuration помечает класс как источник определения бинов для контекста приложения
- @EnableAutoConfiguration говорит Spring Boot о запуске добавления бинов в соответствии с содержанием classpath и других бинов, а также различных параметров настроек
- Обычно вы добавили бы @EnableMVC для Spring MVC, но Spring Boot добавляет её автоматически, когда видит spring-webmvc в classpath. Этот флаг помечает приложение как web приложение и активирует ключевые действия, такие как настройка DispatcherServlet
- @ComponentScan говорит Spring о том, чтобы просмотреть все компоненты, конфигурации и сервисы в пакете hello , сто позволяет ему найти HelloController
Метод main() используется Spring Boot методом SpringApplication.run() для запуска приложения. Вы обратили внимание, что нет ни одной строчки на XML? Файла web.xml нет вообще. Это приложение на 100% из чистой Java и вы ничего не делали для настройки какого-либо инструмента или инфраструктуры.
Метод run() возвращает ApplicationContext и этому приложению отдаются все бины, которые были созданы вашим приложением или автоматически добавлены благодаря Spring Boot. Метод сортирует бины и печатает их имена.
Запуск приложения
- Для запуска приложения выполните:
- Если вы используете Maven, то:
- Вы должны увидеть примерно такое:
Вы можете явно видеть org.springframework.boot.autoconfigure бины. А также tomcatEmbeddedServletContainerFactory .
Добавление сервисов бизнес-уровня
Если вы создаете web-сайт для вашего бизнеса, то вам скорее всего необходимо добавить некоторые сервисы для управления. Spring Boot предоставляет несколько таких “из коробки” в одном из своих модулей, таких как состояние, аудит, бины и другие.
- Добавьте это в список зависимостей вашего файла сборки:
- Если вы используете Maven, то добавьте это в список зависимостей:
- Затем перезапустите приложение:
- Если вы используете Maven, то:
- Вы увидите новый набор RESTful точек выхода, добавленных в приложение. Это сервисы управления, предоставленные Spring Boot:
- это легко проверить по состоянию приложения:
- Вы можете попытаться вызвать завершение работы через curl:
Т.к. мы не включили его, запрос блокирован, потому что его не существует.
Более подробную информацию о каждом из этих REST сервисов и о том, как вы можете настраивать под себя в application.properties , вы можете прочитать в документации.
Просмотр Spring Boot starters
Последний пример показал как Spring Boot упрощает инициализацию бинов, о которых вы не знаете, что они вам нужны. И он показал, как подклюсить удобные для управления сервисы.
Но Spring Boot делает ещё большее. Он поддерживает не только традиционное использование WAR файлов, но также сборку исполняемых JAR файлов, благодаря модулю загрузчика Spring Boot. Различные уроки демонстрируют эту двойную поддержку через spring-boot-gradle-plugin и spring-boot-maven-plugin .
- ко всему прочему, Spring Boot поддерживает Groovy, позволяя вам создавать Spring MVC приложения в небольшом и единственном файле.
- Создайте новый файл app.groovy и поместите в него приведенный ниже код:
- Давайте проверим, что получилось:
Spring Boot динамически добавляет аннотации к вашему коду и использует Groovy Grape для подтягивания необходимых для запуска приложения библиотек. Смотрите документацию, если хотите копнуть шлубже.
Поздравляем! Вы только что создали простое web приложени с использованием Spring Boot и изучили как нарастить ваш темп разработки. вы также настроили некоторые удобные сервисы. Это только малая часть того, что может делать Spring Boot.
Building a RESTful Web Service
This guide walks you through the process of creating a “Hello, World” RESTful web service with Spring.
What You Will Build
- You will build a service that will accept HTTP GET requests at http://localhost:8080/greeting .
- It will respond with a JSON representation of a greeting, as the following listing shows:
- You can customize the greeting with an optional name parameter in the query string, as the following listing shows:
- The name parameter value overrides the default value of World and is reflected in the response, as the following listing shows:
What You Need
- About 15 minutes
- A favorite text editor or IDE
- You can also import the code straight into your IDE:
How to complete this guide
Создаём свой Spring Boot Starter | OTUS
Современный Spring, а если быть точнее — специальный фреймворк Spring Boot, позволяют с минимальными усилиями подключать ту или иную технологию. Необходимость создавать десятки служебных бинов ушла в прошлое.
- Для этого имеются всевозможные starter-ы — специальные Maven/Gradle зависимости, которые необходимо только подключить в проект.
- Например, подключив в проект всего одну зависимость:
org.springframework.boot
spring-boot-starter-jdbc
мы имеем уже созданный в контексте DataSource, созданный по свойствам в application.properties и другими классами, вроде NamedParameterJdbcTemplate.
Подобные starter основаны на двух специальных функциональностях Spring Boot — AutoConfigurations и Conditional. Покажем, как использовать данные функциональности на примере создания собственного Spring Boot Starter.
Для начала представим, что мы работаем в компании “Марсианская Почта” (com.martianpost). В нашей компании написано множество приложений, для простоты, ровно два — консольное app-example и веб-приложение web-app-example.
Создадим эти приложения с помощью Spring Initializr.
Исходные коды их можно найти вот здесь.
Т. к. мы “Марсианская Почта”, то нам очень важно в каждом приложении знать точное марсианское время (а точнее MSD — Mars Sol Date) для всех приложений.
Выпустим Spring Boot Starter, решающий эту задачу. В соответствии с документацией выдадим следующие Maven-координаты:
com.martianpost
martian-time-spring-boot-starter
1.0.0
…
Для больших проектов и технологий, можно вынести отдельно, как саму технологию — martian-time, так и автоконфигурацию — martian-time-autoconfigure и сам стартер — martian-time-spring-boot-starter. Но для педагогических целей мы просто всё напишем в starter-е.
Из зависимостей мы оставим нам необходим только spring-boot-starter, правда, добавим его с optional-параметром — наш starter не является starter-ом уровнем всего приложения (как, например, spring-boot-starter-web), поэтому spring-boot-starter starter уже будет добавлен в приложение.
org.springframework.boot
spring-boot-starter
true
Ну и реализуем наш сервис:
package com.martianpost.martiantime.service; import org.springframework.stereotype.Service; import java.time.Duration; import java.time.ZonedDateTime; @Service
public class MartianTimeService {
private static final ZonedDateTime MID_DAY
= ZonedDateTime.parse(«2000-01-06T00:00:00Z»);
public double toMarsSolDate(ZonedDateTime zonedDateTime) {
double secondsFromMidDay
= (double) Duration.between(MID_DAY, zonedDateTime).getSeconds();
return secondsFromMidDay / 88775.244 + 44795.9998;
}
}
Не забудем про тест:
package com.martianpost.martiantime.service; … @DisplayName(«Сервис MartianTimeService») class MartianTimeServiceTest { private final MartianTimeService service = new MartianTimeService(); @DisplayName(«должен конвертировать совпадение полночей в 06.01.2000») @Test void shouldConvertZeroDay() { ZonedDateTime zeroDayUtc = ZonedDateTime.parse(«2000-01-06T00:00:00Z»); double result = service.toMarsSolDate(zeroDayUtc); assertEquals(44_795.9998, result, 1e-3); } @DisplayName(«Должен конвертировать пример с http://jtauber.github.io/mars-clock/») @Test
void shouldConvertExampleFromGithub() {
ZonedDateTime time = ZonedDateTime.parse(«2020-05-01T09:44:43Z»);
double result = service.toMarsSolDate(time);
assertEquals(52_018.84093, result, 1e-3);
}
}
- Обратим внимание, что если мы подключим данную библиотеку, то сервис не создастcя автоматически (хотя аннотация @Service) — для этого как раз и нужны автоконфигурации.
- Создадим автоконфигурацию для нашего модуля:
package com.martianpost.martiantime; … @Configuration @ComponentScan
public class MartianTimeAutoConfiguration {
}
Данный класс ничем не отличается от обычного класса конфигурации. Его главная задача — найти класс, помеченный @Service и создать его бин.
Но кто найдёт этот класс автоконфигурации? Никто, и нужно дополнительно указать эту автоконфигурацию, чтобы Spring Boot нашёл её:
# resources/META_INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.martianpost.martiantime.MartianTimeAutoConfiguration
Да, теперь можно попробовать подключить данный модуль в наше консольное приложение:
com.martianpost
martian-time-spring-boot-starter
1.0.0
и больше ничего!
@Autowired private MartianTimeService martianTimeService; @PostConstruct
public void printCurrentTime() {
double currentMarsSolDate = martianTimeService.toMarsSolDate(ZonedDateTime.now());
System.out.println(«MSD: » + currentMarsSolDate);
}
И получаем:
Допустим, нам в каждом веб-приложении необходимо сделать, чтобы это время возвращалось RestController-ом. Но проблема в том, что наш стартер может использоваться как в консольных приложениях, так и в веб-приложениях.
ОК, мы это можем сделать с помощью @Conditional. Сначала изменим зависимости нашего starter-а:
org.springframework.boot
spring-boot-starter-web
true
Добавим контроллер, который будет создаваться только в веб-приложениях:
package com.martianpost.martiantime.rest; … import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; @ConditionalOnWebApplication @RestController public class MartianTimeController { private final MartianTimeService martianTimeService; public MartianTimeController(MartianTimeService martianTimeService) { this.martianTimeService = martianTimeService; } @GetMapping(«/mds/current»)
public double getMds() {
return martianTimeService.toMarsSolDate(ZonedDateTime.now());
}
}
Обратите внимание, что за магию включения/выключения бина отвечает аннотация @ConditionalOnWebApplication. Помимо неё существует множество других @Conditional аннотаций — ссылка.
Проверим, что наше консольное приложение работает:
Если вывести список зависимостей консольного приложения, то увидим, что spring-mvc там и не присутствует.
А вот подключив в веб-приложение:
org.springframework.boot
spring-boot-starter
com.martianpost
martian-time-spring-boot-starter
1.0.0
И запустив, мы получим:
GET http://localhost:8080/msd/current
52018.90259483771
- Магия 🙂 Но доступная каждому 🙂
- Целиком пример Вы можете посмотреть на GitHub.
Консольное приложение Spring Boot
Наше консольное приложение состоит из одного класса:SpringBootConsoleApplication.java — это основной класс для нашего консольного приложения Spring Boot.
Мы используемSpring’s @SpringBootApplication annotation в нашем основном классе, чтобы включить автоконфигурацию.
Этот класс также реализуетSpring’s CommandLineRunner interface. CommandLineRunner — это простой интерфейс Spring Boot с методомrun. Spring Boot автоматически вызовет методrun всех компонентов, реализующих этот интерфейс, после загрузки контекста приложения.
Вот наше консольное приложение:
@SpringBootApplication
public class SpringBootConsoleApplication
implements CommandLineRunner {
private static Logger LOG = LoggerFactory
.getLogger(SpringBootConsoleApplication.class);
public static void main(String[] args) {
LOG.info(«STARTING THE APPLICATION»);
SpringApplication.run(SpringBootConsoleApplication.class, args);
LOG.info(«APPLICATION FINISHED»);
}
@Override
public void run(String… args) {
LOG.info(«EXECUTING : command line runner»);
for (int i = 0; i < args.length; ++i) { LOG.info("args[{}]: {}", i, args[i]); } } }
Мы также должны указатьspring.main.web-application-type=NONESpring property. Это свойство явным образом проинформирует Spring, что это не веб-приложение.
Когда мы выполняемSpringBootConsoleApplication, мы видим следующее:
00:48:51.888 [main] INFO c.b.s.SpringBootConsoleApplication — STARTING THE APPLICATION
00:48:52.752 [main] INFO c.b.s.SpringBootConsoleApplication — No active profile set, falling back to default profiles: default
00:48:52.851 [main] INFO o.s.c.a.AnnotationConfigApplicationContext
— Refreshing org.spring[email protected]6497b078: startup date [Sat Jun 16 00:48:52 IST 2018]; root of context hierarchy
00:48:53.832 [main] INFO o.s.j.e.a.AnnotationMBeanExporter — Registering beans for JMX exposure on startup
00:48:53.854 [main] INFO c.b.s.SpringBootConsoleApplication — EXECUTING : command line runner
00:48:53.854 [main] INFO c.b.s.SpringBootConsoleApplication — args[0]: Hello World!
00:48:53.860 [main] INFO c.b.s.SpringBootConsoleApplication — Started SpringBootConsoleApplication in 1.633 seconds (JVM running for 2.373)
00:48:53.860 [main] INFO c.b.s.SpringBootConsoleApplication — APPLICATION FINISHED
00:48:53.868 [Thread-2] INFO o.s.c.a.AnnotationConfigApplicationContext
— Closing org.spring[email protected]6497b078: startup date [Sat Jun 16 00:48:52 IST 2018]; root of context hierarchy
00:48:53.870 [Thread-2] INFO o.s.j.e.a.AnnotationMBeanExporter — Unregistering JMX-exposed beans on shutdown
Обратите внимание, что методrun вызывается после загрузки контекста приложения, но до завершения выполнения методаmain.
В большинстве консольных приложений будет только один класс, реализующийCommandLineRunner. Если ваше приложение имеет несколько классов, реализующихCommandLineRunner, порядок выполнения можно указать с помощьюSpring’s @Order annotation.