Чтобы разработать современное веб приложение, необходимо иметь навыки как в создании серверной части, так и клиентской. Наиболее часто встречаемое в последнее время сочетание в корпоративной среде — это 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:Gitreact-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
Думаю для начала этого более чем достаточно.
Заключение
Все ваши вопросы и пожелания оставляйте в комментариях или пишите мне на почту. Буду рад помочь.
Автор: impressionbit