Быстрый старт веб-проекта (BE — Java Spring, FE — React Redux, взаимодействие — Rest, WebSocket) +8




Чтобы разработать современное веб приложение, необходимо иметь навыки как в создании серверной части, так и клиентской. Наиболее часто встречаемое в последнее время сочетание в корпоративной среде — это Java c использованием Spring Framework для сервера и React для клиента. Однако не все разработчики обладают Full stack навыками (знаниями как в серверной так и в клиентской части), а для начинающих разработчиков создание такой конфигурации оказывается совсем непосильной задачей.

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

Более подробно рассмотрим используемые технологии


Серверная часть:


Сборка проекта — gradle 4.8.1 ( дополнительно gradle-node-plugin для сборки фронта)
Язык — Java 1.8 (или старше)
Фреймворк — Spring 5.x
База данных — HSQL 2.3.1 (для начала будет достаточно)

Клиентская часть:


Сборка проекта — webpack 4.17.2
Язык — JS6
Фреймворк — react 16.4.0, redux 3.7.2, bootstrap (reactstrap 6.3.1)
Если вас всё устраивает, то можно продолжить.

Запуск проекта


Думаю будет намного веселее, если сначала мы всё запустим и убедимся что всё работает!
Скачать проект можно отсюда

Для запуска понадобится совсем немного времени и терпения. Главное делать всё по порядку:
Более подробная информация по установке (по просьбам читателей) внизу статьи


  1. Установить java 1.8 (не забываем прописать JAVA_HOME)
  2. Установить node.js
  3. Открыть командную строку (Надеюсь что вы сами разберётесь как это сделать в вашей операционной системе)
  4. Перейти в папку проекта (Например cd C:\Git\react-start)
  5. Выполнить команду npm i (Эта команда скачает все зависимости для фронта и сложит их в папку node_modules)
  6. Выполнить команду gradle build (Эта команда соберёт ваш проект и сложит всё в папку build)
  7. Выполнить команду gradle bootRun (Теперь ваш проект запущен)
  8. Остаётся только перейти по ссылке и насладится результатом.

Вы должны увидеть нечто подобное:



Вступление


Моя основная задача в этой статье показать структуру проекта. Поэтому я буду в основном максимально доступно рассказывать какой файл в проекте за что отвечает с некоторыми лирическими отступлениями. Для бек энд разработчиков будет интересна в основном клиентская часть и наоборот.

Структура проекта


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

Для начала давайте рассмотрим какие файлы лежат у нас в проекте и зачем они нужны. Разобьем их опять же по назначению сервер и клиент.

Сервер:


build.gradle — Главный файл для сборки нашего проекта. в нём описаны все необходимые нам зависимости и ссылки на репозиторий где их брать. А также там прописан плагин gradle-node-plugin который при сборке серверной части автоматически собирает и фронт что несомненно очень удобно.

gradlew и gradlew.bat и папка gradle — необходимые части для запуска сборщика. Кстати если команда gradle build по каким то причинам не выполняется, то возможно вам придется установить gradle. Сделать это можно с помощью официальной инструкции.

README.md — Универсальный файл для отображения в репозитории информации о проекте.

В папке src/main/webapp/WEB-INF/ лежат два файла jboss-web.xml и web.xml при локальной работе они не используются, но если нужно будет запускать проект на web серверах типа WildFly они обязательно понадобятся.

application.yml — также не маловажный файл. В нем описывается конфигурация Spring. В частности там есть port: 8090 — порт на котором будет запущено приложение и настройки подключения к базе данных.

Если уже заговорили про базы данных то в проекте используется HSQL — это файловая база данных работающая на java. При старте проекта в папке пользователя создастся папка db/ в которой и будет храниться сама база данных. Вы можете использовать любую свою базу данных которая Вам больше нравится, например Postgress, на это нет никаких принципиальных ограничений.

Сам код серверной части располагается в папке src/main/java.

Клиент:


.babelrc — здесь хранятся всякие конфигурации для для babel. Для тех кто не знает babel — это штука которая преобразует всякие новомодные вещи во front-end разработке, такие как JS6, JS7, JSX, в обыкновенный js. В этом файле например у меня подключен плагин «plugins»: [«transform-decorators-legacy»] который позволяет использовать decorators — это как @аннотация в java. Я их не использовал, но Вы можете. Для этого всё уже настроено я проверял.

.npmrc — ссылка на репозиторий для js зависимостей.

package.json — очень важный файл здесь хранится описание всего нашего приложения, ссылки на js зависимости и команды для сборки и запуска клиентской части. Причём зависимости разбиты на две части это dependencies — зависимости которые необходимы для работы самого приложения и devDependencies — зависимости необходимые толmко для сборки проекта. В разделе scripts описаны команды buils и start которые используются для запуска только фронтальной части проекта например фронт можно запустить командой npm run start (Запустится он на порту 9090). По сути этот файл — это аналог build.gradle для клиентской части.

webpack.config.babel.js — самый главный файл во всей конфигурации — настройки сборщика webpack. По этому поводу можно писать отдельную статью, но я всё равно хочу пройтись по основным частям этого файла чтобы сформировать у Вас общее представление о его возможностях.

devServer
devServer: {
        contentBase: `/${publicPath}/`,
        historyApiFallback: {
            rewrites: [{from: /./, to: `/index.html`}]
        },
        open: true,
        port: 9090,
        publicPath: `/`,
        proxy: [{
            context: ['/api', '/endpoint'],
            target: {
                host: "localhost",
                protocol: 'http:',
                port: 8090
            }
        }]
    },


DevServer используется для разработки клиентской части. Как уже говорилось выше мы можем запустить наш фронт на отдельном порту npm run start (Запустится он на порту 9090). Все изменения в коде js будут сразу вступать в силу на этом сервере. СontentBase — корневой путь до нашего приложения. Если на сервере будет запущено несколько приложений то это важно. open: true — при запуске сервера приложение будет автоматически открываться в браузере. proxy — раздел который отвечает за пересылку обращений к серверной части которая у нас будет запущена на порту 8090.

output
output: {
        filename: 'assets/javascripts/[hash].js',
        path: path.join(__dirname, 'src/main/resources/static'),
        publicPath: `/`
    },


output — этот раздел задает место сборки нашего проекта. Если выполнить команду npm run build, то в папке src/main/resources появится клиентская часть нашего проекта.

module
module: {
        rules: [
            {
                exclude: /node_modules/,
                include: path.join(__dirname, 'src/main/js/'),
                test: /\.jsx?$/,
                use: 'babel-loader'
            },
            {
                test: /\.css$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader']
            },
            {
                test: /\.less$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
            },
            {
                test: /\.(ico|png|gif|jpe?g)$/,
                use: {
                    loader: 'file-loader',
                    options: {name: 'assets/images/[name]/[hash].[ext]'}
                }
            },
            {
                test: /\.(svg|woff|woff2|eot|ttf)$/,
                use: {
                    loader: 'file-loader',
                    options: {name: 'assets/fonts/[name]/[hash].[ext]'}
                }
            },
            {test: /\.html$/, use: 'html-loader'},
        ]
    },


Раздел module указывает webpack что нужно искать в проекте файлы с расширениями .jsx, файлы стилей, картинок и шрифтов и тоже включать их в наш проект.

Раздел entry содержит ссылку на главный файл нашего js приложения.

Ну и в заключении HtmlWebpackPlugin создаст index.html файл в который включит все созданные зависимости.

Код клиентской части лежит в папке src/main/js.

Структура самого кода


В проекте я для примера сделал связь клиентской и cсерверной части через Rest и WebSocket. Кому что больше нравится. Описание самих технологий Spring Framework и Rect в интернете великое множество. Эта статья для тех у кого что-то не получается, или что-то лень. Это настроенное готовое рабочее решение содержащее в себе все необходимое чтобы перерасти в полноценный большой проект.

Также Вы можете взять этот проект в качестве отправной точки в изучении Java EE или React приложений.controller/RestController.java

Сервер:


Код клиентской части лежит в папке src/main/java.

То как там всё располагается полностью подчиняется структуре Spring Framework. Для тех кто с ним знаком не найдет там ничего интересного, а для тех кто только начинает опять же просто коротко пройдусь по файлам.

Main.java — главный файл. Содержит метод main который и запускает всё приложение.

configuration/WebSocketConfig.java — для точек входа при работе через webSocket

Контролеры — Классы отвечающие за взаимодействие серверной и клиентской частей.

controller/IndexController.java — контроллер отвечающий за отображение нашей клиентской части. Перебрасываем пользователя на url application/** (Это контекстный путь до нашего приложения)

controller/RestController.java — как видно из названия этот контроллер отвечает за обмен данными между клиентской и серверной частью по Rest. Аннотация @RequestMapping(value = "/api/rest", method = RequestMethod.GET) говорит что по запросу по адресу /api/rest сервер отдаст нам список пользователей.

Метод PUT я использовал для добавления пользователей и DELETE соответственно для удаления пользователя по ID.

controller/WebSocketController.java — определяет путь для обмена данными по webSocket. Метод getAndSendMessage получает сообщение от клиента и оправляет его обратно.

Сервисы — обычно отвечают за логику нашего приложения.

service/ORMUserService.java — в моем случае отвечает за формирование списка пользователей, а также добавление и удаление пользователей в базу данных используя в качестве данных параметры полученные от клиентской части. Для удаления пользователя — это id пользователя, а для создания — это имя, роль и пароль пользователя.

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

domain/User.java — класс который будет соответствовать таблице Table(name = «USER») в базе данных.

Данные для колонки @Column(name = «ID») будут генерироваться автоматически.

domain/Message.java — в моем случае не использует сопоставления с базой данных. данные в нём будут храниться пока приложение запущено. Служит у меня для формирования сообщений отправляемых по webSocket.
На этом с серверной частью у меня всё.

Клиент:


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

Что сделано на фронте:

  • Реализован главный layout приложения и несколько вкладок.
  • Реализован перевод для всего приложения.
  • Реализован state приложения на Redux.
  • Реализовано отображение таблицы пользователей получаемых с сервера через Rest
  • Реализовано удаление пользователей по id
  • Реализовано добавление пользователей
  • Реализована отправка и получение сообщений через WebSocket

Думаю для начала этого более чем достаточно.

Заключение


Все ваши вопросы и пожелания оставляйте в комментариях или пишите мне на почту. Буду рад помочь.

Подробная информация по установке и запуску


ОС «Wondows 10»

Установка Java 1.8 подробная инструкция



Перед началом установки нажимаем сочетание клавиш Win+R и вводим cmd
вводим java -version и видим



Это значит что java на этом компьютере не установлена.

Если компьютер вывел версию java и эта версия не ниже 1.8, то переходите к пункту установки Gradle.

Скачиваем Java по ссылке

Нужно нажать чекбокс Accept License Agreement.

Нужная нам версия Windows x64

Скачивание java



Запускаем

Запуск java



Жмём все время Next и Ok в конце close.

После установки повторно вызываем командную строку Win+R и вводим cmd вводим java -version и видим уже версию установленной нами Java



Откройте свойства Вашего компьютера

Свойства компьютера



Дополнительные параметры — переменные среды

Переменные среды



Убедитесь что в системных переменных есть JAVA_HOME со значением C:\Program Files\Java\jdk1.8.0_181\

JAVA_HOME



И в переменной Path есть строка C:\Program Files\Java\jdk1.8.0_181\bin

Path



Переходим к следующему пункту

Установка Gradle подробная инструкция


Откройте консоль заново и введите gradle -version
Так как он у нас ещё не установлен, то мы увидим по это:



Качаем архив по ссылке

Распаковываем вот например в такую папку C:\gradle-4.10.1

Далее по аналогии с java открываем раздел с системными переменными и уже самостоятельно добавляем в него переменную GRADLE_HOME со значением C:\gradle-4.10.1\bin

GRADLE_HOME



И в переменную path тоже добавляем C:\gradle-4.10.1\bin можно даже рядом со строчкой C:\Program Files\Java\jdk1.8.0_181\bin, но это не обязательно.

gradle path



Обязательно перезапустите консоль Win+R cmd и введите gradle -version



Всё теперь и gradle установлен!

Node JS подробная инструкция



Скачиваем Node JS по ссылке

И устанавливаем
Установка Node js



Перезапускаем командную строку и вводим npm -version и мы обязательно увидим установленную версию



Запуск проекта


Отлично все подготовительные работы выполнены

Качаем проект в виде архива

Весит он всего 135 Kb

Git



И распаковываем в C:\react-start-master\

Папка проекта



Запускаем командную строку и переходим в C:\react-start-master\
Для тех кто не помнит чтобы подняться вверх по дереву папок в командной строке нужно ввести cd..

Так мы переходим до корня диска C:\>
Дальше вводим cd react-start-master и получаем путь C:\react-start-master>


вводим npm i


Сейчас производится скачивание зависимостей JS для нашего проекта



Варнинги допустимы (WARN — предупреждение)
В проекте по явится папка C:\react-start-master\node_modules все зависимости будут в ней.

Сразу после этого вводим в консоли gradle build



Будут скачаны все зависимости для Java в том числе и Spring.
В проекте появится папка C:\react-start-master\build



все обязательно соберётся и мы увидим сообщение об удачной сборке
BUILD SUCCESSFUL

И сразу после этого можно выполнить команду gradle bootRun



Проект начнёт запускаться



В конце запуска в консоли будет примерно следующее



Всё проект запущен!



Не закрывайте консоль просто сверните.

Откройте браузер и введите localhost:8090/application/ или перейдите по этой ссылке

Вы увидите запущенный проект



Запуск только JS



Откройте ещё одну консоль.

Перейдите в папку проекта C:\react-start-master>

Выполните команду npm run start

Если все зависимости для JS уже были скачаны как объяснялось выше (команда npm i)

То браузер сам запустится по ссылке localhost:9090/
И все изменения в Js коде проекта будут там автоматически отображаться!


На этом всё, спасибо за внимание.

Вы можете помочь и перевести немного средств на развитие сайта



Комментарии (22):

  1. Mountaineer
    /#19097645

    Поправте версию BE фреймворка. На Github ето Spring Boot 2.0.4, а здесь Spring 4.0.1.

  2. yaushev_st
    /#19098001

    Спасибо! Интересно почитать. Вы написали, что Spring используется с React в современных приложениях. А Spring+Angular используют сейчас?

    • Mountaineer
      /#19098027

      Да, большая часть проектов, что началась за последний год в нашей фирме — ето связка Spring+Angular.

  3. Mountaineer
    /#19098017

    Первый раз токое слышу :) Версия Spring — ето версия spring-core, а не spring-batch-core(!) и тут вы правы, что Spring Boot 2.0.4 — ето Spring 5, а не 4. Об етом я выше и написал. Вот, посмотрите зависимости: mvnrepository.com/artifact/org.springframework.boot/spring-boot/2.0.4.RELEASE

  4. aol-nnov
    /#19099163

    можно еще более быстрый старт: www.jhipster.tech :)

    • zmejg
      /#19101915

      быстрее, то быстрее, но это такой случай, который в дальнейшем может сыграть злую шутку и придётся откатываться на вариант, предложеный автором, который действительно довольно распространёт. Лучше сразу самостоятельно определить компоненты и роли, чем давать внешнему генератору «сделать всё за тебя»

      • aol-nnov
        /#19101933

        Этот генератор не страшный. Его можно выкинуть на любом этапе. А фронт там разный генерится и реакт тоже заявлен. Я, правда, только бэк им генерил… )

        • zmejg
          /#19102033

          У нас был проект, написанный для Кубернетес-а аутсорсерами со всеми зависимостями — API Gateway, Jhipster registry, Hazelcast, etc. Вычищать JHipster пришлось почти месяц. Редуцировали как раз до модели Spring Boot + Vue + REST.

          • aol-nnov
            /#19102105

            Внушает… Я его тыкал ещё тогда, когда они свой джарник в зависимости каждого проекта не пихали. Там было более-менее прилично. Сейчас уж незнай, до чего они дошли. Но, если честно, я попробовал и мне ванильный спринг бут как-то ближе оказался, чем эта вундервафля…

            • zmejg
              /#19102619

              Да, ваше внутреннее чувство вас не подводит — это действительно вундервафля. Ванильный спринг более предсказуем, понятен и лучше документирован. Последние версии JHipstera нам уже не поддались из-за ошибок YARNA при апгрейде. В ходе «даунгрейда» столкнулись с множеством связей во внешних модулях. Например при наличии актуатора и модуля LDAP автоматически включался мониторинг, который делал 5 AD логинов в секунду с pod-а. Отловили только tcpdump-ом. И в Hibernate он свои щупальца запускает, в общем везде, где нужна «оптимизация» с его точки зрения.
              Нужно наверное быть разработчиком JHipster что бы использовать его без сайд-эффектов.

  5. Grandapple
    /#19099625

    Здравствуйте. После gradle runBoot у меня написал build successful и на localhost ничего не запустилось. Я в java знаю только синтаксис, что я делаю не так?

    • impressionbit
      /#19099651

      build successful пишет после сборки gradle build. После запуска gradle bootRun должен начать запускаться Spring. И не закрывайте консоль.

      • Grandapple
        /#19099903

        Spring надо как то отдельно ставить. Потому что после этой команды build successful пишет.

        • impressionbit
          /#19102639

          Сделал подробную инструкцию по запуску в конце статьи

          • Grandapple
            /#19104831

            Спасибо вам за подробную инструкцию. У меня не запускался потому что выходила ошибка.

  6. impressionbit
    /#19100223

    Я вечером сделаю подробную инструкцию.

  7. EvilBeaver
    /#19103747

    Я так и не понял, где в серверной части формируется тот самый <html>, внутри которого будет тот самый <script>, который заставит браузер скачать результатБабеля.js?

    • impressionbit
      /#19103845

      html и js и css формируются при сборке проекта Gradle. В файле build.gradle подключена зависимость com.moowork.gradle:gradle-node-plugin:1.2.0 которая умеет запускать webpack.
      В этом же файле есть строчки:

      task webpack(type: NpmTask) {
          args = ['run', 'build']
      }
      processResources.dependsOn 'webpack'

      Которые запускают webpack при сборке или старте проекта.
      Gradle этим и хорош что может делать такие вещи.

      Результат работы webpack складывается в папку build\resources\main\static\
      За запуск index.html отвечает src\main\java\ru\impressionbit\server\controller\IndexController.java который открывает этот html по любому url localhost:8090/**. Кок он его находит — это магия Spring. По какому хосту и порту запускать проект описано в файле src\main\resources\application.yml
      server:
      address: 0.0.0.0
      port: 8090


  8. Balynsky
    /#19103813

    Чтобы разработать современное веб приложение, необходимо иметь навыки как в создании серверной части, так и клиентской.

    Конечно в первую очередь все зависит от решаемой задачи, возможно Вам действительно необходимо именно связка Spring + React/Vue/Angular. Но не стоит забывать, что если вы фронтенд девелопер и не имеете навыков бекенд(например, не работали с Node.js ), это никак не помешает Вам создать современное веб приложение используя Serverless решения от крупных вендоров. Например, рекомендую посмотреть на решение Firebase от Google, DynamoDB от Amazon.

    • impressionbit
      /#19103853

      Я написал что это для: «Наиболее часто встречаемое в последнее время сочетание в корпоративной среде» и там серверная часть часто сделана всё же на Java. Поэтому я и написал эту статью.