Как писать на Spring в 2017

  • Tutorial

В одной из классических статей для новичков, мелькавших недавно на Хабре, рассказывалось про создание базового Web приложения на Java. Все начиналось с сервлета, потом создания JSP страницы и, наконец, деплоймента в контейнер. Посмотрев на это свежим взглядом я понял, что для как раз для новичков это, наверняка, выглядит совершенно жутко — на фоне простых и понятных PHP или Node.js, где все просто — написал контроллер, вернул объект, он стал JSON или HTML. Чтобы немного развеять это ощущение, я решил написать "Гайд для новичков в Spring". Цель это статьи — показать, что создание Web приложений на Java, более того — на Spring Framework это не боль и мучительное продирание через web.xml, persistence.xml, beans.xml, и собирание приложения как карточного домика по кусочкам, а вполне себе быстрый и комфортный процесс. Аудитория — начинающие разработчики, разработчики на других языках, ну и те, кто видел Спринг в его не самые лучше времена.


Введение


В этой статье мы посмотрим, что включает в себя современный Спринг, как настроить локальное окружение для разработки Веб приложений, и создадим простое веб-приложение, которое берет данные из БД и отдает HTML страницу и JSON. Как ни странно, большинство статей (на русском языке) для начинающих, которые я нашел в топе поиска описывают и ручное создание контекста, и запуск приложения, и конфигурацию через XML — ничего из этого в современном Спринге делать, разумеется, не обязательно.


Что такое Spring?


Для начала пара слов, что же такое Spring. В настоящее время, под термином "Spring" часто подразумевают целое семейство проектов. В большинстве своем, они развиваются и курируются компанией Pivotal и силами сообщества. Ключевые (но не все) проекты семейства Spring это:


  • Spring Framework (или Spring Core)
    Ядро платформы, предоставляет базовые средства для создания приложений — управление компонентами (бинами, beans), внедрение зависимостей, MVC фреймворк, транзакции, базовый доступ к БД. В основном это низкоуровневые компоненты и абстракции. По сути, неявно используется всеми другими компонентами.


  • Spring MVC (часть Spring Framework)
    Стоит упомянуть отдельно, т.к. мы будем вести речь в основном о веб-приложениях. Оперирует понятиями контроллеров, маппингов запросов, различными HTTP абстракциями и т.п. Со Spring MVC интегрированы нормальные шаблонные движки, типа Thymeleaf, Freemaker, Mustache, плюс есть сторонние интеграции с кучей других. Так что никакого ужаса типа JSP или JSF писать не нужно.


  • Spring Data
    Доступ к данным: реляционные и нереляционные БД, KV хранилища и т.п.


  • Spring Cloud
    Много полезного для микросервисной архитектуры — service discovery, трасировка и диагностика, балансировщики запросов, circuit breaker-ы, роутеры и т.п.


  • Spring Security
    Авторизация и аутентификация, доступ к данным, методам и т.п. OAuth, LDAP, и куча разных провайдеров.


  • Spring Integration
    Обработка данных из разных источников. Если надо раз в час брать файл с ФТП, разбивать его на строки, которые потом фильтровать, а дальше отправлять в какую-то очередь — это к Spring Integration.

Типичное веб приложение скорее всего будет включать набор вроде Spring MVC, Data, Security. Ниже мы увидим, как это все работает вместе.


Особняком стоит отметить Spring Boot — это вишенка на торте (а некоторые думают, что собственно сам торт), которые позволяет избежать всего ужаса XML конфигурации. Boot позволяет быстро создать и сконфигурить (т.е. настроить зависимости между компонентами) приложение, упаковать его в исполняемый самодостаточный артефакт. Это то связующее звено, которое объединяет вместе набор компонентов в готовое приложение. Пару вещей, которые нужно знать про Spring Boot:


  • Он не использует кодогенерацию. Из кода, который генерится, присутствует только метод main. Если вы ищете утилиту для генерации приложений — это скорее JHipster
  • Не использует XML для конфигурации. Все конфигурится через аннотации
  • Используются автоконфигурации по максимуму. Если у вас добавлена зависимость на Mongo, и не указано, куда подключаться — Boot попробует localhost:27017
  • Используется convention over configuration. Для большинства конфигураций не нужно ничего настраивать
  • Его легко отодвинуть в сторону и "перекрыть" конфигурацию по умолчанию. Например, если в настройках указать хост для подключения к Монго — он автоматически перекроет localhost

Настройка окружения


Для того, чтобы создать простое приложение, знать, как создать проект Maven с нуля, как настроить плагины, чтобы создать JAR, какие бывают лейауты в JAR, как настроить Surefire для запуска тестов, как установить и запустить локально Tomcat, а уж тем более, как работает DispatcherServlet — совершенно не нужно.


Современное приложение на Spring создается в два шага:


  1. Идем на Spring Initializr.
  2. … и все, второго шага нет

Spring Initializr позволяет "набрать" в свое приложение нужных компонентов, которые потом Spring Boot (он автоматически включен во все проекты, созданные на Initializr) соберет воедино.


В качестве среды разработки подойдет что угодно, например бесплатная IntelliJ IDEA CE прекрасно справляется — просто импортируйте созданный pom.xml (Maven) или build.gradle (Gradle) файл в IDE.


Стоит отдельно отметить компонент Spring Boot который называется DevTools. Он решает проблему цикла локальной разработки, который раньше выглядел как:


  1. Собрать WAR локально
  2. Задеплоить его в Очень Крутой Энтерпрайз Аппликейшен Сервер на тестовом сервере, потому что настройка ОКЭАС локально требует недюжинной сноровки
  3. Выпить чашку кофе, т.е. ОКЭАС перезапустить приложение в лучшем случае через несколько минут
  4. Скопировать стектрейс ошибки
  5. Перейти на п. 1

В те древние времена даже родилась поговорка, что Spring это DSL для конвертации XML конфигов в стектрейсы.

С включенными Spring Boot DevTools цикл разработки сокращается до:


  1. Запустить приложение через зеленый треугольничек в IDEA

DevTools будут автоматом проверять изменения в скомпилированном коде или шаблонах, и очень быстро перезапускать (hot reload) только "боевую" часть приложения (как nodemon, если вы знакомы с миром node.js). Более того, DevTools включают интеграцию с Live Reload и после установки расширения в браузере, достаточно скомпилировать проект в IDEA, чтобы он автоматом обновился в браузере.


Разработка


Окей, пора приступать к практической части. Итак, наша цель — создать веб-приложение, которое отдает welcome страницу, обращается с нее же к собственному API, получает JSON с данными из базы и выводит их в таблицу.


Новый проект


Для начала, идем на start.spring.io и создаем проект с зависимостями Web, DevTools, JPA (доступ к реляционным базам), H2 (простая in-memory база), Mustache (движок шаблонов). Сгенерированный pom.xml импортируем в IDEA. Все, приложение готово к запуску! Можно его запустить из командной строки командой ./mvnw spring-boot:run или прямо из IDEA — запустив метод main. Да, серверов приложений, контейнеров и деплоймента не нужно.


Точнее, контейнер нужен — только он предоставлен и настроен Spring Boot-ом — используя Embedded Tomcat

Контроллер


Итак, наш следующий шаг — создать контроллер и вернуть "домашнюю" страницу. Код контроллера выглядит так просто, как и ожидается:


@Controller
public class IndexController {
    @GetMapping("/")
    public ModelAndView index() {
        Map<String, String> model = new HashMap<>();
        model.put("name", "Alexey");
        return new ModelAndView("index", model);
    }
}

Пара вещей, на которые стоит обратить внимание.


  1. Метод возвращает ModelAndView — дальше Spring знает, что нужно взять вью index.html из папки resources/templates (это соглашение по умолчанию) и передать туда модель
  2. Модель в нашем случае просто словарь, но это может быть и строго-типизированная модель (объект) тоже

С Котлин это бы выглядело еще лучше и проще, но это потребует введения сразу большого количества новых понятий — язык, фреймворк. Лучше начинать с малого.

Класс, помеченный как @Controller автоматически регистрируется в MVC роутере, а используя аннотации @(Get|Post|Put|Patch)Mapping можно регистрировать разные пути.


Все файлы из каталога resources/static/ считаются статическими, там можно хранить CSS и картинки.

Шаблон


Мы используем Mustache (Handlebar) синтаксис, поэтому шаблон очень напоминает обычный HTML


<!DOCTYPE html>

<html lang="en">

<body>
<h1>Welcome to Spring, {{ name }}</h1>
</body>

</html>

После компиляции проекта (⌘/Ctrl + F9) — можно сразу идти на http://localhost:8080 и увидеть созданную страницу.


Доступ к базе


Для начала, опишем нашу предметную область. Мы будем собирать статистику посещений — каждый раз, когда кто-то заходит на главную страницу, мы будем писать это в базу. Модель выглядит до крайности примитивно:


@Entity
public class Visit {

    @Id
    @GeneratedValue
    public Long id;

    public String description;
}

Предвидя череду комментариев "Как же без геттеров и сеттеров" и "Где же equals / hashCode" — эти элементы упущены сознательно с целью упрощения кода. Совершенно чудовищная ошибка дизайна Java которая заставляет писать эту ерунду (геттеры и методы сравнения), это, конечно, отдельный разговор. Котлин эту проблему, кстати, решает.

Мы снова очень активно используем аннотации — в этот раз из Spring Data (точнее, JPA — это дремучая спецификация для доступа к данным). Этот класс описывает модель с двумя полями, одно из которых генерится автоматически. По этому классу будет автоматически создана модель данных (таблицы) в БД.


Теперь для этой модели пора создать репозиторий. Это еще проще, чем контроллер.


@Repository
public interface VisitsRepository extends CrudRepository<Visit, Long> {
}

Все, репозиторий можно использовать для работы с базой — читать и писать записи. У внимательного читателя должен сработать WTF детектор — что здесь вообще происходит? Мы определяем интерфейс и внезапно он начинает работать с базой? Все так. Благодаря магии Spring Boot и Spring Data "под капотом" происходит следующее:


  • Увидев в зависимостях H2 (встраиваемая БД), Boot автоматически конфигурит DataSource (это ключевой компонент для подключения к базе) чтобы приложение работало с этой базой
  • Spring Data ищет всех наследников CrudRepository и автоматически генерит для них дефолтные реализации, которые включают базовые методы репозитория, типа findOne, findAll, save etc.
  • Spring автоматически конфигурит слой для доступа к данным — JPA (точнее, его реализацию Hibernate)
  • Благодаря аннотации @Repository этот компонент становится доступным в нашем приложении (и мы его используем через пару минут)

Чтобы использовать репозиторий в контроллере мы воспользуемся механизмом внедрения зависимостей, предоставляемый Spring Framework. Чтобы это сделать, как ни странно, нужно всего лишь объявить зависимость в нашем контроллере.


@Controller
public class IndexController {

    final VisitsRepository visitsRepository;

    public IndexController(VisitsRepository visitsRepository) {
        this.visitsRepository = visitsRepository;
    }
...
}

Увидев в нашем конструкторе параметр типа VisitRepository, Spring найдет созданный Spring Data-ой репозиторий и передаст его в конструктор.


Теперь можно писать в базу в методе контроллера.


@GetMapping("/")
    public ModelAndView index() {
        Map<String, String> model = new HashMap<>();
        model.put("name", "Alexey");

        Visit visit = new Visit();
        visit.description = String.format("Visited at %s", LocalDateTime.now());
        visitsRepository.save(visit);

        return new ModelAndView("index", model);
    }

REST контроллер


Следующий шаг — это вернуть все записи из базы в JSON формате, чтобы потом их можно было читать на клиенте.


Для REST в Spring есть отдельный тип контроллера который называется @RestController, код которого не сильно отличается от обычного контроллера.


@RestController
@RequestMapping("/api")
public class ApiController {

    final VisitsRepository visitsRepository;

    public ApiController(VisitsRepository visitsRepository) {
        this.visitsRepository = visitsRepository;
    }

    @GetMapping("/visits")
    public Iterable<Visit> getVisits() {
        return visitsRepository.findAll();
    }
}

На что обратить внимание:


  • В этот раз мы определяем "префикс" для всех методов контроллера использую базовый @RequestMapping
  • Внедрение зависимостей работает точно так же, как и для обычных контроллеров (как и вообще для всего в Spring)
  • Метод теперь возвращает не имя шаблона, а модель. Spring автоматически преобразует это в массив JSON объектов
  • Мы используем persistence модель для сериализации в JSON, что в общем случае не самая лучшая практика

Теперь при запросе http://localhost:8080/api/visits (предварительно скомпилировав проект и дав DevTools обновить приложение) мы получим JSON с нужными данными.


Клиентский код


Оставим за рамками этой статьи, пример можно увидеть в исходном коде. Цель этого кода — исключительно продемонстрировать как получить JSON данные с сервера, интеграции с клиентскими фреймворками React, Angular etc намеренно оставлены вне рамок этой статьи.


Тестирование


Spring так же предоставляет мощные средства для Integration и Unit тестирования приложения. Пример кода, который проверяет контроллер:


@Test
    public void indexControllerShouldReturnHtmlPage() throws Exception {
        mockMvc.perform(get("/"))
                .andExpect(status().isOk())
                .andExpect(content().string(containsString("Welcome to Spring")));
    }

Используя абстракции типа MockMvc можно легко тестировать внешний интерфейс приложения, в то же время имея доступ к его внутренностям. Например, можно целиком заменить компоненты приложения на моки (заглушки).


Аналогично для API тестов есть набор хелперов для проверки JsonPath выражений.


@Test
public void apiControllerShouldReturnVisits() throws Exception {
    mockMvc.perform(get("/"));

    mockMvc.perform(get("/api/visits"))
            .andExpect(jsonPath("$.*.description", iterableWithSize(1)));
}

Тестирование в Spring это все таки отдельная тема, поэтому мы не будем сильно на этом останавливаться сейчас.


Деплоймент


Чтобы собрать и запустить наше приложение в продакшене есть несколько вариантов.


  1. Задеплоить полученный JAR (или даже WAR) в сервлет контейнер, например Tomcat. Это не самый простой путь, его нужно выбирать только если у вас уже есть работающий сервлет контейнер или сервер приложений.
  2. Использовать магию Spring Boot. JAR файл, собранный используя плагин Spring Boot (который автоматически добавляется в проекты созданные через Spring Initializr), является полностью самодостаточным.

Таким образом сборка и запуск приложения выглядит как:


  1. ./mvnw package
  2. java -jar ./target/demo-0.0.1-SNAPSHOT.jar

Для деплоймента этого JAR файла не нужно ничего, кроме установленной Java (JRE). Это так называемый fat JAR — он включает в себя и встроенный сервлет контейнер (Tomcat по умолчанию) и фреймворк, и все библиотеки-зависимости. По сути, он является единственным артефактом деплоймтента — его можно просто копировать на целевой сервер и запускать там.


Более того, файл можно сделать "выполняемым" и запускать его просто из командной строки (Java, конечно, все равно необходима).


На базе этого файла можно легко создать Docker образ или установить его как демон. Больше деталей доступно в официальной документации.


Заключение


Получилось, все же, очень сжато — но уложить даже самый простой вводный курс по Spring в рамки одной статьи не очень просто. Надеюсь, это поможет кому-то сделать первый шаги в Spring-е, и хотя понять его фундаментальные концепции.


Как вы успели заметить, в тексте статьи много раз звучало слово "магия Spring". По сути своей, это очень "магический" фреймворк — даже взглянув на самую верхушку айсберга мы уже видели, что Spring много всего делает в фоне. Это является и плюсом, и минусом фреймворка. Плюс несомненно в том, что многие сложные вещи (очень многие) можно сделать одной аннотацией или зависимостью. Минус же это скрытая сложность — чтобы решить какие-то сложные проблемы, заставить фреймворк работать в крайних случаях или понимать все тонкости и аспекты нужно его неплохо знать.


Чтобы сделать этап "знать" как можно проще, Spring обладает отличной документацией, огромным сообществом, и чистыми исходниками, которые вполне можно читать. Если расположить Spring на шкале Рича Хики, он (Spring) несомненно попадет в easy, но уж точно не simple. Но для современного энтерпрайза (и не только энтерпрайза) он дает невероятные возможности чтобы получить production-ready приложение очень быстро и концентрироваться на логике приложения, а не инфраструктуры вокруг.


Ссылки


AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 110

    +1
    Для новичка статья не очень. Знакомство со спрингом нужно начинать явно не с бута. Для тех, кто со спрингом уже знаком, статья так же не будет полезна, т.к. таких туториалов достаточно на том же spring.io.
      +1
      Если я правильно понял автора, его цель была развеять миф, что Java for Web — это сложно.
      Правда, текста сильно вышло. Можно было сделать короче на 20% — эффект был бы лучше, по-моему.
      • UFO just landed and posted this here
          0
          имхо, но аппликэйшн сервер наоборот убирает сложность от разработчика.
          С аппликэйшн сервером тебе нет необходимости знать где какая база, как к тебе ходят пользователи, по какому протоколу, думать где у тебя продакшен сервер, а где боевой и т.д. ты просто занят бизнес логикой.
          По-моему основной плюс спринг бута, единого джара выскакивает когда у тебе необходимо делать сложные веши, например горизонтальное масштабирование проекта
            +1
            С аппликэйшн сервером тебе нет необходимости знать где какая база, как к тебе ходят пользователи, по какому протоколу, думать где у тебя продакшен сервер, а где боевой и т.д. ты просто занят бизнес логикой.

            Да, это только с одной оговоркой — если все заранее настроено, и работает как часы

              +1
              ну если у вас команда разработчиков, причем разного уровня, то более опытные разрабы(девопсы/админы) как раз таки настроят аппликэйшн сервер, а тем же джунам вообще не надо занть что там происходит
                0
                Если вокруг меня уже есть команда разработчиков, я буду изучать Spring не по хабрастатьям, а по документации и в беседах с коллегами.

                Данная же статья, видимо, рассчитана на тех, кто хочет изучить Spring самостоятельно, соответственно, и сервер приложений поднимать придётся своими руками.
            0
            Честно говоря, в своё время меня тоже отпугнула сложность сервлетов, и первый свой web-проект я писал на Vaadin :) Уже потом я осознал необходимость изучения таких низкоуровневых технологий.
              +3
              «Напишите такую книгу, которую бы вам самим хотелось прочитать» — то же, и со статьей. Я хотел написать статью, которой мне самому не хватало когда-то. Речь в комментарии, о котором идет речь (я его оставил), шла что для новичка это не нужно. Это даже не то, чтобы сложно, это скорее лишний уровень абстракции в самый первый день. Так же, как и деплой WAR-ника на сервер (который же надо поставить и запустить, а мы новички). И там даже ниже в комментариях был вопрос — а как убрать имя WAR из пути? Конечно, мы же все знаем — назвать его root.war. Но я намекну — для человека, который первый раз в жизни видит Tomcat это не так же очевидно.

              Речь не про то, что какие-то концепции (сервлеты) — сложные. Скорее про то, что они не нужны в самом начале пути, их можно узнавать постепенно.
                +1
                Для человека, который имеет опыт и багаж знаний — это действительно не сложно.
                А вот для человека, который мало что знает, но хочет «войти в ИТ» и стоит на раздолье: C# | Java | PHP | JS | Python — это будет страшно и не понятно, в конечном случае, выберет то, что будет проще выучить ;-)

                И плевать, что WAR и энтерпрайз сервера — это «просто». Новичек не захочет тратить полгода на изучение сервера и всех его внутренностей, чтобы написать свое первое простое приложение. Он захочет «тык-тык и в продакшен!». И он будет прав(((
                • UFO just landed and posted this here
                    +4
                    Здесь вопрос не в сложности, а в количестве новых понятий. Архитип — уже новое. Maven плагин для толстого Jar надо ещё настроить, для тонкого — знать какие зависимости и куда деплоить. Надо смотреть что такое WlidFly и GlassFish, выбирать из них. Получается много не сложных по отдельности составных частей — но все вместе получится не очень просто.

                    И цель моей статьи была как раз показать, что чтобы начать — все эти составные части знать не нужно.
                      0
                      У java высокая планка в хода по сравнению с другими языками. Чтобы запустить простейшее приложение необходимо сразу разобраться с кучей вещей. Возможность выбора из нескольких вариантов ясности тоже не добавляет. Например надо выбрать сервер, а для человека начинающего изучать web разница и между tomcat с glassfish далеко не очевидна. Новичек посмотрит на этот зоопарк и плюнет уйдя на nodeJs, где сложность растет постепенно.
                        +1
                        У меня с NodeJS было как-то все наоборот. Нужно было за день запилить сайтик на NodeJS, которым раньше не пользвоался. В первый же час знакомства, попытка прикрутить фреймворк для нормальной авторизации в веб-приложении, вылилась в очень слабую документацию и чтение исходников этого фреймворка. Сайтик запилил, но после этого еще несколько дней приходил в себя от выгорания. Такой-то постепенный рост сложности, дайте два!
                  0
                  Что сложного в сервлете, поставить одну аннотацию и переопределить один метод?..

                  Когда лично я только убегал из мира Java, ни о каких аннотациях речи не шло — требовалось прописать сервлет в web.xml, притом два раза. Вот на тех, кто навеки запомнил мир Java именно таким, пост и рассчитан.

                  • UFO just landed and posted this here
                      0

                      Да, надо было зарегистрировать сам сервлет и отдельно его маппинг. Ужасен он тем, что его модель — сильно избыточна: зачем вообще придумали сервлеты и маппинги отдельно?

                        0
                        Не знаю, есть ли это в jee 6, но в jee 7 в web.xml сервлеты можно вообще не прописывать, у меня, например, в одном из тестовых проектов в web.xml заполнено только название проекта. Сами сервлеты в коде помечаются аннотацией WebServlet.
                        • UFO just landed and posted this here
                            0
                            А конфигурацию и не нужно размазывать по куче файлов. Это уже ошибка в архитектуре проекта и она не имеет отношения к конкретной реализации, будь то конфигурирование с помощью аннотаций или xml.
                            –1
                            Я больше скажу — сам web.xml не обязателен.
                            0
                            Странный вопрос.

                            Маппинг — это отображение url на сервлет. Вот этот сервлет обрабатывает вот такие url. И еще вот такие (потенциально — несколько).

                            Сервлет — это на минутку, сам сервлет. У него есть параметры (настройки). Любые.

                            Отношение между маппингом и сервлетом — M:1. Я готов согласиться, что это сделано не идеально удобно (я бы наверное сделал маппинг дочерним элементом для сервлета), но что это непонятно — хм. Это может быть непонятно если человек почему-то новичок в веб технологиях вообще. Или если доки совсем не читать.
                              0

                              Вот если бы сделали дочерним элементом — то и файл web.xml был бы и не таким страшным...

                                0

                                Тут дело такое — с самого начала в J2EE предполагалось, что компоненты может настраивать как программист, так и деплоер. И эта роль была предусмотрена, вместе с сервер-специфичными xml дескрипторами для него.


                                Я не стану утверждать однозначно, но вполне могу себе представить ситуацию, когда деплоеру нужно сконфигурировать только маппинг. Ну т.е. суть в том, что в других сценариях, про которые мы часто не думаем, может быть удобнее и так и эдак.

                                  0

                                  Только вот в чем проблема — сколько я ни смотрел на формат этого файла, я так и не смог понять в чем тут польза деплоеру от такого формата.


                                  Настраиваемые маппинги возможны только для внешнего API, но не для внутреннего. Потому что при исправлении маппинга нужно как минимум исправить еще и то место, где формируется ссылка. А уж если на правильной иерархии маппингов что-то хитрое завязано — то ее и вовсе при деплое сменить невозможно.

                        0

                        Это действительно сложно для новичка. Когда в одиночку с нуля пытаешься разобраться как запустить свой первый хэлло ворлд то постоянно что-то идёт не так. В интернете огромное количество туториалов разной степени устаревшести. В результате можно запросто потратить несколько дней только на то чтобы получить наконец вожделенную строку в броузере. Все эти war, jar, application server, servlets, jee, spring mvc, tomcat, jboss, glassfish всё это поначалу ужасно непонятно. И каждый апп сервер надо ещё как-то настроить. Spring boot очень всё упрощает.

                      +1

                      Я только начинаю учить джава и после питона с джанго — статья очень понятна. Может тем, кто незнаком с вебом вообще будет трудно, но тем кто использовал уже какие-то веб фреймворки с ОРМ, МВС и тд. особых проблем не должно быть

                        0
                        На джанго, кстати, очень похоже идеологией. Можно провести простое соответствие:
                        models.py в джанго — entity в спрингбуте
                        urls.py и views.py — controller в спрингбуте (маппинг урлов записывается прямо в контроллере)
                        реализация всяких сложных запросов через джанговский foo.objects.filter() — методы findByBlablabla в спрингбутовских репозиториях

                        Еще в спрингбуте «искаропки» идет не упомянутый в статье шаблонизатор Thymeleaf, который хоть и отличается по синтаксису от джанговского, но тоже без проблем позволяет использовать условия, циклы и т.п.

                          0

                          Да аналогия очевидна, хотя нюансы конечно же существуют, но сама идея очень близка. Думаю так же тем, кто знаком с Symphony из мира пхп тоже многое будет понятно, тем более, что там тоже активно аннотации используются

                        +2
                        Да, для тех, кто знаком со Спрингом читать статью вообще не интересно, целевая аудитория исключительно новички.

                        А вот по поводу Boot не соглашусь, тут я, увы, из другого лагеря — я считаю, что в наши дни не использовать Boot — это странно. Т.е. допускаю, что для некоторых команд и проектов проще без него, но в среднем по больнице — это именно то, чего не хватало Spring. Чего-то, что просто работает. А уж тем более для начинающих разработчиков.
                          0
                          в наши дни не использовать Boot — это странно

                          Поддерживаю. И для новичка Spring Boot это то, что надо.

                            +1
                            В буте слишком много «магии», которую можно добавить исключительно через зависимости и конфиг application.properties/yml. Во многом за счёт этой магии приложения на буте сейчас набирают популярность. Новичок в это лезть не будет, а потом, столкнувшись с первыми проблемами, типа «что за странная ошибка при старте приложения?» надолго погрязнет в поиске какого-то решение вместо того, чтобы заниматься изучением основ.
                              +1
                              Новичок в это лезть не будет, а потом, столкнувшись с первыми проблемами, типа «что за странная ошибка при старте приложения?» надолго погрязнет в поиске какого-то решение вместо того, чтобы заниматься изучением основ.

                              С проблемой новичок столкнётся далеко не сразу, к тому времени у него достаточно долго будет работоспособное приложение. Когда он столкнётся с проблемой, он откатит код до последней работающей версии, разберётся, какие изменения сломали код и достаточно быстро либо найдёт решение, либо достигнет похожих результатов другим кодом.

                                0

                                +1. Спринг на мой взгляд и так не слишком сложен, во всяком случае большая его часть.

                            +1
                            К сожалению, это современная тенденция разработки. Берем Spring Boot, делаем что-то дома и идем на собеседование на Senior Java Developer. Если у собеседующего такой же опыт со Spring Framework, то собеседование пройдено. А если собеседующий начнет ходить вокруг всего, то печаль-беда для кандидата :)
                            Но если есть понимание как это все работает, то тут соглашусь с автором, что Spring Boot позволяет получить каркас приложения очень быстро.
                              +2
                              Ну я бы все таки так не обобщал, собеседование это вообще сложная и непростая тема, безотносительно технологий и опыта (я, кстати, недавно переводил статью как раз про собеседования в Pivotal).

                              И в целом, видеть за обучающей статьей людей, которые могут «злоупотребить» отраслью и пройти собеседование на Senior Java Developer — это немного негативный взгляд на мир. Можно же видеть и по другому — это современная тенденция разработки, что для начинающих разработчиков доступно все больше инструментов, чтобы они могли стать продуктивными с самого начала, выпускать продукт как можно раньше, и параллельно учиться, узнавать сложные концепции шаг за шагом. И мне кажется, это прекрасно как для отрасли, так и для разработчиков.
                                +1
                                Соглашусь с Вами. Но многие начинающие специалисты не лезут внутрь сложных концепций и это печально.
                                  0
                                  Но многие начинающие специалисты не лезут внутрь сложных концепций и это печально.

                                  Спринг, спринг бут и фреймворки вообще зачастую сделаны для того, чтобы можно было не лезть внутрь сложных концепций. Непонятно, что вас огорчает.

                              0
                              А почему не с бута? Голый спринг весьма трудоемко конфигурить. Да, гибкости больше, но гораздо больше вариантов ошибиться в хмл конфигурации во всяких xsi:schemaLocation.
                                0
                                Java config позволяет избежать всех жутких xml'ей, да и погибче будет.
                                  0

                                  Никогда не понимал, в чем эта жуть. Многословно (иногда) — ну может быть. Не так гибко, как конфигурирование в java — очевидно тоже да, код более гибок, чем статический xml.

                                    +1
                                    xml не дебажится, к примеру. Это обстоятельство вместе с «многословно» и «не гибко» и порождает «жуть». Ну, или как-то так…
                              0
                              Спасибо, просто и достаточно для начала.
                                0
                                @Controller
                                public class IndexController {
                                
                                    final VisitsRepository visitsRepository;
                                
                                    public IndexController(VisitsRepository visitsRepository) {
                                        this.visitsRepository = visitsRepository;
                                    }
                                ...
                                }
                                


                                Тут наверное @Autowire потерялся на конструкторе. Чтоб понятнее было.
                                  +2
                                  Я нашел что со спринга 4.3 для единственного конструктора необязателен @Autowire. Был не прав.
                                    0
                                    @Repository
                                    public interface VisitsRepository extends CrudRepository<Visit, Long> {
                                    }

                                    Аннотация Repository не нужна для CrudRepository и его детей.
                                    Кроме CrudRepository есть еще PagingAndSortingRepository и JpaRepository. Имеет смысл заглянуть в них.


                                    И забыли написать как генерировать SQL запрос через репозиторий. если добавить в него метод:


                                    List<Visit> findByDescription(String description);

                                    то сгенерируется запрос вида select * from Visit where description =? (т.е. генерируется из названия метода)
                                    Можно самому написать запрос на HQL добавив аннотацию Query("здесь любой HQL запрос")


                                    Для "final VisitsRepository visitsRepository;" я бы добавил private.
                                    И можно заменить конструктор на @Autowired:


                                    @Controller
                                    public class IndexController {
                                    
                                        @Autowired
                                        private VisitsRepository visitsRepository;
                                    ...
                                    }
                                      +1
                                      Аннотация Repository не нужна для CrudRepository и его детей.
                                      Кроме CrudRepository есть еще PagingAndSortingRepository и JpaRepository.

                                      *Не нужна для наследников Repository. Можно так же кастомные репозитории делать, наследуясь прямо от Repository. Если не нужны методы CRUD, к примеру.

                                      И можно заменить конструктор на @Autowired:

                                      Делать @Autowired на полях не рекомендуется. В документации этот момент прописан.
                                        0
                                        Делать @Autowired на полях не рекомендуется. В документации этот момент прописан.

                                        Что-то не могу найти, не поделитесь ссылкой?
                                          +1
                                          Например вот: Setter-based dependency injection, в рамочке, где «Constructor-based or setter-based DI?»
                                            0
                                            Ссылки сейчас не найду, но общее правило, которому рекомендуют придерживаться и которое сильно облегчает рефакторинг и написание тестов это: если зависимость для вашего компонента обязательна и без нее он не работает, то это должно быть в конструкторе (т.к. это контракт), если это зависимость опциональная, и без нее компонент работает (логгер) — ее можно через property injection. Но вообще кейсов для Property Injection очень мало и с ними надо быть очень осторожным.
                                              0
                                              Не соглашусь, что @Autowired через сеттер или конструктор
                                              облегчает рефакторинг и написание тестов
                                              . Я бы даже сказал наоборот — утруждает.

                                              Мне нужна зависимость? Я пишу одну строку кода поля и ставлю одну аннотацию. Все. Никаких сеттеров, конструкторов, присвоения значений в конструкторе не нужно.
                                              Мне нужно написать тест? Легко — аннотации Mock, @InjectMocks и MockitoAnnotations.initMocks(this) в тестовом классе — и мой объект для юнит-тестирования готов. Никаких лишних телодвижений, меньше кода и усилий. Не понимаю, почему кто-то считает @Autowired над полем плохим тоном, я за несколько лет работы со спрингом так и не нашел объяснения для себя почему так делать плохо, а вот через конструктор — хорошо.
                                                +3
                                                1. Инжект в приватное поле требует поставить field.setAccessible(true), которые не всегда возможен.
                                                2. Начиная с Java 9 field.setAccessible(true) — будет не всегда доступен (если не будет выключен полностью).
                                                3. Начиная с Java 10 — его собирались выключить полностью или еще больше ограничить.

                                                4. Инжект в поле класса — это прямой путь в ад в мир, где ты не можешь работать с объектом без рефлексии и без контейнеров. Чтобы выполнить трифиальный тест — нужно подымать контейнер для того, чтобы заинжектить поле!!!

                                                5. Инжект в поле класса не дает возможности сделать оптимизацию по кешированию конструкторов (см. метод референс) и заставляет всегда выполнять инжект только через рефлексию.
                                                  –1
                                                  Спасибо за ответ, но я все равно не вижу преимуществ DI через конструктор вместо инджекта в поле.

                                                  1. Инжект в приватное поле требует поставить field.setAccessible(true), которые не всегда возможен.

                                                  Не всегда — это когда? Я таких случаев не знаю.
                                                  2. Начиная с Java 9 field.setAccessible(true) — будет не всегда доступен (если не будет выключен полностью).
                                                  3. Начиная с Java 10 — его собирались выключить полностью или еще больше ограничить.

                                                  И я почти уверен, что до релиза там будет все как было, так как они поломают кучу библиотек, а backward-compatibility это главная фишка Java. Это все-таки не Unsafe, на backward-compatibility которого можно наплевать, так как он формально не часть спецификации.
                                                  4. Чтобы выполнить трифиальный тест — нужно подымать контейнер для того, чтобы заинжектить поле!!!

                                                  Не нужно, гуглить в сторону @InjectMocks и MockitoAnnotations.initMocks(this)

                                                  5. Инжект в поле класса не дает возможности сделать оптимизацию по кешированию конструкторов (см. метод референс) и заставляет всегда выполнять инжект только через рефлексию.

                                                  И чем же это плохо? При setAccessible(true) у вас перформенс будет почти тот же, что и при сеттере. Кеш конструктора сделает оптимизацию вам в лучшем случае на несколько миллисекунд.
                                                    0
                                                    Лучше инжекшна через конструктор только вообще без инжекшена. Мой любимый подход — это когда бины полностью отвязаны от контейнера и полностью самодостаточны. Вся контейнерная логика находится в java-конфигурации, которая инстанцирует бины явно с нужными параметрами конструктора, вызовами нужных сеттеров, при помощи билдеров или фабрик, не важно как по большому счету. Все инжекшены на уровне конфигурации. Тем самым мы выносим логику инициализации контекста выполнения и создаем косвенность на уровне конфигурации. Зато нам не важно какие объекты у нас выступают в роли бинов. Как заанотированы их поля или конструкторы. Мы можем тестировать этот бин без какой-либо привязке к инжекшенам вообще и делать бины более нативными для языка. Лично для меня это намного более чисто, гибко и представляется как конструктор, где бины это просто классы, которые мы собираем при помощи конфигурации и можем при желании сделать конфигурации разными, гибкими и настраиваемыми. Т.е. есть у меня есть класс TcpServer из реактора, я могу просто получить в один бин конфиг, передать его в другой метод декларации бина и там на основе этих параметров инстанцировать уже сам сервер. Хотя сам сервер если разобраться ничего не знает о контейнерах. То же и с другими компонентами — хорошо, если они никак не завязаны на инжекшн и могут работать независимо — в этом смысле правильное поведение бина, если он всё зависимости принимает в конструктор и просто не создается без них. Мы так проектируем обычные классы, почему те, что мы используем в контейнере должны чем-то отличаться? К слову в самом спринге всё примерно так и сделано (бут вообще весь состоит из таких конфигураций). Нигде вы не увидите аннотаций @Service или @Inject, потому, что всё драйвится внешними конфигами, в свою очередь потому, что это дает возможность гибкости и настриваемости. Не вижу причин, почему мой код не может быть таким.
                                                      0
                                                      Не всегда — это когда? Я таких случаев не знаю.

                                                      Например Java Security Policy позволяет запретить рефлексию (но в этом случае, думаю, весь Spring не будет работать)
                                                      если погуглить немного: https://stackoverflow.com/questions/14639753/reflection-security

                                                      до релиза там будет все как было, так как они поломают кучу библиотек, а backward-compatibility это главная фишка Java.

                                                      С обратной совместимостью будет все хорошо — если запускать приложение «по-старому», все будет работать.
                                                      Но если запускать приложения как Модульные — то это уже будет новый функционал и тут уже можно внедрить новые правила, что успешно и сделали.
                                                      если погуглить немного: http://in.relation.to/2017/04/11/accessing-private-state-of-java-9-modules/

                                                      Не нужно, гуглить в сторону @InjectMocks и MockitoAnnotations.initMocks(this)

                                                      Mockito — это замечательная библиотека, не спорю. Именно Mockito и выступает в роли IoC контейнера в тестах. Или если это правильное Spring Boot приложение с тестами, — там будет свой Spring Boot IoC for Tests.
                                                      ps: Проблемы тестирования через Mockito достойны целой статьи.

                                                      И чем же это плохо? При setAccessible(true) у вас перформенс будет почти тот же, что и при сеттере.

                                                      Это замечательный вопрос!
                                                      Во-первых, в этом случае приватное поле становится публичным, а это уже минус для оптимизации.
                                                      Во-вторых, final поле прекращает быть final, а это в свою очередь значит, что оптимизации, которые связаны с final полями уже не будут работать, а так же, что объект не может быть по-нормальному расшарен между потоками и нужно делать синхронизации.
                                                      В-третьих, это нарушение целостности и безопасности, когда приватное поле, вдруг становится публичным в рантайме и используется не через публичный API класса.

                                                      К слову, добавлю еще один пункт:
                                                      6. Классы, которые используют инъекцию зависимостей в поля (@Inject, @Autowired, Resource etc.) нельзя будет переиспользовать без IoC контейнера. Это не самая большая проблема, но она тоже существует.
                                              –1

                                              Говоря "не рекомендуется" вы пугаете новичков.
                                              Делать через конструктор — это рекомендация, помогает защититься от некоторых ошибок.

                                            0
                                            Я всетаки считаю что прописать стоит ИМХО. Одно слово, зато все понятно что откуда и куда. Хотя я также в гетерах и сетарах все через
                                            this
                                            
                                            пишу.
                                            0
                                            Почему не поставить @Autowire на поле visitsRepository?
                                              0
                                              Можно, но необязательно. В повых версиях спринг сам разберется. А вообще рекомендуют по возможности @Autowire на конструктор. Так меньше шансов что останется не инициализированными. Но в случае циклических зависимостей не прокатит.
                                                0
                                                Задавал этот вопрос про циклические зависимости в конструкторе на собеседованиях, чтобы понять уровень кандидата в спринге и вообще желании разбираться в деталях. Обычно люди не очень хорошо понимают как там всё устроено. К слову, спринг это умеет, если например сделать один из бинов лейзи
                                                  0
                                                  Я обычно спрашиваю, что будет если в singleton scope bean завайрить session scope bean. И копать глубже как эта магия устроена.
                                                    0
                                                    А вот раз уж вы подняли такую тему — а зачем? Я уже давно работаю со Спрингом, но как циклическую зависимость сделать — не знаю. Более того, никогда не делал — и считаю наличие циклической зависимости проблемой дизайна. Т.е. круто, что человек это знает, но вот если не знает, то это о чем говорит?
                                                      0
                                                      В реальности обычно этого никто не знает, потому что, во-первых, плохой тон, во-вторых, нужно очень редко. Поэтому когда человек, говорит, что не знает, тогда я спрашиваю: а как вы думаете такое вообще возможно? А если бы вы сами это собирались реализовать? И тд. А некоторые сами пытаются предположить как оно там или предполагают как это можно было бы реализовать. Кто-то говорит, что это бедпрактис. Что бы человек ни сказал, всё дает представление о нем. А ответ: не знаю и даже представить не могу — больше других.
                                                        0
                                                        Дайте угадаю: если кто-то и ответил, то запросил настолько космических денег, что вы его не стали рассматривать.

                                                        А все-таки: зачем вы на собеседованиях интересуетесь про такие страшные детали?
                                                        Вопрос не праздный.
                                                        1. Собеседование длится всего-то час или около того. Вам больше время некуда потратить?
                                                        2. Если разработчик ответил правильно — как этот ответ характеризует его как специалиста и профессионала?

                                                        Те компании, которые вопят, что «нет нормальных разработчиков», как правило, не умеют правильно проводить технические интервью. Или умеют, но не хотят – потому что нормальный специалист их технологический стек на тряпки раздерёт вместе с архитектором и тим-лидом, а job security – это страшная сила :)
                                                          0
                                                          Дайте угадаю: если кто-то и ответил, то запросил настолько космических денег, что вы его не стали рассматривать.

                                                          Выше писал о том, что правильный ответ здесь не важен, к тому же его обычно никто не знает. И лично мне на денежные претензии кандидата глубоко плевать, потому что моя сфера — это исключительно его техническая компетенция.
                                                          1. Собеседование длится всего-то час или около того. Вам больше время некуда потратить?

                                                          У меня много способов потратить время, но если я провожу интервью, то я трачу время именно на это. Мне нужно максимально быстро получить представление о человеке как о специалисте и коллеге, а этот вопрос не только позволяет в редких случаях выявить человека, который разбирается в нужном мне стеке, но и дает огромное количество материала для обсуждения и понимания уровня кандидата. Лично меня вообще не интересует может ли кандидат засунуть квадратный люк в круглый колодец или знает ли он наизусть все методы SessionImplementor, на мой взгляд в первую очередь важны личные качества кандидата и как он себе представляет разработку, насколько он четко мыслит в этом направлении. Всё это можно выяснить начиная с этого вопроса.
                                                          2. Если разработчик ответил правильно — как этот ответ характеризует его как специалиста и профессионала?

                                                          Вопрос этот очень богат коннотациями, например, он позволяет посмотреть насколько человек представляет как работает язык: кто-то вообще не понимает в чем проблема передать в конструкторы двум классам друг друга. Показывает насколько человек глубоко знает спринг, потому что совершенно не обязательно знать правильный ответ на этот вопрос, чтобы предположить как спринг себя поведет в той или иной ситуации. Если же человек сразу отвечает, то скорее всего он человек прошаренный и можно много времени сэкономить. Опять же, я не требую правильного ответа на этот вопрос, а лишь считаю его хорошим стартом, который всегда дает базу для большинства вопросов, которые я бы хотел задать, особенно если мне нужно очень быстро составить представление о человеке.
                                                      0
                                                      У вас в коде есть циклические зависимости?
                                                        0
                                                        обычно нет, но как я написал выше, тут дело не в самой циклической зависимости, а в том как человек будет думать об этой задаче. Знает ли он о том, что спринг умеет проксировать бины? Предложит ли он использовать прокси для решения такой задачи? Может быть какая-то смешная третья опция… для собеседования всё хорошо.
                                                          0
                                                          смешная

                                                          это избавится от циклических зависимостей?
                                                            0
                                                            Да, опция достаточно смешная. На столько, что на моей памяти никто её не предложил. Обычно люди всё же пытаются решать ту задачу, которую им предложили решить, что часто бывает не менее полезно, чем инициативность.
                                                0
                                                Как писать на Spring в 2017

                                                А не пора уже про webflux писать? Пробовали уже использовать? Не хотите про это дело написать?
                                                  +2
                                                  Пора, пробовал, написал :)
                                                    0
                                                    Кстати, за информацию про DevTools отдельное спасибо!
                                                  +1
                                                  Очень приятно, что моя статья вдохновила Вас на написание этой полезной статьи о Spring. Надеюсь, Ваша статья поможет мне вникнуть в Spring (пока с этим туго).

                                                  Как хорошо, что среди легиона «професиональных комментаторов» попадаются люди, конструктивно подходящие к проблемам новичков :)
                                                    –1
                                                    вникнуть в Spring (пока с этим туго)

                                                    Ютуб, ищите доклады Жеки Борисова «Спринг-потрошитель» две части — он там все кишки Спринга выворачивает с разбором и лайфкодингом. Полезно даже если ничего не понятно, просто потому что все с живыми примерами.
                                                      0
                                                      ищите доклады Жеки Борисова «Спринг-потрошитель»

                                                      Спасибо за наводку, кто еще не нашел, вот ссылка

                                                        0
                                                        Еще посоветую отличное видео про Spring Boot от двух ключевых людей в команде — Andy Wilkinson и Stéphane Nicoll. Правда, видео идет два с половиной часа на английском, но зато там как раз про внутренности Spring Boot, как и что он конфигурит, какие у него могут быть критерии и т.п.
                                                          0

                                                          Большое спасибо, очень полезно, жаль плюс не смогу поставить

                                                        0
                                                        смотрел эту лекцию, нифига она не для новичков в спринге, в начале лекции ещё есть что-то полезное, но потом всё как-то сумбурно-запутанно
                                                      0
                                                      По этой теме есть отличное видео с Joker 2016. Человек наглядно показывает как быстро и просто можно сделать REST API со спрингом.
                                                        +1

                                                        Я думаю что я из ЦА статьи (убежал с серверной джавы ещё до массовой распространенности Boot), но мне статья не понравилась, простите.


                                                        Дело в том, что я не верю туториалам вида:


                                                        Шаг 1: Ставите тулзу-для-проекта/скачиваете этот проект со специального сайта-билдера
                                                        Шаг 2: Вот вам hello world!


                                                        Потому что для чего-то сложнее чем hello world придется отойти на шаг вправо/влево, а там расстрел и долгие мучительные копания в конфигах незнакомой системы сборки или ещё чего.


                                                        То есть вместо объяснения магии Spring, вы показываете как всё типа просто, но вся ваша простота улетучится как только надо будет отойти на шаг влево/вправо. И вместо простоты там будет расстрел похлеще JSP.


                                                        Возможно для совсем новичков в Java это будет круто, но я так понимаю статью вы писали как "Гайд для новичков в Spring", но не в Java.

                                                          0
                                                          Поддержу, в свое время сам нарвался на похожие проблемы с туториалами по Spring-Data-REST. Если делаешь все как в туториале — все супер просто и понятно, потом надо чуть-чуть допилить/поменять и оказывается что чтобы это сделать надо наворотить кучу кода, переопределить какие-то методы у оберток, о которых вообще не рассказывалось, состряпать пару не очевидных реализаций каких-то интерфейсов и подсунуть через @Configuration.

                                                          имхо начинать лучше всетаки с общей картины что/зачем, какие данные кто-как-зачем обрабатывает, а уже потом залезать в частности разработки конкретного приложения
                                                            0
                                                            Вообще это хорошая мысль, может я соберусь продолжить эту статью второй, и пусть на базовом уровне, но объяснить внутренности приложения — типа бинов, конфигурации, автоконфигурации, что делает Boot. Думаю, будет очень полезно. Может даже на этом же приложении рассмотреть, развеять магию и сорвать покровы!
                                                              0
                                                              Чтобы развеять магию и сорвать покровы необходимо много и упорно читать исходный код тех фреймворков, которые вы используете.
                                                          0
                                                          Ну получается что за последнии 5 лет мало что изменилось :-)
                                                            0
                                                            Спасибо автору, статья полезная, особенно в плане получения общего представления как, что и зачем. Для старта самое то, чтобы не испугаться раньше времени )
                                                            По себе заметил интересную особенность: проект на чистом спринге + xml я смог настроить и привести в рабочее состояние быстрее чем аналогичный на boot+java-config.
                                                              0
                                                              А какие у вас размеры WAR файлов в гигабайтах?
                                                                0
                                                                Make JAR, not WAR! Размер JAR с включенным сервером (!) Tomcat, Spring, Spring Data, H2 in-memory DB (пример из этой статьи) — 0.028 Gb (28 Mb). Причем как я уже говорил, кроме этого файла на сервере не нужно ничего (кроме JRE). Так что сарказм, скорее, себя не оправдал :)

                                                                PS. Сразу отвечу про использование памяти — сам фреймворк съедает примерно 32 Мб памяти. У Дейва Сайера, одного из участников команды Spring Boot есть исследование про потребление памяти Спрингом.
                                                                0
                                                                Я вот, PHP-ник, посматриваю в сторону Java. Появилась нужда использовать некоторые библиотеки, а они нормально написаны под Java, а под PHP — так себе…
                                                                Очень интересно было прочитать эту статью, тем более, что пару месяцев назад я уже экспериментировал с этим.

                                                                Вот какие у меня остались вопросы после экспериментов и прочтении статьи. Может это и не совсем вопросы, которые должен задавать новичок, но:

                                                                1) Магия конфигурирования сервера
                                                                Вот есть у меня PHP. Он обычно стоит за Апачем, или за Nginx. А вот Spring работает сам по себе (хотя его конечно тоже можно запроксировать). Ну вот захотелось мне, чтобы сервер слушал на порту 80. И внезапно выяснилось, что для этого надо запускаться по рутом, а это нехорошо. Я погуглил, советов много, но как-то всё не прямо.
                                                                Ну и кроме порта есть и другие настройки. В общем и целом, если хочется что-то подтюнить — то у PHP есть для этого два места: конфиг Апача и php.ini. Там и настройки памяти, и настройки потоков, параллельности и т.д. Я уверен, что всё это можно настраивать и в Spring, но как-то тяжелей тут всё это осмыслить.

                                                                2) Магия с базами данных
                                                                Когда я читаю, что «будет автоматически создана модель данных (таблицы) в БД», то мне становится как-то неуютно: что-то там происходит автоматически, а мне про это не рассказали.
                                                                Конечно, с этим можно разобраться. Но если на PHP я пишу простенькое приложение, то я напишу SELECT да и всё, а тут надо вникать в эту магию и она выглядит не очень просто.
                                                                  0
                                                                  Эти вопросы я здесь оставил не столько для того, чтобы кто-то на них ответил, а больше как идею для второй серии по обзору архитектуры Spring'а.
                                                                    0
                                                                    Вопросы очень хорошие.

                                                                    1) Идея Spring во многом — это абстракции. Мы не работает с базой данных напрямую, работаем с абстракцией — база это (теоретически) заменяемая реализация. То же самое и с сервером — мы не настраиваем сервер напрямую, мы используем конфиг файл, по которому потом Spring Boot настроит сервер. Это делается в файле application.properties — там есть целая секция Web Properties (включая порт). И теперь если мы заменим Tomcat на Jetty (а это тривиальное изменение в pom.xml) — то те же настройки будут применены и там.

                                                                    Настроить именно embedded Tomcat через его конфиг файлы, наверное, тоже можно — но это пример того, как мы будем пытаться заставить Spring делать то, что он не хочет — и вряд ли получится легко и хорошо.

                                                                    Про root думаю актуально и для Апача, просто он скорее всего уже был установлен (под рутом) и работает как демон — поэтому занимает порт 80.

                                                                    2) Важный момент — модель будет автоматически создана только в нашем конкретном приложении, т.к. это in-memory база (и считается временной для разработки). При подключении к реальной базе — Spring (точнее, Spring Data, а еще точнее конкретная ORM — Hibernate) может либо создать схему автоматически, либо проверить, что модель энтитей соответствует структуре таблиц. Первый вариант в продакешене, разумеется, никто не использует — все работают с миграциями БД (flyway или liquibase). Второй вполне работает для прототипов или интеграционных тестов.

                                                                    SELECT и любые другие запросы писать точно так же можно, просто они остались за рамками статьи.
                                                                      0

                                                                      1) можно сделать перенаправление портов с iptables 80->8080 443->8443.
                                                                      2) можно запустить Apache Web-server(или что-то другое) как прокси для tomcat

                                                                      0
                                                                      И внезапно выяснилось, что для этого надо запускаться по рутом, а это нехорошо.
                                                                      Так и апач под рутом нужно запускать, чтобы на порту < 1024 слушать. Это не спринг виноват.
                                                                        0
                                                                        Не совсем так…
                                                                        Да, Апач старует, как рут, но но запросы обрабатываются в контексте пользователя. Обычно www-data.
                                                                        Для этого у Апача есть какой-то свой механизм (it uses setuid to switch to user context of specified user in httpd.conf).

                                                                        Конечно, можно и в Spring написать подобный механизм, но его нужно писать, а там уже есть.
                                                                      +1
                                                                      Как раз недавно пытался разобраться с Java Web и Spring в частности.
                                                                      Одна запись в xml не туда — приложение не деплоится, странные исключения в логах, которые в гугле не ищутся, ошибка 404 в любой непонятной ситуации. Туториалы только по одной IDE — Esclipe, ручное создание xml файлов, ручное прописывание каждого контроллера. О Spring Boot слышу впервые из этой статьи, и это то, что мне нужно. Спасибо автору за такую статью! Жду продолжения.
                                                                        0
                                                                        Вы, похоже, смотрели какие-то древние туториалы. А от привязки к конкретной среде вообще нужно абстрагироваться.
                                                                          0
                                                                          Подписываюсь под каждым предложением, имел аналогичный опыт и возникшие проблемы.
                                                                            0
                                                                            Пишите из 2003 года?
                                                                            0
                                                                            А как написанное приложение задеплоить в Tomcat? Поменял в pom.xml jar на war, в томкате (версия 8.5) через manager app установил полученную war-ку. При обращении к приложению получаю 404 с описанием «The origin server did not find a current representation for the target resource or is not willing to disclose that one exists». С Java Web и Spring никогда не работал.
                                                                              0
                                                                              По идее, просто скоприровать JAR / WAR файл в папку, где лежат WAR / JAR файлы и все. Но нужно учитывать, что во все пути будет добавлено имя файла — если файл называется myapp и определяет роут /index, то полный путь будет /myapp/route. Чтобы пути строились от корня, нужно назвать файл root.jar.
                                                                                0
                                                                                В документации есть отдельная секция. Я обновил код и добавил бранч для деплоймента в Tomcat. Только учитывайте имя приложения (путь будет http://localhost:8888/demo-0.0.1-SNAPSHOT/).
                                                                                0
                                                                                А не подскажете как по человечески добавлять сущность в базу? С возвратом ошибок вдруг чего и т.д. Я то нашел метод save в репозитории он нормально работает, но как вернуть ошибку(на возврат же идет итеребл).
                                                                                  0
                                                                                  Зависит от ошибок. Обычно если что-то не так JPA бросает исключение, так что проще всего наверное обернуть в try / catch и ловить нужные ошибки.
                                                                                  0
                                                                                  SpringBoot удобная штука, спору нет. Но и dropwizard.io решает практически те-же задачи, а порог вхождения гораздо ниже.
                                                                                    0
                                                                                    Сравнение все таки не совсем корректно, Spring Boot это просто конфигурация Spring-a, а Dropwizard преследует другие цели, нежели Spring. Сам по себе Spring не имеет ценности, его инфраструктура — имеет (Spring Cloud / Data / Batch / Integration etc).
                                                                                    0
                                                                                    На текущий момент я освоил синтаксис java, вот пора освоить первый фрейморк.
                                                                                    Пробую делать по статье:

                                                                                    — Зависимости перечислил Web,DevTools,JPA,H2,Mustache
                                                                                    — Название указал.
                                                                                    — Скачал .zip, распаковал, в Idea открыл, main — запускается.
                                                                                    class IndexController — вот тут я споткнулся. Предположил что он уже должен быть, но его нету, как и нет 3х папок под модель вью и контролеры которые я ожидал увидеть.
                                                                                    Если сам создаю IndexController.java и копирую его код из статьи, Idea мне почти все идентефикаторы подчеркивает красным и пишет «Cannot resolve symbol».
                                                                                    Я так понимаю, это потому что к файлу который я создал не добавлены нужные import, то есть мысль приходит к тому, что базовые mvc файлы должны были уже быть в этом .zip который я скачал с start.spring.io но их почему то там нет.
                                                                                    Хелп плиз.
                                                                                      0

                                                                                      По умолчанию Spring Initializr не создает папок под View или контроллеры, он в принципе не навязывает никакую структуру.


                                                                                      Нужные Imports в IDEA можно добавить самому — просто поставить курсор на подчеркнутый символ, нажать Alt+Enter и выбрать 'Import ...'.


                                                                                      Ну и как план Б — исходный код этой статьи доступен на GitHub, вот например реализация IndexControllerhttps://github.com/alek-sys/spring-demo/blob/master/src/main/java/com/example/demo/IndexController.java

                                                                                      +1
                                                                                      Для того чтобы пример работал, нужно добавить в main/resources/application.properties следующие строчки

                                                                                      spring.mustache.prefix=classpath:/templates/
                                                                                      spring.mustache.suffix=.html


                                                                                      Видимо в последних версиях Spring Boot + Mustache требуется явно указать путь где искать View и расширение.
                                                                                      0
                                                                                      Добавил строчки, все равно не заработал пример, вот такая ошибка в IDEA

                                                                                      [ERROR] No goals have been specified for this build. You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>: or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1]
                                                                                      [ERROR]

                                                                                      Если в консоле запускаю ./mvnw package
                                                                                      то просто висит, ничего не происходит.

                                                                                      Когда читаю статьи все выглядит логично, но запустить spring мне пока не удалось ни разу :(
                                                                                      Думаю уже может надо сдаться да пойти начать делать сайт на php, как бы мне не нравилась идеология java но что то не могу я пробиться и сделать на java страницу которую бы было видно через веб.
                                                                                      Консольные приложения освоил, а вот переход на web непробиваемый барьер как будто стоит.
                                                                                        0

                                                                                        Рано сдаваться :)


                                                                                        Первая ошибка странная — это от Maven, а Intellij должна запускать приложение напрямую.


                                                                                        А вторая совсем странно, может установка Maven сломана? Что выдает ./mvnw --version и java -version? Под Windows, кстати, нужно запускать mvnw.cmd.

                                                                                      Only users with full accounts can post comments. Log in, please.