SC24EP01 Разработка веб-приложения - Разработка проектов со Spring
ฝัง
- เผยแพร่เมื่อ 7 ก.พ. 2025
- В первом ролике цикла я демонстрирую разработку классического веб-приложения со Spring WebMVC, Thymeleaf и Jakarta Bean Validation. В ролике демонстрируется несколько способов создания нового проекта на основе Spring Boot, вкратце описывается многоуровневая архитектура и шаблон проектирования MVC, создание базовых компонентов приложения, валидация данных и интернационализация. Кроме этого продемонстрировано несколько способов запуска приложения на основе Spring Boot.
В цикле роликов "Разработка проектов со Spring" я рассказываю на простых примерах о процессе разработки веб-приложений и REST-сервисов на языке программирования Java с использованием экосистемы Spring. Данный цикл охватывает разработку классических и реактивных проектов, вопросы их сопровождения, такие как документация и мониторинг, адаптацию их к облачной инфраструктуре и процесс их развёртывания в Docker и Kubernetes.
Репозиторий проекта: github.com/ale...
Мои ресурсы:
Сайт: alexkosarev.name
Канал на TH-cam: / @shurik_codes
Канал в Telegram: t.me/+TZCuO38v...
Группа для обсуждений в Telegram: t.me/+UFAkw187...
Паблик в VK: shurik....
Канал в Дзене: dzen.ru/shurik...
Канал на Rutube: rutube.ru/chan...
Страница в Boosty: boosty.to/akos...
Поддержать проект:
Доны в VK: donut/s...
Донаты в Boosty: boosty.to/akos...
Через Tinkoff: www.tinkoff.ru...
#java #spring #web #validation #thymeleaf #howto
Очень хорошо, что вы стали записывать такие интересные ролики, которые не только зеленому новичку будут полезны. 🙂👍👍👍
Братик вот хочешь верь или не верь, но то что ты делаешь это имба дикая !
Александр - потрясающий преподаватель. Всегда очень приятно смотреть и слушать. Спасибо, Саш, что ты делаешь.
Присоединяюсь, для меня тоже один из лучших преподавателей 🔥🔥
Классный, полезный ролик без воды. Все полтора часа полезной информации. Хотелось бы по больше фишек, которые применяются в реальной разработки
Отличный контент Александр, продолжайте, не останавливайтесь) Ваши труды поддержал донатом, благодарю за уроки
После всех других роликов по спринг - отбивались руки только. У вас же всё очень понятно и информативно, появилась вера в возможность освоения фреймворка😆. Буду продолжать смотреть ваш канал. Успехов вам!
Отличное видео.
Главное, чтобы запал не пропал у человека.
Хотелось бы про деплой на прод увидеть - как сервис выбрать, как залить, как запустить, какие особенности и т.д. - в общих чертах.
Поддержу комментаторов выше- автор очень понятно и интересно объясняет.
Спасибо! Жду следующие выпуски.
Не пропадет. Он уже отснял все 22 ролика, просто выкладывает поэтапно)
@@alexandr6055 да, спасибо, я увидел его вступительный ролик.
Темы хорошие озвучивает, посмотрю все обязательно.
Опыта работы программистом не имею, только обучаюсь длительное время.
С данного видео получил больше полезной инфы чем от всяких лекций и многих других видео с ютуба.
Очень благодарен за труд, твои видео как клад, очень рад что наткнулся.
было бы интересно, в будущем, увидеть ролики про проектирование приложения в гексагональной архитектуре)
Ждал этот видос больше, чем выход второй Дюны !!
Большое спасибо. Очень информативно. Как раз сейчас начинаю писать свою дипломную работу по Спрингу и очень рад, что вас нашел.
Супер! Смотрится на одном дыхании, как детективная история, чем дальше - тем интереснее
Давненько не видел!! Очень рад, что не забросил дело)))
1,5 часа == ОГОНЬ!!! Спасибо , Александр!
cпасибо большое вы как будто услышали наши пожелания
Спасибо за урок! Я недавно теорию по спрингу выучил, а тут практика годная с объяснением тонких моментов. Сохраняешь работягам кучу времени. Чисто кайф.
P.S. Круто, что оставляешь моменты типа такого 1:26:51 было весело видеть твою реакцию на баг
Спасибо Вам огромное!!!))))
Очень информативно, понятно и интересно
Лучший канал по Джаве))))
Спасибо вам за ваш труд!
Огромное спасибо автору. Отличное видео!
Спасибо! ждем продолжения!
Огромное спасибо за труд! Было бы отлично добавить тайм-коды к видео:) Когда пытаюсь повторить на практике, часто возвращаюсь к разным частям разных уроков, пытаясь вспомнить где и что было рассказано и показано)
Таймкоды будут, не успел их проставить
Офигенно! Спасибо большое, еще и настолько подробно и понятно!
Супер. Спасибо. ❤
Спасибо за то, что делитесь знаниями! Видео отличное, всё чётко и понятно)
Это прекрасно! Мне как раз спринг освоить сильно захотелось день назад :)
Друг, хочу сказать тебе огромное спасибо. Очень тяжело найти свежие ролики, где всё досконально объясняют. Спасибо тебе огромное!
Спасибо ! Но нужно еще раз пересмотреть и попробывать своими ручками. Мне очень понравилось
Давно учила Java core и очень боялась заходить в Spring. Спасибо, Александр, что помогли преодолеть страх перед новым направлением.
Очень полезно, спасибо вам большое за ролики! Видно, что подошли ответственно и с душой!
Спасибо за контент!
Класс, очень понятно и доступно, очень рад что нашел ваши видео вКонтакте, а теперь и здесь на канале! Однозначно подписка.
Спасибо вам огромное за урок!
большое спасибо _ побольше таких уроков +) лайк комент подписка
Отличная серия роликов
Интригующе.
Огонь, смотрится круто и информативно. Спасибо!
как всегда хорошо, спасибо
Успехов Вам и спасибо за полезную информацию
Спасибо, самое то, что мне сейчас нужно
Спасибо за видос, как всегда кайфанул
Огромное спасибо вам за работу 👍
Спасибо! Будем просвещаться )
спасибо) полезно и приятно слушать)
Спасибо! Все крайне понятно
Александр спасибо за ваш труд, просто лучший.
кайф
это настоящий подарок :D
Бомба 💣💣💣
Спасибо! Было интересно узнать про валидацию данных и интернализацию, а также что можно аннотировать @ModelAttribute методы. Как предложение, можно было кратко описать спецсимволы HTML в ходе повествования, либо привести ссылку на документацию, а также добавить пример подключения статических ресурсов CSS и JS, все таки это распространенный кейс
Про валидацию уже был ролик на канале, про Thymeleaf будут
ждееем!!!!!
Классный материал. Очень насыщенный и наглядный! Александр, в начале ролика Вы упомянули, что будете разрабатывать многомодульный проект, и каждый модуль будет развернут как отдельный микросервис. Хотелось бы узнать почему выбран именно такой подход? Если за альтернативу взять вариант с разработкой каждого приложения в отдельном проекте, то какие плюсы и минусы будут в сравнении с выбранным Вами подходом?
Мне так проще всё держать в одном месте) В реальных условиях так не всегда удобно делать
здравствуйте, вот с самого создания проекта, вы рассказываете как это можно выполнить в классическом варианте, а за кадром выполняете свою сборку многомодульного проекта, ну покажите тогда как это сделать.
谢谢老师,你厉害得很
Спасибо, что выпускаешь свои ролики, многие моменты из твоих роликов помогают улучшить мой код. Такой вопрос: Почему ты в подавляющей части роликов используешь систему сборки maven, а не gradle?
Я использую во всех роликах maven, потому что привык)
21:48
Присоединяюсь к комментариям ниже, действительно, смотреть ваши уроки одно удовольствие. Но у меня один вопрос. Почему мы помечаем стереотипными аннотациями саму реализацию интерфейса, а не сам интерфейс. Пометив аннотацией реализацию интерфейса, Spring создаст бины классов реализующих его?
1. Если я ничего не путаю, то применение стереотипичных аннотаций к интерфейсам не регистрирует соответствующие компоненты в контексте приложения, а это ведёт к возникновению NoSuchBeanDefinitionException при попытке внедрения.
2. При таком подходе интерфейс в какой-то мере становится зависимым от Spring, а я стараюсь делать интерфейсы независимыми, не смотря на всю свою любовь к Spring.
Но вообще я на практике из стереотипных аннотаций использую только @Controller, остальные компоненты я предпочитаю конфигурировать руками в @Configuration/@Bean.
коммент для продвижения
Александр, вопрос: можно чуть подробней - для чего нужно что бы при компиляции сохранялись наименования аргументов методов? (об говорится в 20:00 по шкале времени)
Чтобы не уточнять в @PathVariable, @RequestParam и других аналогичных аннотациях названия переменных. Например, если скомпилировать без сохранением названия аргументов такой код:
@RequestMapping("/path/with/{variable}")
String doSomething(@PathVariable String variable)
то аргумент в рантайме будет называться arg0 (вроде), и при вызове метода будет выброшено исключение, т.к. в пути нет {arg0}
@@shurik_codes Спасибо! вот такие объяснения очень ценны для чайников!
Замечательный материал. Огромное спасибо!
почему Вы не настраивали диспатчер сервлет для шаблонизатора что бы указывать откуда брать шаблоны? Это делает Spring boot сам из коробки ?
да, в Spring Boot это уже сконфигурировано
Спасибо за видео!
Но у меня в процессе просмотра возникло пару вопросов:
1. 23:30 А если у меня две реализации ProductService как спринг будет выбирать екземпляр.
2. Почему вы синхронизировали список через Collections а не пакет concurrency.
3. 40:37 Можно ли было написать product.setId(products.size() + 1);?
4. Что за магия происходит с @PostMapping("create") public String createProduct(NewProductPayload payload)
Как класс NewProductPayload собирается над ним даже аннотаций не стоит, как это работает?
5. Почему метод updateProduct в DefaultProductService мы реализовали так как реализовали, а не как до этого вызвали бы метод у productRepository?
1. @Qualifier или @Order/@Priority
2. Первое, что в голову пришло
3. Тогда возможно появление в разных промежутках времени разных товаров с одним идентификатором, но опять же это не играет большой роли
4. Объясняется вот тут в самом конце: docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-methods/arguments.html По сути логика аналогична применению @ModelAttribute к аргументу NewProductPayload payload
5. Не понял вопроса
Здравствуйте, у вас в плейлисте перепутаны первый и второй ролики
Спасибо за отличный контент!
А что за расширение, которое показывает simple (0%) и что оно вообще делает?
Code complexity
Планируете ли делать разбор работы с хибернейтом?
От вас бы было классно посмотреть
Будет
@@shurik_codes
🎉🎉🎉🎉
🔥🔥🔥🔥@@shurik_codes
велосипед не изобрел но под пивасик нормас!
А если spring под капотом работает в многопотоке, то надо все синхронизировать и использовать потокобезопасные структуры данных?
Да, и это касается не только Spring, но и вообще всех многопользовательских систем
@@shurik_codes а синхронизировать нужно только структуры данных или еще много чего
Добрый день! Что бы вы посоветовали использовать для интеграционного тестирования MockMvc, TestRestTemplate, WebTestClient, RestAssure возможно другой вариант. Для работы с WebTestClient обязательно добавлять webflux или в последних версиях Spring можно настроить и без webflux?
По тесты будут 5 и 10 ролики, RestAssured выглядит перспективнее всех за счёт универсальности, но я использую либо MockMvc, либо WebTestClient. Да, для последнего нужен webflux
Используете ли инструменты ИИ для помощи с написанием кода, и с генерацией тестов?
Нет, всё пишу сам
Насколько необходима потребность создавать интерфейс сервисов? Часто ли это применяется на практике при использовании mvc?
Используется регулярно для ослабления связанности между компонентами + проще проще прокси писать
@@shurik_codes Понял, спасибо. Просто довольно много смотрел видеоуроков/курсов, там обычно создаются интерфейсы репозиториев, а сервисы почему-то без интерфейсов.
Простите, а чем обусловлен выбор Linked List в качестве структуры данных для продуктов в ин мемори репо?
скажите, а для чего при обращении в методах к сервисам или репозиториям которые инжектированы внутри класса вы используете конструкцию this.servise...? Что даёт здесь этот this?
для собственного удобства, чтобы видеть, что обращение идёт к свойству экземпляра класса, а не к локальной переменной
Александр, добрый день.
А можно в двух словах про интерполяцию строк на 46:32? Что это, с чем едят - хотя бы какой-нибудь шортс. Либо подскажите что загуглить, а то я поискал и что-то всё не то находится. Спасибо.
Инлайнинг, оговорился
alexkosarev.name/2017/08/08/thymeleaf-template-engine/ www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html#inlining
@@shurik_codes Спасибо!
На 50:05 - там же PostMapping должен быть, разве нет?...
А то получается два одинаковых GetMapping-а
А....
Там не PostMapping
Там должен был быть GetMapping, но на другой урл - в одном "{\\d+}", а во втором - "{\\d+}/edit"
Подскажите, пожалуйста, каким образом payload в методе createProduct() автоматически получил данные из формы. Разве мы не должны прописывать th:object в form, чтобы это работало?
Если метод аннотированного контроллера принимает аргумент какого-то собственного типа, то это равносильно объявлению его с аннотацией @ModelAttribute, подробнее вот тут в самом конце: docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-methods/arguments.html
По сути создаётся экземпляр указанного класса и в него подставляются данные из запроса.
Большое спасибо за разъяснение!@@shurik_codes
Интересно конечно на java делать веб-приложения, но на Golang будет выглядеть намного проще и быстрее
Показываю, что знаю и умею
Если помню Вы где-то хотели в процессе видео объяснить, почему нужно обертку инта использовать вместо примитива, но так и не вернулись к этому. Если, конечно, я не пропустил.
Ну вот как-то да, упустил этот момент. Это нужно, чтобы в 3 ролике корректно работал JPA)
А будет запись стрима... Я в школе просто буду
Это не стрим, а премьера видео, так что да, будет
прошу тебя покажи как палучил изночалний pom.xml file в selmag-parent-sc24
Просто создал новый Maven-проект
Спасибо большое за Ваш труд. Возник вопрос, в связи с последними событиями в РФ ютуб стал не надежным. На других площадках не рассматриваете возможность размещения? Не хотелось бы утром встать а доступ закрыт...
Внимательно смотрим на описание под видео и вкладку "Сообщество". Все ролики продублированы на площадках VK, Дзен, Rutube и Boosty
Благодарю, почему то пропустил это
Здравствуйте! Спасибо за ваши видео. Подскажите пожалуйста, в чем разница между аннотацией @ModelAttribute и использованием модели в качестве параметра и соответственно добавлением атрибутов с помощью метода addAttribute.
Оба данных подхода реализуют одно и то же действие - добавление атрибута в модель. @ModelAttribute позволяет написать метод, добавляющий атрибут в модель для всех запросов, обрабатываемых в контроллере. По сути уменьшается дублирование кода.
Александр. Спасибо за уроки. у меня вопрос. Я совсем начинающая. у меня версия maven 3.9.4 и spring-boot-maven-plugin у меня красный и никак не хочет добавляться. что делать? поставить вашу версию maven поможет?
1. Если версия плагина не указана через pluginManagement в текущем или родительском проекте, то её нужно указать явно
2. groupId должна быть org.springframework.boot, artifactId - spring-boot-maven-plugin
Если даже после этого плагин выделен красным и речь идёт об IDEA, то нужно чистить кеш
@@shurik_codes я там в каком-то уроке сделала обертку для maven. теперь не знаю как её убрать
и еще когда создается проект через сайт. то главный модуль уже получается дочерний от spring-boot и модуль у меня не добавляется. только директория manager-app
Посмотрел код в гитхабе. И мне показалось, что конечная задумка будет что-то вроде книги spring microservices in action. Я правильно понимаю?
Я из этой книги взял кусок про Spring Cloud и Helm, остальное - авторское) Ну и если буду переснимать в будущем цикл, то Spring Cloud будет фундаментально переписан
@@shurik_codes Круто, спасибо.
Народ, где сейчас больше денег можно заработать на сеньорной позиции в срденем, golang или java?
В среднем - на Go
Здравствуйте, спасибо за видео, подскажите, зачем делать 2 pom.xml файла?
Каждый pom-файл отвечает за отдельный модуль, корневой - за весь проект в целом
Очень полезное видео.
Только вот если в валидации я убираю аннотацию Size, оставляя только NotNull, то могу создавать объекты без названий
Импорты все из одного пакета(
Всё логично
@@shurik_codes Я думал NotNull для того чтобы мы не могли сохранить значение вообще без символов, но видимо я не правильно понимаю(
@@3am6ep @NotNull только для проверки на null
А подскажите, как вообще создавать такие многомодульные проекты в intellij? У вас в selmage-parent нет src и вложенных в него папок. Я когда пытаюсь создать пустой "родительский" maven проект, то у меня все равно эта папка появляется. Или вы просто вручную из parent их удаляете?
Я создаю обычный maven-проект и удаляю src
Как напечатать перечеркнутое равно? Перебрал все: ≠, ≠, U+2260, !=, (ne), ne, =!, , !==, Alt+8800. Не печатается.
Спасибо проклятому автору за действительно крутое и полезное видео и будь он проклят. Добавь крипту для доната.
Нужно включить поддержку лигатур в настройках шрифта, если речь об IDEA
как-то можно сопоставить разные имена из формы и атрибуты payload?
Да, при помощи методов с аннотацией @InitBinder
Можно ли вместо Integer использовать класс UUID, вместо обозначения для поля id?
Конечно можно
А что делать есть у меня .jar файл собирается, но после команды java -jar name.jar ничего не происходит? И соответственно localhost ничего не возвращает в браузере. Все остальные способы работают нормально.
Возможно, jar собран либо без Spring Boot Maven Plugin, либо он не "толстый".
@@shurik_codes спасибо большое
можно было обойтись без класса NewProductPayload, сразу создавая Product?
Теоретически - да, ничто не мешает так делать, но с точки зрения архитектуры это плохая идея. Структуры данных должны соответствовать намерениям и нести только тот набор свойств, которые могут быть заполнены пользователем.
Всё здорово, всё полезно, но почему ты не показал с нуля как создавать много модульный проект, я не понял
создаёшь новый проект, удаляешь директорию src, создаёшь модуль в проекте... всё
А вы пользуетесь Jpa buddy ?
Нет, я на практике с JPA вообще редко сталкиваюсь
Я так понял таких роликов будет много , да?
Да, всего в цикле будет 22 ролика, полный список роликов я публиковал у себя в Telegram-канале и во вступительном ролике
А зачем везде писать this, если нет конфликтов имён?
Привычка, чтобы сразу было видно, где идёт обращение к свойствам класса, а где - к локальным переменным
как добавить локали на другие языки сразу же?
Создавать соответствующие файлы интернационализации
На каком сайте? Ваш сайт почему то не работает(
alexkosarev.name, в теории он может быть недоступен из-за пределов РФ
Я ведь правильно понял, что NewProductPayload это DTO?
да
@@shurik_codes это понятно что Вы юзаете вместо dto record, а почему? В чем причина?
@@СергейЗаря-х9ь как Александр писал, он считает, что рекорды идеальны для ДТО. Всё-таки меньше кода пишется, как минимум
Вау, спринг мвс с таймлифом в 2024 году?!😂 Надеюсь там и jsp будет?
А почему нет? Оно всё вполне актуальное
Так это же плейлист по основам, так что стоило ожидать. Тем более сам создатель канала опубликовал объявления об этой серии видео
@@shurik_codes Актуальное может быть, но таймлиф и вообще шаблонизаторы - редко применимы в проде, только для специфических задач. Хотя похоже вы не захотели отвлекаться на spa-js-фреймворки. А спринг мвс типа не модный, в отличии от вебфлакса. Хотя на нем большинство даже новых сервисов пишут, потому что настоящая потребность в реактивных сервисах редка.
Почему нет? Новичкам очень важно потрогать то, что они пишут, превратить их работы в реальный продукт. Не думаю, что js с 0 учить для такой цели рационально)
32:38
К чему такие сложности? Почему нельзя написать так: data-th-href="@{/catalogue/products/${product.id}}"
12:31:49.908 [restartedMain] ERROR org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter --
***************************
APPLICATION FAILED TO START
***************************
Description:
No spring.config.import property has been defined
Action:
Add a spring.config.import=configserver: property to your configuration.
If configuration is not required add spring.config.import=optional:configserver: instead.
To disable this check, set spring.cloud.config.enabled=false or
spring.cloud.config.import-check.enabled=false.
К этому ролику код с тэгом sc24ep01
product.setId(products.size() + 1);
Можно и так, только в случае удаления товара не из конца списка возможно дублирование идентификаторов