Этим постом я хочу начать серию статей о Spring Boot, в которой расскажу и покажу на наглядных примерах, как разрабатывать приложения используя Spring Boot и Spring Framework. За год активного использования этого фреймворка накопилось немало опыта, информации и нетривиальных моментов, которые приходилось решать, что пора бы и поделиться этим всем.
Spring Boot - это фреймворк для быстрой разработки приложений на основе Spring Framework и его компонентов, входящих в Spring Data, Spring Security и другие подпроекты. Spring Boot предоставляет огромное количество сконфигурированных компонентов, что позволяет сократить время, затрачиваемое на конфигурирование приложения и состредоточиться непосредственно на разработке, а так же упрощает работу с зависимостями. Ну и конечно Spring Boot позволяет легко и просто разрабатывать bootiful-приложения (так разработчики Spring называют standalone-приложения, основанные на Spring Boot). Но это всё лишь поверхностно, на самом деле возможности Spring Boot значительно мощнее. В целом, Spring Boot является идеальным инструментом для разработки микросервисов.
В рамках цикла статей я буду демонстрировать примеры использования Spring Boot на примере разработки достаточно простого, но в то же время наглядного веб-приложения - сервисдеска/хелпдеска.
Для проекта потребуется JDK 1.8, Maven и любая среда разработки (в моём случае - NetBeans).
Создадим новый maven-проект с упаковкой в WAR. В нашем случае это обусловлено тем, что в рамках статей будет продемонстрировано использование JSP для построения представлений, а так же будет продемонстрировано развёртывание приложения в сервере приложений. Если вам этого не нужно, то с лихвой хватит и JAR-упаковки. В любом случае, и JAR, и WAR являются исполняемыми при использовании Spring Boot.
Первое, что нужно сделать - добавить управление зависимостями, предоставляемое Spring Boot.
Это можно сделать двумя способами:
1. Указать в качестве родительского проекта spring-boot-starter-parent, если у проекта нет родительского:
2. Указать dependencyManagement:
Это решит все возможные проблемы с версиями зависимостей, которые описаны в Spring Boot. Хоть этот шаг и необязателен, я рекомендую его проделывать при разработке приложений, так как разные стартеры одной версии Spring Boot могут ссылаться на разные версии одной и той же зависимости, что может привести к неожиданным и неочевидным ошибкам.
Второй шаг при подготовке проекта - указание maven-плагина, предоставляемого Spring Boot для сборки проекта:
1. При использовании родительского проекта:
2. При использовании dependencyManagement:
Этот плагин найдёт класс, содержащий метод public static void main, пометит его главным и соберёт исполняемый JAR или WAR-файл, а так же скопирует в него все зависимости.
Ну и последний шаг, что бы получить работающее приложение - добавление в зависимости как минимум одного стартера (spring-boot-starter). В нашем случае понадобится spring-boot-starter-thymeleaf:
Spring Boot предоставляет большое количество стартеров практически на все случаи жизни. Стартер - это зависимость, содержащая все зависимости необходимые для реализации какой-либо функциональности в рамках разрабатывамого приложения. Так, например, что бы добавить приложению веб-функциональность, понадобится spring-boot-starter-web, который позволяет разрабатывать как стандартные веб-приложения, основанные на Spring WebMVC, так и REST-сервисы. Если же есть необходимость добавить приложению управление доступом, то можно добавить spring-boot-starter-security. Указанный мной стартер spring-boot-starter-thymeleaf содержит все зависимости, необходимые для разработки веб-приложения с использованием Thymeleaf в качестве фреймворка для построения представлений.
Теперь у нас всё готово для непосредственной разработки приложения на Spring Boot.
Первым делом создадим, класс, с которого будет начинаться работа нашего приложения:
Вкратце пробегусь по написанному коду:
Кстати, на данном этапе приложение уже можно запустить. Но мы не добавили в приложение ничего, что можно было бы увидеть.
Создадим класс WebConfig в name.alexkosarev.bootdesk.config, в котором сконфигурируем перенаправление с / на /site/index и добавим отображение главной страницы при переходе на /site/index:
Осталось добавить представление. Spring WebMVC по умолчанию в Spring Boot ищет представления в директории templates. Создадим html-файл в директории templates/site (как мы указали в WebConfig). Обратите внимание, что Thymeleaf в режиме HTML5, который выставлен по умолчанию, ожидает XML-валидный HTML (по сути XHTML). Если же вы привыкли писать простой HTML, то нужно проделать следующие два шага:
NekoHTML будет превращать обычный HTML-код в XML-валидный.
На данном этапе приложение имеет минимальную функциональность и готово к первому запуску.
Для начала соберём приложение стандартным способом: командой mvn package или при помощи IDE. В директории target окажется два варианта WAR-архива: bootiful, с именем файла, заканчивающимся на .war, и обычный, заканчивающийся на .war.orginal. Обычный WAR-файл не является исполняемым, не содержит provided-зависимости, но может быть развёрнут в сервере приложений. Bootiful-вариант содержит все необходимые для работы зависимости, не может быть развёрнут в сервере приложений (попытка развернуть его в сервере приложений приведёт к ошибке), но может быть запущен как самостоятельное приложение при помощи команды java -jar bootdesk-1.0.0.war.
Кстати, если вы разрабатываете приложение на основе Spring Boot с упаковкой в JAR, то после сборки получите так же два варианта: bootiful, содержащий все необходимые для работы зависимости, и обычный вариант, зависимости для запуска которого нужно будет указывать при помощи -classpath.
Запустив приложение при помощи команды java -jar bootdesk-1.0.0.war мы увидим вывод нашего приложения.
Если мы откроем адрес http://localhost:8080, приложение сначала нас перенаправит на http://localhost:8080/site/index, а затем покажет нам содержимое index.html:
По умолчанию ни один стартер из предоставляемых Spring Boot не предоставляет возможности работать с JSP. Но это решается достаточно просто:
1. В зависимости проекта нужно добавить tomcat-embed-jasper и jstl:
Обратите внимание на scope=provided для tomcat-embed-jasper.
2. В WebConfig сконфигурировать ViewResolver:
После этого можно будет использовать JSP-представления, а так же использовать Apache Tiles, если в этом будет необходимость.
В следующем посте я добавлю приложению немного функцональности, добавив взаимодействие с базой данных посредством Spring Data JPA. Так же я постараюсь в ближайшие несколько дней выложить проект в GitHub и опубликую видеоподкаст.
Что такое Spring Boot?
Spring Boot - это фреймворк для быстрой разработки приложений на основе Spring Framework и его компонентов, входящих в Spring Data, Spring Security и другие подпроекты. Spring Boot предоставляет огромное количество сконфигурированных компонентов, что позволяет сократить время, затрачиваемое на конфигурирование приложения и состредоточиться непосредственно на разработке, а так же упрощает работу с зависимостями. Ну и конечно Spring Boot позволяет легко и просто разрабатывать bootiful-приложения (так разработчики Spring называют standalone-приложения, основанные на Spring Boot). Но это всё лишь поверхностно, на самом деле возможности Spring Boot значительно мощнее. В целом, Spring Boot является идеальным инструментом для разработки микросервисов.
О демонстрационном проекте
В рамках цикла статей я буду демонстрировать примеры использования Spring Boot на примере разработки достаточно простого, но в то же время наглядного веб-приложения - сервисдеска/хелпдеска.
Для проекта потребуется JDK 1.8, Maven и любая среда разработки (в моём случае - NetBeans).
Подготовка проекта
Создадим новый maven-проект с упаковкой в WAR. В нашем случае это обусловлено тем, что в рамках статей будет продемонстрировано использование JSP для построения представлений, а так же будет продемонстрировано развёртывание приложения в сервере приложений. Если вам этого не нужно, то с лихвой хватит и JAR-упаковки. В любом случае, и JAR, и WAR являются исполняемыми при использовании Spring Boot.
Первое, что нужно сделать - добавить управление зависимостями, предоставляемое Spring Boot.
Это можно сделать двумя способами:
1. Указать в качестве родительского проекта spring-boot-starter-parent, если у проекта нет родительского:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.3.RELEASE</version>
</parent>
2. Указать dependencyManagement:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.3.3.RELEASE</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
Это решит все возможные проблемы с версиями зависимостей, которые описаны в Spring Boot. Хоть этот шаг и необязателен, я рекомендую его проделывать при разработке приложений, так как разные стартеры одной версии Spring Boot могут ссылаться на разные версии одной и той же зависимости, что может привести к неожиданным и неочевидным ошибкам.
Второй шаг при подготовке проекта - указание maven-плагина, предоставляемого Spring Boot для сборки проекта:
1. При использовании родительского проекта:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
2. При использовании dependencyManagement:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
Этот плагин найдёт класс, содержащий метод public static void main, пометит его главным и соберёт исполняемый JAR или WAR-файл, а так же скопирует в него все зависимости.
Ну и последний шаг, что бы получить работающее приложение - добавление в зависимости как минимум одного стартера (spring-boot-starter). В нашем случае понадобится spring-boot-starter-thymeleaf:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Spring Boot предоставляет большое количество стартеров практически на все случаи жизни. Стартер - это зависимость, содержащая все зависимости необходимые для реализации какой-либо функциональности в рамках разрабатывамого приложения. Так, например, что бы добавить приложению веб-функциональность, понадобится spring-boot-starter-web, который позволяет разрабатывать как стандартные веб-приложения, основанные на Spring WebMVC, так и REST-сервисы. Если же есть необходимость добавить приложению управление доступом, то можно добавить spring-boot-starter-security. Указанный мной стартер spring-boot-starter-thymeleaf содержит все зависимости, необходимые для разработки веб-приложения с использованием Thymeleaf в качестве фреймворка для построения представлений.
Теперь у нас всё готово для непосредственной разработки приложения на Spring Boot.
Разработка приложения
Самый простой пример - отображение представления в браузере без использования контроллера.Первым делом создадим, класс, с которого будет начинаться работа нашего приложения:
package name.alexkosarev.bootdesk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args)
.registerShutdownHook();
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}
}
Вкратце пробегусь по написанному коду:
- Аннтоация @SpringBootApplication объединяет аннотации @Configuration, @EnableAutoConfiguration и @ComponentScan, объявляет Application классом-конфигурацией, включает автоматическую конфигурацию приложения и включает автоматический поиск компонентов в пакете name.alexkosarev.bootdesk и во всех вложенных.
- SpringApplication.run(Application.class, args) запускает приложение при запуске при помощи java -jar
- Класс Application расширяет класс SpringBootServletInitializer и переопределяет метод SpringApplicationBuilder configure(SpringApplicationBuilder builder) для запуска приложения при развёртывании в сервере приложении.
Кстати, на данном этапе приложение уже можно запустить. Но мы не добавили в приложение ничего, что можно было бы увидеть.
Создадим класс WebConfig в name.alexkosarev.bootdesk.config, в котором сконфигурируем перенаправление с / на /site/index и добавим отображение главной страницы при переходе на /site/index:
package name.alexkosarev.bootdesk.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController("/", "/site/index");
registry.addViewController("/site/index")
.setViewName("site/index");
}
}
Осталось добавить представление. Spring WebMVC по умолчанию в Spring Boot ищет представления в директории templates. Создадим html-файл в директории templates/site (как мы указали в WebConfig). Обратите внимание, что Thymeleaf в режиме HTML5, который выставлен по умолчанию, ожидает XML-валидный HTML (по сути XHTML). Если же вы привыкли писать простой HTML, то нужно проделать следующие два шага:
- Добавить в файл свойств application.properties, расположенном в ресурсах проекта, строку spring.thymeleaf.mode=LEGACYHTML5
- Добавить в зависимости проекта nekohtml из группы nekohtml:
<dependency> <groupId>nekohtml</groupId> <artifactId>nekohtml</artifactId> <version>1.9.6.2</version> </dependency>
NekoHTML будет превращать обычный HTML-код в XML-валидный.
На данном этапе приложение имеет минимальную функциональность и готово к первому запуску.
Сборка и запуск приложения
Для начала соберём приложение стандартным способом: командой mvn package или при помощи IDE. В директории target окажется два варианта WAR-архива: bootiful, с именем файла, заканчивающимся на .war, и обычный, заканчивающийся на .war.orginal. Обычный WAR-файл не является исполняемым, не содержит provided-зависимости, но может быть развёрнут в сервере приложений. Bootiful-вариант содержит все необходимые для работы зависимости, не может быть развёрнут в сервере приложений (попытка развернуть его в сервере приложений приведёт к ошибке), но может быть запущен как самостоятельное приложение при помощи команды java -jar bootdesk-1.0.0.war.
Кстати, если вы разрабатываете приложение на основе Spring Boot с упаковкой в JAR, то после сборки получите так же два варианта: bootiful, содержащий все необходимые для работы зависимости, и обычный вариант, зависимости для запуска которого нужно будет указывать при помощи -classpath.
Запустив приложение при помощи команды java -jar bootdesk-1.0.0.war мы увидим вывод нашего приложения.
Если мы откроем адрес http://localhost:8080, приложение сначала нас перенаправит на http://localhost:8080/site/index, а затем покажет нам содержимое index.html:
Spring Boot и JSP
По умолчанию ни один стартер из предоставляемых Spring Boot не предоставляет возможности работать с JSP. Но это решается достаточно просто:
1. В зависимости проекта нужно добавить tomcat-embed-jasper и jstl:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
Обратите внимание на scope=provided для tomcat-embed-jasper.
2. В WebConfig сконфигурировать ViewResolver:
@Bean
public ViewResolver viewResolver() {
UrlBasedViewResolver urlBasedViewResolver = new UrlBasedViewResolver();
urlBasedViewResolver.setViewClass(JstlView.class);
urlBasedViewResolver.setPrefix("/WEB-INF/templates/");
urlBasedViewResolver.setSuffix(".jspx");
return urlBasedViewResolver;
}
После этого можно будет использовать JSP-представления, а так же использовать Apache Tiles, если в этом будет необходимость.
В следующем посте я добавлю приложению немного функцональности, добавив взаимодействие с базой данных посредством Spring Data JPA. Так же я постараюсь в ближайшие несколько дней выложить проект в GitHub и опубликую видеоподкаст.


Очень полезный туториал. К тому же на русском языке.
ОтветитьУдалитьА я правильно понимаю, tomcat-embed-jasper должен быть provided даже в JAR-варианте приложения?
Нет, в jar-варианте данная зависимость должна быть compile или runtime.
Удалитьу меня при добавлении provided страница открывает как текст, сборка war. Без provided норм но ресурсы не видит.
ОтветитьУдалить