Этим постом я хочу начать серию статей о 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 норм но ресурсы не видит.
ОтветитьУдалить