Чтобы разработать современное веб приложение, необходимо иметь навыки как в создании серверной части, так и клиентской. Наиболее часто встречаемое в последнее время сочетание в корпоративной среде — это 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)
Если вас всё устраивает, то можно продолжить.
Запуск проекта
Думаю будет намного веселее, если сначала мы всё запустим и убедимся что всё работает!
Скачать проект можно отсюда
Для запуска понадобится совсем немного времени и терпения. Главное делать всё по порядку:
Более подробная информация по установке (по просьбам читателей) внизу статьи
- Установить java 1.8 (не забываем прописать JAVA_HOME)
- Установить node.js
- Открыть командную строку (Надеюсь что вы сами разберётесь как это сделать в вашей операционной системе)
- Перейти в папку проекта (Например cd C:\Git\react-start)
- Выполнить команду npm i (Эта команда скачает все зависимости для фронта и сложит их в папку node_modules)
- Выполнить команду gradle build (Эта команда соберёт ваш проект и сложит всё в папку build)
- Выполнить команду gradle bootRun (Теперь ваш проект запущен)
- Остаётся только перейти по ссылке и насладится результатом.
Вы должны увидеть нечто подобное:
Вступление
Моя основная задача в этой статье показать структуру проекта. Поэтому я буду в основном максимально доступно рассказывать какой файл в проекте за что отвечает с некоторыми лирическими отступлениями. Для бек энд разработчиков будет интересна в основном клиентская часть и наоборот.
Структура проекта
Я постарался по возможности убрать все лишнее из проекта, то чем любой проект обрастает со временем, но пугает начинающих разработчиков.
Для начала давайте рассмотрим какие файлы лежат у нас в проекте и зачем они нужны. Разобьем их опять же по назначению сервер и клиент.
Сервер:
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: {
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: {
filename: 'assets/javascripts/[hash].js',
path: path.join(__dirname, 'src/main/resources/static'),
publicPath: `/`
},
output — этот раздел задает место сборки нашего проекта. Если выполнить команду npm run build, то в папке src/main/resources появится клиентская часть нашего проекта.
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
Запускаем
Жмём все время Next и Ok в конце close.
После установки повторно вызываем командную строку Win+R и вводим cmd вводим java -version и видим уже версию установленной нами Java
Откройте свойства Вашего компьютера
Дополнительные параметры — переменные среды
Убедитесь что в системных переменных есть JAVA_HOME со значением C:\Program Files\Java\jdk1.8.0_181\
И в переменной Path есть строка C:\Program Files\Java\jdk1.8.0_181\bin
Переходим к следующему пункту
Установка Gradle подробная инструкция
Откройте консоль заново и введите gradle -version
Так как он у нас ещё не установлен, то мы увидим по это:
Качаем архив по ссылке
Распаковываем вот например в такую папку C:\gradle-4.10.1
Далее по аналогии с java открываем раздел с системными переменными и уже самостоятельно добавляем в него переменную GRADLE_HOME со значением C:\gradle-4.10.1\bin
И в переменную path тоже добавляем C:\gradle-4.10.1\bin можно даже рядом со строчкой C:\Program Files\Java\jdk1.8.0_181\bin, но это не обязательно.
Обязательно перезапустите консоль Win+R cmd и введите gradle -version
Всё теперь и gradle установлен!
Node JS подробная инструкция
Скачиваем Node JS по ссылке
И устанавливаем
Перезапускаем командную строку и вводим npm -version и мы обязательно увидим установленную версию
Запуск проекта
Отлично все подготовительные работы выполнены
Качаем проект в виде архива
Весит он всего 135 Kb
И распаковываем в 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)
yaushev_st
11.09.2018 21:52Спасибо! Интересно почитать. Вы написали, что Spring используется с React в современных приложениях. А Spring+Angular используют сейчас?
Mountaineer
11.09.2018 21:59Да, большая часть проектов, что началась за последний год в нашей фирме — ето связка Spring+Angular.
Mountaineer
11.09.2018 21:56Первый раз токое слышу :) Версия 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
aol-nnov
12.09.2018 09:45можно еще более быстрый старт: www.jhipster.tech :)
zmejg
12.09.2018 19:24быстрее, то быстрее, но это такой случай, который в дальнейшем может сыграть злую шутку и придётся откатываться на вариант, предложеный автором, который действительно довольно распространёт. Лучше сразу самостоятельно определить компоненты и роли, чем давать внешнему генератору «сделать всё за тебя»
aol-nnov
12.09.2018 19:28Этот генератор не страшный. Его можно выкинуть на любом этапе. А фронт там разный генерится и реакт тоже заявлен. Я, правда, только бэк им генерил… )
zmejg
12.09.2018 19:51У нас был проект, написанный для Кубернетес-а аутсорсерами со всеми зависимостями — API Gateway, Jhipster registry, Hazelcast, etc. Вычищать JHipster пришлось почти месяц. Редуцировали как раз до модели Spring Boot + Vue + REST.
aol-nnov
12.09.2018 19:59Внушает… Я его тыкал ещё тогда, когда они свой джарник в зависимости каждого проекта не пихали. Там было более-менее прилично. Сейчас уж незнай, до чего они дошли. Но, если честно, я попробовал и мне ванильный спринг бут как-то ближе оказался, чем эта вундервафля…
zmejg
12.09.2018 21:54Да, ваше внутреннее чувство вас не подводит — это действительно вундервафля. Ванильный спринг более предсказуем, понятен и лучше документирован. Последние версии JHipstera нам уже не поддались из-за ошибок YARNA при апгрейде. В ходе «даунгрейда» столкнулись с множеством связей во внешних модулях. Например при наличии актуатора и модуля LDAP автоматически включался мониторинг, который делал 5 AD логинов в секунду с pod-а. Отловили только tcpdump-ом. И в Hibernate он свои щупальца запускает, в общем везде, где нужна «оптимизация» с его точки зрения.
Нужно наверное быть разработчиком JHipster что бы использовать его без сайд-эффектов.
Grandapple
12.09.2018 11:05Здравствуйте. После gradle runBoot у меня написал build successful и на localhost ничего не запустилось. Я в java знаю только синтаксис, что я делаю не так?
impressionbit Автор
12.09.2018 11:11build successful пишет после сборки gradle build. После запуска gradle bootRun должен начать запускаться Spring. И не закрывайте консоль.
Grandapple
12.09.2018 11:58Spring надо как то отдельно ставить. Потому что после этой команды build successful пишет.
impressionbit Автор
12.09.2018 21:58Сделал подробную инструкцию по запуску в конце статьи
Grandapple
13.09.2018 11:51Спасибо вам за подробную инструкцию. У меня не запускался потому что выходила ошибка.
EvilBeaver
13.09.2018 07:38Я так и не понял, где в серверной части формируется тот самый <html>, внутри которого будет тот самый <script>, который заставит браузер скачать результатБабеля.js?
impressionbit Автор
13.09.2018 08:20html и 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
Balynsky
13.09.2018 08:04Чтобы разработать современное веб приложение, необходимо иметь навыки как в создании серверной части, так и клиентской.
Конечно в первую очередь все зависит от решаемой задачи, возможно Вам действительно необходимо именно связка Spring + React/Vue/Angular. Но не стоит забывать, что если вы фронтенд девелопер и не имеете навыков бекенд(например, не работали с Node.js ), это никак не помешает Вам создать современное веб приложение используя Serverless решения от крупных вендоров. Например, рекомендую посмотреть на решение Firebase от Google, DynamoDB от Amazon.impressionbit Автор
13.09.2018 08:28Я написал что это для: «Наиболее часто встречаемое в последнее время сочетание в корпоративной среде» и там серверная часть часто сделана всё же на Java. Поэтому я и написал эту статью.
Mountaineer
Поправте версию BE фреймворка. На Github ето Spring Boot 2.0.4, а здесь Spring 4.0.1.
impressionbit Автор
Версия Spring считается по версии ядра — spring-batch-core, а не Spring Boot. Вот посмотрите уже пятая версия вышла
aol-nnov
spring-batch — абсолютно точно не ядро спринга. (зануда моде офф)