SC24EP02 Разработка REST-сервиса - Разработка проектов со Spring

Во втором ролике цикла я рассказываю об особенностях разработки REST-сервисов с помощью Spring WebMVC.
В цикле роликов "Разработка проектов со Spring" я рассказываю на простых примерах о процессе разработки веб-приложений и REST-сервисов на языке программирования Java с использованием экосистемы Spring. Данный цикл охватывает разработку классических и реактивных проектов, вопросы их сопровождения, такие как документация и мониторинг, адаптацию их к облачной инфраструктуре и процесс их развёртывания в Docker и Kubernetes.
Репозиторий проекта: github.com/alex-kosarev/sc24/...
Мои ресурсы:
- Сайт: alexkosarev.name
- Канал на KZread: / @shurik_codes
- Канал в Telegram: t.me/+TZCuO38vG3oqu_Jq
- Группа для обсуждений в Telegram: t.me/+UFAkw187WstX0wqy
- Паблик в VK: shurik.codes
- Канал в Дзене: dzen.ru/shurik_codes
- Канал на Rutube: rutube.ru/channel/24432001/
- Страница в Boosty: boosty.to/akosarev
Поддержать проект:
- Доны в VK: donut/shurik.codes
- Донаты в Boosty: boosty.to/akosarev/donate
- Через Tinkoff: www.tinkoff.ru/cf/4PEOiVCZQuS
#java #spring #rest #howto

Пікірлер: 92

  • @user-ne1ks8xu8z
    @user-ne1ks8xu8z3 ай бұрын

    Я - человек простой. Вижу видео от Саши - ставлю лайк) спасибо за туториал)

  • @partiec6065
    @partiec60659 күн бұрын

    Спасибо, братиш 🙂🤘

  • @user-ss4nl3zb8v
    @user-ss4nl3zb8v3 ай бұрын

    Спасибо за новый урок

  • @vladislavchaplin894
    @vladislavchaplin8943 ай бұрын

    ОЧень годно, спасибо большое, что делитесь

  • @Edu-wi3il
    @Edu-wi3il3 ай бұрын

    Спасибо! Было полезно узнать про классы ProblemDetail и RestClient, как альтернатива RestTemplate

  • @itmaker1821
    @itmaker18212 ай бұрын

    Очень классный гайд, всё на высоте, спасибо

  • @webicode
    @webicodeАй бұрын

    СПАСИБО за труд !!!

  • @user-rk3ic3qz3h
    @user-rk3ic3qz3h3 ай бұрын

    Отличное начало. Супер. Как всегда качественный профессиональный материал.

  • @user-rk3ic3qz3h
    @user-rk3ic3qz3h2 ай бұрын

    Наконец-то осилил до конца. Смотрю дальше. Отличный материал.

  • @Devivl
    @Devivl3 ай бұрын

    Саш, как всегда, жирный лайк! Судя по гитхабу на выходе серьезный проект получается. Отличная практика. От души спасибо.

  • @akalavan5395
    @akalavan53952 ай бұрын

    Второй день, второе видео пройдено, всё очень интересно и познавательно.

  • @shluhogon_42
    @shluhogon_423 ай бұрын

    Благодарю!

  • @user-yf2er5vr8q
    @user-yf2er5vr8q3 ай бұрын

    спасибо большое

  • @tekkaruwer8789
    @tekkaruwer87892 ай бұрын

    Очень крутое качество кода, зная все это, все равно очень полезно смотреть лекции, хотя бы просто для того, чтобы поучиться так грамотно писать) ❤

  • @romanovichihin2429
    @romanovichihin242914 күн бұрын

    Комент для продвижения

  • @artemv5226
    @artemv52263 ай бұрын

    Эх, жаль, что цикла этого не было еще, когда ваял свой первый проект:) От прыжков по многочисленным граблям бы избавился. Спасибо за труды!

  • @Boraldan
    @Boraldan3 ай бұрын

    Спасибо!

  • @user-vq2hi1df2i
    @user-vq2hi1df2i3 ай бұрын

    Спасибо Александр и все таки URL и URI это не одно и тоже:)

  • @tusman4ik
    @tusman4ik3 ай бұрын

    ❤)

  • @user-cm4jg9on2j
    @user-cm4jg9on2j3 ай бұрын

    Александр, спасибо за видео, с интересом посмотрел. Печалька, что такой полезный класс как ProblemDetail сделали только в 6 версии Spring, не могу его использовать - у нас на проекте 5-я версия)

  • @shurik_codes

    @shurik_codes

    3 ай бұрын

    Самостоятельно описать)

  • @user-in8uk6yz9r
    @user-in8uk6yz9r3 ай бұрын

    Привет. Отличный курс, большая работа проделана, виден системный подход. Большой лайк за труды. Вопрос по блоку возвращения ResponseEntity при обработке ошибок. Заметил, что статус ошибки заполняется два раза, сначала в ProblemDetail, потом как статус ResponseEntity, а problemDetail возвращается в body. В этом есть сакральный смысл (спрашиваю, т.к. есть ощущение, что просто так ничего в роликах не говорится и не делается)? Я у себя сделал вариант ResponseEntity .of(problemDetails) .build() Вроде работает ))

  • @shurik_codes

    @shurik_codes

    3 ай бұрын

    Да, действительно работает, я упустил этот момент

  • @pavelgurevich4018
    @pavelgurevich4018Ай бұрын

    Всем привет, подскажите почему в методе createProduct надо возвращать заголовок ?

  • @Hocorend
    @HocorendАй бұрын

    Спасибо за видео, уже становится сложнее всё запоминать из-за большой плотности информации, хоть и не впервой это вижу. Хоть уроков уже много выпущено, хотелось бы попросить озвучивать горячие клавиши, используемые при разработке, чтобы научиться так же быстро управляться с кодом, и прочие фишки IDEA . Ещё хотел уточнить, DTO не создаются для упрощения уроков и отсутствия работы с БД(на данный момент) или их создание устаревшая практика?

  • @shurik_codes

    @shurik_codes

    Ай бұрын

    Исключительно для упрощения уроков, на практике DTO нужны

  • @artyomzolotoverkhov8468

    @artyomzolotoverkhov8468

    Ай бұрын

    Чтобы лучше запоминать рекомендую повторять за Александром в своей IDE

  • @Hocorend

    @Hocorend

    Ай бұрын

    @@artyomzolotoverkhov8468 Это-то я несомненно делаю, просто смотреть вообще бестолку) Но по ему опыту, информация более менее железно укладывается только через пол года повторений

  • @alexandr6055
    @alexandr60553 ай бұрын

    Заметил у вас интересную штуку. Вот к примеру в методе мы не находим по id и в блоке if кидаем исключение. Затем отдельный метод "ловец" этого исключения. А не проще ли не кидать эксепшн, а просто в блоке иф делать обращение к методу "ловцу"? Как-то выглядит более прямой такая логика, нет?

  • @shurik_codes

    @shurik_codes

    3 ай бұрын

    Я немного ненаглядно показал, да, но предполагается, что в реальных условиях исключение может возникнуть в нескольких местах, и чтобы везде не писать обработку на месте, таким образом дублируя код, гораздо удобнее написать метод с @ExceptionHandler

  • @alexandr6055

    @alexandr6055

    3 ай бұрын

    Понял, спасибо ​@@shurik_codes

  • @ji1ja

    @ji1ja

    3 ай бұрын

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

  • @oleksandrhavryush9250
    @oleksandrhavryush92502 ай бұрын

    Спасибо автору за отличный материал. У меня вопрос: объясните пожалуйста почему сервис и менеджер крутятся на разных портах, если мы в ямл файлах прописали один порт? Почему в постман мы посылаем запросы на порт 8081, а в браузере видим порт 8080? Вот этот момент до сих пор понять не могу.

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

    В сервисе каталога порт - 8081 github.com/alex-kosarev/sc24/blob/SC24EP02-servlet-api-rest-service/catalogue-service/src/main/resources/application-standalone.yaml

  • @viewer_evgeniy
    @viewer_evgeniy2 ай бұрын

    Я верно понимаю, что ResponseEntity по сути нужен только, если требуется кастомизация статуса? Если достаточно каких-то дефолтных (на успех это 200, а на ошибки не помню, что там спринг по умолчанию использует), то соответственно из методов контроллеров возвращаем просто нужный нам объект?

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

    В целом да

  • @user-nw2mu7vu3h
    @user-nw2mu7vu3h2 ай бұрын

    Спасибо за ролик! С первого ролика не совсем понял, может кто нибудь объяснить почему мы используем NewPayload и UpdatePayload? Можно же вроде Product передавать?

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

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

  • @user-nw2mu7vu3h

    @user-nw2mu7vu3h

    2 ай бұрын

    @@shurik_codes Спасибо понял. А правильно ли я понимаю, что почти в таком же контексте(для не изменения сущности, и отделения ее) для таких целей при работе с базами данных используют DTO?

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

    @@user-nw2mu7vu3h да

  • @ji1ja
    @ji1ja3 ай бұрын

    Привет, спасибо за видос) Вопрос такой, почему просто не отлавливать в глобальном эксэпшн хэндлере ошибки валидации без BindingResult'а в контроллере?

  • @shurik_codes

    @shurik_codes

    3 ай бұрын

    А откуда взяться исключению?

  • @ji1ja

    @ji1ja

    3 ай бұрын

    @@shurik_codes у спринга есть MethodArgumentNotValidException который экстендит bindexception и выбрасывается при фейле валидации

  • @rainrainov4495

    @rainrainov4495

    3 күн бұрын

    @@shurik_codes Добрый день. Через хэндлер отлавливается, просто нужно в настройках ProblemDetail подключить. К сожалению для ошибок валидации все равно придется в хендлере из BindingResult вытаскивать. Жаль стандарт не включает ошибки валидации и при тесте приходится заморачиваться с проверкой проперти, хотя можно просто расширить ProblemDetail, что мне кажется предпочтительней.

  • @user-yf2er5vr8q
    @user-yf2er5vr8qАй бұрын

    а если у вас будет время можете показать какой-то реальный пример из жизни несложного проекта на спрингу

  • @user-ox1hp7sm4o
    @user-ox1hp7sm4o3 ай бұрын

    Спасибо за видео. Но у меня есть вопрос) в Вашем примере объект UpdateProductPayload содержит всего два свойства. Предположим этих свойств гораздо больше и содержать новые данные для обновления могут не все т.е. допускается null значение. Как тогда оптимальней всего реализовать обновление объекта, может есть вариант, как избежать ручной проверки данных в каждом из свойств объекта?

  • @shurik_codes

    @shurik_codes

    3 ай бұрын

    Bean Validation)

  • @user-ox1hp7sm4o

    @user-ox1hp7sm4o

    3 ай бұрын

    @@shurik_codes Не очень понимаю, как это поможет если свойство может быть null, т.е. это значение разрешено, то при сохранении null заменит уже имеющееся значение в бд. А задача сохранить только те значения которые не null.

  • @shurik_codes

    @shurik_codes

    3 ай бұрын

    А, вот про что вопрос. Есть два варианта: 1. Описывать структуры данных для каждого варианта изменения, чтобы они содержали только те свойства, которые могут быть изменены 2. Для каждого варианта изменения описывать свой запрос к БД (специфично для SQL, JPA, Spring Data и т.д.)

  • @javac

    @javac

    3 ай бұрын

    Просто мысль вслух: можно попробовать @DynamicUpdate на сущность поставить, а при маппинге из payload в сущность null-ы пропускать (но это уже hibernate на борту подразумевается). Неизмененные поля в SQL не попадут (но потеряется перф, т.к. запрос динамический и не закешируется).

  • @bazilval

    @bazilval

    2 ай бұрын

    @@user-ox1hp7sm4o Посмотрите связку mapStruct и JsonNullable для этих целей. Если кратко, то в DTO, которые отвечают за создание и обновление сущности нужным полям нужно сделать тип JsonNullable (или не String). Это такая обёртка, которая позволит различать null явный, когда мы хотим, чтобы у сущности поле стало null и null от того, что мы не указали это поле в теле запроса. Далее при отправке запроса, в случае если это поле не будет указано в теле запроса, то его значение будет null, а если указали и явно указали ему стать null, то этот null будет зашит внутри обёртки После этого мы настраиваем mapStruct для того, чтобы такие поля корректно мапились при преобразовании DTO в объект Если интересно, могу скинуть учебный проект, где я такое реализовывал @shurik_codes также интересно ваше мнение про этот подход!

  • @SlevySoddik
    @SlevySoddik3 ай бұрын

    вопрос по структуре методов контроллера с ветвлениями, зачем блок else если в блоке if есть return? верификация в контроллере не нарушает SRP?

  • @shurik_codes

    @shurik_codes

    3 ай бұрын

    Про метод с ветвлениями - не понял о каком методе идёт речь. Блок else затем, чтобы выполнить код, если условие в if не сработало. Валидация выполняется не в контроллере, а в валидаторе силами фреймворка, контроллер обрабатывает результат валидации, так что никакого нарушения SRP здесь нет.

  • @SlevySoddik

    @SlevySoddik

    3 ай бұрын

    @@shurik_codes про if имел ввиду такую структуру: if(somePredicate){ return x; } return anotherX; таким образом else нет, и порядок обработки не теряется, но это, наверно, больше к код стайлу относится.

  • @shurik_codes

    @shurik_codes

    3 ай бұрын

    @@SlevySoddik а, ну так да, можно делать

  • @sdhfdsfh2413
    @sdhfdsfh24133 ай бұрын

    Привет, а как можно сделать, чтобы можно было скрывать левую боковую панель по бинду??

  • @shurik_codes

    @shurik_codes

    3 ай бұрын

    Alt+1

  • @user-ng7ed9dv5i
    @user-ng7ed9dv5i2 ай бұрын

    Приветствую. Что за плагин стоит и оставляет отметку simple (проценты)?

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

    Code Complexity

  • @user-uv1ui7hg2r
    @user-uv1ui7hg2r5 күн бұрын

    Здравствуйте, а зачем нужна проверка является ли BindingResult экземпляром BindException, нельзя сразу выбросить BindException(bindingResult)?

  • @shurik_codes

    @shurik_codes

    5 күн бұрын

    У BindingResult есть и другие реализации, не являющиеся исключением

  • @denisskyter4526
    @denisskyter45263 ай бұрын

    Я так понял restclient в manager-app это для взаимодействия с сервисом каталога что бы с клиента туда кидать запросы

  • @shurik_codes

    @shurik_codes

    3 ай бұрын

    да

  • @user-vs6ce8vq2h
    @user-vs6ce8vq2h2 ай бұрын

    Добрый день! Спасибо за курс. У меня проблема - вроде делаю все также, но вылезает ошибка MissingPathVariableException: Required URI template variable 'productId' for method parameter type Integer is not present

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

    Какой путь и как объявлен аргумент метода, получающий переменную пути?

  • @user-vs6ce8vq2h

    @user-vs6ce8vq2h

    2 ай бұрын

    Появляется на страницах catalogue/products/list и catalogue/products/create, где в пути вообще нет productId

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

    А в контроллере есть метод с аннотацией @ModelAttribute и аргументом, отмеченным аннотацией @PathVariable?

  • @user-vs6ce8vq2h

    @user-vs6ce8vq2h

    2 ай бұрын

    @@shurik_codes Спасибо, поняла ))

  • @user-lq5zj6ci1r
    @user-lq5zj6ci1r9 күн бұрын

    Доброго времени суток! Подскажите, на JDK17 этот код должен работать?

  • @shurik_codes

    @shurik_codes

    8 күн бұрын

    Не тестировал, но вроде ничего из JDK 18+ в проекте не используется

  • @user-fs7qm9tw2d
    @user-fs7qm9tw2dАй бұрын

    Привет, ты указываешь active profile - standalone на 59 минуте, как это сделать если версия community ?

  • @shurik_codes

    @shurik_codes

    Ай бұрын

    spring.profiles.active в application.yml

  • @user-fs7qm9tw2d

    @user-fs7qm9tw2d

    Ай бұрын

    @@shurik_codes то есть в файле application-standalone.yaml прописать строчку spring: profile: active ------------- да?

  • @shurik_codes

    @shurik_codes

    Ай бұрын

    @@user-fs7qm9tw2d не, в файле application.yml, ну или при запуске mvn spring-boot:run -Dspring.profiles.active=standalone но это не точно

  • @GyMaNoiD-ql3wb

    @GyMaNoiD-ql3wb

    27 күн бұрын

    @@user-fs7qm9tw2d С помощью терминала через cd заходите в директорию вашего сервиса("cd catalogue-service", например) и в терминале пишете: mvn spring-boot:run -D"spring-boot.run.profiles"=standalone

  • @denisskyter4526
    @denisskyter45263 ай бұрын

    А откуда у вас ultimate idea , с community не хочу ходить

  • @shurik_codes

    @shurik_codes

    3 ай бұрын

    Неравнодушные люди помогают обновлять подписку)

  • @Hocorend

    @Hocorend

    Ай бұрын

    На торрентах поищи, тебе же для обучения, никто штраф не предъявит, версию 2022 года точно можно найти

  • @svyatoiambrozii
    @svyatoiambrozii2 ай бұрын

    Вам как профессиональному разработчику приятнее с REST или MVC работать? Где проще разработка выходит?)

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

    С классическими веб-приложениями я работаю крайне редко (не знаю уж, к счастью или к сожалению), REST в моей практике занимает существенно больше времени. В целом мне без разницы с чем работать)

  • @romoshi
    @romoshi2 ай бұрын

    Не пойму почему не выводит продукт, на выхлопе получается "ID: 0, Название: , Описание: ", но в самом списке товаров id и title корректные. :(

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

    Возможно, где-то есть ошибки, код к ролику: github.com/alex-kosarev/sc24/tree/SC24EP02-servlet-api-rest-service

  • @romoshi

    @romoshi

    2 ай бұрын

    @@shurik_codes Спасибо, буду разбираться!

  • @bolekrus
    @bolekrusАй бұрын

    Catalague-service запускается без проблем, а Manager запускается один раз. Потом выключаешь, перезагружаешь программу, но всё равно ошибка Web server failed to start. Port 8080 was already in use.. Что за???

  • @shurik_codes

    @shurik_codes

    Ай бұрын

    Ну, значит, приложение менеджера не выключается корректно

  • @ladamira3477
    @ladamira34772 ай бұрын

    У меня у одной что-ли в BindException нет метода getAllErrors()?

  • @ladamira3477

    @ladamira3477

    2 ай бұрын

    а, все, исправила импорт)) но у меня в toList просто не собирается, требует collect(Collectors.toList()))

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

    Это для JDK 17+, в примере используется JDK 21

  • @ladamira3477

    @ladamira3477

    2 ай бұрын

    ​@@shurik_codes у меня 17. По идее должно работать. И ещё приложение при запуске каждый раз требует новый порт чтобы развернуться. В чем причина?

  • @shurik_codes

    @shurik_codes

    2 ай бұрын

    Что-то занимает этот порт, возможно, запущенный ранее сервис

Келесі