Spring Boot: быстрое знакомство и старт на примере простого веб-приложения
Изучите Spring Boot, создав веб-приложение с минимальным набором классов. Подробная инструкция с примером структуры проекта.
Юрий Авраменко
Senior Software Developer
На этом примере рассмотрим, как можно быстро научиться создавать веб-приложения, которые могут из микроприложений вырасти в серьезные проекты.
Первоначальная настройка приложения
Переходим на сайт Spring Initializr и подготавливаем минимальный шаблон для нашего будущего приложения:
На данный момент этот блок не поддерживается, но мы не забыли о нём! Наша команда уже занята его разработкой, он будет доступен в ближайшее время.
В левой части оставляем настройки по умолчанию, кроме версии Java (будет достаточно 8), и заполняем Project Metadata.
В правой части необходимо добавить зависимости, нужные для приложения.
- Spring Web — модуль, включающий необходимые компоненты для веб-приложения и имеющий встроенный контейнер сервлетов Apache Tomcat.
- Spring Data JPA — библиотека, используемая для взаимодействия с сущностями базы данных.
- H2 Database — очень удобная база данных. Располагается в памяти, следовательно, хранит данные только пока запущено приложение. Не используется в продакшене, но для знакомства в этом проекте её будет достаточно.
- Apache Freemarker — шаблонизатор, будем использовать его для генерации HTML-страниц.
Всё готово, нажимаем GENERATE и получаем архив с исходным кодом проекта. Это минимальный каркас, который импортируем в используемую IDE.
В этом проекте используется IntelliJ IDEA.
Следуем по пути File -> New -> Project from Existing Sources, в диалоговом окне выбираем папку, где находится pom.xml файл проекта. Импортируем проект.
На данный момент этот блок не поддерживается, но мы не забыли о нём! Наша команда уже занята его разработкой, он будет доступен в ближайшее время.
В следующих диалоговых окнах все настройки оставляем по умолчанию. Единственное, в одном из окон удостоверимся, что имеем ранее установленную JDK соответствующей версии, в данном случае 8.
На данный момент этот блок не поддерживается, но мы не забыли о нём! Наша команда уже занята его разработкой, он будет доступен в ближайшее время.
Если JDK не была установлена ранее, её можно скачать с официального сайта.
Все остальные окна кликаем Next и в последнем — Finish.
Кратко рассмотрим структуру проекта. В первую очередь интересны:
- файл pom.xml — файл с описанием всех зависимостей, необходимых для приложения;
- файл application.properties — файл с настройками проекта;
- каталог java — основной каталог пакетов и классов;
- каталог resources — каталог для хранения ресурсов (шаблоны, файлы настроек, локализации и т.д.).
Создадим дополнительные пакеты :
- entity— для сущностей, в текущем проекте это будет класс Task;
- controller— для классов контроллера;
- repository— для слоя Repository, интерфейс с описанием общих методов, которые будут использоваться при взаимодействии с базой данных;
- service— для классов с бизнес-логикой.
Основной сущностью данного приложения будет сущность Task, которая будет иметь идентификатор, описание задачи, дату выполнения, приоритет выполнения.
Создадим класс Task в пакете entity
package com.myorganization.Organizer.entity; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import java.util.Date; @Entity public class Task < @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private Integer priorityId; private String description; private Date date; public Task() < >public Task(Integer id, Integer priorityId, String description, Date date) < this.id = id; this.priorityId = priorityId; this.description = description; this.date = date; >public Integer getId() < return id; >public void setId(Integer id) < this.id = id; >public Integer getPriorityId() < return priorityId; >public void setPriorityId(Integer priorityId) < this.priorityId = priorityId; >public String getDescription() < return description; >public void setDescription(String description) < this.description = description; >public Date getDate() < return date; >public void setDate(Date date) < this.date = date; >>
Класс помечен аннотацией @Entity. Она указывает на то, что данный класс является сущностью и будет сохраняться в БД.
Данная сущность имеет первичный ключ поле id. Поле помечено аннотацией @Id и аннотацией @GeneratedValue, которая задает стратегию генерации первичного ключа как автоматическую генерацию, в этой сущности – целые числа в порядке возрастания.
Создадим интерфейс TaskRepository в пакете repository
package com.myorganization.Organizer.repository; import com.myorganization.Organizer.entity.Task; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface TaskRepository extends JpaRepository
Класс унаследован от JpaRepository – интерфейса фреймворка Spring Data, предоставляющего набор стандартных методов JPA для работы с БД. Для данного приложения нет необходимости создавать дополнительные методы.
Создадим класс TaskService в пакете service
package com.myorganization.Organizer.service; import com.myorganization.Organizer.entity.Task; import com.myorganization.Organizer.repository.TaskRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import java.util.List; @Service public class TaskService < @Autowired private TaskRepository taskRepository; public ListgetAll() < return taskRepository.findAll(Sort.by(Sort.Order.asc("date"), Sort.Order.desc("priorityId"))); >public Task save(Task task) < return taskRepository.save(task); >public void delete(int id) < taskRepository.deleteById(id); >>
Класс содержит три метода для работы с задачами:
- getAll() – метод, возвращающий все задачи, отсортированные в порядке возрастания даты и порядке убывания приоритета.
- save(Task task) – метод создания новой задачи.
- delete(int id) – метод, удаляющий задачу по переданному id.
Создадим контроллер TaskController в пакете controller
package com.myorganization.Organizer.controller; import com.myorganization.Organizer.entity.Task; import com.myorganization.Organizer.service.TaskService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import java.util.List; @Controller public class TaskController < @Autowired private TaskService taskService; @GetMapping("/") public String getAll(Model model) < ListtaskList = taskService.getAll(); model.addAttribute("taskList", taskList); model.addAttribute("taskSize", taskList.size()); return "index"; > @RequestMapping("/delete/") public String deleteTask(@PathVariable int id) < taskService.delete(id); return "redirect:/"; >@PostMapping("/add") public String addTask(@ModelAttribute Task task) < taskService.save(task); return "redirect:/"; >>
Класс контроллер содержит три метода для управления задачами. При вызове методы обращаются в сервис TaskService, производят необходимые действия с сущностью и перенаправляют по заданному пути.
Замечание. Более правильно было бы добавить еще один интерфейс TaskService, который будет реализовывать существующий класс TaskService (изменим название на TaskServiceImpl), но в рамках этого приложения делать это не будем.
Создадим index.ftlh – шаблон для Freemarker в каталоге resources/templates
Organizer
Add task to list
Task list(task count : $)
| Id | Priority | Task description | Date | Delete from list |
| $ | $ | $ | $ | Delete |
Spring boot что это такое для новичка
Из-за громоздкой конфигурации зависимостей настройка Spring для корпоративных приложений превратилась в весьма утомительное и подверженное ошибкам занятие. Особенно это относится к приложениям, которые используют также несколько сторонних библиотек.
Каждый раз, создавая очередное корпоративное Java-приложение на основе Spring, вам необходимо повторять одни и те же рутинные шаги по его настройке:
- В зависимости от типа создаваемого приложения (Spring MVC, Spring JDBC, Spring ORM и т. д.) импортировать необходимые Spring-модули
- Импортировать библиотеку web-контейнеров (в случае web-приложений)
- Импортировать необходимые сторонние библиотеки (например, Hibernate, Jackson), при этом вы должны искать версии, совместимые с указанной версией Spring
- Конфигурировать компоненты DAO, такие, как: источники данных, управление транзакциями и т. д.
- Конфигурировать компоненты web-слоя, такие, как: диспетчер ресурсов, view resolver
- Определить класс, который загрузит все необходимые конфигурации
1. Представляем Spring Boot
Авторы Spring решили предоставить разработчикам некоторые утилиты, которые автоматизируют процедуру настройки и ускоряют процесс создания и развертывания Spring-приложений, под общим названием Spring Boot.
Spring Boot — это полезный проект, целью которого является упрощение создания приложений на основе Spring. Он позволяет наиболее простым способом создать web-приложение, требуя от разработчиков минимум усилий по его настройке и написанию кода.
2. Особенности Spring Boot
Spring Boot обладает большим функционалом, но его наиболее значимыми особенностями являются: управление зависимостями, автоматическая конфигурация и встроенные контейнеры сервлетов.
2.1. Простота управления зависимостями
Чтобы ускорить процесс управления зависимостями, Spring Boot неявно упаковывает необходимые сторонние зависимости для каждого типа приложения на основе Spring и предоставляет их разработчику посредством так называемых starter-пакетов (spring-boot-starter-web, spring-boot-starter-data-jpa и т. д.).
Starter-пакеты представляют собой набор удобных дескрипторов зависимостей, которые можно включить в свое приложение. Это позволит получить универсальное решение для всех, связанных со Spring технологий, избавляя программиста от лишнего поиска примеров кода и загрузки из них требуемых дескрипторов зависимостей (пример таких дескрипторов и стартовых пакетов будет показан ниже).
Например, если вы хотите начать использовать Spring Data JPA для доступа к базе данных, просто включите в свой проект зависимость spring-boot-starter-data-jpa и все будет готово (вам не придется искать совместимые драйверы баз данных и библиотеки Hibernate).
Если вы хотите создать Spring web-приложение, просто добавьте зависимость spring-boot-starter-web, которая подтянет в проект все библиотеки, необходимые для разработки Spring MVC-приложений, таких как spring-webmvc, jackson-json, validation-api и Tomcat.
Другими словами, Spring Boot собирает все общие зависимости и определяет их в одном месте, что позволяет разработчикам просто использовать их, вместо того, чтобы изобретать колесо каждый раз, когда они создают новое приложение.
Следовательно, при использовании Spring Boot, файл pom.xml содержит намного меньше строк, чем при использовании его в Spring-приложениях.
Обратитесь к документации, чтобы ознакомиться со всеми Spring Boot starter-пакетами.
2.2. Автоматическая конфигурация
Второй превосходной возможностью Spring Boot является автоматическая конфигурация приложения.
После выбора подходящего starter-пакета, Spring Boot попытается автоматически настроить Spring-приложение на основе добавленных вами jar-зависимостей.
Например, если вы добавите Spring-boot-starter-web, Spring Boot автоматически сконфигурирует такие зарегистрированные бины, как DispatcherServlet, ResourceHandlers, MessageSource.
Если вы используете spring-boot-starter-jdbc, Spring Boot автоматически регистрирует бины DataSource, EntityManagerFactory, TransactionManager и считывает информацию для подключения к базе данных из файла application.properties.
Если вы не собираетесь использовать базу данных, и не предоставляете никаких подробных сведений о подключении в ручном режиме, Spring Boot автоматически настроит базу в памяти, без какой-либо дополнительной конфигурации с вашей стороны (при наличии H2 или HSQL библиотек).
Автоматическая конфигурация может быть полностью переопределена в любой момент с помощью пользовательских настроек.
2.3. Встроенная поддержка сервера приложений — контейнера сервлетов
Каждое Spring Boot web-приложение включает встроенный web-сервер. Посмотрите на список контейнеров сервлетов, которые поддерживаются «из коробки».
Разработчикам теперь не надо беспокоиться о настройке контейнера сервлетов и развертывании приложения на нем. Теперь приложение может запускаться само, как исполняемый jar-файл с использованием встроенного сервера.
Если вам нужно использовать отдельный HTTP-сервер, для этого достаточно исключить зависимости по умолчанию. Spring Boot предоставляет отдельные starter-пакеты для разных HTTP-серверов.
Создание автономных web-приложений со встроенными серверами не только удобно для разработки, но и является допустимым решением для приложений корпоративного уровня и становится все более полезно в мире микросервисов. Возможность быстро упаковать весь сервис (например, аутентификацию пользователя) в автономном и полностью развертываемом артефакте, который также предоставляет API — делает установку и развертывание приложения значительно проще.
Spring Boot, Hibernate и Kotlin для новичков шаг за шагом

Всем привет, меня зовут Олег, я техлид в ДомКлике. В нашей команде ядром стека является Kotlin и Spring Boot. Хочу поделиться с вами своим опытом по взаимодействию и особенностях работы с PostgreSQL и Hibernate в связке со Spring Boot и Kotlin. Также на примере микросервиса, покажу преимущества Kotlin и его отличия от аналогичного приложения на Java. Расскажу о не совсем очевидных сложностях, с которыми могут столкнуться новички при использовании этого стека с Hibernate. Статья будет полезна разработчикам, желающим перейти на Kotlin и знакомых со Spring Boot, Hibernate Java.
Плагины
Для приложения на Kotlin в качестве сборщика проекта возьмём Gradle Kotlin DSL. Список подключенных плагинов будет стандартным для Spring Boot, а для Kotlin с Hibernate у нас появится несколько новых:
plugins
Рассмотрим три последних.
kotlin(«jvm») — базовый плагин Kotlin для работы на JVM. Без которого не заведется ни одно приложение на Java-стеке.
kotlin(«plugin.spring») — поскольку классы в Kotlin по умолчанию финальны, то этот плагин автоматически сделает классы, помеченные аннотациями @Component , @Async , @Transactional , @Cacheable и @SpringBootTest открытыми к наследованию, а в тематике, относящейся этой статье, это позволит классам, написанным на Kotlin быть проксированными в Spring через CGLib прокси.
Важно отметить, что сущности, помеченные аннотациями @Entity , @MappedSuperclass и @Embaddable , не станут open после подключения плагина. Более того, get accessor ’ы тоже будут финальными, и тогда мы потеряем возможность работать с entity reference . Чтобы этого избежать и сделать Entity и его поля open , добавим в build.gradle.kts:
allOpen
kotlin(«plugin.jpa») — Если предыдущие два плагина применяются к любому приложению на Kotlin + Spring Boot, то следующий, уже относится напрямую к Hibernate. А он, как известно, для инициализации Entity использует рефлексию и инициализирует класс с конструктором без аргументов. Но так как мы пишем на Kotlin, такового конструктора может и не найтись. Если мы определили свой собственный первичный конструктор (primary constructor), то при загрузке Entity у нас выкинет исключение:
org.hibernate.InstantiationException: No default constructor for entity
Зависимости
Набор зависимостей у нас тоже будет не совсем идентичный набору на Java:
dependencies
Добавим еще пару зависимостей в дополнение к стандартному веб-стартеру Spring Boot и к основному интересующему нас стартеру org.springframework.boot:spring-boot-starter-data-jpa , который в качестве реализации JPA по умолчанию тянет Hibernate:
org.jetbrains.kotlin:kotlin-reflect — нужен для рефлексии на Kotlin, которая уже поддерживается в Spring Boot и широко используется для инициализации классов.
org.jetbrains.kotlin:kotlin-stdlib-jdk8 — добавляет возможность работать с коллекциями Java, поддержку стримов и многое другое.
На этом различия в конфигурировании проекта на Kotlin по сравнению с Java у нас заканчиваются, перейдем к самому проекту, его структуре таблиц и сущностей.
Таблицы и сущности
Наше приложение будет состоять из двух таблиц department и employee, которые связаны отношением «один ко многим».

В качестве базы будем использовать СУБД PostgreSQL. Структуру таблиц создадим с помощью liquibase, а в качестве тестовых зависимостей будем использовать стандартный стартер:
org.springframework.boot:spring-boot-starter-test — тестировать будем в Docker с помощью testcontainers.
Сущности
Как и в любом приложении с более чем одной сущностью, создадим общего предка для всех entity .
@MappedSuperclass abstract class BaseEntity < @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: T? = null override fun equals(other: Any?): Boolean < other ?: return false if (this === other) return true if (javaClass != ProxyUtils.getUserClass(other)) return false other as BaseEntityreturn this.id != null && this.id == other.id > override fun hashCode() = 25 override fun toString(): String < return "$(id=$id)" > >
@Entity @Table(name = "department") class DepartmentEntity( val name: String, @OneToMany( mappedBy = "department", fetch = FetchType.LAZY, orphanRemoval = true, cascade = [CascadeType.ALL] ) val employees: MutableList = mutableListOf() ) : BaseAuditEntity() < fun addEmployee(block: DepartmentEntity.() ->EmployeeEntity) < employees.add(block()) >fun setEmployees(block: DepartmentEntity.() -> MutableSet) < employees.clear() employees.addAll(block()) >>
@Entity @Table(name = "employee") class EmployeeEntity( val firstName: String, var lastName: String? = null, @ManyToOne @JoinColumn(name = "department_id") val department: DepartmentEntity ) : BaseAuditEntity()
Мы не используем Data-классы. Это кажется явным преимуществом Kotlin перед Java (до 14 версии), и этому есть объяснение.
Почему не использовать?
Data-классы, помимо того, что они финальны сами по себе, имеют по всем полям определенные equals , hashCode и toString . А это недопустимо в связке с Hibernate.
Почему? А также зачем hashCode всегда равен константе — ответ в документации самого Hibernate. Конкретно нас интересует вот этот раздел:
Although using a natural-id is best for equals and hashCode, sometimes you only have the entity identifier that provides a unique constraint.
It’s possible to use the entity identifier for equality check, but it needs a workaround:
- you need to provide a constant value for hashCode so that the hash code value does not change before and after the entity is flushed.
- you need to compare the entity identifier equality only for non-transient entities.
То есть сравнивать нужно либо по natural id , либо, как в нашем примере, по primary key id . Это позволит избежать множества проблем при сравнении сущности и убережет от ее потери при использовании сущности в качестве элемента в Set .
Наличие же toString , определенного по всем полям, и вовсе убивает всю ленивость, например, при журналировании сущности, так как будут проинициализированы все поля для вывода в строку.
Учитывая особенности Hibernate, эта функциональность Kotlin нам не подойдет.
Конструктор класса
Kotlin позволяет задавать переменным значения через конструктор, чем грех не воспользоваться. Рассмотрим еще раз DepartmentEntity :
class DepartmentEntity( val name: String, @OneToMany( mappedBy = "department", fetch = FetchType.LAZY, orphanRemoval = true, cascade = [CascadeType.ALL] ) val employees: MutableList = mutableListOf() ) : BaseAuditEntity()
Также мы можем проинициализировать через конструктор название подразделения, например:
departmentRepository.save(DepartmentEntity(name = "Department One"))
Через конструктор можно инициализировать, в том числе, и список сотрудников employees. Коллекции, разумеется, объявим изменяемыми.
Используйте var/val в зависимости от необходимости изменения поля
Название организации мы пометили как val :
class DepartmentEntity( val name: String,
и оно не может быть null .
Выбор var / val является удобной опцией и зависит от бизнес-логики. Выбирать между var и val надо исходя из требования: должно ли поле сущности быть изменяемым.
Допустимость null в полях только в соответствии с БД
Насчет допустимости значений null в полях всё не так просто. Ранее мы погрузились немного в глубины Hibernate: говоря о plugin.jpa, я упомянул про использование конструктора без аргументов при инициализации сущности.
При инициализации полей тоже используется рефлексия. И если в базе в соответствующей колонке хранилось значение null , то класс спокойно инициализируется с этим полем со значением null . При обращении к нему мы рискуем получить NPE, хотя поле и помечено как not nullable . Чтобы этого не случилось, надо следить за синхронностью структуры таблиц и классов.
Если посмотреть на описанное в последних двух разделах более комплексно, то эти правила применимы не только к примитивам, но и к связке сущностей.
Например, EmployeeEntity всегда привязан к DepartmentEntity :
class EmployeeEntity( val firstName: String, var lastName: String? = null, @ManyToOne @JoinColumn(name = "department_id") val department: DepartmentEntity ) : BaseAuditEntity()
Department является не null и его нельзя изменить, что может избавить от разного рода ошибок, в особенности, если бизнес-логика требует неизменяемости.
Репозитории
При использовании Kotlin, у репозиториев из коробки появилась проверка на допустимость null . Так, если мы уверены, что при поиске department по имени результат будет уникальный и единственный, то можно возвращаемый тип указать как non nullable :
interface DepartmentRepository : JpaRepository
Здесь DepartmentEntity указан единственным и не может быть null . Если же по какой-то причине мы не нашли искомый department , то поймаем уже не NPE, а нечто другое:
org.springframework.dao.EmptyResultDataAccessException: Result must not be null!
Такая обработка достигается с помощью добавления специализированной поддержки Kotlin в MethodInvocationValidator и ReflectionUtils в spring data commons.
lateinit var
Ещё одной фичей Kotlin, которую хотелось бы рассмотреть, является lateinit var .
Добавим новый класс-предок: BaseAuditEntity .
@MappedSuperclass @EntityListeners(AuditingEntityListener::class) abstract class BaseAuditEntity : BaseEntity()
Рассмотрим применение lateinit var на примере полей аудита ( created , modified ).
lateinit var — это not null поле с отложенной инициализацией. Обращение к полю до его инициализации генерирует ошибку:
kotlin.UninitializedPropertyAccessException: lateinit property has not been initialized
Как правило, мы обращаемся к полям created и modified уже после того, как сущность была сохранена в БД. В нашем случае, данные в этих поляхпроставляются на этапе сохранения и они not null , то lateinit var нам более чем подходит.
Итоги
Мы создали приложение, в котором учтены многие преимущества Kotlin, и рассмотрели важные отличия от Java, избежав многих скрытых сюрпризов. Буду рад, если эта статья окажется полезна не только новичкам. Позднее мы продолжим тему общения микросервиса с БД.
- Блог компании Домклик
- Программирование
- Kotlin
Уроки Java Spring Boot

Уроки Java Spring Boot / #1 - Создание веб-сайта на Java
Представляем вам большой курс по изучению технологии Spring Boot MVC. В ходе курса вы научитесь работать с фреймворком Spring и на его основе создадите небольшой веб блог. Вы научитесь работать с базами данных, шаблонами и общим построением сайтов на основе языка Java.
Видеоурок
Полезные ссылки:
- Официальный сайт IntelliJ IDEA ;
- Официальный сайт Spring ;
- Конструктор проекта на Spring.
Информация про Java Spring Boot
Платформа Java Spring Boot была впервые выпущена в 2004 году. С тех пор платформа постоянно обновляется и пополняется новыми функциями. На сегодняшний день платформа является наиболее продвинутым фреймворком для создания веб сайтов на основе языка Java.
C первых дней выпуска Spring был тепло встречен разработчиками Java, так как это был первый достойный конкурент технологии JavaBeans . JavaBeans, как и Spring, предоставляют набор различных решений для реализации веб проектов.

На основе Spring Boot вы можете создавать веб сайты различных жанров и возможностей. Вы можете создать простой одностаничник или крупный веб проект для какого-либо международного банка.
Spring содержит хорошо описанную документацию, а также множество готовых решений, что можно копировать и использовать в своих проектах.
Технология MVC
Spring реализует шаблон проектирования MVC. MVC расшифровывается как «model-view-controller» или же модель вид контроллер. Данный шаблон позволяет структурировать все файлы внутри проекта и делает чтобы каждый файл отвечал лишь за свою часть работы.
Рассмотрим простой запрос к веб сайту, написанному на Spring Boot. Когда пользователь переходит на какую-либо страницу сайта, то переход отслеживается в контроллере. Контроллер понимает по какому URL адресу перешёл пользователь и далее обращается к модели. Модели могут обратиться к базе данных, получить оттуда какие-то значение, выполнить различные вычисления и далее вернуть эти данные обратно в контроллер. Далее контроллер передает все данные в шаблон, который как раз и показывается пользователю. Шаблон в свою очередь представляет из себя простую HTML страницу с различными текстами, кнопками, картинками и прочим.

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

В случае использования сервиса Start Spring.io вы можете выбрать нужные для вас пакеты, после чего нажать на клавишу «Generate» для генерации и скачивания архивного проекта.

Чтобы открыть проект вы можете воспользоваться любой средой разработки, к примеру программой IntelliJ IDEA .
План курса
В ходе курса мы научимся писать сайты с использованием Java Spring Boot MVC. Мы рассмотрим все основные моменты при работе с данным фреймворком. За курс мы создадим множество шаблонов, рассмотрим работу с шаблонизаторами, рассмотрим работу с базой данных, а также создадим небольшой полноценный проект по типу веб-блога.
К концу курса у вас будет достаточно знаний чтобы начать разрабатывать сайты на основе Java Spring.
Перед изучением курса вам необходимо ознакомиться с языками для вёрстки сайта: HTML , CSS и JavaScript . Также вам необходимо обладать навыками работы с языком Java прежде чем изучать платформу Спринг. Все дополнительные курсы можно посмотреть на нашем ресурсе.
