Skip to content

1. Вступ

PDF цього документа доступний за посиланням |TYT|.

Приклади з цього документа доступні за посиланням |TYT|.

У цій статті ми пропонуємо на прикладах ознайомити вас з важливими поняттями Spring MVC — веб-фреймворку на Java, який забезпечує основу для розробки веб-додатків за моделлю MVC (Модель — Вигляд — Контролер). Spring MVC є гілкою екосистеми Spring [http://projects.spring.io/spring-framework/]. Ми також представимо движок візуалізації Thymeleaf [http://www.thymeleaf.org/].

Цей курс призначений для читачів, які добре володіють мовою Java. Знання веб-програмування не є обов’язковим.

Хоча цей документ є докладним, він, ймовірно, є неповним. Spring — це величезний фреймворк із численними розгалуженнями. Для поглиблення знань про Spring MVC можна скористатися такими джерелами:

  • довідковий документ фреймворку Spring [http://docs.spring.io/spring/docs/current/spring-framework-reference/pdf/spring-framework-reference.pdf];
  • численні навчальні матеріали щодо Spring можна знайти на URL [http://spring.io/guides]
  • сайт [developpez.com], присвячений Spring [http://spring.developpez.com/].

Цей документ написано таким чином, щоб його можна було читати навіть без комп’ютера під рукою. Тому в ньому наведено багато знімків екрана.

1.1. Sources

Цей документ має два основні джерела:

  • [Вступ до фреймворку ASP.NET MVC на прикладах (2013)]. Spring MVC та ASP.NET MVC — це два аналогічні фреймворки, причому другий було створено значно пізніше за перший. Щоб мати змогу порівняти ці два фреймворки, я дотримався тієї самої послідовності, що й у документі про ASP.NET та MVC;
  • документ про ASP.NET MVC наразі (грудень 2014 р.) не містить прикладу з його рішенням. Я використав тут приклад із документа [Приклад клієнт-серверної архітектури — AngularJS 1.x / Spring 4 (2014)], який змінив наступним чином:
    • приклад у [Tutoriel AngularJS / Spring 4] стосується клієнт-серверного додатка, де сервер — це веб-сервіс / jSON, створений на базі Spring MVC, а клієнт — це веб-клієнт AngularJS,
    • у цьому документі розглядається той самий веб-сервіс / jSON, але клієнтом є дворівневий веб-додаток [client jQuery] / [service web / jSON];

Окрім цих джерел, я шукав у Інтернеті відповіді на свої запитання. Найбільше мені тоді допоміг сайт [http://stackoverflow.com/].

1.2. Використані інструменти

Наведені нижче приклади було протестовано в такому середовищі:

  • комп’ютер із Windows 8.1 Pro 64-біт;
  • JDK 1.8;
  • IDE Spring Tool Suite 3.6.3 (див. розділ 9.3);
  • браузер Chrome (інші браузери не використовувалися);
  • розширення для Chrome [Advanced Rest Client] (див. розділ 9.6);

Зверніть увагу на JDK 1.8. Один із методів у цьому прикладі використовує метод із пакета [java.lang] у Java 8.

Усі приклади — це проекти Maven, які можна відкрити як у IDE Eclipse, так і в IntellijIDEA або NetBeans. Далі наведені знімки екрана з IDE Spring Tool Suite — варіанту Eclipse.

1.3. Приклади

Приклади доступні за посиланням URL [Вступ до Spring MVC та Thymeleaf на прикладі (2015)] у вигляді файлу zip, який можна завантажити.

  

Щоб завантажити всі проекти в STS, слід виконати такі дії:

  • у [1-3] імпортуйте проекти Maven;
  • у [4] вкажіть папку з прикладами;
  • у [5], виберіть усі проекти з папки;
  • у [6], підтвердіть;
  • у [7] — імпортовані проекти;

1.4. Місце Spring MVC у веб-додатку

Розглянемо роль Spring MVC у розробці веб-додатку. Найчастіше такий додаток будується на багатошаровій архітектурі, наприклад, такій:

  • шар [Web] — це шар, що взаємодіє з користувачем веб-додатка. Користувач взаємодіє з веб-додатком через веб-сторінки, що відображаються у браузері. Саме в цьому шарі, і лише в ньому, розташований Spring MVC;
  • шар [métier] реалізує правила управління додатком, такі як розрахунок заробітної плати або рахунку-фактури. Цей рівень використовує дані, що надходять від користувача через рівень [Web], а також дані з SGBD через рівень [DAO];
  • шар [DAO] (об’єкти доступу до даних), шар [ORM] (об’єктно-реляційний мапер) та драйвер JDBC керують доступом до даних шару SGBD. Рівень [ORM] забезпечує зв’язок між об’єктами, що обробляються рівнем [DAO], та рядками й стовпцями таблиць реляційної бази даних. Тут ми будемо використовувати ORM Hibernate. Специфікація під назвою JPA (Java Persistence API) дозволяє абстрагуватися від використовуваного ORM, якщо він реалізує ці специфікації. Це стосується Hibernate та інших ORM Java. Отже, відтепер ми називатимемо цей рівень ORM, а інший — JPA;
  • інтеграція шарів здійснюється фреймворком Spring;

У більшості прикладів, наведених далі, буде використовуватися лише один рівень — рівень [Web]:

Проте цей документ завершиться створенням багаторівневого веб-додатка:

Браузер підключиться до додатка [Web1], реалізованого за допомогою Spring MVC / Thymeleaf, яке отримуватиме дані з веб-сервісу [Web2], також реалізованого за допомогою Spring MVC. Цей другий веб-додаток матиме доступ до бази даних.

1.5. Модель розробки Spring MVC

Spring MVC реалізує так звану архітектурну модель MVC (Модель – Вигляд – Контролер) наступним чином:

Обробка запиту клієнта відбувається наступним чином:

  1. запит — запитувані URL мають вигляд http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&.... [Front Controller] використовує файл конфігурації або анотації Java для «маршрутизації» запиту до відповідного контролера та відповідної дії в межах цього контролера. Для цього він використовує поле [Action] з URL. Решта URL [/param1/param2/...] складається з необов’язкових параметрів, які будуть передані до дії. Змінною «C» у MVC тут є рядок [Front Controller, Contrôleur, Action]. Якщо жоден контролер не може обробити запитувану дію, веб-сервер відповість, що запитувана дія URL не знайдена.
  1. Обробка
  • обрана дія може використовувати параметри parami, які їй передала дія [Front Controller]. Вони можуть походити з кількох джерел:
    • з шляху [/param1/param2/...] об’єкта URL,
    • з параметрів [p1=v1&p2=v2] від URL,
    • з параметрів, надісланих браузером разом із запитом;
  • під час обробки запиту користувача дії може знадобитися рівень [métier] [2b]. Після обробки запиту клієнта це може викликати різні відповіді. Класичним прикладом є:
    • сторінка з повідомленням про помилку, якщо запит не вдалося обробити належним чином
    • сторінка підтвердження в іншому випадку
  • дія вимагає відображення певного виду [3]. Цей вид відображатиме дані, які називаються моделлю виду. Це «M» у MVC. Акція створить цю модель M [2c] і вимагатиме відображення певного виду V [3];
  1. відповідь — обраний вигляд V використовує модель M, створену дією, для ініціалізації динамічних частин відповіді HTML, яку він повинен надіслати клієнту, а потім надсилає цю відповідь.

Тепер уточнимо зв’язок між веб-архітектурою MVC та багаторівневою архітектурою. Залежно від того, як ми визначаємо модель, ці два поняття можуть бути пов’язані або ні. Розглянемо однорівневий веб-додаток на базі Spring MVC:

Якщо ми реалізуємо рівень [Web] за допомогою Spring MVC, ми отримаємо веб-архітектуру MVC, але не багаторівневу архітектуру. У цьому випадку шар [web] буде відповідати за все: представлення, бізнес-логіку, доступ до даних. Цю роботу виконуватимуть дії.

Тепер розглянемо багаторівневу веб-архітектуру:

Рівень [Web] можна реалізувати без фреймворку та без дотримання моделі MVC. У цьому випадку ми дійсно маємо багаторівневу архітектуру, але веб-рівень не реалізує модель MVC.

Наприклад, у середовищі .NET цей шар [Web]може бути реалізований за допомогою ASP.NET та MVC, і тоді ми отримуємо багатошарову архітектуру з шаром [Web] типу MVC. Зробивши це, можна замінити цей шар ASP.NET MVC на класичний шар ASP.NET (WebForms), зберігаючи решту (бізнес-логіка, DAO, ORM) без змін. У результаті ми отримуємо багаторівневу архітектуру з рівнем [Web], який більше не є типом MVC.

У MVC ми зазначили, що модель M відповідає представленню V, c.a.d, — сукупності даних, що відображаються представленням V. Наводимо ще одне визначення моделі M для MVC:

Багато авторів вважають, що те, що знаходиться праворуч від шару [Web], утворює модель M для MVC. Щоб уникнути двозначностей, можна говорити про:

  • моделі домену, коли мається на увазі все, що знаходиться праворуч від шару [Web]
  • про модель подання, коли йдеться про дані, що відображаються поданням V

Надалі термін «модель M» позначатиме виключно модель подання V.

1.6. Перший проєкт Spring MVC

Відтепер ми працюватимемо з IDE Spring Tool Suite (STS) — це налаштована під Spring версія Eclipse. На сайті [http://spring.io/guides] доступні навчальні матеріали для початківців, які допоможуть ознайомитися з екосистемою Spring. Ми скористаємося одним із них, щоб дізнатися про конфігурацію Maven, необхідну для проекту Spring MVC.

Примітка: більшість початківців не зможуть до кінця зрозуміти деталі проекту. Це не має значення. Ці деталі пояснюються далі в цьому документі. Ми просто повторимо необхідні дії.

1.6.1. Демонстраційний проєкт

  • у [1] ми імпортуємо один із Spring-гайдів;
  • у [2] ми обираємо приклад [Serving Web Content];
  • у [3] вибираємо проект Maven;
  • у [4] вибираємо остаточну версію посібника;
  • у [5] підтверджуємо;
  • у [6] — імпортований проєкт;

Розглянемо проект, спочатку його конфігурацію Maven.

1.6.2. Конфігурація Maven

Файл [pom.xml] має такий вигляд:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-serving-web-content</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <start-class>hello.Application</start-class>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestone</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestone</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>

</project>
  • рядки 6–8: властивості проекту Maven. Відсутній тег [<packaging>], що вказує на тип файлу, який створюється під час компіляції Maven. За його відсутності використовується тип [jar]. Отже, додаток є консольним виконуваним файлом, а не веб-додатком, для якого тип упаковки був би [war];
  • рядки 10–14: проект Maven має батьківський проект [spring-boot-starter-parent]. Саме він визначає основну частину залежностей проекту. Їх може бути достатньо, і в цьому випадку додаткові залежності не додаються, або ж їх може не вистачати, і тоді додаються відсутні залежності;
  • рядки 17–20: артефакт [spring-boot-starter-thymeleaf] містить бібліотеки, необхідні для проекту Spring MVC, який використовується разом із механізмом відображення, що називається [Thymeleaf]. Цей артефакт містить величезну кількість бібліотек, зокрема бібліотеки вбудованого сервера Tomcat. Саме на цьому сервері буде виконуватися додаток;

Бібліотек, що входять до цієї конфігурації, дуже багато:

Вище показано архіви сервера Tomcat.

Spring Boot — це гілка екосистеми Spring [http://projects.spring.io/spring-boot/]. Цей проєкт має на меті максимально спростити налаштування проєктів Spring. Для цього Spring Boot здійснює автоналаштування на основі залежностей, присутніх у Classpath проєкту. Spring Boot надає безліч готових до використання залежностей. Так, залежність [spring-boot-starter-thymeleaf], знайдена в попередньому проєкті Maven, забезпечує всі необхідні залежності для додатка Spring MVC, що використовує механізм відображення [Thymeleaf]. Завдяки цим двом особливостям:

  • готові до використання залежності;
  • автоконфігурація на основі цих залежностей та «розумних» значень за замовчуванням, можна дуже швидко отримати робочий додаток Spring MVC. Саме так і є у випадку з проектом, що розглядається тут;

1.6.3. Архітектура додатка Spring MVC

Spring MVC реалізує архітектурну модель, відому як MVC (Модель – Представлення – Контролер):

Обробка запиту клієнта відбувається наступним чином:

  1. запит — запитувані URL мають вигляд http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&... [Dispatcher Servlet] — це клас Spring, який обробляє вхідні URL. Вона «направляє» URL до дії, яка має її обробити. Ці дії — це методи певних класів, що називаються [Contrôleurs]. Літера «C» у MVC тут є рядком [Dispatcher Servlet, Contrôleur, Action]. Якщо для обробки вхідного запиту URL не було налаштовано жодної дії, сервлет [Dispatcher Servlet] відповість, що запитуваний URL не знайдено (помилка 404 NOT FOUND);
  2. обробка
  • обрана дія може використовувати параметри parami, які їй передала сервлета [Dispatcher Servlet]. Вони можуть походити з кількох джерел:
    • з шляху [/param1/param2/...] сервлета URL,
    • з параметрів [p1=v1&p2=v2] сервлета URL,
    • параметрів, надісланих браузером разом із запитом;
  • під час обробки запиту користувача дії може знадобитися рівень [metier] [2b]. Після обробки запиту клієнта ця дія може викликати різні відповіді. Типовим прикладом є:
    • сторінка з повідомленням про помилку, якщо запит не вдалося обробити належним чином
    • сторінка підтвердження в іншому випадку
  • дія вимагає відображення певного виду [3]. Цей вид відображатиме дані, які називаються моделлю виду. Це «M» у MVC. Дія створить цю модель M [2c] і вимагатиме відображення виду V [3];
  1. відповідь — обраний вигляд V використовує модель M, створену дією, для ініціалізації динамічних частин відповіді HTML, яку він повинен надіслати клієнту, а потім надсилає цю відповідь.

Ми розглянемо ці різні елементи в проекті, що вивчається.

1.6.4. Контролер C

  

Імпортований додаток має такий контролер:


package hello;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class GreetingController {

    @RequestMapping("/greeting")
    public String greeting(@RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
        model.addAttribute("name", name);
        return "greeting";
    }

}
  • рядок 8: анотація [@Controller] перетворює клас [GreetingController] на контролер Spring, тобто його методи зареєстровані для обробки URL. Контролер Spring є синглтоном. Він створюється в єдиному екземплярі;
  • рядок 11: анотація [@RequestMapping] вказує на URL, який обробляє метод, у даному випадку URL [/greeting]. Пізніше ми побачимо, що цей URL можна налаштувати і що ці параметри можна отримати;
  • рядок 12: метод приймає два параметри:
    • [String name]: цей параметр ініціалізується параметром з іменем [name] у запиті, що обробляється, наприклад [/greeting?name=alfonse]. Цей параметр є необов’язковим [required=false], і коли його немає, параметр [name] прийме значення «World» [defaultValue="World"],
    • [Model model] — це модель подання. Вона передається порожньою, і завданням дії (методу greeting) є її заповнення. Саме ця модель буде передана до подання, яке відобразить дія. Отже, це модель подання;
  • рядок 13: значення [name] вставляється в модель подання. Клас [Model] працює як словник;
  • рядок 14: метод повертає ім’я подання, яке має відобразити побудовану модель. Точне ім’я подання залежить від конфігурації [Thymeleaf]. За відсутності такої конфігурації тут відображатиметься представлення [/templates/greeting.html], або папка [templates] має знаходитися в кореневому каталозі Classpath проекту;

Розглянемо наш проект Eclipse:

Папки [src/main/java] та [src/main/resources] — це папки, вміст яких буде додано до Classpath проекту. Щодо [src/main/java], то туди будуть додані скомпільовані версії вихідного коду Java. Вміст папки [src/main/resources] додається до Classpath без змін. Отже, бачимо, що папка [templates] буде в Classpath проекту [1].

Це можна перевірити у вікні [Navigator] програми Eclipse для [2-3]. Папка [target] створюється в результаті компіляції (з назвою build) проекту. Папка [classes] є кореневою папкою Classpath. Бачимо, що папка [templates] там присутня.

1.6.5. Вигляд V

У MVC ми щойно розглянули контролер C та модель представлення M. Представлення V тут представлене наступним файлом [greeting.html]:


<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <p th:text="'Hello, ' + ${name} + '!'" />
</body>
</html>
  • рядок 2: простір імен тегів Thymeleaf;
  • рядок 8: тег <p> (абзац) з атрибутом Thymeleaf. Атрибут [th:text] визначає вміст абзацу. Усередині символьного рядка міститься вираз [${name}]. Це означає, що потрібно отримати значення атрибута [name] з шаблону подання. Однак ми пам’ятаємо, що цей атрибут був доданий до шаблону за допомогою дії:

model.addAttribute("name", name);

Перший параметр визначає ім’я атрибута, другий — його значення.

1.6.6. Виконання

  

Клас [Application.java] є класом виконання проекту. Його код такий:


package hello;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan
@EnableAutoConfiguration
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}
  • рядок 11: клас є виконуваним із методом [main], характерним для консольних додатків. Клас [SpringApplication] у рядку 12 запустить сервер Tomcat, що міститься у залежностях, та розгорне на ньому веб-сервіс;
  • рядок 4: бачимо, що клас [SpringApplication] належить до проєкту [Spring Boot];
  • рядок 12: перший параметр — це клас, що налаштовує проєкт, другий — можливі додаткові параметри;
  • рядок 8: анотація [@EnableAutoConfiguration] вимагає від Spring Boot виконати конфігурацію проєкту;
  • рядок 7: анотація [@ComponentScan] забезпечує сканування папки, що містить клас [Application], з метою пошуку компонентів Spring. Буде знайдено клас [GreetingController], який має анотацію [@Controller], що робить його компонентом Spring;

Запустимо проект:

 

Ми отримаємо такі журнали консолі:

.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.9.RELEASE)

2014-11-27 16:48:12.567  INFO 3908 --- [           main] hello.Application                        : Starting Application on Gportpers3 with PID 3908 (started by ST in D:\data\istia-1415\spring mvc\dvp\gs-serving-web-content-complete)
2014-11-27 16:48:12.723  INFO 3908 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@1a38c59b: startup date [Thu Nov 27 16:48:12 CET 2014]; root of context hierarchy
2014-11-27 16:48:13.813  INFO 3908 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanNameViewResolver': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]
2014-11-27 16:48:15.247  INFO 3908 --- [           main] .t.TomcatEmbeddedServletContainerFactory : Server initialized with port: 8080
2014-11-27 16:48:15.574  INFO 3908 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2014-11-27 16:48:15.575  INFO 3908 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/7.0.56
2014-11-27 16:48:15.955  INFO 3908 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2014-11-27 16:48:15.955  INFO 3908 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3236 ms
2014-11-27 16:48:16.918  INFO 3908 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2014-11-27 16:48:16.922  INFO 3908 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2014-11-27 16:48:17.354  INFO 3908 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-11-27 16:48:17.679  INFO 3908 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/greeting],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String hello.GreetingController.greeting(java.lang.String,org.springframework.ui.Model)
2014-11-27 16:48:17.681  INFO 3908 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2014-11-27 16:48:17.682  INFO 3908 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[text/html],custom=[]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
2014-11-27 16:48:17.696  INFO 3908 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] на обробник типу [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-11-27 16:48:17.697  INFO 3908 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] обробник типу [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-11-27 16:48:18.159  INFO 3908 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2014-11-27 16:48:18.491  INFO 3908 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080/http
2014-11-27 16:48:18.493  INFO 3908 --- [           main] hello.Application                        : Started Application in 6.833 seconds (JVM running for 8.658)
  • рядок 13: сервер Tomcat запускається на порту 8080 (рядок 12);
  • рядок 17: сервлет [DispatcherServlet] присутній;
  • рядок 20: виявлено метод [hello.GreetingController.greeting], а також URL, який обробляє [/greeting];

Щоб протестувати веб-додаток, запускаємо URL та [http://localhost:8080/greeting]:

 

Може бути цікаво переглянути заголовки HTTP, які надсилає сервер. Для цього ми скористаємося плагіном для Chrome під назвою [Advanced Rest Client] (див. розділ 9.6):

  • у [1] — запитуваний URL;
  • у [2] використовується метод GET;
  • у [3] сервер повідомив, що надсилає відповідь у форматі HTML;
  • у запиті [4] отримано відповідь HTML;
  • у запиті [5] запитується той самий URL, але цього разу з POST;
  • у [7] інформація надсилається на сервер у вигляді [urlencoded];
  • у [6] — параметр name із його значенням;
  • у [8] браузер повідомляє серверу, що надсилає йому інформацію [urlencoded];
  • у [9] — відповідь сервера HTML;

Щоб зупинити додаток:

1.6.7. Створення виконуваного архіву

Виконувальний архів можна створити поза Eclipse. Необхідні налаштування містяться у файлі [pom.xml]:


    <properties>
        <start-class>hello.Application</start-class>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
</build>
  • рядки 7–10 визначають плагін, який створюватиме виконуваний архів;
  • рядок 2 визначає клас виконуваного файлу проекту;

Діємо таким чином:

  • у [1]: виконується ціль Maven;
  • в [2]: є дві цілі (goals): [clean] для видалення папки [target] з проекту Maven, [package] для її повторного створення;
  • у [3]: згенерована папка [target] буде розміщена в цій папці;
  • у [4]: генерується ціль;

Примітка: щоб генерація пройшла успішно, JVM, що використовується STS, має бути JDK [Window / Preferences / Java / Installed JREs]:

 

У журналах, що з’являються в консолі, важливо бачити згадку про плагін [spring-boot-maven-plugin]. Саме він генерує виконуваний архів.

[INFO] --- spring-boot-maven-plugin:1.1.9.RELEASE:repackage (default) @ gs-serving-web-content ---

За допомогою консолі перейдіть до створеної папки:


gs-serving-web-content-complete\target>dir
 ...

 Répertoire de D:\data\istia-1415\spring mvc\dvp\gs-serving-web-content-complete
\target

27/11/2014  17:07    <DIR>          .
27/11/2014  17:07    <DIR>          ..
27/11/2014  17:07    <DIR>          classes
27/11/2014  17:07    <DIR>          generated-sources
27/11/2014  17:07        13 419 551 gs-serving-web-content-0.1.0.jar
27/11/2014  17:07             3 522 gs-serving-web-content-0.1.0.jar.original
27/11/2014  17:07    <DIR>          maven-archiver
27/11/2014  17:07    <DIR>          maven-status
  • рядок 12: створений архів;

Цей архів запускається наступним чином:


gs-serving-web-content-complete\target>java -jar gs-serving-web-content-0.1.0.jar

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.9.RELEASE)

2014-11-27 17:14:50.439  INFO 8172 --- [           main] hello.Application                        : Starting Application on Gportpers3 with PID 8172 (D:\data\istia-1415\spring mvc\dvp\gs-serving-web-content-complete\target\gs-serving-web-content-0.1.0.jar started by ST in D:\data\istia-1415\spring mvc\dvp\gs-serving-web-content-complete\target)
2014-11-27 17:14:50.491  INFO 8172 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@12f4ec3a: startup date [Thu Nov 27 17:14:50 CET 2014]; root of context hierarchy

Примітка: попередньо потрібно зупинити веб-службу, яка, можливо, запущена в Eclipse (див. стор. 17).

Тепер, коли веб-додаток запущено, його можна відкрити у веб-браузері:

 

1.6.8. Розгортання додатка на сервері Tomcat

Хоча Spring Boot є дуже зручним у режимі розробки, у виробничому середовищі додаток розгортається на реальному сервері Tomcat. Ось як це зробити:

Змініть файл [pom.xml] наступним чином:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-serving-web-content</artifactId>
    <version>0.1.0</version>
    <packaging>war</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <!-- середовище Thymeleaf -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- генерація WAR-файлу -->
<!--         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency> -->
    </dependencies>

    <properties>
        <start-class>hello.Application</start-class>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestone</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestone</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>

</project>

Зміни потрібно внести у двох місцях:

  • рядок 9: потрібно вказати, що буде створено архів war (Web ARchive);
  • рядки 24–28: потрібно додати залежність від артефакту [spring-boot-starter-tomcat]. Цей артефакт додає всі класи Tomcat до залежностей проєкту;
  • рядок 27: цей артефакт — [provided], тобто відповідні архіви не будуть розміщені у згенерованому WAR-файлі. Адже ці архіви будуть знаходитися на сервері Tomcat, на якому працюватиме додаток;

Насправді, якщо подивитися на поточні залежності проєкту, можна побачити, що залежність [spring-boot-starter-tomcat] уже присутня:

  

Тому немає потреби додавати її до файлу [pom.xml]. Ми залишили її у коментарях для довідки.

Крім того, потрібно налаштувати веб-додаток. За відсутності файлу [web.xml] це робиться за допомогою класу, що успадковує [SpringBootServletInitializer]:

  

Клас [ApplicationInitializer] має такий вигляд:


package hello;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;

public class ApplicationInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

}
  • рядок 6: клас [ApplicationInitializer] розширює клас [SpringBootServletInitializer];
  • рядок 9: метод [configure] перевизначено (рядок 8);
  • рядок 10: вказано клас, який налаштовує проект;

Щоб виконати проект, можна вчинити так:

  • у [1] — запускаємо проект на одному із серверів, зареєстрованих у IDE Eclipse;
  • у [2] вибираємо вищезазначений [Tomcat v8.0];

Після цього можна відкрити URL [http://localhost:8080/gs-rest-service/greeting/?name=Mitchell] у браузері:

 

Примітка: залежно від версій [tomcat] та [tc Server Developer] це виконання може завершитися невдачею. Так сталося, наприклад, із версією [Apache Tomcat 8.0.3 et 8.0.15]. У наведеному вище прикладі використовувалася версія Tomcat [8.0.9].

Тепер ми знаємо, як створити архів war. Далі ми продовжимо працювати зі Spring Boot та його виконуваним архівом jar.

1.7. Другий проект Spring — MVC

1.7.1. Демонстраційний проєкт

  • у [1] ми імпортуємо один із посібників Spring;
  • у [2] ми обираємо приклад [Rest Service];
  • у [3] вибираємо проект Maven;
  • у [4] вибираємо остаточну версію посібника;
  • у [5] підтверджуємо;
  • у [6] — імпортований проєкт;

Веб-сервіси, доступні через стандартні URL і які надають текст jSON, часто називають сервісами REST (REpresentational State Transfer). У цьому документі я просто називатиму сервіс, який ми будемо створювати, веб-сервісом / jSON. Сервіс вважається Restful, якщо він дотримується певних правил. Я не намагався дотримуватися цих правил.

Тепер розглянемо імпортований проєкт, насамперед його конфігурацію Maven.

1.7.2. Конфігурація Maven

Файл [pom.xml] має такий вигляд:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-rest-service</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <start-class>hello.Application</start-class>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>
</project>
  • рядки 6–8: властивості проекту Maven. Відсутній тег [<packaging>], що вказує тип файлу, який створюється під час компіляції Maven. За його відсутності використовується тип [jar]. Отже, додаток є консольним виконуваним файлом, а не веб-додатком, для якого тип упаковки був би [war];
  • рядки 10–14: проект Maven має батьківський проект [spring-boot-starter-parent]. Саме він визначає основну частину залежностей проекту. Їх може бути достатньо, і в цьому випадку додаткові залежності не додаються, або ж їх може не вистачати, і тоді додаються відсутні залежності;
  • рядки 17–20: артефакт [spring-boot-starter-web] містить бібліотеки, необхідні для проекту Spring MVC типу веб-сервісу, у якому не генеруються візуальні елементи. Цей артефакт містить величезну кількість бібліотек, зокрема бібліотеки вбудованого сервера Tomcat. Саме на цьому сервері буде виконуватися додаток;

Бібліотек, що входять до складу цієї конфігурації, дуже багато:

Вище показано три архіви сервера Tomcat.

1.7.3. Архітектура сервісу Spring [web / jSON]

Нагадаємо, як Spring MVC реалізує модель MVC:

Обробка запиту клієнта відбувається наступним чином:

  1. запит — запитувані URL мають вигляд http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&... [Dispatcher Servlet] — це клас Spring, який обробляє вхідні URL. Вона «направляє» URL до дії, яка має її обробити. Ці дії — це методи певних класів, що називаються [Contrôleurs]. Літера «C» у MVC тут є рядком [Dispatcher Servlet, Contrôleur, Action]. Якщо для обробки вхідного запиту URL не було налаштовано жодної дії, сервлет [Dispatcher Servlet] відповість, що запитуваний URL не знайдено (помилка 404 NOT FOUND);
  2. обробка
  • обрана дія може використовувати параметри parami, які їй передала сервлета [Dispatcher Servlet]. Вони можуть походити з кількох джерел:
    • з шляху [/param1/param2/...] сервлета URL,
    • з параметрів [p1=v1&p2=v2] сервлета URL,
    • з параметрів, надісланих браузером разом із запитом;
  • під час обробки запиту користувача дії може знадобитися рівень [metier] [2b]. Після обробки запиту клієнта це може викликати різні відповіді. Класичним прикладом є:
    • сторінка з повідомленням про помилку, якщо запит не вдалося обробити належним чином
    • сторінка підтвердження в іншому випадку
  • дія вимагає відображення певного виду [3]. Цей вид відображатиме дані, які називаються моделлю виду. Це «M» у MVC. Акція створить цю модель M [2c] і вимагатиме відображення певного виду V [3];
  1. відповідь — обраний вигляд V використовує модель M, створену дією, для ініціалізації динамічних частин відповіді HTML, яку він повинен надіслати клієнту, а потім надсилає цю відповідь.

Для веб-сервісу / jSON попередня архітектура дещо змінена:

  • у [4a] модель, яка є класом Java, перетворюється на рядок jSON за допомогою бібліотеки jSON;
  • у [4b] цей рядок jSON надсилається до браузера;

1.7.4. Контролер C

  

Імпортований додаток має такий контролер:


package hello;

import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    @RequestMapping("/greeting")
    public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
        return new Greeting(counter.incrementAndGet(), String.format(template, name));
    }
}
  • рядок 9: анотація [@RestController] перетворює клас [GreetingController] на контролер Spring, тобто його методи зареєстровані для обробки об’єктів типу URL. Ми вже бачили подібну анотацію [@Controller]. Результатом роботи методів цього контролера був тип [String], який являв собою ім’я поданого виду. Тут ситуація інша. Методи контролера типу [@RestController] повертають об’єкти, які серіалізуються для відправки до браузера. Тип серіалізації залежить від конфігурації Spring MVC. У цьому випадку вони будуть серіалізовані у формат jSON. Саме наявність бібліотеки jSON у залежностях проєкту змушує Spring Boot шляхом автоконфігурації налаштувати проєкт саме таким чином;
  • рядок 14: анотація [@RequestMapping] вказує на URL, який обробляє метод, у даному випадку URL [/greeting];
  • рядок 15: ми вже пояснювали анотацію [@RequestParam]. Результатом, що повертається методом, є об’єкт типу [Greeting].
  • рядок 12: ціле число типу «long» атомарного типу. Це означає, що воно підтримує паралельний доступ. Кілька потоків можуть одночасно намагатися збільшити значення змінної [counter]. Це відбуватиметься коректно. Потік може зчитати значення лічильника лише тоді, коли потік, який його змінює, завершив свою операцію.

1.7.5. Модель M

Модель M, створена за допомогою попереднього методу, є таким об’єктом [Greeting]:

  

package hello;

public class Greeting {

    private final long id;
    private final String content;

    public Greeting(long id, String content) {
        this.id = id;
        this.content = content;
    }

    public long getId() {
        return id;
    }

    public String getContent() {
        return content;
    }
}

Перетворення jSON цього об’єкта створить рядок {"id":n,"content":"текст"}. У підсумку рядок jSON, створений методом контролера, матиме такий вигляд:

{"id":2,"content":"Hello, World!"}

або

{"id":2,"content":"Hello, John!"}

1.7.6. Виконання

  

Клас [Application.java] є виконуваним класом проекту. Його код такий:


package hello;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan
@EnableAutoConfiguration
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

Ми вже зустрічали та пояснювали цей код у попередньому прикладі.

1.7.7. Виконання проекту

Запустимо проект:

 

Отримуємо такі записи консолі:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.9.RELEASE)

2014-11-28 15:22:55.005  INFO 3152 --- [           main] hello.Application                        : Starting Application on Gportpers3 with PID 3152 (started by ST in D:\data\istia-1415\spring mvc\dvp-final\gs-rest-service)
2014-11-28 15:22:55.046  INFO 3152 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@62e136d3: startup date [Fri Nov 28 15:22:55 CET 2014]; root of context hierarchy
2014-11-28 15:22:55.762  INFO 3152 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanNameViewResolver': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]
2014-11-28 15:22:56.567  INFO 3152 --- [           main] .t.TomcatEmbeddedServletContainerFactory : Server initialized with port: 8080
2014-11-28 15:22:56.738  INFO 3152 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2014-11-28 15:22:56.740  INFO 3152 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/7.0.56
2014-11-28 15:22:56.869  INFO 3152 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2014-11-28 15:22:56.870  INFO 3152 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1827 ms
2014-11-28 15:22:57.478  INFO 3152 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2014-11-28 15:22:57.481  INFO 3152 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2014-11-28 15:22:57.685  INFO 3152 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-11-28 15:22:57.879  INFO 3152 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/greeting],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public hello.Greeting hello.GreetingController.greeting(java.lang.String)
2014-11-28 15:22:57.884  INFO 3152 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2014-11-28 15:22:57.885  INFO 3152 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[text/html],custom=[]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
2014-11-28 15:22:57.906  INFO 3152 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] на обробник типу [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-11-28 15:22:57.907  INFO 3152 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] на обробник типу [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-11-28 15:22:58.231  INFO 3152 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2014-11-28 15:22:58.318  INFO 3152 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080/http
2014-11-28 15:22:58.319  INFO 3152 --- [           main] hello.Application                        : Started Application in 3.788 seconds (JVM running for 4.424)
  • рядок 13: сервер Tomcat запускається на порту 8080 (рядок 12);
  • рядок 17: сервлет [DispatcherServlet] присутній;
  • рядок 20: виявлено метод [GreetingController.greeting];

Щоб протестувати веб-додаток, надсилаємо запит на URL [http://localhost:8080/greeting]:

 

Отримано очікуваний рядок jSON.

Примітка: цей приклад не працював із вбудованим браузером Eclipse.

Може бути цікаво переглянути заголовки HTTP, надіслані сервером. Для цього ми використаємо плагін для Chrome під назвою [Advanced Rest Client] (див. Додатки, параграф 9.6):

  • у [1] — запитуваний URL;
  • у [2] використовується метод GET;
  • у [3] — відповідь jSON;
  • у [4] сервер повідомив, що надсилає відповідь у форматі jSON;
  • у [5] запитується той самий URL, але цього разу з POST;
  • у [7] інформація надсилається на сервер у формі [urlencoded];
  • у [6] — параметр name із його значенням;
  • у [8] браузер повідомляє серверу, що надсилає йому інформацію [urlencoded];
  • у [9] — відповідь сервера jSON;

1.7.8. Створення виконуваного архіву

Як і в попередньому проєкті, ми створюємо виконуваний архів:

  • у [1]: виконуємо ціль Maven;
  • у [2]: є дві цілі (goals): [clean] для видалення папки [target] з проекту Maven, [package] для її повторного створення;
  • у [3]: папка [target], що буде згенерована, розміститься в цій папці;
  • у [4]: генерується ціль;

У журналах, що з’являються в консолі, важливо побачити плагін [spring-boot-maven-plugin]. Саме він генерує виконуваний архів.

[INFO] --- spring-boot-maven-plugin:1.1.0.RELEASE:repackage (default) @ gs-rest-service ---

За допомогою консолі перейдіть до створеної папки:


D:\Temp\wksSTS\gs-rest-service\target>dir
 ...
11/06/2014  15:30    <DIR>          classes
11/06/2014  15:30    <DIR>          generated-sources
11/06/2014  15:30        11 073 572 gs-rest-service-0.1.0.jar
11/06/2014  15:30             3 690 gs-rest-service-0.1.0.jar.original
11/06/2014  15:30    <DIR>          maven-archiver
11/06/2014  15:30    <DIR>          maven-status
...
  • рядок 5: створений архів;

Цей архів запускається наступним чином:


D:\Temp\wksSTS\gs-rest-service-complete\target>java -jar gs-rest-service-0.1.0.jar

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.0.RELEASE)

2014-06-11 15:32:47.088  INFO 4972 --- [           main] hello.Application
                  : Starting Application on Gportpers3 with PID 4972 (D:\Temp\wk
sSTS\gs-rest-service-complete\target\gs-rest-service-0.1.0.jar started by ST in
D:\Temp\wksSTS\gs-rest-service-complete\target)
...

Примітка: попередньо необхідно зупинити веб-службу, яка, можливо, запущена в Eclipse (див. розділ 1.6.6).

Тепер, коли веб-додаток запущено, його можна відкрити у браузері:

 

1.7.9. Розгортання додатка на сервері Tomcat

Як і в попередньому проєкті, ми змінюємо файл [pom.xml] наступним чином:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-rest-service</artifactId>
    <version>0.1.0</version>
    <packaging>war</packaging>

    ...
</project>
  • рядок 9: потрібно вказати, що буде створено архів war (Web ARchive);

Крім того, потрібно налаштувати веб-додаток. За відсутності файлу [web.xml] це робиться за допомогою класу, що успадковує [SpringBootServletInitializer]:

  

Клас [ApplicationInitializer] має такий вигляд:


package hello;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;

public class ApplicationInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

}
  • рядок 6: клас [ApplicationInitializer] успадковує клас [SpringBootServletInitializer];
  • рядок 9: метод [configure] перевизначено (рядок 8);
  • рядок 10: вказано клас, який налаштовує проект;

Щоб виконати проект, можна вчинити так:

  • у [1-2] запускаємо проект на одному із серверів, зареєстрованих у IDE Eclipse;

Після цього можна завантажити URL [http://localhost:8080/gs-rest-service/greeting/?name=Mitchell] у браузері:

 

1.8. Conclusion

Ми запровадили два типи проектів Spring MVC:

  • проект, у якому веб-додаток надсилає потік HTML до браузера. Цей потік генерується механізмом відображення [Thymeleaf];
  • проект, у якому веб-додаток надсилає потік jSON до браузера;

У першому випадку для проекту потрібні дві залежності Maven:


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
</dependencies>

У другому випадку залежності Maven такі:


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
</dependencies>

Залежності, що виникають у результаті цих конфігурацій, є дуже численними, і багато з них є непотрібними. Для введення додатка в експлуатацію ми використаємо ручну конфігурацію Maven, у якій будуть присутні лише ті залежності, що необхідні для проекту.

Тепер повернемося до основ веб-програмування, розглянувши два базові поняття:

  • діалог HTTP (HyperText Transfer Protocol) між браузером та веб-додатком;
  • мова HTML (HyperText Markup Language), яку браузер інтерпретує для відображення отриманої сторінки;