From 572d0459e0c109ad051119757ef65d11b70f6302 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 18 Feb 2020 11:51:18 +0300 Subject: [PATCH 001/226] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 228b708b7094..ab4d97e44213 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,9 @@ Java Enterprise Online Project - Выполнить задание и залить на GitHub (commit + push) - Переключиться в основную ветку проекта master. +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Тех.задание: библия или допускаются изменения. Полуоткрытый интервал.](https://drive.google.com/file/d/123XyBYVeKLC3ZcRr_dUkwyvO9NC6WLkY/view?usp=sharing) +- [Типы промежутков](https://ru.wikipedia.org/wiki/Промежуток_(математика)) + ## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Домашнее задание HW0 ``` Реализовать метод `UserMealsUtil.filteredByCycles` через циклы (`forEach`): From 796d81b362a3e087d016e90e503fe208eb55740b Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 5 Mar 2020 23:56:35 +0300 Subject: [PATCH 002/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ab4d97e44213..6b840eac3b03 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ Java Enterprise Online Project #### Java (базовые вещи) - Интуит. Программирование на Java - 1й урок MasterJava: Многопоточность -- Основы Java garbage collection +- [Основы Java garbage collection](http://web.archive.org/web/20180831013112/https://ggenikus.github.io/blog/2014/05/04/gc) - Размер Java объектов - Введение в Java Reflection API - Структуры данных в картинках From 80a3c742a574cfaf871982aeedb95fcd62722f66 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 26 Mar 2020 16:02:15 +0300 Subject: [PATCH 003/226] Update cv.md --- cv.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cv.md b/cv.md index a24d881fdeba..60860899fb3c 100644 --- a/cv.md +++ b/cv.md @@ -106,6 +106,8 @@ - Выдели самое главное путем опроса босса и важных коллег. Не распыляйся на мелочи. - [**5 вещей, которые разработчик должен сделать прежде чем попросить о помощи**](https://techrocks.ru/2018/07/16/5-things-a-developer-should-do-before-asking-for-help/) - [**Советы новичкам**](http://blog.csssr.ru/2016/09/19/how-to-be-a-beginner-developer) +- [ТОП-13 ошибок начинающего программиста](https://proglib.io/p/beginners-fails/) +- [25 ошибок начинающего программиста](https://habr.com/ru/post/413129/) - [Нетехнические навыки](https://tproger.ru/experts/softskills-for-job) ## [Отзывы по стажировке Topjava](https://vk.com/topic-74381644_30447246) From bee6ffcbffc764b82c1abd2fb4f6ff1087faa0a1 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 23 Apr 2020 14:05:13 +0300 Subject: [PATCH 004/226] Update ReleaseNotes.md --- ReleaseNotes.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index f4e7412eb816..f0cf1ed046f5 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,4 +1,20 @@ # TopJava Release Notes +### Topjava 19 +- Изменилась логика для интервалов времени (исключаем `endTime`) +- Заменил собственный `MessageUtil` велосипед на спринговый `MessageSourceAccessor` +- В ролях убрал префиксы `ROLE_` ([Role and GrantedAuthority](https://stackoverflow.com/a/19542316/548473)) +- Добавился удобный метод `int AbstractBaseEntity.id()` +- Фикс `Location` в `ProfileRestController.register` +- Фикс валидации `UniqueMailValidator` для REST update без `user.id` +- Заменил `jdbc.initLocation` на полный путь - IDEA не ругается +- В конфигурации `cargo-maven2-plugin` сделал [индивидуальный контекст приложения](https://stackoverflow.com/a/60797999/548473) +- Тесты + - Обновил даты еды на 2020г. + - Зарефакторил тесты сервисов на удаление - `NotFoundException` может бросаться при `delete()` + - В тестах контроллеров вернулся к реализации без обертки над `MockMvcRequestBuilders` + - Для `InMemory` тестов подключаю только `inmemory.xml` (добавил туда необходимую конфигурацию из `spring-app.xml`) + + ### Topjava 18 - В `ErrorType` добавил `HttpStatus status` From 2620c6f93e413d51271a5398e8545f3569036638 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 10 May 2020 23:16:00 +0300 Subject: [PATCH 005/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6b840eac3b03..f2777b677f7a 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ Java Enterprise Online Project - без циклов по другим коллекциям - решение должно быть рабочим в общем случае (не только при запуске main) - через Stream API за 1 проход по исходному списку `meals.streem()` - - нельзя использовать внешние коллекции, не являющиеся частью коллектора или 2 раза проходить по исходному списку (его копиям). + - нельзя использовать внешние коллекции, не являющиеся частью коллектора или 2 раза проходить по исходному списку (в том числе модифицированному, например отфильтрованому). Т.е. в решении не должно быть 2 раза `meal.stream()` (в том числе неявно, в составных коллекторах) - возможно дополнительные проходы по частям списка From 3449156db3deb9fb8cb0d4c8d9bd5e8809729304 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 10 May 2020 23:26:52 +0300 Subject: [PATCH 006/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f2777b677f7a..eece6c31d014 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ Java Enterprise Online Project - без циклов по другим коллекциям - решение должно быть рабочим в общем случае (не только при запуске main) - через Stream API за 1 проход по исходному списку `meals.streem()` - - нельзя использовать внешние коллекции, не являющиеся частью коллектора или 2 раза проходить по исходному списку (в том числе модифицированному, например отфильтрованому). + - нельзя использовать внешние коллекции, не являющиеся частью коллектора или 2 раза проходить по исходному списку (в том числе модифицированному, например отфильтрованному). Т.е. в решении не должно быть 2 раза `meal.stream()` (в том числе неявно, в составных коллекторах) - возможно дополнительные проходы по частям списка From 052adf67944cf47671f94293014fbcfce7caa270 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 13 May 2020 22:03:35 +0300 Subject: [PATCH 007/226] Update cv.md --- cv.md | 1 + 1 file changed, 1 insertion(+) diff --git a/cv.md b/cv.md index 60860899fb3c..f765942cf700 100644 --- a/cv.md +++ b/cv.md @@ -20,6 +20,7 @@ ### Наши истории (делимся опытом и успехом) ### Тесты/задачи онлайн: +-[Interviewing: the most profitable skill you can learn](https://www.pramp.com) - [Java Programming Test](https://tests4geeks.com/java) - game: test Java skills - Codility lesson tests From 7c31a8ee0c7a6f87064a23a6d69f8b053a4b1cbf Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 13 May 2020 22:04:00 +0300 Subject: [PATCH 008/226] Update cv.md --- cv.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cv.md b/cv.md index f765942cf700..51f5a7527ad9 100644 --- a/cv.md +++ b/cv.md @@ -20,7 +20,7 @@ ### Наши истории (делимся опытом и успехом) ### Тесты/задачи онлайн: --[Interviewing: the most profitable skill you can learn](https://www.pramp.com) +- [Interviewing: the most profitable skill you can learn](https://www.pramp.com) - [Java Programming Test](https://tests4geeks.com/java) - game: test Java skills - Codility lesson tests From 54f4ec0d6363ef814f3001f831b484dff60f3a7b Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 13 May 2020 22:05:03 +0300 Subject: [PATCH 009/226] Update cv.md --- cv.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cv.md b/cv.md index 51f5a7527ad9..a330bc3c71cb 100644 --- a/cv.md +++ b/cv.md @@ -20,7 +20,7 @@ ### Наши истории (делимся опытом и успехом) ### Тесты/задачи онлайн: -- [Interviewing: the most profitable skill you can learn](https://www.pramp.com) +- [Interviewing: the most profitable skill you can learn (pramp.com)](https://www.pramp.com/) - [Java Programming Test](https://tests4geeks.com/java) - game: test Java skills - Codility lesson tests @@ -29,7 +29,6 @@ - Sphere online judge - Codility programmers lessons - Hackerrank practice coding -- [Interviewing: the most profitable skill you can learn (pramp.com)](https://www.pramp.com/) - [start.interviewing.io](https://start.interviewing.io/) ## [Тестовое собеседование, самые спрашиваемые темы](http://javaops.ru/interview/test.html) From 5fe982c3fa982a20b6d31aee74dfc15bfff8ab62 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 17 May 2020 23:21:23 +0300 Subject: [PATCH 010/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eece6c31d014..a91e1e814c5a 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ Java Enterprise Online Project ### Полезные ресурсы > ВНИМАНИЕ: -> - **ДЗ первого урока будет связано с [созданием небольшого CRUD приложения (в памяти, без DB) на JSP и сервлетах](http://danielniko.com/2012/04/17/simple-crud-using-jsp-servlet-and-mysql/)**. Введение будет, но предварительное знакомство не помешает. +> - **ДЗ первого урока будет связано с [созданием небольшого CRUD приложения (в памяти, без DB) на JSP и сервлетах](https://danielniko.wordpress.com/2012/04/17/simple-crud-using-jsp-servlet-and-mysql/)**. Введение будет, но предварительное знакомство не помешает. > - основы JavaSсript необходимы для понимания проекта, начиная с 8-го занятия! Все остальное - опционально. From c2180201f5095afdaf632c3e71681acf44d56014 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 19 May 2020 11:43:39 +0300 Subject: [PATCH 011/226] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a91e1e814c5a..040f70a6e44e 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,8 @@ Java Enterprise Online Project - Шпаргалка Java Stream API - Алексея Владыкин: Элементы функционального программирования в Java - Yakov Fain о новом в Java 8 -- stream.map vs forEach +- stream.map vs forEach Date: Tue, 19 May 2020 11:45:35 +0300 Subject: [PATCH 012/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 040f70a6e44e..f7cefcd90fb8 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ Java Enterprise Online Project Т.е. в решении не должно быть 2 раза `meal.stream()` (в том числе неявно, в составных коллекторах) - возможно дополнительные проходы по частям списка -- [Полное руководство по Java 8 Stream API в картинках и примерах](https://easyjava.ru/java/language/java-8-stream-api-chast-shestaya-sobstvennyj-kollektor/) +- [Java 8 Stream API, часть шестая: собственный коллектор](https://easyjava.ru/java/language/java-8-stream-api-chast-shestaya-sobstvennyj-kollektor) - [Руководство по Java 8 Stream API: Collector](https://annimon.com/article/2778#collector) ### Замечания по использованию Stream API: From 3b91874e6df53a7d7fcebb7efa8fc0bf40ad2be9 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 19 May 2020 11:46:05 +0300 Subject: [PATCH 013/226] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index f7cefcd90fb8..6a58dbce5545 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,6 @@ Java Enterprise Online Project - нельзя использовать внешние коллекции, не являющиеся частью коллектора или 2 раза проходить по исходному списку (в том числе модифицированному, например отфильтрованному). Т.е. в решении не должно быть 2 раза `meal.stream()` (в том числе неявно, в составных коллекторах) - возможно дополнительные проходы по частям списка - - [Java 8 Stream API, часть шестая: собственный коллектор](https://easyjava.ru/java/language/java-8-stream-api-chast-shestaya-sobstvennyj-kollektor) - [Руководство по Java 8 Stream API: Collector](https://annimon.com/article/2778#collector) From 18f0374c537cd28f46b4e1db8f98fc5088f8ac9a Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 19 May 2020 11:47:22 +0300 Subject: [PATCH 014/226] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 6a58dbce5545..d3a4c1e67cec 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,8 @@ Java Enterprise Online Project - нельзя использовать внешние коллекции, не являющиеся частью коллектора или 2 раза проходить по исходному списку (в том числе модифицированному, например отфильтрованному). Т.е. в решении не должно быть 2 раза `meal.stream()` (в том числе неявно, в составных коллекторах) - возможно дополнительные проходы по частям списка + +Ресурсы: - [Java 8 Stream API, часть шестая: собственный коллектор](https://easyjava.ru/java/language/java-8-stream-api-chast-shestaya-sobstvennyj-kollektor) - [Руководство по Java 8 Stream API: Collector](https://annimon.com/article/2778#collector) From ba240e81eca53c90ca40ec4bfa771393bc8ef71e Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 20 May 2020 22:16:40 +0300 Subject: [PATCH 015/226] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d3a4c1e67cec..8755b22281f5 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,8 @@ Java Enterprise Online Project - [Git - для новичков](https://www.youtube.com/watch?list=PLY4rE9dstrJyTdVJpv7FibSaXB4BHPInb&v=PEKN8NtBDQ0) ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. Работа с проектом (выполнять инструкции) -**ВНИМАНИЕ: выбирайте для проекта простой пусть без пробелов и русских букв, например (Windows) `c:\projects\topjava\`. Иначе впоследствии будут проблемы** +- **ВНИМАНИЕ: выбирайте для проекта простой пусть без пробелов и русских букв, например (Windows) `c:\projects\topjava\`. Иначе впоследствии будут проблемы** +- **Плагин уже Git Intergation не требуется и вкладку `Version control` в IDEA переименовали в `Git`** ### Патч [prepare_to_HW0.patch](https://drive.google.com/file/d/1LNPpu9OkuCpfpD8ZJHO-o0vwu49p2i5M) (скачать и положить в каталог вашего проекта) > Проект постоянно улучшается, поэтому видео иногда отличается от кода проекта. Изменения указываю после видео: From 7eb4a67c93f47950a420d561b7de6956c1a9eb1b Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sat, 23 May 2020 19:10:30 +0300 Subject: [PATCH 016/226] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8755b22281f5..777992140667 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ Java Enterprise Online Project - Git Overview - [Основы Git за 20 минут](https://www.youtube.com/watch?v=TMeZGvtQnT8) - [Git - для новичков](https://www.youtube.com/watch?list=PLY4rE9dstrJyTdVJpv7FibSaXB4BHPInb&v=PEKN8NtBDQ0) + - [Руководство по написанию комментариев в коммитах](https://techrocks.ru/2019/12/02/writing-good-commit-messages) ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. Работа с проектом (выполнять инструкции) - **ВНИМАНИЕ: выбирайте для проекта простой пусть без пробелов и русских букв, например (Windows) `c:\projects\topjava\`. Иначе впоследствии будут проблемы** From efd86a06ca26f316d5a38a58de6b887789c7cd36 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 24 May 2020 01:00:39 +0300 Subject: [PATCH 017/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 777992140667..754e9d2cdf25 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ Java Enterprise Online Project - 10: `System.out.println` нельзя делать нигде, кроме как в `main`. Позже введем логирование. - 11: Результаты, возвращаемые `UserMealsUtil.filteredByStreams` мы будем использовать [в нашем приложении](http://topjava.herokuapp.com/) для фильтрации по времени и отображения еды правильным цветом. - 12: Обращайте внимание на комментарии к вашим коммитам в git. Они должны быть короткие и информативные (лучше на english) -- 13: Не полагайтесь в решении на то, что список будет подаваться отсортированным. Такого условия нет. +- 13: Не полагайтесь в решении на то, что список еды будет подаваться отсортированным. Такого условия нет. ----- ## [Пример 7-го занятия онлайн стажировки, несколько видео открыто](https://github.com/JavaOPs/topjava/blob/master/doc/lesson07.md) From 628eb10dea9635fd23acb08b6477f897d14426d8 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 24 May 2020 13:32:50 +0300 Subject: [PATCH 018/226] Update graduation.md --- graduation.md | 1 + 1 file changed, 1 insertion(+) diff --git a/graduation.md b/graduation.md index 6e4af3e023cc..c1cb45c337b2 100644 --- a/graduation.md +++ b/graduation.md @@ -66,6 +66,7 @@ _Антуан де Сент-Экзюпери_ - 21: Проверьте, станет ли код проще с `@AuthenticationPrincipal` (урок 11, Доступ к AuthorizedUser). - 22: Не размещайте логику приложения и преобразования в TO в слое доступа к DB - 23: Если используете кэширование, **тщательно продумайте, что надо кэшировать (самые частые запросы)**, а что нет (большие или редкозапрашиваемые данные)! +- 24: Если задание на English, `readme.md` тоже пишите на English. То же самое относится к языку резюме: вакансия на English предполагает ваше резюме на English. ## Попробуйте подергать свое API по всем типичным сценариям ТЗ! - Удобно использовать? Можно сделать проще? Например чтобы проголосовать за ресторан залогиненному юзеру достаточно `restorauntId`. From c7a9d42c53c720477944de607b83e722ef3fb750 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 24 May 2020 13:37:51 +0300 Subject: [PATCH 019/226] Update graduation.md --- graduation.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/graduation.md b/graduation.md index c1cb45c337b2..60fdff4b9d1d 100644 --- a/graduation.md +++ b/graduation.md @@ -66,7 +66,10 @@ _Антуан де Сент-Экзюпери_ - 21: Проверьте, станет ли код проще с `@AuthenticationPrincipal` (урок 11, Доступ к AuthorizedUser). - 22: Не размещайте логику приложения и преобразования в TO в слое доступа к DB - 23: Если используете кэширование, **тщательно продумайте, что надо кэшировать (самые частые запросы)**, а что нет (большие или редкозапрашиваемые данные)! -- 24: Если задание на English, `readme.md` тоже пишите на English. То же самое относится к языку резюме: вакансия на English предполагает ваше резюме на English. +- 24: `readme.md`: + - Если задание на English, описание пишите также на English (то же самое относится к языку резюме: вакансия на English предполагает ваше резюме на English) + - Требуемые примеры `curl` не прячте- пишите здесь! + - Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven:) ## Попробуйте подергать свое API по всем типичным сценариям ТЗ! - Удобно использовать? Можно сделать проще? Например чтобы проголосовать за ресторан залогиненному юзеру достаточно `restorauntId`. From 7d0145036d3e3e1c69fd053cb6195379aaf9c9ff Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 27 May 2020 13:45:01 +0300 Subject: [PATCH 020/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 754e9d2cdf25..379464cf4f6b 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ Java Enterprise Online Project - [Сергей Куксенко — Stream API, часть 1](https://www.youtube.com/watch?v=O8oN4KSZEXE) - [Сергей Куксенко — Stream API, часть 2](https://www.youtube.com/watch?v=i0Jr2l3jrDA) -### Optional 2 (+5 бонусов) +### Optional 2 (+5 бонусов, только после выполнения базового и Optional задания!) Сделать реализацию со сложностью O(N) (обратите внимание на п.13 замечаний): - циклом за 1 проход по `List` - без циклов по другим коллекциям From 6464f3cab8aa6fdfd9732d83ee15e972dc9809b7 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 27 May 2020 16:02:09 +0300 Subject: [PATCH 021/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 379464cf4f6b..39f4548d8b6f 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ Java Enterprise Online Project ### Optional 2 (+5 бонусов, только после выполнения базового и Optional задания!) Сделать реализацию со сложностью O(N) (обратите внимание на п.13 замечаний): - циклом за 1 проход по `List` - - без циклов по другим коллекциям + - без циклов по другим коллекциям (к ним также относим методы коллекций `addAll()/removeAll()`) - решение должно быть рабочим в общем случае (не только при запуске main) - через Stream API за 1 проход по исходному списку `meals.streem()` - нельзя использовать внешние коллекции, не являющиеся частью коллектора или 2 раза проходить по исходному списку (в том числе модифицированному, например отфильтрованному). From 8f2c0376054663ce5c73dcbb68a7a2d3cdab6298 Mon Sep 17 00:00:00 2001 From: JavaOPs Date: Thu, 28 May 2020 11:32:08 +0300 Subject: [PATCH 022/226] Update graduate --- graduation.md | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/graduation.md b/graduation.md index 60fdff4b9d1d..af0f4f74078c 100644 --- a/graduation.md +++ b/graduation.md @@ -26,7 +26,7 @@ P.P.S.: Asume that your API will be used by a frontend developer to build fronte ----------------------------- ### ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Рекомендации -- Если ты закончил [стажировку Topjava](http://javaops.ru/reg/topjava/grd), **cделай новый проект и добавляй туда из Topjava только то что нужно!** Локализация, типы ошибок, BeanMatcher, Json View, излишние делегирования и наследования - **не нужны!** +- **Сделай новый проект и добавляй туда из Topjava только то что нужно! Локализация, типы ошибок, BeanMatcher, Json View, излишние делегирования и наследования - не нужны!** - **API продумывай с точки зрения не программиста и объектов, а с точки зрения того, кто им будет пользоваться (frontend)** - **Сначала сделай основной сценарий по ТЗ. Все остальное (если очень хочется, 3 раза подумай) - потом.** @@ -45,27 +45,36 @@ _Антуан де Сент-Экзюпери_ - 5.2 НЕ надо делать абстрактных контроллеров на всякий случай. - 5.3 НЕ надо делать **классов репозиториев и сервисов**, если там нет ничего, кроме делегирования. - 5.4 Из потребностей приложения (которую надо самим придумать) реализовывать только очевидные сценарии. Те.- НИЧЕГО ЛИШНЕГО. -- 6: базу лучше взять без установки (H2 или HSQLDB). Ваше приложение должно сразу запуститься, **без всяких настроек и переменных окружения** +- 6: База Данных + - берите без установки (H2 или HSQLDB). Одну!! Ваше приложение должно сразу запуститься, **без всяких настроек и переменных окружения** + - сделайте индексы к таблицам. Попробуйте обеспечит UNIQUE (один голос пользователя в день, один уникальный пункт меню в день). Следите за порядком полей в индексе. + - **историю еды и голосований сделать НУЖНО! Есть базовые вещи, которые закладываются в архитектуру приложения и неочевидные доработки к ТЗ, которых лучше не делать.** - 7: по возможности сделать JUnit тесты - 8: уделяйте внимание обработке ошибок -- 9: далаем REST API в соответствии с концепцией REST - - [15 тривиальных фактов о правильной работе с протоколом HTTP](https://habrahabr.ru/company/yandex/blog/265569/) - - 10 Best Practices for Better RESTful API +- 9: далаем REST API в соответствии с концепцией REST (url в общем имеют вид`{ресурс}/{id_ресурсa}[/{подресурс}/{id_подресурсa}][параметры]`) + - **[15 тривиальных фактов о правильной работе с протоколом HTTP](https://habrahabr.ru/company/yandex/blog/265569/)** + - **10 Best Practices for Better RESTful API** - [REST resource hierarchy](https://stackoverflow.com/questions/20951419/what-are-best-practices-for-rest-nested-resources) - 10: не смешивайте TO и Entity вместе. Лучше всего, если они будут независимыми друг от друга. -- 11: если приложению в объекте требуется только его id, используйте reference (как мы при сохранении еды вставляем туда юзера) -- 12: [Use for money in java app](http://stackoverflow.com/a/43051227/548473) -- 13: **Историю еды и голосований сделать НУЖНО! Есть базовые вещи, которые закладываются в архитектуру приложения и неочевидные доработки к ТЗ, которых лучше не делать.** -- 14: Еще раз про [hashCode/equals в Entity](https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma): не делайте сравнение по полям! -- 15: Название пакетов, имен классов для `model/to/web` достаточно стандартные (например `model/domain`). НЕ надо придумывать своих собственных правил. +- 11: не размещайте логику приложения и преобразования в TO в слое доступа к DB +- 12: если приложению в объекте требуется только его id, используйте reference (как мы при сохранении еды вставляем туда юзера) +- 13: [Use for money in java app](http://stackoverflow.com/a/43051227/548473) +- 14: еще раз про [hashCode/equals в Entity](https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma): не делайте сравнение по полям! +- 15: название пакетов, имен классов для `model/to/web` достаточно стандартные (например `model/domain`). НЕ надо придумывать своих собственных правил. - 16: **Используйте DATA-JPA** (можно без лишней делегации, напрямую из сервиса/контроллера дергать Repository). -- 17: В DATA-JPA 2.x используются `Optional`. Попробуйте работать с ними, это безопасный способ работать с null значениями (используйте `orElseThrow`). -- 18: На topjava мы смотрели разные варианты использования, тут делаем максимально просто. С TO многие вещи упрощаются. -- 19: Проверьте, не торчат ли из кода учебные уши topjava, типа `ProfileRestController.testUTF()`, `AbstractServiceTest.printResult()` или закомментированные `JdbcTemplate`. Назначение этого проекта совсем другое. +- 17: в DATA-JPA 2.x используются `Optional`. Попробуйте работать с ними, это безопасный способ работать с null значениями (используйте `orElseThrow`). +- 18: на topjava мы смотрели разные варианты использования, тут делаем максимально просто. С TO многие вещи упрощаются. +- 19: проверьте, не торчат ли из кода учебные уши topjava, типа `ProfileRestController.testUTF()`, `AbstractServiceTest.printResult()` или закомментированные `JdbcTemplate`. Назначение этого проекта совсем другое. - 20: ORM работает с объектами. [В простейших случаях fk_id как поля допустимы](https://stackoverflow.com/questions/6311776/hibernate-foreign-keys-instead-of-entities), но при этом JPA их уже никак не обрабатывает и не используйте их вместе с объектами. Ссылка на stackoverwrflow в коде обязательна! -- 21: Проверьте, станет ли код проще с `@AuthenticationPrincipal` (урок 11, Доступ к AuthorizedUser). -- 22: Не размещайте логику приложения и преобразования в TO в слое доступа к DB -- 23: Если используете кэширование, **тщательно продумайте, что надо кэшировать (самые частые запросы)**, а что нет (большие или редкозапрашиваемые данные)! +- 21: проверьте, станет ли код проще с `@AuthenticationPrincipal` (урок 11, Доступ к AuthorizedUser). +- 22: Кэширование + - необязательно, но желательно + - **тщательно продумайте, что надо кэшировать (самые частые запросы)**, а что нет (большие или редкозапрашиваемые данные)! + - проверьте соответствие ключей к кэшу (параметры кэшируемого метода) с конфигурацией (например в singleNonExpiryCache, heap=1 в кэше может содержаться только ОДНО значение). +- 23: Валидация + - желательна + - одних аннотаций недостаточно. Должны быть `@Valid/@Validation` + - проверяйте входные данные при `create/update` в контроллерах! В TopJava это `ValidationUtil.checkNew()/assureIdConsistent()` - 24: `readme.md`: - Если задание на English, описание пишите также на English (то же самое относится к языку резюме: вакансия на English предполагает ваше резюме на English) - Требуемые примеры `curl` не прячте- пишите здесь! From 79efab669a610cb09e16621ff25d9240046911cf Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 31 May 2020 23:26:28 +0300 Subject: [PATCH 023/226] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 39f4548d8b6f..c0d69a45fe7e 100644 --- a/README.md +++ b/README.md @@ -119,12 +119,12 @@ Java Enterprise Online Project ### Optional 2 (+5 бонусов, только после выполнения базового и Optional задания!) Сделать реализацию со сложностью O(N) (обратите внимание на п.13 замечаний): - циклом за 1 проход по `List` - - без циклов по другим коллекциям (к ним также относим методы коллекций `addAll()/removeAll()`) - - решение должно быть рабочим в общем случае (не только при запуске main) + - без циклов по другим коллекциям/массивам (к ним также относим методы коллекций `addAll()/removeAll()`) + - решение должно быть рабочим в общем случае (работать в приложении с многими пользователями, не только при запуске main) - через Stream API за 1 проход по исходному списку `meals.streem()` - - нельзя использовать внешние коллекции, не являющиеся частью коллектора или 2 раза проходить по исходному списку (в том числе модифицированному, например отфильтрованному). - Т.е. в решении не должно быть 2 раза `meal.stream()` (в том числе неявно, в составных коллекторах) - - возможно дополнительные проходы по частям списка + - нельзя использовать внешние коллекции, не являющиеся частью коллектора + - возможно дополнительные проходы по частям списка, при этом превышение должно считаться один раз для всего подсписка. Те например нельзя разбить список на на 2 подсписка с четными и нечетными датами и затем их объединить, с подсчетом превышения для каждого элемента. + Ресурсы: - [Java 8 Stream API, часть шестая: собственный коллектор](https://easyjava.ru/java/language/java-8-stream-api-chast-shestaya-sobstvennyj-kollektor) From 7664bb38066ab8843696b719a8bdc13a3e138e07 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 4 Jun 2020 18:14:35 +0300 Subject: [PATCH 024/226] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c0d69a45fe7e..f2020bbfcd53 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,7 @@ Java Enterprise Online Project - решение должно быть рабочим в общем случае (работать в приложении с многими пользователями, не только при запуске main) - через Stream API за 1 проход по исходному списку `meals.streem()` - нельзя использовать внешние коллекции, не являющиеся частью коллектора + - нельзя 2 раза проходить по исходному списку (в том числе его отфильтрованной копии) - возможно дополнительные проходы по частям списка, при этом превышение должно считаться один раз для всего подсписка. Те например нельзя разбить список на на 2 подсписка с четными и нечетными датами и затем их объединить, с подсчетом превышения для каждого элемента. From 2cf32713038aae3a29ed2bb3f49ce8ca75ac9068 Mon Sep 17 00:00:00 2001 From: "admin@javaops.ru" Date: Thu, 4 Jun 2020 18:27:09 +0300 Subject: [PATCH 025/226] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f2020bbfcd53..638048568128 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Java Enterprise Online Project > - в `UserMeals/UserMealWithExcess` поля изменились на `private` > - обновил данные `UserMealsUtil.meals` и переименовал некоторые пременные, поля и методы > - добавил `UserMealWithExcess.toString()` и метод для выполнения _Optional домашнего задания_ - +> - метод фильтрации в `TimeUtil` переименовали в `isBetweenHalfOpen` (также изменилась логика сравнения - `startTime` включается в интервал) ## Инструкция по шагам (из видео): - Установить ПО (git, JDK8, IntelliJ IDEA, Maven) From 4331b732f57e2bbef144489026f07581d1fa0d6f Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 17 Jun 2020 15:35:54 +0300 Subject: [PATCH 026/226] Update graduation.md --- graduation.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/graduation.md b/graduation.md index af0f4f74078c..4580cd250957 100644 --- a/graduation.md +++ b/graduation.md @@ -67,15 +67,16 @@ _Антуан де Сент-Экзюпери_ - 19: проверьте, не торчат ли из кода учебные уши topjava, типа `ProfileRestController.testUTF()`, `AbstractServiceTest.printResult()` или закомментированные `JdbcTemplate`. Назначение этого проекта совсем другое. - 20: ORM работает с объектами. [В простейших случаях fk_id как поля допустимы](https://stackoverflow.com/questions/6311776/hibernate-foreign-keys-instead-of-entities), но при этом JPA их уже никак не обрабатывает и не используйте их вместе с объектами. Ссылка на stackoverwrflow в коде обязательна! - 21: проверьте, станет ли код проще с `@AuthenticationPrincipal` (урок 11, Доступ к AuthorizedUser). -- 22: Кэширование +- 22: обновление в базе делается через `update`, даже если `delete/insert` сократит java код на несколько строк +- 23: Кэширование - необязательно, но желательно - **тщательно продумайте, что надо кэшировать (самые частые запросы)**, а что нет (большие или редкозапрашиваемые данные)! - проверьте соответствие ключей к кэшу (параметры кэшируемого метода) с конфигурацией (например в singleNonExpiryCache, heap=1 в кэше может содержаться только ОДНО значение). -- 23: Валидация +- 24: Валидация - желательна - одних аннотаций недостаточно. Должны быть `@Valid/@Validation` - проверяйте входные данные при `create/update` в контроллерах! В TopJava это `ValidationUtil.checkNew()/assureIdConsistent()` -- 24: `readme.md`: +- 25: `readme.md`: - Если задание на English, описание пишите также на English (то же самое относится к языку резюме: вакансия на English предполагает ваше резюме на English) - Требуемые примеры `curl` не прячте- пишите здесь! - Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven:) From 64590f1ca576fbc18c743227f61ca33eb21c14f4 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 17 Jun 2020 15:44:52 +0300 Subject: [PATCH 027/226] Update graduation.md --- graduation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graduation.md b/graduation.md index 4580cd250957..3c8d83d87b49 100644 --- a/graduation.md +++ b/graduation.md @@ -39,7 +39,7 @@ _Антуан де Сент-Экзюпери_ - 1: **читаем ТЗ ОЧЕНЬ внимательно, НЕ надо ничего своего туда домысливать и творчески изменять** - 2: **тщательно считайте количество обращений в базу на каждый запрос. Особенно при запросах от юзеров, которых очень много! Также на сложность запросов от них, чтобы не положить базу** - 3: **тщательно считайте количество запросов в вашем API для отображения нужной информации** -- 4: **учитывайте, что пользователей может быть ооочень много, а админов- мало** +- 4: учитывайте, что **пользователей может быть ОООЧЕНЬ много, а админов - МАЛО** - 5: в проекте (и тестовом задании на работу) в отличие от нашего учебного topjava оставляйте только необходимый для работы приложения код, ничего лишнего: - 5.1 НЕ надо делать разные профили базы и работы с ней. - 5.2 НЕ надо делать абстрактных контроллеров на всякий случай. From 3823848bb585a052d04d6f55c4654e8a6c25b0ea Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 20 Sep 2020 15:47:52 +0300 Subject: [PATCH 028/226] Update graduation.md --- graduation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graduation.md b/graduation.md index 3c8d83d87b49..7dd13808b7e1 100644 --- a/graduation.md +++ b/graduation.md @@ -37,7 +37,7 @@ P.P.S.: Asume that your API will be used by a frontend developer to build fronte _Антуан де Сент-Экзюпери_ - 1: **читаем ТЗ ОЧЕНЬ внимательно, НЕ надо ничего своего туда домысливать и творчески изменять** -- 2: **тщательно считайте количество обращений в базу на каждый запрос. Особенно при запросах от юзеров, которых очень много! Также на сложность запросов от них, чтобы не положить базу** +- 2: **тщательно считайте количество обращений в базу на каждый запрос. Особенно при запросах от юзеров, которых очень много! Также на сложность запросов от них, чтобы не положить базу**. Самое худшее в коде - обращение в базу в цикле. - 3: **тщательно считайте количество запросов в вашем API для отображения нужной информации** - 4: учитывайте, что **пользователей может быть ОООЧЕНЬ много, а админов - МАЛО** - 5: в проекте (и тестовом задании на работу) в отличие от нашего учебного topjava оставляйте только необходимый для работы приложения код, ничего лишнего: From f2d884f882826c78d00020049f42a5d81cf1c3ae Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 20 Sep 2020 15:49:23 +0300 Subject: [PATCH 029/226] Update graduation.md --- graduation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graduation.md b/graduation.md index 7dd13808b7e1..34809fc454db 100644 --- a/graduation.md +++ b/graduation.md @@ -61,7 +61,7 @@ _Антуан де Сент-Экзюпери_ - 13: [Use for money in java app](http://stackoverflow.com/a/43051227/548473) - 14: еще раз про [hashCode/equals в Entity](https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma): не делайте сравнение по полям! - 15: название пакетов, имен классов для `model/to/web` достаточно стандартные (например `model/domain`). НЕ надо придумывать своих собственных правил. -- 16: **Используйте DATA-JPA** (можно без лишней делегации, напрямую из сервиса/контроллера дергать Repository). +- 16: **Используйте DATA-JPA** (сделайте без лишней делегации, напрямую из сервиса/контроллера дергать Repository). - 17: в DATA-JPA 2.x используются `Optional`. Попробуйте работать с ними, это безопасный способ работать с null значениями (используйте `orElseThrow`). - 18: на topjava мы смотрели разные варианты использования, тут делаем максимально просто. С TO многие вещи упрощаются. - 19: проверьте, не торчат ли из кода учебные уши topjava, типа `ProfileRestController.testUTF()`, `AbstractServiceTest.printResult()` или закомментированные `JdbcTemplate`. Назначение этого проекта совсем другое. From fd2d8522aab499c9aae6d12832b91d8f48bd68cb Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 20 Sep 2020 16:46:23 +0300 Subject: [PATCH 030/226] Update graduation.md --- graduation.md | 1 + 1 file changed, 1 insertion(+) diff --git a/graduation.md b/graduation.md index 34809fc454db..d947b113c79f 100644 --- a/graduation.md +++ b/graduation.md @@ -49,6 +49,7 @@ _Антуан де Сент-Экзюпери_ - берите без установки (H2 или HSQLDB). Одну!! Ваше приложение должно сразу запуститься, **без всяких настроек и переменных окружения** - сделайте индексы к таблицам. Попробуйте обеспечит UNIQUE (один голос пользователя в день, один уникальный пункт меню в день). Следите за порядком полей в индексе. - **историю еды и голосований сделать НУЖНО! Есть базовые вещи, которые закладываются в архитектуру приложения и неочевидные доработки к ТЗ, которых лучше не делать.** + - при популировании добавте записи за сегодняшний день - now(), чтобы всегда были актуальные исходные данные - 7: по возможности сделать JUnit тесты - 8: уделяйте внимание обработке ошибок - 9: далаем REST API в соответствии с концепцией REST (url в общем имеют вид`{ресурс}/{id_ресурсa}[/{подресурс}/{id_подресурсa}][параметры]`) From b2b9a19dbf33f24e9a1e532c6d74a498328370e1 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 20 Sep 2020 22:20:46 +0300 Subject: [PATCH 031/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 638048568128..38831adc6f29 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ Java Enterprise Online Project - решение должно быть рабочим в общем случае (работать в приложении с многими пользователями, не только при запуске main) - через Stream API за 1 проход по исходному списку `meals.streem()` - нельзя использовать внешние коллекции, не являющиеся частью коллектора - - нельзя 2 раза проходить по исходному списку (в том числе его отфильтрованной копии) + - нельзя 2 раза проходить по исходному списку (в том числе его отфильтрованной или преобразованной копии) - возможно дополнительные проходы по частям списка, при этом превышение должно считаться один раз для всего подсписка. Те например нельзя разбить список на на 2 подсписка с четными и нечетными датами и затем их объединить, с подсчетом превышения для каждого элемента. From 7c7e37e548ddc01369ff9448a1a9d390be387141 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 21 Sep 2020 17:37:53 +0300 Subject: [PATCH 032/226] Update graduation.md --- graduation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graduation.md b/graduation.md index d947b113c79f..208ee73c69cb 100644 --- a/graduation.md +++ b/graduation.md @@ -76,7 +76,7 @@ _Антуан де Сент-Экзюпери_ - 24: Валидация - желательна - одних аннотаций недостаточно. Должны быть `@Valid/@Validation` - - проверяйте входные данные при `create/update` в контроллерах! В TopJava это `ValidationUtil.checkNew()/assureIdConsistent()` + - проверяйте входные данные при `create/update` **в контроллерах!** В TopJava это `ValidationUtil.checkNew()/assureIdConsistent()` - 25: `readme.md`: - Если задание на English, описание пишите также на English (то же самое относится к языку резюме: вакансия на English предполагает ваше резюме на English) - Требуемые примеры `curl` не прячте- пишите здесь! From 9c995f9b94680892e8e805462de14e1797aebc29 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 24 Sep 2020 14:26:51 +0300 Subject: [PATCH 033/226] Update graduation.md --- graduation.md | 1 + 1 file changed, 1 insertion(+) diff --git a/graduation.md b/graduation.md index 208ee73c69cb..a4468a0f8ec9 100644 --- a/graduation.md +++ b/graduation.md @@ -50,6 +50,7 @@ _Антуан де Сент-Экзюпери_ - сделайте индексы к таблицам. Попробуйте обеспечит UNIQUE (один голос пользователя в день, один уникальный пункт меню в день). Следите за порядком полей в индексе. - **историю еды и голосований сделать НУЖНО! Есть базовые вещи, которые закладываются в архитектуру приложения и неочевидные доработки к ТЗ, которых лучше не делать.** - при популировании добавте записи за сегодняшний день - now(), чтобы всегда были актуальные исходные данные + - таблицы обычно именуются в единственном числе. Исключение - users, т. к. user - зарезервированное слово. `date`/`timestamp` - зарезервированное слово, лучше избегать их при именовании - 7: по возможности сделать JUnit тесты - 8: уделяйте внимание обработке ошибок - 9: далаем REST API в соответствии с концепцией REST (url в общем имеют вид`{ресурс}/{id_ресурсa}[/{подресурс}/{id_подресурсa}][параметры]`) From 00424a0eaa980dcfcacc6bc6a9bef81b4472b983 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 28 Sep 2020 22:45:15 +0300 Subject: [PATCH 034/226] Update ReleaseNotes.md --- ReleaseNotes.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index f0cf1ed046f5..bf225b9b0647 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,4 +1,15 @@ # TopJava Release Notes + +### Topjava 20 +- мигрировали на JDK 14 +- в `@SafeHtml` запрещаем весь html (`whitelistType = NONE`) +- в API добавили `/users/{id}/with-meals` (см. [двунаправленные отношения](https://www.codeflow.site/ru/article/jackson-bidirectional-relationships-and-infinite-recursion)) +- в js убрал объект контекст, передаю 3-мя параметрами +- в UI контроллерах убрал префикс `ajax` +- из тестов сервисов убрал `repository`. При проверке через `assertThrows` он не требуется +- в `TestMatcher` сценарии сравнения сделал параметризируемыми (паттерн стратегия) +- добавил `UserTestData.USER_WITH_MEALS_MATCHER` (проверки пользователя сразу с едой) и константу id `NOT_FOUND` + ### Topjava 19 - Изменилась логика для интервалов времени (исключаем `endTime`) - Заменил собственный `MessageUtil` велосипед на спринговый `MessageSourceAccessor` From 61cd81364ee3d2247ef9a53958d23d21a8671f6b Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 28 Sep 2020 22:50:02 +0300 Subject: [PATCH 035/226] Update ReleaseNotes.md --- ReleaseNotes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index bf225b9b0647..b102200d7ac1 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -3,11 +3,11 @@ ### Topjava 20 - мигрировали на JDK 14 - в `@SafeHtml` запрещаем весь html (`whitelistType = NONE`) -- в API добавили `/users/{id}/with-meals` (см. [двунаправленные отношения](https://www.codeflow.site/ru/article/jackson-bidirectional-relationships-and-infinite-recursion)) -- в js убрал объект контекст, передаю 3-мя параметрами +- в `topjava.common.js` в `makeEditable()` вместо объекта контекст передаю 3 параметра - в UI контроллерах убрал префикс `ajax` - из тестов сервисов убрал `repository`. При проверке через `assertThrows` он не требуется - в `TestMatcher` сценарии сравнения сделал параметризируемыми (паттерн стратегия) +- в API добавили `/users/{id}/with-meals` (см. [двунаправленные отношения](https://www.codeflow.site/ru/article/jackson-bidirectional-relationships-and-infinite-recursion)) - добавил `UserTestData.USER_WITH_MEALS_MATCHER` (проверки пользователя сразу с едой) и константу id `NOT_FOUND` ### Topjava 19 From 91841cb912cc4ff8711016f34a166cfe94789469 Mon Sep 17 00:00:00 2001 From: "admin@javaops.ru" Date: Thu, 29 Oct 2020 14:10:49 +0300 Subject: [PATCH 036/226] fix grammar --- ReleaseNotes.md | 2 +- description.md | 125 +++++++++++++++++++++++------------------------- graduation.md | 40 ++++++++-------- 3 files changed, 81 insertions(+), 86 deletions(-) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index b102200d7ac1..65a0c209f4c1 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -29,7 +29,7 @@ ### Topjava 18 - В `ErrorType` добавил `HttpStatus status` -- В PostgreSQL обнаружилась бага: граничное значение `0:00` из за ошибок округления попадает в предыдущий интервал. +- В PostgreSQL обнаружилась бага: граничное значение `0:00` из-за ошибок округления попадает в предыдущий интервал. Мораль: всегда в тестах проверяйте граничные значения. Добавил этот случай в тестовые данные. - Изменил `MealRepository.getBetween` (принимаю `@Nullable LocalDate`). Изменились реализации. - Выделил метод `UserService.prepareAndSave` diff --git a/description.md b/description.md index d2448ca99e57..0619c6d9516d 100644 --- a/description.md +++ b/description.md @@ -1,77 +1,72 @@ #### Разработка полнофункционального Spring/JPA Enterprise приложения c авторизацией и правами доступа на основе ролей с использованием наиболее популярных инструментов и технологий Java: Maven, Spring MVC, Security, JPA(Hibernate), REST(Jackson), Bootstrap (css,js), datatables, jQuery + plugins, Java 8 Stream and Time API и сохранением в базах данных Postgresql и HSQLDB. -- Основное внимание будет уделяться способам решения многочисленных проблем разработки в Spring/JPA, а также структурному (красивому и надежному) java кодированию и архитектуре приложения. -- Каждая итерация проекта закрепляется домашним заданием по реализации схожей функциональности. Следующее занятие начинается с разбора домашних заданий. -- Большое внимание уделяется тестированию кода: в проекте более 100 JUnit тестов. -- Несмотря на относительно небольшой размер, приложение разрабатывается с нуля как большой проект (например мы используем кэш 2-го уровня Hibernate, настраиваем Jackson для работы с ленивой загрузкой +- Основное внимание будет уделяться способам решения многочисленных проблем разработки в Spring/JPA, а также структурному (красивому и надежному) java кодированию и архитектуре приложения. +- Каждая итерация проекта закрепляется домашним заданием по реализации схожей функциональности. Следующее занятие начинается с разбора домашних заданий. +- Большое внимание уделяется тестированию кода: в проекте более 100 JUnit тестов. +- Несмотря на относительно небольшой размер, приложение разрабатывается с нуля как большой проект (например, мы используем кэш 2-го уровня Hibernate, настраиваем Jackson для работы с ленивой загрузкой Hibernate, делаем конверторы для типов LocalDateTime (Java 8 time API). - Разбираются архитектурные паттерны: слои приложения и как правильно разбивать логику по слоям, когда нужно применять Data Transfer Object. - Т.е на выходе получается не учебный проект, а хорошо маштабируемый шаблон для большого проекта на всех пройденных технологиях. -- Большое внимание уделяется деталям: популяция базы, использование транзакционности, тесты сервисов и REST - контроллеров, насторойка EntityManagerFactory, - выбор реализации пула коннектов. Особое внимание уделяется работе с базой: через Spring JDBC, Spring ORM и - Spring Data Jpa. -- Используются самые востребованные на сегодняшний момент фреймворки: Maven, Spring Security 4 - вместе с Spring Security Test, наиболее удобный для работы с базой проект Spring Data Jpa, библиотека логирования logback, реализующая SLF4J, повсеместно используемый Bootstrap и jQuery. +- Разбираются архитектурные паттерны: слои приложения и как правильно разбивать логику по слоям, когда нужно применять Data Transfer Object. То есть на выходе получается не учебный проект, а хорошо масштабируемый шаблон для большого проекта на всех пройденных технологиях. +- Большое внимание уделяется деталям: популяция базы, использование транзакционности, тесты сервисов и REST контроллеров, настройка EntityManagerFactory, выбор реализации пула коннектов. Особое внимание уделяется работе с базой: через Spring JDBC, Spring ORM и Spring Data Jpa. +- Используются самые востребованные на сегодняшний момент фреймворки: Maven, Spring Security 4 вместе с Spring Security Test, наиболее удобный для работы с базой проекта Spring Data Jpa, библиотека логирования logback, реализующая SLF4J, повсеместно используемый Bootstrap и jQuery. #### Демо разрабатываемого приложения ## План проекта (ссылки на некоторые темы открыты для просмотра) ### Архитектура проекта. Персистентность. -- Системы управления версиями -- Java 8: Lambda, Stream API -- Обзор используемых в проекте технологий и инструментов. -- Инструмент сборки Maven. -- WAR. Веб-контейнер Tomcat. Сервлеты. -- Логирование. -- Обзор стандартных библиотек. Apache Commons, Guava -- Слои приложения. Создание каркаса приложения. -- Обзор Spring Framework. Spring Context. -- Тестирование через JUnit. -- Spring Test -- Базы данных. PostgreSQL. Обзор NoSQL и Java persistence solution без ORM. -- Настройка Database в IDEA. -- Скрипты инициализации базы. Spring Jdbc Template. -- Spring: инициализация и популирование DB -- ORM. Hibernate. JPA. +- Системы управления версиями +- Java 8: Lambda, Stream API +- Обзор используемых в проекте технологий и инструментов. +- Инструмент сборки Maven. +- WAR. Веб-контейнер Tomcat. Сервлеты. +- Логирование. +- Обзор стандартных библиотек. Apache Commons, Guava +- Слои приложения. Создание каркаса приложения. +- Обзор Spring Framework. Spring Context. +- Тестирование через JUnit. +- Spring Test +- Базы данных. PostgreSQL. Обзор NoSQL и Java persistence solution без ORM. +- Настройка Database в IDEA. +- Скрипты инициализации базы. Spring Jdbc Template. +- Spring: инициализация и популирование DB +- ORM. Hibernate. JPA. - [Тестирование JPA сервиса через AssertJ](https://www.youtube.com/watch?v=BlyaXT6tOaw) -- Поддержка HSQLDB -- Транзакции -- Профили Maven и Spring -- Пул коннектов -- Spring Data JPA -- Кэш Hibernate +- Поддержка HSQLDB +- Транзакции +- Профили Maven и Spring +- Пул коннектов +- Spring Data JPA +- Кэш Hibernate ### Разработка WEB -- Spring кэш -- Spring Web -- JSP, JSTL, i18n -- Tomcat maven plugin. JNDI -- Spring Web MVC -- Spring Internationalization -- Тестирование Spring MVC -- REST контроллеры -- Тестирование REST контроллеров. Jackson. -- jackson-datatype-hibernate. Тестирование через матчеры. -- Тестирование через SoapUi. UTF-8 -- WebJars. -- Bootstrap. jQuery datatables. -- AJAX. jQuery. Notifications. -- Spring Security -- Spring Binding/Validation -- Работа с datatables через Ajax. -- Spring Security Test +- Spring кэш +- Spring Web +- JSP, JSTL, i18n +- Tomcat maven plugin. JNDI +- Spring Web MVC +- Spring Internationalization +- Тестирование Spring MVC +- REST контроллеры +- Тестирование REST контроллеров. Jackson. +- jackson-datatype-hibernate. Тестирование через матчеры. +- Тестирование через SoapUi. UTF-8 +- WebJars. +- Bootstrap. jQuery datatables. +- AJAX. jQuery. Notifications. +- Spring Security +- Spring Binding/Validation +- Работа с datatables через Ajax. +- Spring Security Test - [Кастомизация JSON (@JsonView) и валидации (groups)](https://drive.google.com/open?id=0B9Ye2auQ_NsFRTFsTjVHR2dXczA) -- Encoding password -- CSRF (добавление в проект защиты от межсайтовой подделки запроса) -- form-login. Spring Security Taglib -- Handler interceptor -- Spring Exception Handling -- Смена локали -- Фильтрация JSON через @JsonView -- Защита от XSS (Cross Site Scripting) -- Деплой в Heroku -- Локализация datatables, ошибок валидации -- Обработка ошибок 404 (NotFound) -- Доступ к AuthorizedUser -- Собеседование. Разработка ПО +- Encoding password +- CSRF (добавление в проект защиты от межсайтовой подделки запроса) +- form-login. Spring Security Taglib +- Handler interceptor +- Spring Exception Handling +- Смена локали +- Фильтрация JSON с помощью @JsonView +- Защита от XSS (Cross Site Scripting) +- Деплой в Heroku +- Локализация datatables, ошибок валидации +- Обработка ошибок 404 (NotFound) +- Доступ к AuthorizedUser +- Собеседование. Разработка ПО \ No newline at end of file diff --git a/graduation.md b/graduation.md index a4468a0f8ec9..442ce82b8c47 100644 --- a/graduation.md +++ b/graduation.md @@ -11,17 +11,17 @@ Build a voting system for deciding where to have lunch. * Users can vote on which restaurant they want to have lunch at * Only one vote counted per user * If user votes again the same day: - - If it is before 11:00 we asume that he changed his mind. + - If it is before 11:00 we assume that he changed his mind. - If it is after 11:00 then it is too late, vote can't be changed -Each restaurant provides new menu each day. +Each restaurant provides a new menu each day. As a result, provide a link to github repository. It should contain the code, README.md with API documentation and couple curl commands to test it. ----------------------------- P.S.: Make sure everything works with latest version that is on github :) -P.P.S.: Asume that your API will be used by a frontend developer to build frontend on top of that. +P.P.S.: Assume that your API will be used by a frontend developer to build frontend on top of that. ----------------------------- ### ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Рекомендации @@ -30,7 +30,7 @@ P.P.S.: Asume that your API will be used by a frontend developer to build fronte - **API продумывай с точки зрения не программиста и объектов, а с точки зрения того, кто им будет пользоваться (frontend)** - **Сначала сделай основной сценарий по ТЗ. Все остальное (если очень хочется, 3 раза подумай) - потом.** -*Представьте себе, что ПМ (лид, архитектор) дал вам ТЗ и некоторое время недоступен. У вас конечно есть много мыслей, для чего нужно приложение, как исправить ТЗ, дополнить его и сделать правильно. НО НЕ НАДО ИХ РЕАЛИЗОВЫВАТЬ В КОДЕ. Нужно сделать все максимально просто, удобно для доработок и для использования со стороны клиента (если конечно в ТЗ нет оговорок). Все свои вопросы и предложения и хотелки оформляйете отдельно (в `read.me` например). Если делаете что-то сложнее простейшего случая (например справочник еды)- обязательно напишите в read.me. Как и выбор стратегии кэширования.* +*Представьте себе, что ПМ (лид, архитектор) дал вам ТЗ и некоторое время недоступен. У вас, конечно, есть много мыслей, для чего нужно приложение, как исправить ТЗ, дополнить его и сделать правильно. НО НЕ НАДО ИХ РЕАЛИЗОВЫВАТЬ В КОДЕ. Нужно сделать все максимально просто, удобно для доработок и для использования со стороны клиента (если, конечно, в ТЗ нет оговорок). Все свои вопросы, предложения и хотелки оформляйте отдельно (в `read.me` например). Если делаете что-то сложнее простейшего случая (например, справочник еды) - обязательно напишите в read.me. Как и выбор стратегии кэширования.* > Совершенство достигнуто не тогда, когда нечего добавить, а тогда, когда нечего отнять @@ -40,20 +40,20 @@ _Антуан де Сент-Экзюпери_ - 2: **тщательно считайте количество обращений в базу на каждый запрос. Особенно при запросах от юзеров, которых очень много! Также на сложность запросов от них, чтобы не положить базу**. Самое худшее в коде - обращение в базу в цикле. - 3: **тщательно считайте количество запросов в вашем API для отображения нужной информации** - 4: учитывайте, что **пользователей может быть ОООЧЕНЬ много, а админов - МАЛО** -- 5: в проекте (и тестовом задании на работу) в отличие от нашего учебного topjava оставляйте только необходимый для работы приложения код, ничего лишнего: - - 5.1 НЕ надо делать разные профили базы и работы с ней. - - 5.2 НЕ надо делать абстрактных контроллеров на всякий случай. - - 5.3 НЕ надо делать **классов репозиториев и сервисов**, если там нет ничего, кроме делегирования. - - 5.4 Из потребностей приложения (которую надо самим придумать) реализовывать только очевидные сценарии. Те.- НИЧЕГО ЛИШНЕГО. +- 5: в проекте (и тестовом задании на работу), в отличие от нашего учебного topjava, оставляйте только необходимый для работы приложения код, ничего лишнего: + - 5.1 НЕ надо делать разные профили базы и работы с ней + - 5.2 НЕ надо делать абстрактных контроллеров на всякий случай + - 5.3 НЕ надо делать **классов репозиториев и сервисов**, если там нет ничего, кроме делегирования + - 5.4 Из потребностей приложения (которую надо самим придумать) реализовывать только очевидные сценарии. То есть НИЧЕГО ЛИШНЕГО. - 6: База Данных - берите без установки (H2 или HSQLDB). Одну!! Ваше приложение должно сразу запуститься, **без всяких настроек и переменных окружения** - - сделайте индексы к таблицам. Попробуйте обеспечит UNIQUE (один голос пользователя в день, один уникальный пункт меню в день). Следите за порядком полей в индексе. + - сделайте индексы к таблицам. Попробуйте обеспечит UNIQUE (один голос пользователя в день, один уникальный пункт меню в день). Следите за порядком полей в индексе - **историю еды и голосований сделать НУЖНО! Есть базовые вещи, которые закладываются в архитектуру приложения и неочевидные доработки к ТЗ, которых лучше не делать.** - при популировании добавте записи за сегодняшний день - now(), чтобы всегда были актуальные исходные данные - таблицы обычно именуются в единственном числе. Исключение - users, т. к. user - зарезервированное слово. `date`/`timestamp` - зарезервированное слово, лучше избегать их при именовании - 7: по возможности сделать JUnit тесты - 8: уделяйте внимание обработке ошибок -- 9: далаем REST API в соответствии с концепцией REST (url в общем имеют вид`{ресурс}/{id_ресурсa}[/{подресурс}/{id_подресурсa}][параметры]`) +- 9: делаем REST API в соответствии с концепцией REST (url в общем имеют вид`{ресурс}/{id_ресурсa}[/{подресурс}/{id_подресурсa}][параметры]`) - **[15 тривиальных фактов о правильной работе с протоколом HTTP](https://habrahabr.ru/company/yandex/blog/265569/)** - **10 Best Practices for Better RESTful API** - [REST resource hierarchy](https://stackoverflow.com/questions/20951419/what-are-best-practices-for-rest-nested-resources) @@ -62,25 +62,25 @@ _Антуан де Сент-Экзюпери_ - 12: если приложению в объекте требуется только его id, используйте reference (как мы при сохранении еды вставляем туда юзера) - 13: [Use for money in java app](http://stackoverflow.com/a/43051227/548473) - 14: еще раз про [hashCode/equals в Entity](https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma): не делайте сравнение по полям! -- 15: название пакетов, имен классов для `model/to/web` достаточно стандартные (например `model/domain`). НЕ надо придумывать своих собственных правил. -- 16: **Используйте DATA-JPA** (сделайте без лишней делегации, напрямую из сервиса/контроллера дергать Repository). -- 17: в DATA-JPA 2.x используются `Optional`. Попробуйте работать с ними, это безопасный способ работать с null значениями (используйте `orElseThrow`). -- 18: на topjava мы смотрели разные варианты использования, тут делаем максимально просто. С TO многие вещи упрощаются. -- 19: проверьте, не торчат ли из кода учебные уши topjava, типа `ProfileRestController.testUTF()`, `AbstractServiceTest.printResult()` или закомментированные `JdbcTemplate`. Назначение этого проекта совсем другое. -- 20: ORM работает с объектами. [В простейших случаях fk_id как поля допустимы](https://stackoverflow.com/questions/6311776/hibernate-foreign-keys-instead-of-entities), но при этом JPA их уже никак не обрабатывает и не используйте их вместе с объектами. Ссылка на stackoverwrflow в коде обязательна! +- 15: название пакетов, имен классов для `model/to/web` достаточно стандартные (например `model/domain`). НЕ надо придумывать своих собственных правил +- 16: **Используйте DATA-JPA** (можно без лишней делегации, напрямую из сервиса/контроллера дергать Repository) +- 17: в DATA-JPA 2.x используются `Optional`. Попробуйте работать с ними, это безопасный способ работать с null значениями (используйте `orElseThrow`) +- 18: на topjava мы смотрели разные варианты использования, тут делаем максимально просто. С TO многие вещи упрощаются +- 19: проверьте, не торчат ли из кода учебные уши topjava, типа `ProfileRestController.testUTF()`, `AbstractServiceTest.printResult()` или закомментированные `JdbcTemplate`. Назначение этого проекта совсем другое +- 20: ORM работает с объектами. [В простейших случаях fk_id как поля допустимы](https://stackoverflow.com/questions/6311776/hibernate-foreign-keys-instead-of-entities), но при этом JPA их уже никак не обрабатывает и не используйте их вместе с объектами. Ссылка на stackoverflow в коде обязательна! - 21: проверьте, станет ли код проще с `@AuthenticationPrincipal` (урок 11, Доступ к AuthorizedUser). - 22: обновление в базе делается через `update`, даже если `delete/insert` сократит java код на несколько строк - 23: Кэширование - необязательно, но желательно - - **тщательно продумайте, что надо кэшировать (самые частые запросы)**, а что нет (большие или редкозапрашиваемые данные)! + - **тщательно продумайте, что надо кэшировать (самые частые запросы)**, а что нет (большие или редко запрашиваемые данные)! - проверьте соответствие ключей к кэшу (параметры кэшируемого метода) с конфигурацией (например в singleNonExpiryCache, heap=1 в кэше может содержаться только ОДНО значение). - 24: Валидация - желательна - одних аннотаций недостаточно. Должны быть `@Valid/@Validation` - проверяйте входные данные при `create/update` **в контроллерах!** В TopJava это `ValidationUtil.checkNew()/assureIdConsistent()` - 25: `readme.md`: - - Если задание на English, описание пишите также на English (то же самое относится к языку резюме: вакансия на English предполагает ваше резюме на English) - - Требуемые примеры `curl` не прячте- пишите здесь! + - Если задание на English, описание пишите также на English (тоже самое относится к языку резюме: вакансия на English предполагает ваше резюме на English) + - Требуемые примеры `curl` не прячьте, а пишите здесь! - Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven:) ## Попробуйте подергать свое API по всем типичным сценариям ТЗ! From bddd4a8dffcca8b081a25862586b6e09e850a8b5 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 23 Nov 2020 12:02:40 +0300 Subject: [PATCH 037/226] Update cv.md --- cv.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cv.md b/cv.md index a330bc3c71cb..04a98a01039d 100644 --- a/cv.md +++ b/cv.md @@ -109,5 +109,7 @@ - [ТОП-13 ошибок начинающего программиста](https://proglib.io/p/beginners-fails/) - [25 ошибок начинающего программиста](https://habr.com/ru/post/413129/) - [Нетехнические навыки](https://tproger.ru/experts/softskills-for-job) - +- Типичные ошибки начинающих программистов от JavaRush: + - [Часть 1](https://javarush.ru/groups/posts/3044-razbor-tipichnihkh-oshibok-nachinajujshikh-programmistov-chastjh-1) + - [Часть 2](https://javarush.ru/groups/posts/3055-razbor-tipichnihkh-oshibok-nachinajujshikh-programmistov-chastjh-2) ## [Отзывы по стажировке Topjava](https://vk.com/topic-74381644_30447246) From 325763b91c1a02b99061b39ede1085dbffda9d09 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 7 Dec 2020 23:33:54 +0300 Subject: [PATCH 038/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 38831adc6f29..9636181f4588 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Java Enterprise Online Project - Выполнить задание и залить на GitHub (commit + push) - Переключиться в основную ветку проекта master. -## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Тех.задание: библия или допускаются изменения. Полуоткрытый интервал.](https://drive.google.com/file/d/123XyBYVeKLC3ZcRr_dUkwyvO9NC6WLkY/view?usp=sharing) +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Тех.задание: библия или допускаются изменения. Полуоткрытый интервал.](https://drive.google.com/file/d/1BpTzjNFjS0TSekCyt_xvt6YoLvuw5KTZ/view) - [Типы промежутков](https://ru.wikipedia.org/wiki/Промежуток_(математика)) ## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Домашнее задание HW0 From 52f1f76870923b3715f1d9561547de45bcb1fbdf Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 21 Dec 2020 17:32:32 +0300 Subject: [PATCH 039/226] Update cv.md --- cv.md | 1 + 1 file changed, 1 insertion(+) diff --git a/cv.md b/cv.md index 04a98a01039d..cc5ff22da638 100644 --- a/cv.md +++ b/cv.md @@ -88,6 +88,7 @@ - Яндекс агрегатор - HH - LinkedIn +- ХабрКарьера - djinni.co (более актуально для Украины) ## Как выжить на испытательном сроке From 1edcd14a9f5d1c780add0a7f2e56069e711c3b3d Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 21 Dec 2020 17:40:10 +0300 Subject: [PATCH 040/226] Update cv.md --- cv.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cv.md b/cv.md index cc5ff22da638..46a3442a81f4 100644 --- a/cv.md +++ b/cv.md @@ -89,8 +89,10 @@ - HH - LinkedIn - ХабрКарьера +- [headz.io](https://app.headz.io/candidates/new) - djinni.co (более актуально для Украины) + ## Как выжить на испытательном сроке - Учись грамотно формулировать проблему. Проблема "у меня не работает" может иметь тысячи причин. В процессе формулирования очень часто приходит ее решение. From 5f6d0c40136522bfa67e6b856997f402f295660e Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sat, 16 Jan 2021 00:31:31 +0300 Subject: [PATCH 041/226] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 9636181f4588..1bf92ee2cdd5 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ Java Enterprise Online Project - Java 8: Lambda выражения - Java 8: Потоки - Pуководство по Java 8 Stream -- Java 8 Stream API в картинках и примерах +- [Полное руководство по Java 8 Stream API в картинках и примерах](https://annimon.com/article/2778) - [7 способов использовать groupingBy в Stream API](https://habrahabr.ru/post/348536) - Лямбда-выражения в Java 8 - A Guide to Java 8 @@ -111,7 +111,6 @@ Java Enterprise Online Project - Алексея Владыкин: Элементы функционального программирования в Java - Yakov Fain о новом в Java 8 - stream.map vs forEach Date: Mon, 18 Jan 2021 00:28:34 +0300 Subject: [PATCH 042/226] Update ReleaseNotes.md --- ReleaseNotes.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 65a0c209f4c1..7c03206fe59c 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,5 +1,15 @@ # TopJava Release Notes +### Topjava 21 +- **добавили документирование REST API: Swagger** +- мигрировали на JDK 15 и используем текстовые блоки +- Вынес `produces = MediaType.APPLICATION_JSON_VALUE` на уровень контроллеров +- Правильно используем [глабальные переменные в js](https://stackoverflow.com/a/5064235/548473) +- Зарефакторил `inputField.tag` +- Тестовые переменные переименовал из UPPERCASE в camelCase +- Из тестов сервисов убрал `throws Exception` (в IDEA больше не генерятся по умолчанию) +- **Мигрировали на Spring Boot 2.4.1** + ### Topjava 20 - мигрировали на JDK 14 - в `@SafeHtml` запрещаем весь html (`whitelistType = NONE`) From c2344fec7ec9f27edb507ec78aa05cbf912be732 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 18 Jan 2021 02:08:41 +0300 Subject: [PATCH 043/226] Update cv.md --- cv.md | 1 + 1 file changed, 1 insertion(+) diff --git a/cv.md b/cv.md index 46a3442a81f4..17e0faf1ee83 100644 --- a/cv.md +++ b/cv.md @@ -111,6 +111,7 @@ - [**Советы новичкам**](http://blog.csssr.ru/2016/09/19/how-to-be-a-beginner-developer) - [ТОП-13 ошибок начинающего программиста](https://proglib.io/p/beginners-fails/) - [25 ошибок начинающего программиста](https://habr.com/ru/post/413129/) +- [Путеводитель по синдрому самозванца](https://dou.ua/lenta/articles/impostor-syndrome-guide-part1/) - [Нетехнические навыки](https://tproger.ru/experts/softskills-for-job) - Типичные ошибки начинающих программистов от JavaRush: - [Часть 1](https://javarush.ru/groups/posts/3044-razbor-tipichnihkh-oshibok-nachinajujshikh-programmistov-chastjh-1) From 2ec0a12b5ecbbc6191188ae38d2bd42085578b73 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 18 Jan 2021 02:10:14 +0300 Subject: [PATCH 044/226] Update cv.md --- cv.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cv.md b/cv.md index 17e0faf1ee83..73ca6a62be71 100644 --- a/cv.md +++ b/cv.md @@ -111,7 +111,7 @@ - [**Советы новичкам**](http://blog.csssr.ru/2016/09/19/how-to-be-a-beginner-developer) - [ТОП-13 ошибок начинающего программиста](https://proglib.io/p/beginners-fails/) - [25 ошибок начинающего программиста](https://habr.com/ru/post/413129/) -- [Путеводитель по синдрому самозванца](https://dou.ua/lenta/articles/impostor-syndrome-guide-part1/) +- [Путеводитель по синдрому самозванца](https://vc.ru/hr/167443-eshche-odin-putevoditel-po-sindromu-samozvanca-korni-prichiny-simptomy-i-posledstviya-chast-1) - [Нетехнические навыки](https://tproger.ru/experts/softskills-for-job) - Типичные ошибки начинающих программистов от JavaRush: - [Часть 1](https://javarush.ru/groups/posts/3044-razbor-tipichnihkh-oshibok-nachinajujshikh-programmistov-chastjh-1) From 4be539c0796b7cd3028cd2279259e23cb19624aa Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Fri, 22 Jan 2021 15:40:25 +0300 Subject: [PATCH 045/226] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 1bf92ee2cdd5..7cae831f37ca 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,11 @@ Java Enterprise Online Project ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. Работа с проектом (выполнять инструкции) - **ВНИМАНИЕ: выбирайте для проекта простой пусть без пробелов и русских букв, например (Windows) `c:\projects\topjava\`. Иначе впоследствии будут проблемы** - **Плагин уже Git Intergation не требуется и вкладку `Version control` в IDEA переименовали в `Git`** + +Для переключения режима отображения изменений из вкладки Commit в Git: Local Changes нужно переключить `Settings/Preferences | Version Control | Commit | Use non-modal commit interface` или в контекстном меню вкладки `Commit`: + +![image](https://user-images.githubusercontent.com/13649199/105491518-72d8f300-5cc7-11eb-8b79-c46382562deb.png) ![image](https://user-images.githubusercontent.com/13649199/105488663-05c35e80-5cc3-11eb-962e-30f403d623e8.png) + ### Патч [prepare_to_HW0.patch](https://drive.google.com/file/d/1LNPpu9OkuCpfpD8ZJHO-o0vwu49p2i5M) (скачать и положить в каталог вашего проекта) > Проект постоянно улучшается, поэтому видео иногда отличается от кода проекта. Изменения указываю после видео: From a779519ad62dc8287b7a9296397a3521c453bdf3 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 28 Jan 2021 00:30:29 +0300 Subject: [PATCH 046/226] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7cae831f37ca..cb332ffa033b 100644 --- a/README.md +++ b/README.md @@ -198,6 +198,7 @@ Java Enterprise Online Project - A Guide to Java 8 ### Туториалы, разное +- [Открытый курс: Spring Boot + HATEOAS](https://javaops.ru/view/bootjava) - [Что нужно знать о бэкенде новичку в веб-разработке](https://tproger.ru/translations/backend-web-development) - [Туториалы: Spring Framework, Hibernate, Java Core, JDBC](http://proselyte.net/tutorials/) From c91877064f1b5b7554849e02d7479cdabac24219 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 28 Jan 2021 11:41:19 +0300 Subject: [PATCH 047/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cb332ffa033b..71288706bc75 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Java Enterprise Online Project - Оцените Time complexity алгоритма. Если она больше O(N), например O(N*N) или N*log(N), сделайте O(N). ``` - Java 8 Date and Time API -- Алгоритмы и структуры данных для начинающих: сложность алгоритмов +- Алгоритмы и структуры данных для начинающих: сложность алгоритмов - [Головач: сложность алгоритмов в теме коллекций](https://www.youtube.com/watch?v=Ek9ijOiplNE&feature=youtu.be&t=778) - Time complexity - Временная сложность алгоритма From d026d2cf746fca5b071f3b54422ffeb46dcb3868 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Fri, 29 Jan 2021 12:25:27 +0300 Subject: [PATCH 048/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71288706bc75..8a58f7f11632 100644 --- a/README.md +++ b/README.md @@ -148,7 +148,7 @@ Java Enterprise Online Project ## ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Замечания к HW0 - 1: Код проекта менять можно! Одна из распространенных ошибок как в тестовых заданиях на собеседовании, так и при работе на проекте, что ничего нельзя менять. Конечно при правках в рабочем проекте обязательно нужно проконсультироваться/проревьюироваться у авторов кода (находится по истории VCS) -- 2: Наследовать `UserMealWithExcess` от `UserMeal` я не буду, т.к. это разные сущности: Transfer Object и Entity. Мы будет их проходить на 2м уроке. +- 2: Наследовать `UserMealWithExcess` от `UserMeal` нельзя, т.к. это разные сущности: Transfer Object и Entity. Мы будет их проходить на 2м уроке. Это относится и к зависимости. - 3: Правильная реализация должна быть простой и красивой, можно сделать 2-мя способами: через стримы и через циклы. Сложность должна быть O(N), т.е. без вложенных стримов и циклов. - 4: При реализации через циклы посмотрите в `Map` на методы `getOrDefault` или `merge` - 5: **При реализации через `Stream` заменяйте `forEach` оператором `stream.map(..)`** From 86a6795a6e1997d32c972f53b7a7c045ac55f1dc Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 2 Feb 2021 20:06:39 +0300 Subject: [PATCH 049/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a58f7f11632..470cce9ecab8 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,7 @@ Java Enterprise Online Project - Введение в Java Reflection API - Структуры данных в картинках - Обзор java.util.concurrent.* -- Синхронизация потоков +- Синхронизация потоков - String literal pool - Маленькие хитрости Java - A Guide to Java 8 From dc1eed9977324cd4b5f5d066382edc572aa09317 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 2 Feb 2021 20:10:55 +0300 Subject: [PATCH 050/226] Update description.md --- description.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/description.md b/description.md index 0619c6d9516d..58fb5d2cdf74 100644 --- a/description.md +++ b/description.md @@ -16,24 +16,24 @@ Hibernate, делаем конверторы для типов LocalDateTime (Ja - Системы управления версиями - Java 8: Lambda, Stream API - Обзор используемых в проекте технологий и инструментов. -- Инструмент сборки Maven. +- Инструмент сборки Maven - WAR. Веб-контейнер Tomcat. Сервлеты. - Логирование. - Обзор стандартных библиотек. Apache Commons, Guava - Слои приложения. Создание каркаса приложения. - Обзор Spring Framework. Spring Context. - Тестирование через JUnit. -- Spring Test +- Spring Test - Базы данных. PostgreSQL. Обзор NoSQL и Java persistence solution без ORM. - Настройка Database в IDEA. - Скрипты инициализации базы. Spring Jdbc Template. -- Spring: инициализация и популирование DB +- Spring: инициализация и популирование DB - ORM. Hibernate. JPA. - [Тестирование JPA сервиса через AssertJ](https://www.youtube.com/watch?v=BlyaXT6tOaw) - Поддержка HSQLDB - Транзакции - Профили Maven и Spring -- Пул коннектов +- Пул коннектов - Spring Data JPA - Кэш Hibernate @@ -69,4 +69,4 @@ Hibernate, делаем конверторы для типов LocalDateTime (Ja - Локализация datatables, ошибок валидации - Обработка ошибок 404 (NotFound) - Доступ к AuthorizedUser -- Собеседование. Разработка ПО \ No newline at end of file +- Собеседование. Разработка ПО From fada483294ca81e52c50622b864646106a66d5bd Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sat, 27 Feb 2021 21:51:50 +0300 Subject: [PATCH 051/226] Update cv.md --- cv.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cv.md b/cv.md index 73ca6a62be71..878437e24bb4 100644 --- a/cv.md +++ b/cv.md @@ -93,7 +93,7 @@ - djinni.co (более актуально для Украины) -## Как выжить на испытательном сроке +

Как выжить на испытательном сроке

- Учись грамотно формулировать проблему. Проблема "у меня не работает" может иметь тысячи причин. В процессе формулирования очень часто приходит ее решение. - Учись инвестигировать проблему. Внимательное чтение логов и умение дебажить - основные навыки From 1d8f32a0b890d5b7a7c04ed798c10df51841ca9d Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sat, 27 Feb 2021 21:54:16 +0300 Subject: [PATCH 052/226] Update cv.md --- cv.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cv.md b/cv.md index 878437e24bb4..d3789a9e796a 100644 --- a/cv.md +++ b/cv.md @@ -94,6 +94,7 @@

Как выжить на испытательном сроке

+ - Учись грамотно формулировать проблему. Проблема "у меня не работает" может иметь тысячи причин. В процессе формулирования очень часто приходит ее решение. - Учись инвестигировать проблему. Внимательное чтение логов и умение дебажить - основные навыки @@ -113,6 +114,7 @@ - [25 ошибок начинающего программиста](https://habr.com/ru/post/413129/) - [Путеводитель по синдрому самозванца](https://vc.ru/hr/167443-eshche-odin-putevoditel-po-sindromu-samozvanca-korni-prichiny-simptomy-i-posledstviya-chast-1) - [Нетехнические навыки](https://tproger.ru/experts/softskills-for-job) +- Видео [Junior и испытательный срок на первой работе](https://www.youtube.com/watch?v=GsGlsCbok-c) - Типичные ошибки начинающих программистов от JavaRush: - [Часть 1](https://javarush.ru/groups/posts/3044-razbor-tipichnihkh-oshibok-nachinajujshikh-programmistov-chastjh-1) - [Часть 2](https://javarush.ru/groups/posts/3055-razbor-tipichnihkh-oshibok-nachinajujshikh-programmistov-chastjh-2) From 699c90299d78fcbb30ebb65f7ec2712d4925d29d Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sat, 10 Apr 2021 12:12:14 +0300 Subject: [PATCH 053/226] Update cv.md --- cv.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cv.md b/cv.md index d3789a9e796a..f459060b227a 100644 --- a/cv.md +++ b/cv.md @@ -37,6 +37,8 @@ - Михаил Портнов. Собеседование на работу: как продать себя грамотно - Михаил Портнов. Какие вопросы мы задаем на собеседовании? - Михаил Портнов. Собеседование на работу: жизненный путь +- [Лёша Корепанов. Признаки плохих компаний для программиста](https://www.youtube.com/watch?v=Sj-WSWr-n7U) +- [Лёша Корепанов. Как отвечать на вопросы, которые ты не знаешь. Техническое интервью для программиста](https://www.youtube.com/watch?v=Beoh3tfgPEk) - Канал: Резюме, поиск работы, интервью - Яков Файн: Как стать профессиональным Java разработчиком - Ответы на вопросы на собеседовании Junior Java Developer From b7f28e7176958c11c1e49680be14559eb8045ed7 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Fri, 16 Apr 2021 15:10:41 +0300 Subject: [PATCH 054/226] Update description.md --- description.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/description.md b/description.md index 58fb5d2cdf74..0834140f19a7 100644 --- a/description.md +++ b/description.md @@ -70,3 +70,11 @@ Hibernate, делаем конверторы для типов LocalDateTime (Ja - Обработка ошибок 404 (NotFound) - Доступ к AuthorizedUser - Собеседование. Разработка ПО + +### Миграция на Spring Boot +- Основы Spring Boot. Spring Boot maven plugin +- Lombok, база H2, ApplicationRunner +- Spring Data REST + HATEOAS +- Swagger/ OpenAPI 3.0 +- Тестирование и кэширование в Spring Boot +- Миграция приложения TopJava на Spring Boot From bc6880c6100e3abcc932958ae72717fcf369af90 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 26 May 2021 13:42:29 +0300 Subject: [PATCH 055/226] Update graduation.md --- graduation.md | 1 + 1 file changed, 1 insertion(+) diff --git a/graduation.md b/graduation.md index 442ce82b8c47..50494a26ab8f 100644 --- a/graduation.md +++ b/graduation.md @@ -82,6 +82,7 @@ _Антуан де Сент-Экзюпери_ - Если задание на English, описание пишите также на English (тоже самое относится к языку резюме: вакансия на English предполагает ваше резюме на English) - Требуемые примеры `curl` не прячьте, а пишите здесь! - Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven:) +- 26: на управление (CRUD) рестаранами и едой должны быть ОТДЕЛЬНЫЕ контроллеры. Не надо все, что может админ сваливать в одну кучу! ## Попробуйте подергать свое API по всем типичным сценариям ТЗ! - Удобно использовать? Можно сделать проще? Например чтобы проголосовать за ресторан залогиненному юзеру достаточно `restorauntId`. From 8c4236cdbaa50c5d397be711be33065c4ee388f7 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 26 May 2021 17:55:43 +0300 Subject: [PATCH 056/226] Update graduation.md --- graduation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graduation.md b/graduation.md index 50494a26ab8f..e04d13c35885 100644 --- a/graduation.md +++ b/graduation.md @@ -82,7 +82,7 @@ _Антуан де Сент-Экзюпери_ - Если задание на English, описание пишите также на English (тоже самое относится к языку резюме: вакансия на English предполагает ваше резюме на English) - Требуемые примеры `curl` не прячьте, а пишите здесь! - Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven:) -- 26: на управление (CRUD) рестаранами и едой должны быть ОТДЕЛЬНЫЕ контроллеры. Не надо все, что может админ сваливать в одну кучу! +- 26: на управление (CRUD) рестаранами и едой должны быть ОТДЕЛЬНЫЕ контроллеры. Не надо все, что может админ, сваливать в одну кучу! ## Попробуйте подергать свое API по всем типичным сценариям ТЗ! - Удобно использовать? Можно сделать проще? Например чтобы проголосовать за ресторан залогиненному юзеру достаточно `restorauntId`. From 657ed5fcd836df938c6d540cd7cc919c5e50ece9 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Fri, 28 May 2021 15:52:56 +0300 Subject: [PATCH 057/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 470cce9ecab8..2941a385669b 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ Java Enterprise Online Project - циклом за 1 проход по `List` - без циклов по другим коллекциям/массивам (к ним также относим методы коллекций `addAll()/removeAll()`) - решение должно быть рабочим в общем случае (работать в приложении с многими пользователями, не только при запуске main) -- через Stream API за 1 проход по исходному списку `meals.streem()` +- через Stream API за 1 проход по исходному списку `meals.stream()` - нельзя использовать внешние коллекции, не являющиеся частью коллектора - нельзя 2 раза проходить по исходному списку (в том числе его отфильтрованной или преобразованной копии) - возможно дополнительные проходы по частям списка, при этом превышение должно считаться один раз для всего подсписка. Те например нельзя разбить список на на 2 подсписка с четными и нечетными датами и затем их объединить, с подсчетом превышения для каждого элемента. From 1dcc68b58d81d385c867835fa28561f72396fbea Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Fri, 28 May 2021 15:54:28 +0300 Subject: [PATCH 058/226] Create README.md From ad6225f2f50a3edbc5eb46f6af969e2995027df4 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 30 May 2021 10:48:37 +0300 Subject: [PATCH 059/226] Update graduation.md --- graduation.md | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/graduation.md b/graduation.md index e04d13c35885..4aa2c1b00dae 100644 --- a/graduation.md +++ b/graduation.md @@ -16,7 +16,7 @@ Build a voting system for deciding where to have lunch. Each restaurant provides a new menu each day. -As a result, provide a link to github repository. It should contain the code, README.md with API documentation and couple curl commands to test it. +As a result, provide a link to github repository. It should contain the code, README.md with API documentation and couple curl commands to test it (better - Swagger). ----------------------------- P.S.: Make sure everything works with latest version that is on github :) @@ -27,8 +27,9 @@ P.P.S.: Assume that your API will be used by a frontend developer to build front ### ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Рекомендации - **Сделай новый проект и добавляй туда из Topjava только то что нужно! Локализация, типы ошибок, BeanMatcher, Json View, излишние делегирования и наследования - не нужны!** -- **API продумывай с точки зрения не программиста и объектов, а с точки зрения того, кто им будет пользоваться (frontend)** +- **Рекомендую переписать проект современно: Spring Boot + Swagger/OpenAPI 3.0. Оптимально подойдет код миграции TopJava на Spring Boot в конце стажировки.** - **Сначала сделай основной сценарий по ТЗ. Все остальное (если очень хочется, 3 раза подумай) - потом.** +- API продумывай с точки зрения не программиста и объектов, а с точки зрения того, кто им будет пользоваться (frontend) *Представьте себе, что ПМ (лид, архитектор) дал вам ТЗ и некоторое время недоступен. У вас, конечно, есть много мыслей, для чего нужно приложение, как исправить ТЗ, дополнить его и сделать правильно. НО НЕ НАДО ИХ РЕАЛИЗОВЫВАТЬ В КОДЕ. Нужно сделать все максимально просто, удобно для доработок и для использования со стороны клиента (если, конечно, в ТЗ нет оговорок). Все свои вопросы, предложения и хотелки оформляйте отдельно (в `read.me` например). Если делаете что-то сложнее простейшего случая (например, справочник еды) - обязательно напишите в read.me. Как и выбор стратегии кэширования.* @@ -36,11 +37,11 @@ P.P.S.: Assume that your API will be used by a frontend developer to build front _Антуан де Сент-Экзюпери_ -- 1: **читаем ТЗ ОЧЕНЬ внимательно, НЕ надо ничего своего туда домысливать и творчески изменять** -- 2: **тщательно считайте количество обращений в базу на каждый запрос. Особенно при запросах от юзеров, которых очень много! Также на сложность запросов от них, чтобы не положить базу**. Самое худшее в коде - обращение в базу в цикле. -- 3: **тщательно считайте количество запросов в вашем API для отображения нужной информации** -- 4: учитывайте, что **пользователей может быть ОООЧЕНЬ много, а админов - МАЛО** -- 5: в проекте (и тестовом задании на работу), в отличие от нашего учебного topjava, оставляйте только необходимый для работы приложения код, ничего лишнего: +- 1: **Читаем ТЗ ОЧЕНЬ внимательно, НЕ надо ничего своего туда домысливать и творчески изменять** +- 2: **Тщательно считайте количество обращений в базу на каждый запрос. Особенно при запросах от юзеров, которых очень много! Также на сложность запросов от них, чтобы не положить базу**. Самое худшее в коде - обращение в базу в цикле. +- 3: **Тщательно считайте количество запросов в вашем API для отображения нужной информации** +- 4: Учитывайте, что **пользователей может быть ОООЧЕНЬ много, а админов - МАЛО** +- 5: В проекте (и тестовом задании на работу), в отличие от нашего учебного topjava, оставляйте только необходимый для работы приложения код, ничего лишнего: - 5.1 НЕ надо делать разные профили базы и работы с ней - 5.2 НЕ надо делать абстрактных контроллеров на всякий случай - 5.3 НЕ надо делать **классов репозиториев и сервисов**, если там нет ничего, кроме делегирования @@ -51,27 +52,27 @@ _Антуан де Сент-Экзюпери_ - **историю еды и голосований сделать НУЖНО! Есть базовые вещи, которые закладываются в архитектуру приложения и неочевидные доработки к ТЗ, которых лучше не делать.** - при популировании добавте записи за сегодняшний день - now(), чтобы всегда были актуальные исходные данные - таблицы обычно именуются в единственном числе. Исключение - users, т. к. user - зарезервированное слово. `date`/`timestamp` - зарезервированное слово, лучше избегать их при именовании -- 7: по возможности сделать JUnit тесты -- 8: уделяйте внимание обработке ошибок -- 9: делаем REST API в соответствии с концепцией REST (url в общем имеют вид`{ресурс}/{id_ресурсa}[/{подресурс}/{id_подресурсa}][параметры]`) +- 7: По возможности сделать JUnit тесты +- 8: Уделяйте внимание обработке ошибок +- 9: Делаем REST API в соответствии с концепцией REST (url в общем имеют вид`{ресурс}/{id_ресурсa}[/{подресурс}/{id_подресурсa}][параметры]`) - **[15 тривиальных фактов о правильной работе с протоколом HTTP](https://habrahabr.ru/company/yandex/blog/265569/)** - **10 Best Practices for Better RESTful API** - [REST resource hierarchy](https://stackoverflow.com/questions/20951419/what-are-best-practices-for-rest-nested-resources) -- 10: не смешивайте TO и Entity вместе. Лучше всего, если они будут независимыми друг от друга. -- 11: не размещайте логику приложения и преобразования в TO в слое доступа к DB -- 12: если приложению в объекте требуется только его id, используйте reference (как мы при сохранении еды вставляем туда юзера) +- 10: Не смешивайте TO и Entity вместе. Лучше всего, если они будут независимыми друг от друга. +- 11: Не размещайте логику приложения и преобразования в TO в слое доступа к DB +- 12: Если приложению в объекте требуется только его id, используйте reference (как мы при сохранении еды вставляем туда юзера) - 13: [Use for money in java app](http://stackoverflow.com/a/43051227/548473) -- 14: еще раз про [hashCode/equals в Entity](https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma): не делайте сравнение по полям! -- 15: название пакетов, имен классов для `model/to/web` достаточно стандартные (например `model/domain`). НЕ надо придумывать своих собственных правил +- 14: Еще раз про [hashCode/equals в Entity](https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma): не делайте сравнение по полям! +- 15: Название пакетов, имен классов для `model/to/web` достаточно стандартные (например `model/domain`). НЕ надо придумывать своих собственных правил - 16: **Используйте DATA-JPA** (можно без лишней делегации, напрямую из сервиса/контроллера дергать Repository) -- 17: в DATA-JPA 2.x используются `Optional`. Попробуйте работать с ними, это безопасный способ работать с null значениями (используйте `orElseThrow`) -- 18: на topjava мы смотрели разные варианты использования, тут делаем максимально просто. С TO многие вещи упрощаются -- 19: проверьте, не торчат ли из кода учебные уши topjava, типа `ProfileRestController.testUTF()`, `AbstractServiceTest.printResult()` или закомментированные `JdbcTemplate`. Назначение этого проекта совсем другое +- 17: В DATA-JPA 2.x используются `Optional`. Попробуйте работать с ними, это безопасный способ работать с null значениями (используйте `orElseThrow`) +- 18: На topjava мы смотрели разные варианты использования, тут делаем максимально просто. С TO многие вещи упрощаются +- 19: Проверьте, не торчат ли из кода учебные уши topjava, типа `ProfileRestController.testUTF()`, `AbstractServiceTest.printResult()` или закомментированные `JdbcTemplate`. Назначение этого проекта совсем другое - 20: ORM работает с объектами. [В простейших случаях fk_id как поля допустимы](https://stackoverflow.com/questions/6311776/hibernate-foreign-keys-instead-of-entities), но при этом JPA их уже никак не обрабатывает и не используйте их вместе с объектами. Ссылка на stackoverflow в коде обязательна! -- 21: проверьте, станет ли код проще с `@AuthenticationPrincipal` (урок 11, Доступ к AuthorizedUser). -- 22: обновление в базе делается через `update`, даже если `delete/insert` сократит java код на несколько строк +- 21: Проверьте, станет ли код проще с `@AuthenticationPrincipal` (урок 11, Доступ к AuthorizedUser). +- 22: Обновление в базе делается через `update`, даже если `delete/insert` сократит java код на несколько строк - 23: Кэширование - - необязательно, но желательно + - необязательно, но желательно. Чем проще реализация - тем лучше. - **тщательно продумайте, что надо кэшировать (самые частые запросы)**, а что нет (большие или редко запрашиваемые данные)! - проверьте соответствие ключей к кэшу (параметры кэшируемого метода) с конфигурацией (например в singleNonExpiryCache, heap=1 в кэше может содержаться только ОДНО значение). - 24: Валидация @@ -80,13 +81,13 @@ _Антуан де Сент-Экзюпери_ - проверяйте входные данные при `create/update` **в контроллерах!** В TopJava это `ValidationUtil.checkNew()/assureIdConsistent()` - 25: `readme.md`: - Если задание на English, описание пишите также на English (тоже самое относится к языку резюме: вакансия на English предполагает ваше резюме на English) - - Требуемые примеры `curl` не прячьте, а пишите здесь! + - Требуемые примеры `curl` не прячьте, а пишите здесь! Оптимально - ссылка на Swagger. - Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven:) -- 26: на управление (CRUD) рестаранами и едой должны быть ОТДЕЛЬНЫЕ контроллеры. Не надо все, что может админ, сваливать в одну кучу! +- 26: На управление (CRUD) рестаранами и едой должны быть ОТДЕЛЬНЫЕ контроллеры. Не надо все, что может админ, сваливать в одну кучу! ## Попробуйте подергать свое API по всем типичным сценариям ТЗ! - Удобно использовать? Можно сделать проще? Например чтобы проголосовать за ресторан залогиненному юзеру достаточно `restorauntId`. -- Сколько раз пришлось его вызвать API для типичного сценария (нарпимер посмотреть рестораны с едой)? +- Сколько раз пришлось его вызвать API для типичного сценария (нарпимер посмотреть рестораны с едой на сегодня)? - Сколько запросов к базе было сделано? Можно ли сократить (например с FETCH/Graph или через кэширование)? - **API ДОЛЖНО соответствовать принципам REST (см. ссылки выше)** - **ОБЯЗАТЕЛЬНО: запустите `mvn test`- ошибок быть не должно** From 04a5ef7b35a72c30fdc68805081308a7ac60d3e7 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 28 Jul 2021 12:55:54 +0300 Subject: [PATCH 060/226] Update graduation.md --- graduation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graduation.md b/graduation.md index 4aa2c1b00dae..070424ded69d 100644 --- a/graduation.md +++ b/graduation.md @@ -83,7 +83,7 @@ _Антуан де Сент-Экзюпери_ - Если задание на English, описание пишите также на English (тоже самое относится к языку резюме: вакансия на English предполагает ваше резюме на English) - Требуемые примеры `curl` не прячьте, а пишите здесь! Оптимально - ссылка на Swagger. - Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven:) -- 26: На управление (CRUD) рестаранами и едой должны быть ОТДЕЛЬНЫЕ контроллеры. Не надо все, что может админ, сваливать в одну кучу! +- 26: На управление (CRUD) ресторанами и едой должны быть ОТДЕЛЬНЫЕ контроллеры. Не надо все, что может админ, сваливать в одну кучу! ## Попробуйте подергать свое API по всем типичным сценариям ТЗ! - Удобно использовать? Можно сделать проще? Например чтобы проголосовать за ресторан залогиненному юзеру достаточно `restorauntId`. From 0471c423de6f18ab565c7aba2337ec78993b25a4 Mon Sep 17 00:00:00 2001 From: "admin@javaops.ru" Date: Fri, 30 Jul 2021 02:12:18 +0300 Subject: [PATCH 061/226] Add text to lesson07 --- doc/lesson07.md | 588 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 481 insertions(+), 107 deletions(-) diff --git a/doc/lesson07.md b/doc/lesson07.md index c4f4992a61df..2b46394101bf 100644 --- a/doc/lesson07.md +++ b/doc/lesson07.md @@ -13,59 +13,171 @@ ### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. HW6 #### Apply 7_01_HW6_fix_tests.patch -> - Добавил `AbstractServiceTest.isJpaBased()` и `Assume.assumeTrue(isJpaBased())` в `AbstractMealServiceTest.testValidation()`. -> - Как вариант можно было вместо наследования от `AbstractJpaUserServiceTest` сделать `@Autowired(required = false) JpaUtil` и чистить кэш по условию `isJpaBased()`. -> - В новой версии Spring классы `spring-mvc` требуют `WebApplicationContext`, поэтому поправил `inmemory.xml` #### Apply 7_02_HW6_meals.patch -При переходе на AJAX `JspMealController` удалим за ненадобностью, возвращение всей еды `meals()` останется в `RootController`. + +> сделал фильтрацию еды через `get`: операция идемпотентная, можно делать в браузере обновление по F5 + +### Внимание: чиним пути в следующем патче #### Apply 7_03_HW6_fix_relative_url_utf8.patch -- Relative paths in JSP -- Spring redirect: prefix + +- + Relative paths in JSP +- + Spring redirect: prefix ### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2. HW6 Optional + #### Apply 7_04_HW6_optional_add_role.patch -`JdbcUserServiceTest` отвалились. Будем чинить в `7_06_HW6_optional_jdbc.patch` + +#### `JdbcUserServiceTest` отвалились. Будем чинить в `7_06_HW6_jdbc_transaction_roles.patch` #### Apply 7_05_fix_hint_graph.patch -- В `JpaUserRepositoryImpl.getByEmail` DISTINCT попадает в запрос, хотя он там не нужен. Это просто указание Hibernate не дублировать данные. -Для оптимизации можно указать Hibernate делать запрос без distinct: [15.16.2. Using DISTINCT with entity queries](https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#hql-distinct) - - Бага [HINT_PASS_DISTINCT_THROUGH does not work if 'hibernate.use_sql_comments=true'](https://hibernate.atlassian.net/browse/HHH-13280). При `hibernate.use_sql_comments=false` все работает- в SELECT нет DISTINCT. -- Тест `DataJpaUserServiceTest.testGetWithMeals()` не работает для admin (у админа 2 роли, и еда при JOIN дублируется). `DISTINCT` при нескольких JOIN не помогает. -Оставил в графе только `meals`. Корректно поставить тип `LOAD`, чтобы остальные ассоциации доставались по стратегии модели. Однако [с типом по умолчанию `FETCH` роли также достаются](https://stackoverflow.com/a/46013654/548473) (похоже, что бага). +- В `JpaUserRepositoryImpl.getByEmail` DISTINCT попадает в запрос, хотя он там не нужен. Это просто указание Hibernate + не дублировать данные. Для оптимизации можно указать Hibernate делать запрос без + distinct: [15.16.2. Using DISTINCT with entity queries](https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#hql-distinct) +- Бага [HINT_PASS_DISTINCT_THROUGH does not work if 'hibernate.use_sql_comments=true'](https://hibernate.atlassian.net/browse/HHH-13280). При `hibernate.use_sql_comments=false` все работает - в SELECT нет DISTINCT. +- Тест `DataJpaUserServiceTest.getWithMeals()` не работает для admin (у админа 2 роли, и еда при JOIN дублируется). ... -#### Apply 7_06_HW6_optional_jdbc.patch -> - реализовал в `JdbcUserRepositoryImpl.getAll()` доставание ролей через лямбду -> - в `insertRoles` поменял метод `batchUpdate` и сделал проверку на empty -> - в `setRoles` достаю роли через `queryForList` - -Еще интересные JDBC реализации: - - в `getAll()/ get()/ getByEmail()` делать запросы с `LEFT JOIN` и сделать реализацию `ResultSetExtractor` - - подключить зависимость `spring-data-jdbc-core`. Там есть готовый `OneToManyResultSetExtractor`. Можно посмотреть, как он реализован. - - реализация, зависимая от БД (для postgres): доставать агрегированные роли и делать им `split(",")`: -``` -SELECT u.*, string_agg(r.role, ',') AS roles -FROM users u - JOIN user_roles r ON u.id=r.user_id -GROUP BY u.id -``` +#### Apply 7_06_HW6_jdbc_transaction_roles.patch + +Еще интересные JDBC реализации: ... + +### Валидация для `JdbcUserRepository` через Bean Validation API + +#### Apply 7_07_HW6_optional_jdbc_validation.patch + +- [Валидация данных при помощи Bean Validation API](https://alexkosarev.name/2018/07/30/bean-validation-api/). + +На данный момент у нас реализована валидация сущностей только для jpa- и dataJpa-репозиториев. При работе +через JDBC-репозиторий может произойти попытка записи в БД некорректных данных, что приведет к `SQLException` из-за нарушения +ограничений, наложенных на столбцы базы данных. Для того, чтобы перехватить невалидные данные еще до +обращения в базу, воспользуемся API *javax.validation* (ее реализация `hibernate-validator` используется для проверки данных в Hibernate и будет использоваться в Spring Validation, которую подключим позже). +В `ValidationUtil` создадим один потокобезопасный валидатор, который можно переиспользовать (см. *javadoc*). +С его помощью в методах сохранения и обновления сущности в jdbc-репозиториях мы можем производить валидацию этой сущности: `ValidationUtil.validate(object);` +Чтобы проверка не падала, `@NotNull Meal.user` пришлось пока закомментировать. Починим в 10-м занятии через `@JsonView`. + +### Отключение кэша в тестах: + +Вместо наших приседаний с `JpaUtil` и проверкой профилей мы можем ... + +#### Apply 7_08_HW06_optional2_disable_tests_cache.patch + +- [Example of PropertyOverrideConfigurer](https://www.concretepage.com/spring/example_propertyoverrideconfigurer_spring) +- [Spring util schema](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#xsd-schemas-util) ## Занятие 7: -### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. Тестирование Spring MVC -#### Apply 7_07_controller_test.patch + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. Тестирование Spring MVC + +
+ Краткое содержание + +#### Тестирование Spring MVC + +Для более удобного сравнения объектов в тестах мы будем использовать библиотеку *Harmcrest* с Matcher'ами, которая +позволяет делать сложные проверки. С *Junit* по умолчанию подтягивается *Harmcrest core*, но нам потребуется расширенная версия: +в `pom.xml` из зависимости Junit исключим дочернюю `hamcrest-core` и добавим `hamcrest-all`. + +Для тестирования web создадим вспомогательный класс `AbstractControllerTest`, от которого будут наследоваться все +тесты контроллеров. Его особенностью будет наличие `MockMvc` - эмуляции Spring MVC для тестирования web-компонентов. +Инициализируем ее в методе, отмеченном `@PostConstruct`: + + ``` +mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).addFilter(CHARACTER_ENCODING_FILTER).build(); + ``` + +Для того, чтобы в тестах контроллеров не популировать базу перед каждым тестом, пометим этот базовый тестовый класс аннотацией `@Transactional`. +Теперь каждый тестовый метод будет выполняться в транзакции, которая будет откатываться после окончания метода и возвращать базу данных в исходное +состояние. Однако теперь в работе тестов могут возникнуть нюансы, связанные с пропагацией транзакций: все +транзакции репозиториев станут вложенными во внешнюю транзакцию теста. При этом, например, кэш первого уровня станет работать не +так, как ожидается. Т.е при таком подходе нужно быть готовыми к ошибкам: мы их увидим и поборем в тестах на обработку ошибок на последних занятиях TopJava. + +#### UserControllerTest + +Создадим тестовый класс для контроллера юзеров, он должен наследоваться от `AbstractControllerTest`. +В `MockMvc` используется [паттерн проектирования Builder](https://refactoring.guru/ru/design-patterns/builder). + + ``` + mockMvc.perform(get("/users")) // выполнить HTTP метод GET к "/users" + .andDo(print()) // распечатать содержимое ответа + .andExpect(status().isOk()) // от контроллера ожидается ответ со статусом HTTP 200(ok) + .andExpect(view().name("users")) // контроллер должен вернуть view с именем "users" + .andExpect(forwardedUrl("/WEB-INF/jsp/users.jsp")) // ожидается, что клиент должен быть перенаправлен на "/WEB-INF/jsp/users.jsp" + .andExpect(model().attribute("users", hasSize(2))) // в модели должен быть атрибут "users" размером = 2 + .andExpect(model().attribute("users", hasItem( // внутри которого есть элемент ... + allOf( + hasProperty("id", is(START_SEQ)), // ... с аттрибутом id = START_SEQ + hasProperty("name", is(USER.getName())) //... и name = user + ) + ))); +} + ``` + +В параметры метода `andExpect()` передается реализация `ResultMatcher`, в которой мы определяем как должен быть обработан ответ контроллера. + +
+ +#### Apply 7_09_controller_test.patch + > - в `MockMvc` добавился `CharacterEncodingFilter` -> - добавил `AllActiveProfileResolver` -> - реализация Ehcache нетранзакционная, после отката транзакции в тестах по `@Transactional` Hibernate-кеш не восстанавливал роль для USER. Добавил очистку кэша Hibernate в `AbstractControllerTest.setUp` (с учетом того, что `Profiles.REPOSITORY_IMPLEMENTATION` можно переключить на `JDBC`). +> - добавил [`AllActiveProfileResolver`](//http://stackoverflow.com/questions/23871255/spring-profiles-simple-example-of-activeprofilesresolver) для возвращения массива профилей +> - сделал вспомогательный метод `AbstractControllerTest.perform()` + +- Hamcrest +- Unit Testing of Spring MVC Controllers + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Миграция на JUnit 5](https://drive.google.com/open?id=16wi0AJLelso-dPuDj6xaGL7yJPmiO71e) + +
+ Краткое содержание + +Для миграции на 5-ю версию JUnit в файле `pom.xml` поменяем зависимость `junit` на `junit-jupiter-engine` ([No need `junit-platform-surefire-provider` dependency in `maven-surefire-plugin`](https://junit.org/junit5/docs/current/user-guide/#running-tests-build-maven)). +Актуальную версию всегда можно посмотреть [в центральном maven репозитории](https://search.maven.org/search?q=junit-jupiter-engine), берем только релизы (..-Mx означают предварительные milestone версии) +Изменять конфигурацию плагина `maven-sureface-plugin` в новых версиях JUnit уже не требуется. +Junit5 не содержит в себе зависимости от *Harmcrest* (которую нам приходилось вручную +отключать для JUnit4 в предыдущих шагах), поэтому исключение `hamcrest-core` просто удаляем. +В итоге у нас останутся зависимости JUnit5 и расширенный Harmcrest. +Теперь мы можем применить все нововведения пятой версии в наших тестах: + 1. Для всех тестов теперь мы можем удалить `public`. + 2. Аннотацию `@Before` исправим на `@BeforeEach` - теперь метод, который будет выполняться перед +каждым тестом, помечается именно так. + 3. В Junit5 работа с исключениями похожа на Junit4 версии 4.13: вместо ожидаемых исключений в параметрах аннотации `@Test(expected = Exception.class)` используется метод `assertThrows()`, +в который первым аргументом мы передаем ожидаемое исключение, а вторым аргументом — реализацию функционального интерфейса `Executable` (кода теста, +в котором ожидается возникновение исключения). + 4. Метод `assertThrows()` возвращает исключение, которое было выброшено в переданном ему коде. Теперь мы можем получить это исключение, извлечь из него сообщение с помощью + `e.getMessage()` и сравнить с ожидаемым. + 5. Для теста на валидацию при проверке предусловия, только при выполнении которого +будет выполняться следующий участок кода (например, в нашем случае тесты на валидацию выполнялись +только в jpa профиле), - теперь нужно пользоваться утильным методом `Assumptions` (нам уже не требуется). + 6. Проверку Root Cause - причины, из-за которой было выброшено пойманное исключение, мы будем делать позднее, при тестах на ошибки. + 7. Из JUnit5 исключена функциональность `@Rule`, вместо них теперь нужно использовать `Extensions`, которые +могут встраиваться в любую фазу тестов. Чтобы добавить их в тесты, пометим базовый тестовый класс аннотацией `@ExtendWith`. + +JUnit предоставляет нам набор коллбэков — интерфейсов, которые будут исполняться в определенный момент тестирования. +Создадим класс `TimingExtension`, который будет засекать время выполнения тестовых методов. +Этот класс будет имплементировать маркерные интерфейсы — коллбэки JUnit: + - `BeforeTestExecutionCallback` - коллбэк, который будет вызывать методы этого интерфейса перед каждым тестовым методом. + - `AfterTestExecutionCallback` - методы этого интерфейса будут вызываться после каждого тестового метода; + - `BeforeAllCallback` - методы перед выполнением тестового класса; + - `AfterAllCallback` - методы после выполнения тестового класса; + +Осталось реализовать соответствующие методы, которые описываются в каждом из этих интерфейсов, они и будут вызываться JUnit в нужный момент: + - в методе `beforeAll` (который будет вызван перед запуском тестового класса) создадим спринговый утильный секундомер `StopWatch` для текущего тестового класса; + - в методе `beforeTestExecution` (будет вызван перед тестовым методом) - запустим секундомер; + - в методе `afterTestExecution` (будет вызван после тестового метода) - остановим секундомер. + - в методе `afterAll` (который будет вызван по окончанию работы тестового класса) - выведем результат работы этого секундомера в консоль; -- Hamcrest -- Unit Testing of Spring MVC Controllers + 8. Аннотации `@ContextConfiguration` и `@ExtendWith(SpringExtension.class)` (замена `@RunWith`) мы можем заменить одной `@SpringJUnitConfiguration` (в старых версиях IDEA ее не понимает) + +
+ +#### Apply 7_10_JUnit5.patch -### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Миграция на JUnit 5](https://www.youtube.com/watch?v=YmLzT-j1hU4) -#### Apply 7_08_JUnit5.patch > - [No need `junit-platform-surefire-provider` dependency in `maven-surefire-plugin`](https://junit.org/junit5/docs/current/user-guide/#running-tests-build-maven) -> - [Наконец пофиксили баг с `@SpringJUnitConfig`](https://youtrack.jetbrains.com/issue/IDEA-166549). Можно обновить IDEA до 2019.2 (обновите, только если достаточно памяти: минимум 3Gb. `Help menu -> Edit Custom VM Options`) +> - [Наконец пофиксили баг с `@SpringJUnitConfig`](https://youtrack.jetbrains.com/issue/IDEA-166549) - [JUnit 5 homepage](https://junit.org/junit5) - [Overview](https://junit.org/junit5/docs/snapshot/user-guide/#overview) @@ -79,114 +191,376 @@ GROUP BY u.id - [Third party Extensions](https://github.com/junit-team/junit5/wiki/Third-party-Extensions) - [Реализация assertThat](https://stackoverflow.com/questions/43280250) +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 5. [Принципы REST. REST контроллеры](https://drive.google.com/open?id=1e4ySjV15ZbswqzL29UkRSdGb4lcxXFm1) + +
+ Краткое содержание + +#### Принципы REST, REST-контроллеры + +> [REST](http://spring-projects.ru/understanding/rest/) - архитектурный стиль проектирования распределенных систем (типа клиент-сервер). + +Чаще всего в REST сервер и клиент общаются посредством обмена JSON-объектами через HTTP-методы GET/POST/PUT/DELETE/PATCH. +Особенностью REST является отсутствие состояния (контекста) взаимодействий клиента и сервера. + +В нашем приложении есть контроллеры для Admin и для User. Чтобы сделать их REST-контроллерами, +заменим аннотацию `@Controller` на `@RestController` + +> Не поленитесь зайти чз Ctrl+Click в `@RestController`: к аннотации `@Controller` добавлена `@ResponseBody`. Т.е. ответ от нашего приложения будет не имя View, а данные в теле ответа. + +В `@RequestMapping`, кроме пути для методов контроллера (`value`) добавляем параметр `produces = MediaType.APPLICATION_JSON_VALUE`. +Это означает, что в заголовки ответа будет добавлен тип `ContentType="application/json"` - в ответе от контроллера будет приходить JSON-объект. + +> Чтобы было удобно использовать путь к этому контроллеру в приложении и в тестах, +> выделим путь к нему в константу REST_URL, к которой можно будет обращаться из других классов + +1. Метод `AdminRestController.getAll` пометим аннотацией `@GetMapping` - маршрутизация к методу по HTTP GET. + +2. Метод `AdminRestController.get` пометим аннотацией `@GetMapping("/{id}")`. +В скобках аннотации указано, что к основному URL контроллера будет добавляться `id` пользователя - переменная, которая передается в запросе непосредственно в URL. + Соответствующий параметр метода нужно пометить аннотацией `@PathVariable` (если имя в URL и имя аргумента метода не совпадают, в параметрах аннотации дополнительно нужно будет уточнить + имя в URL. Если они совпадают, [этого не требуется](https://habr.com/ru/post/440214/). + +3. Метод создания пользователя `create` отметим аннотацией `@PostMapping` - маршрутизация к методу по HTTP POST. + В метод мы передаем объект `User` в теле запроса (аннотация `@RequestBody`) и в формате JSON (`consumes = MediaType.APPLICATION_JSON_VALUE`). + При создании нового ресурса правила хорошего тона - вернуть в заголовке ответа URL созданного ресурса. + Для этого возвращем не `User`, а `ResponseEntity`, который мы можем с помощью билдера `ServletUriComponentsBuilder` дополнить заголовком ответа `Location` и вернуть статус `CREATED(201)` + (если пойти в код `ResponseEntity.created` можно докопаться до сути, очень рекомендую смотреть в исходники кода). + +4. Метод `delete` помечаем `@DeleteMapping("/{id}")` - HTTP DELETE. + Он ничего не возвращает, поэтому помечаем его аннотацией `@ResponseStatus(HttpStatus.NO_CONTENT)`. Статус ответа будет HTTP.204; + +5. Над методом обновления ставим `@PutMapping` (HTTP PUT). В аргументах метод принимает `@RequestBody User user` и `@PathVariable int id`. + +6. Метод поиска по `email` также помечаем `@GetMapping`, и, чтобы не было конфликта маршрутизации с методом `get()`, + указываем в URL добавку "/by". В этот метод `email` передается как параметр запроса, аннотация `@RequestParam`. + +> **Все это СТАНДАРТ архитектурного стиля REST. НЕ придумывайте ничего своего в своих выпускных проектах! Это очень большая ошибка - не придерживаться стандартов API.** + +7. `ProfileRestController` выполняем аналогичным способом с учетом того, что пользователь имеет доступ только к своим данным. -### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 5. [Принципы REST. REST контроллеры](https://youtu.be/33_2yOck4ak) -#### Apply 7_09_rest_controller.patch - -- Понимание REST -- JSON (JavaScript Object Notation) +Если на данном этапе попытаться запустить приложение и обратиться к какому-либо методу контроллера, сервер ответит нам ошибкой со статусом 406, +так как Spring не знает, как преобразовать объект User в JSON... + +
+ +#### Apply 7_11_rest_controller.patch + +- Понимание REST +- JSON (JavaScript Object Notation) - [15 тривиальных фактов о правильной работе с протоколом HTTP](https://habrahabr.ru/company/yandex/blog/265569/) -- [10 Best Practices for Better RESTful](http://blog.mwaysolutions.com/2014/06/05/10-best-practices-for-better-restful-api/) +- [10 Best Practices for Better RESTful](https://medium.com/@mwaysolutions/10-best-practices-for-better-restful-api-cbe81b06f291) - [Best practices for rest nested resources](https://stackoverflow.com/questions/20951419/what-are-best-practices-for-rest-nested-resources) -- Request mapping -- Дополнительно: - - JAX-RS vs Spring MVC - - RESTful API для сервера – делаем правильно (Часть 1) - - RESTful API для сервера – делаем правильно (Часть 2) - - И. Головач. RestAPI - - [value/name в аннотациях @PathVariable и @RequestParam](https://habr.com/ru/post/440214/) - -### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 6. [Тестирование REST контроллеров. Jackson](https://drive.google.com/file/d/1aZm2qoMh4yL_-i3HhRoyZFjRAQx-15lO) -#### Apply 7_10_rest_test_jackson.patch -- [Jackson databind github](https://github.com/FasterXML/jackson-databind) -- [Jackson Annotation Examples](https://www.baeldung.com/jackson-annotations) - -### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 7. [Кастомизация Jackson Object Mapper](https://drive.google.com/file/d/1CM6y1JhKG_yeLQE_iCDONnI7Agi4pBks) - -#### Apply 7_11_jackson_object_mapper.patch -- Сериализация hibernate lazy-loading с помощью jackson-datatype-hibernate -- Handle Java 8 dates with Jackson -- Дополнительно: - - Jackson JSON Serializer & Deserializer - -### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 8. [Тестирование REST контроллеров через JSONassert](https://drive.google.com/file/d/1oa3e0_tG57E71g6PW7_tfb3B61Qldctl) -#### Apply 7_12_json_assert_tests.patch +- + Request mapping +- [Лучшие практики разработки REST API: правила 1-7,15-17](https://tproger.ru/translations/luchshie-praktiki-razrabotki-rest-api-20-sovetov/) +- Дополнительно: + - [Подборка практик REST](https://gist.github.com/Londeren/838c8a223b92aa4017d3734d663a0ba3) + - JAX-RS vs Spring MVC + - RESTful API для сервера – делаем правильно (Часть 1) + - RESTful API для сервера – делаем правильно (Часть 2) + - И. Головач. + RestAPI + - [value/name в аннотациях @PathVariable и @RequestParam](https://habr.com/ru/post/440214/) + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 6. [Тестирование REST контроллеров. Jackson.](https://drive.google.com/open?id=1aZm2qoMh4yL_-i3HhRoyZFjRAQx-15lO) + +
+ Краткое содержание + +Для работы с JSON добавляем в `pom.xml` зависимость `jackson-databind`. +Актуальную версию библиотеки можно посмотреть в [центральном maven-репозитории](https://search.maven.org/artifact/com.fasterxml.jackson.core/jackson-databind). +Теперь спринг будет автоматически использовать эту библиотеку для сериализации/десериализации объектов в JSON (найдя ее в *classpath*). +Если сейчас запустить приложение и обратиться к методам REST-контроллера, то оно выбросит `LazyInitializationException`. +Оно возникает из-за того, что у наших сущностей есть лениво загружаемые поля, отмеченные `FetchType.LAZY` - при загрузке сущности из базы, вместо этого поля подставится Proxy, который и должен вернуть +реальный экземпляр этого поля при первом же обращении. Jackson при сериализации в JSON использует все поля сущности, +и при обращении к *Lazy* полям возникает исключение, так как сессия работы с БД в этот момент уже закрыта, и нужный объект +не может быть инициализирован. Чтобы Jackson игнорировал эти поля, пометим их аннотацией `@JsonIgnore`. + +Теперь при запуске приложения REST-контроллер будет работать. Но при получении JSON объектов мы можем увидеть, что Jackson сериализовал объект +через геттеры (например в ответе есть поле `new` от метода `Persistable.isNew()`). +Чтобы учитывались только поля объектов, добавим над `AbstractBaseEntity`: +````java +@JsonAutoDetect(fieldVisibility = ANY, // jackson видит все поля + getterVisibility = NONE, // ... но не видит геттеров + isGetterVisibility = NONE, //... не видит геттеров boolean полей + setterVisibility = NONE) // ... не видит сеттеров +```` +Теперь все сущности, унаследованные от базового класса, будут сериализоваться/десериализоваться через поля. + +
+ +#### Apply 7_12_rest_test_jackson.patch + +- [Jackson databind github](https://github.com/FasterXML/jackson-databind) +- [Jackson Annotation Examples](https://www.baeldung.com/jackson-annotations) + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 7. [Кастомизация Jackson Object Mapper](https://drive.google.com/open?id=1CM6y1JhKG_yeLQE_iCDONnI7Agi4pBks) + +
+ Краткое содержание + +Сейчас, чтобы не сериализовать *Lazy* поля, мы должны пройтись по каждой сущности и +вручную пометить их аннотацией `@JsonIgnore`. Это неудобно, засоряет код и допускает возможные ошибки. К тому же, +при некоторых условиях, нам иногда нужно загрузить и в ответе передать эти *Lazy* поля. +Чтобы запретить сериализацию Lazy полей для всего проекта, подключим в `pom.xml` библиотеку `jackson-datatype-hibernate`. +Также изменим сериализацию/десериализацию полей объектов в JSON: не через аннотацию `@JsonAutoDetect`, а в классе `JacksonObjectMapper`, который +унаследуем от `ObjectMapper` (стандартный Mapper, который использует Jackson) и сделаем в нем другие настройки. +В конструкторе: +- регистрируем `Hibernate5Module` - модуль `jackson-datatype-hibernate`, который не делает сериализацию ленивых полей. +- модуль для корректной сериализации `LocalDateTime` в поля JSON - `JavaTimeModule` модуль библиотеки `jackson-datatype-jsr310` +- запрещаем доступ ко всем полям и методам класса и потом разрешаем доступ только к полям +- не сериализуем null-поля (`setSerializationInclusion(JsonInclude.Include.NON_NULL)`) + +Чтобы подключить наш кастомный `JacksonObjectMapper` в проект, в конфигурации `spring-mvc.xml` к +настройке `` добавим `MappingJackson2HttpMessageConverter`, который будет использовать наш маппер. + +
+ + +#### Apply 7_13_jackson_object_mapper.patch + +- Сериализация hibernate lazy-loading с помощью + jackson-datatype-hibernate +- Handle Java 8 dates with Jackson +- Дополнительно: + - Jackson JSON + Serializer & Deserializer + +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 8. [Тестирование REST контроллеров через JSONassert и Матчеры](https://drive.google.com/open?id=1oa3e0_tG57E71g6PW7_tfb3B61Qldctl) + +
+ Краткое содержание + +Сейчас в тестах REST-контроллера мы проводим проверку только на статус ответа и тип возвращаемого контента. Добавим проверку содержимого ответа. + +#### 7_14_json_assert_tests + +Чтобы сравнивать содержимое ответа контроллера в виде JSON и сущность, воспользуемся библиотекой +`jsonassert`, которую подключим в `pom.xml` со scope *test*. + +Эта библиотека при сравнении в тестах в качестве ожидаемого значения ожидает от +нас объект в виде JSON-строки. Чтобы вручную не преобразовывать объекты в JSON и не +хардкодить их в виде строк в наши тесты, воспользуемся Jackson. +Для преобразования объектов в JSON и обратно создадим утильный класс `JsonUtil`, в котором +с помощью нашего `JacksonObjectMapper` и будет конвертировать объекты. +И мы сталкиваемся с проблемой: `JsonUtil` - утильный класс и не является +бином спринга, а для его работы требуется наш кастомный маппер, который находится под управлением +спринга и расположен в контейнере зависимостей. Поэтому, чтобы была возможность получить +наш маппер из других классов - сделаем его синглтоном и сделаем в нем статический +метод, который будет возвращать его экземпляр. Теперь `JsonUtil` сможет его получить. +И нам нужно указать спрингу, чтобы он не создавал второй экземпляр этого объекта, а клал в свой контекст существующий. +Для этого в конфигурации `spring-mvc.xml` определим factory-метод, с помощью которого спринг должен +получить экземпляр (instance) этого класса: +```xml + +``` +а в конфигурации `message-converter` вместо создания бина просто сошлемся на сконфигурированный `objectMapper`. + +Метод `ContentResultMatchers.json()` из `spring-test` использует библиотеку `jsonassert` для сравнения 2-х JSON строк: одну из ответа контроллера и вторую - +JSON-сериализация `admin` без поля `registered` (это поле инициализируется в момент создания и отличается). +В методе `JsonUtil.writeIgnoreProps` мы преобразуем объект `admin` в мапу, удаляем из нее игнорируемые поля и снова сериализуем в JSON. + +Также сделаем тесты для утильного класса `JsonUtil`. В тестах мы записываем +объект в JSON-строку, затем конвертируем эту строку обратно в объект и сравниваем с исходным. И то же самое делаем со списком объектов. + +#### 7_15_tests_refactoring + +**`RootControllerTest`** + +Сделаем рефакторинг `RootControllerTest`. Ранее мы в тесте получали модель, доставали из нее сущности и с помощью `hamcrest-all` +производили по одному параметру их сравнение с ожидаемыми значениями. +Метод `ResultActions.andExpect()` позволяет передавать реализацию интерфейса `Matcher`, в котором можно делать любые сравнения. +Функциональность сравнения списка юзеров по ВСЕМ полям у нас уже есть - мы просто делегируем сравнение объектов в `UserTestData.MATCHER`. +При этом нам больше не нужен `harmcrest-all`, нам достаточно только `harmcrest-core`. + +**`MatcherFactory`** + +Теперь вместо `jsonassert` и сравнения JSON-строк в тестах контроллеров сделаем сравнения JSON-объектов через `MatcherFactory`. +Преобразуем ответ контроллера из JSON в объект и сравним с эталоном через уже имеющийся у нас матчер. +Вместо сравнения JSON-строк в метод `andExpect()` мы будем передавать реализации интерфейса `ResultMatcher` из `MATCHER.contentJson(..)`. + +`MATCHER.contentJson(..)` принимают ожидаемый объект и возвращают для него `ResultMatcher` с реализацией единственного метода `match(MvcResult result)`, +в котором делегируем сравнение уже существующим у нас матчерам. +Мы берем JSON-тело ответа (`MatcherFactory.getContent`), десериализуем его в объект (`JsonUtil.readValue/readValues`) и сравниваем через имеющийся `MATCHER.assertMatch` +десериализованный из тела контроллера объект и ожидаемое значение. + +> Методы из класса `TestUtil` перенес в `MatcherFactory`, лишние удалил. + +**`AdminRestControllerTest`** + +- `getByEmail()` - сделан по аналогии с тестом `get()`. Дополнительно нужно дополнить строку URL параметрами запроса. +- `delete()` - выполняем HTTP.DELETE. Проверяем статус ответа 204. Проверяем, что пользователь удален. + +> Раньше я получал всех users из базы и проверял, что среди них нет удаленного. При этом тесты становятся чувствительными ко всем users в базе и ломаются при добавлении-удалении новых тестовых данных. + +- `update()` - выполняем HTTP.PUT. В тело запроса подаем сериализованный `JsonUtil.writeValue(updated)`. После выполнения проверяем, что объект в базе обновился. +- `create()` - выполняем HTTP.POST аналогично `update()`. Но сравнить результат мы сразу не можем, т.к. при создании объекта ему присваивается `id`. + Поэтому мы извлекаем созданного пользователя из ответа (`MATCHER.readFromJson(action)`), получаем его `id`, и уже с этим `id` эталонный объект мы можем сравнить с объектом в ответе контроллера и со + значением в базе. +- `getAll()` - аналогично get(). Список пользователей из ответа в формате JSON сравниваем с эталонным списком (`MATCHER.contentJson(admin, user)`). + +Тесты для `ProfileRestController` выполнены аналогично. + +
+ +#### Apply 7_14_json_assert_tests.patch + +> - В `JsonUtil.writeIgnoreProps` вместо цикла по мапе сделал `map.keySet().removeAll` + - [JSONassert](https://github.com/skyscreamer/JSONassert) - [Java Code Examples for ObjectMapper](https://www.programcreek.com/java-api-examples/index.php?api=com.fasterxml.jackson.databind.ObjectMapper) -#### Apply 7_13_tests_refactoring.patch +#### Apply 7_15_tests_refactoring.patch + +> - Методы из класса `TestUtil` перенес в `MatcherFactory`, лишние удалил. +> - Раньше в тестах я для проверок получал всех users из базы и сравнивал с эталонным списком. При этом тесты становятся чувствительными ко всем users в базе и ломаются при добавлении-удалении новых тестовых данных. + +- [Java @SafeVarargs Annotation](https://www.baeldung.com/java-safevarargs) ### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 9. Тестирование через SoapUi. UTF-8 -#### Apply 7_14_soapui_utf8_converter.patch + +
+ Краткое содержание + +SOAP UI - это один из инструментов для тестирования API приложений, которые работают по REST и по SOAP. +Он позволяет нам по HTTP протоколу дернуть методы нашего API и увидеть ответ контроллеров. + +Если в контроллер мы добавим метод, который в теле ответа будет возвращать текст на кириллице, то мы увидим кодировка теряться. +Для сохранения кодировки используем `StringHttpMessageConverter`, который конфигурируем в `spring-mvc.xml`. +При этом мы должны явно указать, что конвертор будет работать только с текстом в кодировке *UTF-8*. + +
+ +#### Apply 7_16_soapui_utf8_converter.patch - Инструменты тестирования REST: - - SoapUi - - Написание HTTP-запросов с помощью Curl -(для Windows можно использовать Git Bash). Для работы с UTF-8 в Windows 10 нужны пляски с бубном: ["Язык и региональные стандарты" -> "Сопутствующие параметры" -> "Административные языковые параметры" -> "Изменить язык системы" -> галка "Бета-версия:Использовать Юникод (UTF-8) для поддержки языка во всем мире"](https://drive.google.com/open?id=1J1WquTv9wenJQ9ptMymXPYGnrvFzAV-L), перезагрузка. - - Postman - - IDEA: Tools->HTTP Client->... - - [Insomnia REST client](https://insomnia.rest/) + - SoapUi + - Написание HTTP-запросов с помощью + Curl. + Для Windows 7 можно использовать Git Bash, с Windows 10 v1803 можно прямо из консоли. Возможны проблемы с UTF-8: + - [CURL doesn't encode UTF-8](https://stackoverflow.com/a/41384903/548473) + - [Нстройка кодировки в Windows](https://support.socialkit.ru/ru/knowledge-bases/4/articles/11110-preduprezhdenie-obnaruzhenyi-problemyi-svyazannyie-s-raspoznavaniem-russkih-simvolov) + - **[IDEA: Tools->HTTP Client->...](https://www.jetbrains.com/help/idea/rest-client-tool-window.html)** + - Postman + - [Insomnia REST client](https://insomnia.rest/) -**Импортировать проект в SoapUi из config\Topjava-soapui-project.xml. Response смотреть в формате JSON.** +**Импортировать проект в SoapUi из `config\Topjava-soapui-project.xml`. Response смотреть в формате JSON.** -> Проверка UTF-8: http://localhost:8080/topjava/rest/profile/text +> Проверка UTF-8: http://localhost:8080/topjava/rest/profile/text -ResponseBody and UTF-8 +[ResponseBody and UTF-8](http://web.archive.org/web/20190102203042/http://forum.spring.io/forum/spring-projects/web/74209-responsebody-and-utf-8) ## ![question](https://cloud.githubusercontent.com/assets/13649199/13672858/9cd58692-e6e7-11e5-905d-c295d2a456f1.png) Ваши вопросы + +> Зачем у нас и UIController'ы, и RestController'ы? То есть в общем случае backend-разработчику недостаточно предоставить REST-api и RestController? + +В общем случае нужны и те и другие. REST обычно используют для отдельного UI например на React или Angular или для +интеграции / мобильного приложения. У нас REST контроллеры используются только для тестирования. UI мы используем для +нашего приложения на JSP шаблонах. Таких сайтов без богатой UI логики тоже немало. Например https://javaops.ru/ :) +Разница в запросах: + +- для UI используются только GET и POST +- при создании-обновлении в UI мы принимаем данные из формы `application/x-www-form-urlencoded` (посмотрите + вкладку `Network`, не в формате JSON) +- для REST запросы GET, POST, PUT, DELETE, PATCH и возвращают только данные (обычно JSON) + +и в способе авторизации: + +- для RESТ у нас будет базовая авторизация +- для UI - через cookies + +Также часто бывают смешанные сайты - где есть и отдельное JS приложение и шаблоны. + > При выполнении тестов через MockMvc никаких изменений на базе не видно, почему оно не сохраняет? -`AbstractControllerTest` аннотируется `@Transactional` - это означает, что тесты идут в транзакции, и после каждого теста JUnit делает rollback базы. +`AbstractControllerTest` аннотируется `@Transactional` - это означает, что тесты идут в транзакции, и после каждого +теста JUnit делает rollback базы. -> Что получается в результате выполнения запроса `SELECT DISTINCT(u) FROM User u LEFT JOIN FETCH u.roles ORDER BY u.name, u.email`? В чем разница в SQL без `DISTINCT`. +> Что получается в результате выполнения запроса `SELECT DISTINCT(u) FROM User u LEFT JOIN FETCH u.roles ORDER BY u.name, u.email`? В чем разница в SQL без `DISTINCT`. -Запросы SQL можно посмотреть в логах. Т.е. `DISTINCT` в `JPQL` влияет на то, как Hibernate обрабатывает дублирующиеся записи (с `DISTINCT` их исключает). Результат можно посмотреть в тестах или приложении, поставив брекпойнт. -По поводу `SQL DISTINCT` не стесняйтесь пользоваться google, например, [оператор SQL DISTINCT](http://2sql.ru/novosti/sql-distinct/) +Запросы SQL можно посмотреть в логах. Т.е. `DISTINCT` в `JPQL` влияет на то, как Hibernate обрабатывает дублирующиеся +записи (с `DISTINCT` их исключает). Результат можно посмотреть в тестах или приложении, поставив брекпойнт. По +поводу `SQL DISTINCT` не стесняйтесь пользоваться google, +например, [оператор SQL DISTINCT](http://2sql.ru/novosti/sql-distinct/) -> В чем заключается расширение функциональности hamcrest в нашем тесте, что нам пришлось его отдельно от JUnit прописывать? +> В чем заключается расширение функциональности hamcrest в нашем тесте, что нам пришлось его отдельно от JUnit прописывать? hamcrest-all используется в проверках `RootControllerTest`: `org.hamcrest.Matchers.*` -> Jackson мы просто подключаем в помнике, и Спринг будет с ним работать без любых других настроек? +> Jackson мы просто подключаем в помнике, и Spring будет с ним работать без любых других настроек? Да, Spring смотрит в classpath и если видит там Jackson, то подключает интеграцию с ним. -> Где-то слышал, что любой ресурс по REST должен однозначно идентифицироваться через url без параметров. Правильно ли задавать URL для фильтрации в виде `http://localhost/topjava/rest/meals/filter/{startDate}/{startTime}/{endDate}/{endTime}` ? +> Где-то слышал, что любой ресурс по REST должен однозначно идентифицироваться через url без параметров. Правильно ли задавать URL для фильтрации в виде `http://localhost/topjava/rest/meals/filter/{startDate}/{startTime}/{endDate}/{endTime}` ? + +Так делают, только при +отношении +агрегация, например, если давать админу право смотреть еду любого юзера, URL мог бы быть похож +на `http://localhost/topjava/rest/users/{userId}/meals/{mealId}` (не рекомендуется, см ссылку ниже). В случае критериев +поиска или страничных данных они передаются как параметр. Смотри также: -Так делают, только при отношении агрегация, например, если давать админу право смотреть еду любого юзера, URL мог бы быть похож на `http://localhost/topjava/rest/users/{userId}/meals/{mealId}`. В случае критериев поиска или страничных данных они передаются как параметр. Смотри также: - [15 тривиальных фактов о правильной работе с протоколом HTTP](https://habrahabr.ru/company/yandex/blog/265569/) -- 10 Best Practices for Better RESTful +- 10 Best Practices + for Better RESTful - [REST resource hierarchy (если кратко: не рекомендуется)](https://stackoverflow.com/questions/15259843/how-to-structure-rest-resource-hierarchy) > Что означает конструкция в `JsonUtil`: `reader.readValues(json)`; -См. Generic Methods. Когда компилятор не может вывести тип, можно его уточнить при вызове generic метода. Неважно, static или нет. +См. Generic Methods. Когда компилятор +не может вывести тип, можно его уточнить при вызове generic метода. Неважно, static или нет. ## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Домашнее задание HW07 - 1: Добавить тесты контроллеров: - - 1.1 `RootControllerTest.testMeals` для `meals.jsp` - - 1.2 `ResourceControllerTest` для `style.css` (проверить `status` и `ContentType`) + - 1.1 `RootControllerTest.getMeals` для `meals.jsp` + - 1.2 Сделать `ResourceControllerTest` для `style.css` (проверить `status` и `ContentType`) - 2: Реализовать `MealRestController` и протестировать его через `MealRestControllerTest` - - 2.1 следите, чтобы url в тестах совпадал с параметрами в методе контроллера. Можно добавить логирование `` для проверки маршрутизации. - - 2.2 в параметрах `getBetween` принимать `LocalDateTime` (конвертировать через @DATETIMEFORMAT WITH JAVA 8 DATE-TIME API), а передавать в тестах в формате `ISO_LOCAL_DATE_TIME` (например `'2011-12-03T10:15:30'`). Вызывать `super.getBetween()` пока без проверки на `null`, используя `toLocalDate()/toLocalTime()` (см. Optional п.3) - -#### Optional -- 3: Переделать `MealRestController.getBetween` на параметры `LocalDate/LocalTime` c раздельной фильтрацией по времени/дате, работающий при `null` значениях (см. демо и `JspMealController.getBetween`). Заменить `@DateTimeFormat` на свои LocalDate/LocalTime конверторы или форматтеры. - - Spring Type Conversion - - Spring Field Formatting - - Difference between Spring MVC formatters and converters -- 4: Протестировать `MealRestController` (SoapUi, curl, IDEA Test RESTful Web Service, Postman). Запросы `curl` занести в отдельный `md` файл (либо `README.md`) - -**На следующем занятии используется JavaScript/jQuery. Если у вас там пробелы, пройдите его основы** - + - 2.1 следите, чтобы url в тестах совпадал с параметрами в методе контроллера. Можно добавить + логирование `` для проверки маршрутизации. + - 2.2 в параметрах `getBetween` принимать `LocalDateTime` (конвертировать + через @DateTimeFormat with Java + 8 Date-Time API), пока без проверки на `null` (используя `toLocalDate()/toLocalTime()`, см. Optional п.3). В + тестах передавать в формате `ISO_LOCAL_DATE_TIME` ( + например `'2011-12-03T10:15:30'`). + +### Optional + +- 3: Переделать `MealRestController.getBetween` на параметры `LocalDate/LocalTime` c раздельной фильтрацией по + времени/дате, работающий при `null` значениях (см. демо и `JspMealController.getBetween`) + . Заменить `@DateTimeFormat` на свои LocalDate/LocalTime конверторы или форматтеры. + - Spring Type + Conversion + - Spring Field + Formatting + - + Difference between Spring MVC formatters and converters +- 4: Протестировать `MealRestController` (SoapUi, curl, IDEA Test RESTful Web Service, Postman). Запросы `curl` занести + в отдельный `md` файл (или `README.md`) +- 5: Добавить в `AdminRestController` и `ProfileRestController` методы получения пользователя вместе с + едой (`getWithMeals`, `/with-meals`). + - [Jackson – Bidirectional Relationships](https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion) + +### Optional 2 + +- 6: Сделать тесты на методы контроллеров `getWithMeals()` (п.5) + +**На следующем занятии используется JavaScript/jQuery. Если у вас там +пробелы, пройдите его основы** --------------------- + ## ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Типичные ошибки и подсказки по реализации + - 1: Ошибка в тесте _Invalid read array from JSON_ обычно расшифровывается немного ниже: читайте внимательно. -- 2: Jackson и неизменяемые объекты -- 3: Jackson JSON Tutorial -- 4: Если у meal, приходящий в контроллер, поля `null`, проверьте `@RequestBody` перед параметром (данные приходят в формате JSON) -- 5: При проблемах с собственным форматтером убедитесь, что в конфигурации `Jackson и неизменяемые объекты (для + сериализации MealTo) +- 3: Если у meal, приходящий в контроллер, поля `null`, проверьте `@RequestBody` перед параметром (данные приходят в + формате JSON) +- 4: При проблемах с собственным форматтером убедитесь, что в конфигурации ` Date: Mon, 23 Aug 2021 11:26:05 +0300 Subject: [PATCH 062/226] Update ReleaseNotes.md --- ReleaseNotes.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 7c03206fe59c..68ebc2ef69d7 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,5 +1,22 @@ # TopJava Release Notes +### Topjava 23 +- migrate to JDK 16 +- в новой spring-data-jpa `getOne` заменили на `getById` +- в UserUtil#prepareToSave убрал проверку пароля на `hasText`. На UI поле проверяется на `@NotBlank` +- `ProfileRestController#register` делаю по правилам REST (POST без "/register") +- css стили `data-...` сделал [low-case через дефисы](https://stackoverflow.com/questions/36176474/548473) +- `TestMatcher` переименовал в `MatcherFactory` +- Для Swagger UI пометил `AuthorizedUser` аннотацией `@ApiIgnore` + +### Topjava 22 + - очистка пароля `AuthorizedUser#userTo` + - заменил `@SafeHtml`, который удалили из `hibernate.validator` на [Jsoup.clean](https://stackoverflow.com/a/68888601/548473) + - перенес запрет на обновление admin/user в `UserService` + - проверку email на уникальность для update с `id=null` в теле запроса сделал на основе анализа `HttpServletRequest.getRequestURI()` + - проверку класса в `classpath` в `Profiles#getActiveDbProfile` делаю на `org.springframework.util.ClassUtils#isPresent` + - удалил `type="text/javascript"` + ### Topjava 21 - **добавили документирование REST API: Swagger** - мигрировали на JDK 15 и используем текстовые блоки From 86178d56da8d171f8afb5e6b185c5709e9eba26f Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 7 Sep 2021 13:04:44 +0300 Subject: [PATCH 063/226] Update graduation.md --- graduation.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/graduation.md b/graduation.md index 070424ded69d..f1f2fe3cbf5a 100644 --- a/graduation.md +++ b/graduation.md @@ -26,8 +26,7 @@ P.P.S.: Assume that your API will be used by a frontend developer to build front ----------------------------- ### ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Рекомендации -- **Сделай новый проект и добавляй туда из Topjava только то что нужно! Локализация, типы ошибок, BeanMatcher, Json View, излишние делегирования и наследования - не нужны!** -- **Рекомендую переписать проект современно: Spring Boot + Swagger/OpenAPI 3.0. Оптимально подойдет код миграции TopJava на Spring Boot в конце стажировки.** +- **Рекомендую писать проект современно: Spring Boot + Swagger/OpenAPI 3.0. Оптимально подойдет код миграции TopJava на Spring Boot в конце стажировки. Локализация, типы ошибок, BeanMatcher, Json View, излишние делегирования и наследования - не нужны!** - **Сначала сделай основной сценарий по ТЗ. Все остальное (если очень хочется, 3 раза подумай) - потом.** - API продумывай с точки зрения не программиста и объектов, а с точки зрения того, кто им будет пользоваться (frontend) From 2e65460975c07b60da4c9f3549f21862cd90a62d Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 7 Sep 2021 13:10:51 +0300 Subject: [PATCH 064/226] Update graduation.md --- graduation.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/graduation.md b/graduation.md index f1f2fe3cbf5a..5457a21193e0 100644 --- a/graduation.md +++ b/graduation.md @@ -63,11 +63,11 @@ _Антуан де Сент-Экзюпери_ - 13: [Use for money in java app](http://stackoverflow.com/a/43051227/548473) - 14: Еще раз про [hashCode/equals в Entity](https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma): не делайте сравнение по полям! - 15: Название пакетов, имен классов для `model/to/web` достаточно стандартные (например `model/domain`). НЕ надо придумывать своих собственных правил -- 16: **Используйте DATA-JPA** (можно без лишней делегации, напрямую из сервиса/контроллера дергать Repository) +- 16: **Используйте DATA-JPA** (без лишней делегации, напрямую из сервиса/контроллера дергать Repository) - 17: В DATA-JPA 2.x используются `Optional`. Попробуйте работать с ними, это безопасный способ работать с null значениями (используйте `orElseThrow`) -- 18: На topjava мы смотрели разные варианты использования, тут делаем максимально просто. С TO многие вещи упрощаются +- 18: На topjava мы смотрели разные варианты c использованием TO и без, критерий - делаем максимально просто. - 19: Проверьте, не торчат ли из кода учебные уши topjava, типа `ProfileRestController.testUTF()`, `AbstractServiceTest.printResult()` или закомментированные `JdbcTemplate`. Назначение этого проекта совсем другое -- 20: ORM работает с объектами. [В простейших случаях fk_id как поля допустимы](https://stackoverflow.com/questions/6311776/hibernate-foreign-keys-instead-of-entities), но при этом JPA их уже никак не обрабатывает и не используйте их вместе с объектами. Ссылка на stackoverflow в коде обязательна! +- 20: ORM работает с объектами. [Иногда, для упрощения логики, fk_id как поля допустимы](https://stackoverflow.com/questions/6311776/hibernate-foreign-keys-instead-of-entities) - 21: Проверьте, станет ли код проще с `@AuthenticationPrincipal` (урок 11, Доступ к AuthorizedUser). - 22: Обновление в базе делается через `update`, даже если `delete/insert` сократит java код на несколько строк - 23: Кэширование From d34fee895acb76b633c233f9e8d022c3c19bb844 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 7 Sep 2021 13:15:14 +0300 Subject: [PATCH 065/226] Update graduation.md --- graduation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graduation.md b/graduation.md index 5457a21193e0..02fb145d3b8a 100644 --- a/graduation.md +++ b/graduation.md @@ -25,7 +25,7 @@ P.P.S.: Assume that your API will be used by a frontend developer to build front ----------------------------- ### ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Рекомендации - +- **Не изобретай велосипедов! Грубая ошибка - пытаться сделать стандартные вещи по-своему, чаще всего криво. На проекте все должно быть единообразно! Ваш проект TopJava - сделай все МАКСИМАЛЬНО в этом стиле. Если тебе кажется, что у тебя есть лучшее решение, чем в TopJava - [пиши мне в личку](https://javaops.ru/#contacts), я всегда открыт для улучшений.** - **Рекомендую писать проект современно: Spring Boot + Swagger/OpenAPI 3.0. Оптимально подойдет код миграции TopJava на Spring Boot в конце стажировки. Локализация, типы ошибок, BeanMatcher, Json View, излишние делегирования и наследования - не нужны!** - **Сначала сделай основной сценарий по ТЗ. Все остальное (если очень хочется, 3 раза подумай) - потом.** - API продумывай с точки зрения не программиста и объектов, а с точки зрения того, кто им будет пользоваться (frontend) From 525c685f6f1a8963d31460d709c390efc40561a0 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 7 Sep 2021 13:22:40 +0300 Subject: [PATCH 066/226] Update graduation.md --- graduation.md | 1 + 1 file changed, 1 insertion(+) diff --git a/graduation.md b/graduation.md index 02fb145d3b8a..eab47ab2e652 100644 --- a/graduation.md +++ b/graduation.md @@ -79,6 +79,7 @@ _Антуан де Сент-Экзюпери_ - одних аннотаций недостаточно. Должны быть `@Valid/@Validation` - проверяйте входные данные при `create/update` **в контроллерах!** В TopJava это `ValidationUtil.checkNew()/assureIdConsistent()` - 25: `readme.md`: + - Будет хорошо поместить сюда ТЗ проекта - Если задание на English, описание пишите также на English (тоже самое относится к языку резюме: вакансия на English предполагает ваше резюме на English) - Требуемые примеры `curl` не прячьте, а пишите здесь! Оптимально - ссылка на Swagger. - Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven:) From 516b1a2329dcb4c772d7bb3da6a5c3f306da66a1 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 7 Sep 2021 13:35:14 +0300 Subject: [PATCH 067/226] Update graduation.md --- graduation.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/graduation.md b/graduation.md index eab47ab2e652..61024535f5de 100644 --- a/graduation.md +++ b/graduation.md @@ -84,6 +84,9 @@ _Антуан де Сент-Экзюпери_ - Требуемые примеры `curl` не прячьте, а пишите здесь! Оптимально - ссылка на Swagger. - Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven:) - 26: На управление (CRUD) ресторанами и едой должны быть ОТДЕЛЬНЫЕ контроллеры. Не надо все, что может админ, сваливать в одну кучу! +- 27: Git + - Должна быть история ваших комитов с внятными коментариями. Это смотрят. + - Не комить служенбые файлы: логи, DB, настройки IDEA и пр., это сразу тебя зачислит в Junior. Все это должно быть в `.gitignore` ## Попробуйте подергать свое API по всем типичным сценариям ТЗ! - Удобно использовать? Можно сделать проще? Например чтобы проголосовать за ресторан залогиненному юзеру достаточно `restorauntId`. From 3cbe770163af7f60d8299fcd468c470460dfd327 Mon Sep 17 00:00:00 2001 From: "admin@javaops.ru" Date: Sat, 18 Sep 2021 12:01:25 +0300 Subject: [PATCH 068/226] update graduation --- graduation.md | 191 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 124 insertions(+), 67 deletions(-) diff --git a/graduation.md b/graduation.md index 61024535f5de..360fd9da2d02 100644 --- a/graduation.md +++ b/graduation.md @@ -1,4 +1,5 @@ -## Выпускной проект +## Выпускной проект [стажировки TopJava](https://javaops.ru/view/topjava) + Design and implement a REST API using Hibernate/Spring/SpringMVC (or Spring-Boot) **without frontend**. The task is: @@ -16,82 +17,138 @@ Build a voting system for deciding where to have lunch. Each restaurant provides a new menu each day. -As a result, provide a link to github repository. It should contain the code, README.md with API documentation and couple curl commands to test it (better - Swagger). +As a result, provide a link to github repository. It should contain the code, README.md with API documentation and couple curl commands to test it (**better - link to Swagger**). ----------------------------- -P.S.: Make sure everything works with latest version that is on github :) - +P.S.: Make sure everything works with latest version that is on github :) P.P.S.: Assume that your API will be used by a frontend developer to build frontend on top of that. ----------------------------- -### ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Рекомендации -- **Не изобретай велосипедов! Грубая ошибка - пытаться сделать стандартные вещи по-своему, чаще всего криво. На проекте все должно быть единообразно! Ваш проект TopJava - сделай все МАКСИМАЛЬНО в этом стиле. Если тебе кажется, что у тебя есть лучшее решение, чем в TopJava - [пиши мне в личку](https://javaops.ru/#contacts), я всегда открыт для улучшений.** -- **Рекомендую писать проект современно: Spring Boot + Swagger/OpenAPI 3.0. Оптимально подойдет код миграции TopJava на Spring Boot в конце стажировки. Локализация, типы ошибок, BeanMatcher, Json View, излишние делегирования и наследования - не нужны!** -- **Сначала сделай основной сценарий по ТЗ. Все остальное (если очень хочется, 3 раза подумай) - потом.** -- API продумывай с точки зрения не программиста и объектов, а с точки зрения того, кто им будет пользоваться (frontend) -*Представьте себе, что ПМ (лид, архитектор) дал вам ТЗ и некоторое время недоступен. У вас, конечно, есть много мыслей, для чего нужно приложение, как исправить ТЗ, дополнить его и сделать правильно. НО НЕ НАДО ИХ РЕАЛИЗОВЫВАТЬ В КОДЕ. Нужно сделать все максимально просто, удобно для доработок и для использования со стороны клиента (если, конечно, в ТЗ нет оговорок). Все свои вопросы, предложения и хотелки оформляйте отдельно (в `read.me` например). Если делаете что-то сложнее простейшего случая (например, справочник еды) - обязательно напишите в read.me. Как и выбор стратегии кэширования.* +## ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Рекомендации + +**Пишем выпускной проект как тестовое задание на работу** + +- **Не изобретай велосипедов!** Грубая ошибка - пытаться сделать стандартные вещи по-своему, чаще всего криво. На проекте все должно быть единообразно! Ваш проект TopJava - сделай все МАКСИМАЛЬНО в этом + стиле. Если тебе кажется, что у тебя есть лучшее решение, чем в TopJava - пишите мне в личку, я всегда открыт для улучшений. +- **Рекомендую писать проект современно**: Spring Boot + Swagger/OpenAPI 3.0. Оптимально подойдет код миграции TopJava на Spring Boot в конце стажировки. + +*Представьте себе, что ПМ (лид, архитектор) дал вам ТЗ и некоторое время недоступен. У вас, конечно, есть много мыслей, для чего нужно приложение, как исправить ТЗ, дополнить его и сделать правильно. +НО НЕ НАДО ИХ РЕАЛИЗОВЫВАТЬ В КОДЕ. Нужно сделать все максимально просто, удобно для доработок и для использования со стороны клиента (если, конечно, в ТЗ нет оговорок).* > Совершенство достигнуто не тогда, когда нечего добавить, а тогда, когда нечего отнять _Антуан де Сент-Экзюпери_ -- 1: **Читаем ТЗ ОЧЕНЬ внимательно, НЕ надо ничего своего туда домысливать и творчески изменять** -- 2: **Тщательно считайте количество обращений в базу на каждый запрос. Особенно при запросах от юзеров, которых очень много! Также на сложность запросов от них, чтобы не положить базу**. Самое худшее в коде - обращение в базу в цикле. -- 3: **Тщательно считайте количество запросов в вашем API для отображения нужной информации** -- 4: Учитывайте, что **пользователей может быть ОООЧЕНЬ много, а админов - МАЛО** -- 5: В проекте (и тестовом задании на работу), в отличие от нашего учебного topjava, оставляйте только необходимый для работы приложения код, ничего лишнего: - - 5.1 НЕ надо делать разные профили базы и работы с ней - - 5.2 НЕ надо делать абстрактных контроллеров на всякий случай - - 5.3 НЕ надо делать **классов репозиториев и сервисов**, если там нет ничего, кроме делегирования - - 5.4 Из потребностей приложения (которую надо самим придумать) реализовывать только очевидные сценарии. То есть НИЧЕГО ЛИШНЕГО. -- 6: База Данных - - берите без установки (H2 или HSQLDB). Одну!! Ваше приложение должно сразу запуститься, **без всяких настроек и переменных окружения** - - сделайте индексы к таблицам. Попробуйте обеспечит UNIQUE (один голос пользователя в день, один уникальный пункт меню в день). Следите за порядком полей в индексе - - **историю еды и голосований сделать НУЖНО! Есть базовые вещи, которые закладываются в архитектуру приложения и неочевидные доработки к ТЗ, которых лучше не делать.** - - при популировании добавте записи за сегодняшний день - now(), чтобы всегда были актуальные исходные данные - - таблицы обычно именуются в единственном числе. Исключение - users, т. к. user - зарезервированное слово. `date`/`timestamp` - зарезервированное слово, лучше избегать их при именовании -- 7: По возможности сделать JUnit тесты -- 8: Уделяйте внимание обработке ошибок -- 9: Делаем REST API в соответствии с концепцией REST (url в общем имеют вид`{ресурс}/{id_ресурсa}[/{подресурс}/{id_подресурсa}][параметры]`) +### 1: ТЗ + +- 1.1: Читай ТЗ ОЧЕНЬ внимательно, НЕ надо ничего своего туда домысливать и творчески изменять +- 1.2: Учитывай, что пользователей может быть ОООЧЕНЬ много, а админов - МАЛО +- 1.3: Сначала сделай основной сценарий по ТЗ. Все остальное (если очень хочется, 3 раза подумай) - потом. + +### 2. API + +- 2.1: API продумывай с точки зрения не программиста и объектов, а с точки зрения того, кто им будет пользоваться (клиента, UI) +- 2.1: Тщательно считайте количество запросов в вашем API для отображения нужной информации +- 2.3: Из потребностей приложения (клиента) реализуй только очевидные сценарии. Необходимо и достаточно: ВСЕ НЕОБХОДИМОЕ для клиента и НИЧЕГО ЛИШНЕГО. Процесс творческий, приходит с опытом. +- 2.4: Делаем REST API в соответствии с концепцией REST (url в общем имеют вид`{ресурс}/{id_ресурсa}[/{подресурс}/{id_подресурсa}][параметры]`). Имена ресурсов во множественном числе! +Самая распространенная и грубая ошибка - не придерживаться этих простых правил. - **[15 тривиальных фактов о правильной работе с протоколом HTTP](https://habrahabr.ru/company/yandex/blog/265569/)** - - **10 Best Practices for Better RESTful API** + - **[10 Best Practices for Better RESTful API](https://medium.com/@mwaysolutions/10-best-practices-for-better-restful-api-cbe81b06f291)** - [REST resource hierarchy](https://stackoverflow.com/questions/20951419/what-are-best-practices-for-rest-nested-resources) -- 10: Не смешивайте TO и Entity вместе. Лучше всего, если они будут независимыми друг от друга. -- 11: Не размещайте логику приложения и преобразования в TO в слое доступа к DB -- 12: Если приложению в объекте требуется только его id, используйте reference (как мы при сохранении еды вставляем туда юзера) -- 13: [Use for money in java app](http://stackoverflow.com/a/43051227/548473) -- 14: Еще раз про [hashCode/equals в Entity](https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma): не делайте сравнение по полям! -- 15: Название пакетов, имен классов для `model/to/web` достаточно стандартные (например `model/domain`). НЕ надо придумывать своих собственных правил -- 16: **Используйте DATA-JPA** (без лишней делегации, напрямую из сервиса/контроллера дергать Repository) -- 17: В DATA-JPA 2.x используются `Optional`. Попробуйте работать с ними, это безопасный способ работать с null значениями (используйте `orElseThrow`) -- 18: На topjava мы смотрели разные варианты c использованием TO и без, критерий - делаем максимально просто. -- 19: Проверьте, не торчат ли из кода учебные уши topjava, типа `ProfileRestController.testUTF()`, `AbstractServiceTest.printResult()` или закомментированные `JdbcTemplate`. Назначение этого проекта совсем другое -- 20: ORM работает с объектами. [Иногда, для упрощения логики, fk_id как поля допустимы](https://stackoverflow.com/questions/6311776/hibernate-foreign-keys-instead-of-entities) -- 21: Проверьте, станет ли код проще с `@AuthenticationPrincipal` (урок 11, Доступ к AuthorizedUser). -- 22: Обновление в базе делается через `update`, даже если `delete/insert` сократит java код на несколько строк -- 23: Кэширование - - необязательно, но желательно. Чем проще реализация - тем лучше. - - **тщательно продумайте, что надо кэшировать (самые частые запросы)**, а что нет (большие или редко запрашиваемые данные)! - - проверьте соответствие ключей к кэшу (параметры кэшируемого метода) с конфигурацией (например в singleNonExpiryCache, heap=1 в кэше может содержаться только ОДНО значение). -- 24: Валидация - - желательна - - одних аннотаций недостаточно. Должны быть `@Valid/@Validation` - - проверяйте входные данные при `create/update` **в контроллерах!** В TopJava это `ValidationUtil.checkNew()/assureIdConsistent()` -- 25: `readme.md`: - - Будет хорошо поместить сюда ТЗ проекта - - Если задание на English, описание пишите также на English (тоже самое относится к языку резюме: вакансия на English предполагает ваше резюме на English) - - Требуемые примеры `curl` не прячьте, а пишите здесь! Оптимально - ссылка на Swagger. - - Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven:) -- 26: На управление (CRUD) ресторанами и едой должны быть ОТДЕЛЬНЫЕ контроллеры. Не надо все, что может админ, сваливать в одну кучу! -- 27: Git - - Должна быть история ваших комитов с внятными коментариями. Это смотрят. - - Не комить служенбые файлы: логи, DB, настройки IDEA и пр., это сразу тебя зачислит в Junior. Все это должно быть в `.gitignore` - -## Попробуйте подергать свое API по всем типичным сценариям ТЗ! -- Удобно использовать? Можно сделать проще? Например чтобы проголосовать за ресторан залогиненному юзеру достаточно `restorauntId`. -- Сколько раз пришлось его вызвать API для типичного сценария (нарпимер посмотреть рестораны с едой на сегодня)? -- Сколько запросов к базе было сделано? Можно ли сократить (например с FETCH/Graph или через кэширование)? -- **API ДОЛЖНО соответствовать принципам REST (см. ссылки выше)** -- **ОБЯЗАТЕЛЬНО: запустите `mvn test`- ошибок быть не должно** -- **ОБЯЗАТЕЛЬНО: запустите приложение без всяких предварительных настроек (базы, переменных окружения, ..), лучше на другом компьютере. Должно запускаться!** + - [Лучшие практики разработки REST API: правила 1-7,15-17](https://tproger.ru/translations/luchshie-praktiki-razrabotki-rest-api-20-sovetov/) +- 2.5: Разделение на роли я предпочитаю на уровне URL. Сразу и однозначно видно, какой API у админа, какое у юзера. +- 2.6: На управление (CRUD) ресторанами и едой должны быть ОТДЕЛЬНЫЕ контроллеры. Не надо все, что может админ, сваливать в одну кучу! +- 2.7: Проверьте в Swagger, что в POST и GET нет ничего лишнего, а в GET есть все необходимые данные. Например, при запросе голоса должен быть `id` ресторана, а при +создании-редактировании ресторана не должно быть меню и еды. +- 2.8: `Profile` означает, что данные принадлежат профилю пользователя. Все остальное называйте по-другому. + +### 3: Код: +- 5.1: Строго соблюдайте соглашения Java по именованию: пакеты ТОЛЬКО маленькими буквами, методы начинаются с маленькой буквы, классы с большой. Незнания Java Core - тестовое задание сразу в корзину. +- 5.2 В проекте (и тестовом задании на работу), в отличие от нашего учебного topjava, оставляйте только необходимый для работы по ТЗ приложения код, ничего лишнего + - 5.2.1: НЕ надо делать разные профили базы и работы с ней + - 5.2.2: НЕ надо делать абстрактных контроллеров на всякий случай + - 5.2.3: НЕ надо делать сервисов, если там нет ничего, кроме делегирования + - 5.2.4: НЕ нужны локализация, UI, типы ошибок, Json View +- 5.3: Название пакетов, имен классов для `model/to/web` стандартные (например `model/domain`). НЕ надо придумывать своих собственных правил +- 5.4: Проверьте, не торчат ли из кода учебные уши TopJava, типа `ProfileRestController.testUTF()`, `AbstractServiceTest.printResult()` или закомментированные `JdbcTemplate`. Назначение выпускного + совсем другое +- 5.5: Вместо `return ResponseEntity.ok(object)` в контроллерах пишите `return object`. Проще! + +### 4: Модель + +- 4.1: Историю еды и голосований делать НУЖНО (история означает, что в БД хранятся и не удаляются голоса пользователей и меню на любой день. Есть базовые вещи, которые закладываются в архитектуру + приложения и неочевидные доработки к ТЗ, которых лучше не делать. +- 4.2: Не делайте в модели объектов, которые не будут использоваться в коде (например, не надо двунаправленных связей, если достаточно однонаправленных) +- 4.3: еще раз про [hashCode/equals в Entity](https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma): не делайте в модели сравнение по полям! +- 4.4: ORM работает с объектами. [Иногда, для упрощения логики, fk_id как поля допустимы](https://stackoverflow.com/questions/6311776/hibernate-foreign-keys-instead-of-entities) + +### 5: Архитектура +- 5.1: Можно: + - или подключить DATA-REST (см.курс [Spring Boot 2.x + HATEOAS](https://javaops.ru/view/bootjava)). Контроллеры генерируются автоматически по репозиториям, требуется настройка ресурсов в кастомных контроллерах + - или делать на основе миграции TopJava / кода [TopJava-2](https://github.com/JavaOPs/topjava2) + +Нельзя смешивать эти подходы вместе! Я рекомендую 2-й вариант, без data-rest. Обязательно посмотрите, что у вас получилось в результате в swagger. +- 5.2: Не размещайте бизнес-логику приложения и преобразования в TO в слое доступа к DB +- 5.3: Не смешивайте TO и Entity вместе. Они должны быть независимыми друг от друга. На TopJava мы смотрели разные варианты [c использованием TO и без](https://stackoverflow.com/a/21569720/548473). + Делаем максимально просто. +- 5.4: Репозитории + - 5.4.1: Используйте DATA-JPA (без лишней делегации). Из сервиса/контроллера напрямую вызывайте Repository + - 5.4.2: Если приложению в объекте требуется только его id, используйте reference (`getById`) + - 5.4.3: В DATA-JPA 2.x используются `Optional`. Попробуйте работать с ними, это безопасный способ работать с null-значениями (используйте `orElseThrow`) + - 5.4.4: Обновление в базе делается через `update`, даже если `delete/insert` сократит java-код на несколько строк +- 5.5: [Use for money in java app](http://stackoverflow.com/a/43051227/548473) + +### 6: База Данных + +- 6.1: Берите без установки (H2 или HSQLDB). Одну и **в памяти**! Ваше приложение должно сразу запуститься, без всяких настроек и переменных окружения +- 6.2: Тщательно считайте количество обращений в базу на каждый запрос. Особенно при запросах от юзеров, которых очень много! Также на сложность запросов от них, чтобы не положить базу +- 6.3: Сделайте индексы к таблицам. Попробуйте обеспечить UNIQUE (один голос пользователя в день, один уникальный пункт меню в день). Следите за порядком полей в индексе +- 6.4: При популировании добавь записи за сегодняшний день - `now()`, чтобы всегда были актуальные исходные данные +- 6.5: Поля базы case insensitive, на пишите camelStyle. +- 6.6: Таблицы обычно именуются в единственном числе. Исключение - users, т. к. user - зарезервированное слово. +- 6.7: `date`/`timestamp` - зарезервированное слово, лучше избегать их при именовании полей + +### 7: Security + +- 7.1: Проверьте, станет ли код проще с `@AuthenticationPrincipal` (урок 11, Доступ к AuthorizedUser). +- 7.2: Я предпочитаю четкое разделение ролей на основе URL. Для админа URL содержит `/admin` +- 7.3: Еще раз - призываю не менять код TopJava + +### 8: Кэширование необязательно, но желательно. Старайтесь сделать реализацию попроще. + +- 8.1: Тщательно продумайте, что надо кэшировать (самые частые запросы), а что нет (большие или редко запрашиваемые данные)! +- 8.2: Проверьте соответствие ключей к кэшу (параметры кэшируемого метода) с конфигурацией (например в singleNonExpiryCache, heap=1 в кэше может содержаться только ОДНО значение). + +### 9: Валидация данных желательна + +- 9.1: Одних аннотаций недостаточно. Должны быть `@Valid/@Validation` +- 9.2: Проверяйте входные данные при `create/update` в контроллерах! В TopJava это `ValidationUtil.checkNew()/assureIdConsistent()` + +### 10: Дополнительно + +- 10.1: По возможности сделать JUnit-тесты. Можно не делать 100% покрытие, только основные сценарии +- 10.2: Уделяйте внимание обработке ошибок + +### 11: `readme.md`: + +- 11.1: Поместите вначале `readme` ТЗ - будет понятно о чем он проект +- 11.2: Если задание на English, описание пишите также на English (тоже самое относится к языку резюме: вакансия на English предполагает ваше резюме на English) +- 11.3: Требуемые примеры `curl` не прячьте, а пишите здесь! Оптимально здесь должна быть ссылка на `Swagger UI` с креденшелами для выполнения запросов +- 11.4: Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven:) + +### 12: Git + +- Должна быть история ваших комитов с внятными комментариями. Это смотрят. +- Не комить служенбые файлы: логи, DB, настройки IDEA и пр., это сразу - уровень Junior. +- Все служебные файлы должны быть в `.gitignore` + +### 13: Проверка + +- 13.1: Попробуйте подергать свое API по всем типичным сценариям ТЗ! + - 13.1.2: Удобно использовать? Можно сделать проще? Например, чтобы проголосовать за ресторан залогиненному юзеру, достаточно `restorauntId`. + - 13.1.3: Сколько раз пришлось его вызвать API для типичного сценария (например посмотреть рестораны с едой на сегодня)? + - 13.1.4: Сколько запросов к базе было сделано? Можно ли сократить (например с `FETCH/Graph` или через кэширование)? +- 13.2: API ДОЛЖЕН соответствовать принципам REST (см. ссылки выше) +- 13.3: ОБЯЗАТЕЛЬНО: запустите `mvn test` - ошибок быть не должно +- 13.4: ОБЯЗАТЕЛЬНО: запустите приложение без всяких предварительных настроек (базы, переменных окружения, ..), лучше на другом компьютере. Приложение должно запускаться и работать! From 00763ee072815c33b7b5f6245b88961ae188b476 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 21 Sep 2021 21:30:56 +0300 Subject: [PATCH 069/226] Update cv.md --- cv.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cv.md b/cv.md index f459060b227a..29d5aec06555 100644 --- a/cv.md +++ b/cv.md @@ -94,7 +94,7 @@ - [headz.io](https://app.headz.io/candidates/new) - djinni.co (более актуально для Украины) - +[Как изучать Java. Подборка от JavaRush](https://javarush.ru/groups/posts/3538-v-zakladki-kak-izuchatjh-java-boljhshaja-podborka-po-planu-obuchenija-instrumentam-i-poiskam-mo)

Как выжить на испытательном сроке

- Учись грамотно формулировать проблему. Проблема "у меня не работает" может иметь тысячи причин. В @@ -120,4 +120,5 @@ - Типичные ошибки начинающих программистов от JavaRush: - [Часть 1](https://javarush.ru/groups/posts/3044-razbor-tipichnihkh-oshibok-nachinajujshikh-programmistov-chastjh-1) - [Часть 2](https://javarush.ru/groups/posts/3055-razbor-tipichnihkh-oshibok-nachinajujshikh-programmistov-chastjh-2) +- [От джуна к миддлу: практические советы](https://tproger.ru/articles/ot-dzhuna-k-middlu-prakticheskie-sovety) ## [Отзывы по стажировке Topjava](https://vk.com/topic-74381644_30447246) From eb6bc99faaa38dbefd16a0667fbcbb488e09c96e Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 21 Sep 2021 22:42:29 +0300 Subject: [PATCH 070/226] Update README.md --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2941a385669b..f99b0d5a8c1e 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,12 @@ Java Enterprise Online Project =============== ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. Осваиваем Java Enterprise. Трудоустройство. Ответы на вопросы. - Слайды презентации -- Java Tools and Technologies Landscape Report 2016 -- [Java in 2017 Survey](http://www.baeldung.com/java-in-2017) -- Из юниоров в разработчики: получаем первую работу +- [Популярность Java-технологий в 2019 году](https://topjava.ru/blog/sostoyanie-java-v-2019-godu) +- [Java Technology Report 2021](https://www.jrebel.com/blog/2021-java-technology-report) +- [The State of Developer Ecosystem 2020](https://www.jetbrains.com/lp/devecosystem-2020/java/) +- [JVM Ecosystem Report 2021](https://snyk.io/jvm-ecosystem-report-2021/) +- [Быть программистом: от детства к зрелости](https://www.youtube.com/watch?v=D5Hej0TyLaU) +- [Литература](https://javaops.ru/view/books) #### Spring Pet-Clinic - Spring PetClinic Sample Application From 485118a6668d580599b7e80fbde87f12043fcbfe Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 22 Sep 2021 01:01:21 +0300 Subject: [PATCH 071/226] Update graduation.md --- graduation.md | 1 + 1 file changed, 1 insertion(+) diff --git a/graduation.md b/graduation.md index 360fd9da2d02..b42a9cce210b 100644 --- a/graduation.md +++ b/graduation.md @@ -149,6 +149,7 @@ _Антуан де Сент-Экзюпери_ - 13.1.2: Удобно использовать? Можно сделать проще? Например, чтобы проголосовать за ресторан залогиненному юзеру, достаточно `restorauntId`. - 13.1.3: Сколько раз пришлось его вызвать API для типичного сценария (например посмотреть рестораны с едой на сегодня)? - 13.1.4: Сколько запросов к базе было сделано? Можно ли сократить (например с `FETCH/Graph` или через кэширование)? + - 13.1.5: **Еще раз - проверьте все запросы в Sawgger, смотрите на формат запросов и данные в ответе. Все должно работать, есть все данные и нет ничего лишнего** - 13.2: API ДОЛЖЕН соответствовать принципам REST (см. ссылки выше) - 13.3: ОБЯЗАТЕЛЬНО: запустите `mvn test` - ошибок быть не должно - 13.4: ОБЯЗАТЕЛЬНО: запустите приложение без всяких предварительных настроек (базы, переменных окружения, ..), лучше на другом компьютере. Приложение должно запускаться и работать! From 464e6be7fb5177ed56af585dba3596af9bd32b21 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 26 Sep 2021 22:57:12 +0300 Subject: [PATCH 072/226] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f99b0d5a8c1e..8f9eb1c5fb58 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Java Enterprise Online Project =============== ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. Осваиваем Java Enterprise. Трудоустройство. Ответы на вопросы. - Слайды презентации +- [Как стать профессиональным Java разработчиком](https://www.youtube.com/watch?v=ft0Nj8Cm9kk) - [Популярность Java-технологий в 2019 году](https://topjava.ru/blog/sostoyanie-java-v-2019-godu) - [Java Technology Report 2021](https://www.jrebel.com/blog/2021-java-technology-report) - [The State of Developer Ecosystem 2020](https://www.jetbrains.com/lp/devecosystem-2020/java/) From 7bcdf2c92b2c5fc80cdeee974442a59bd4dd4bc5 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 26 Sep 2021 23:23:29 +0300 Subject: [PATCH 073/226] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8f9eb1c5fb58..e4cdd4bbb95f 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Java Enterprise Online Project Вводное занятие (обязательно смотреть все видео) =============== -## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. Осваиваем Java Enterprise. Трудоустройство. Ответы на вопросы. +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. Осваиваем Java Enterprise. Трудоустройство. Ответы на вопросы. - Слайды презентации - [Как стать профессиональным Java разработчиком](https://www.youtube.com/watch?v=ft0Nj8Cm9kk) - [Популярность Java-технологий в 2019 году](https://topjava.ru/blog/sostoyanie-java-v-2019-godu) @@ -33,7 +33,7 @@ Java Enterprise Online Project - Spring PetClinic Sample Application - Presentation -## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2. Системы управления версиями. Git. +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 2. Системы управления версиями. Git. - **Wiki по ведению проекта в Git** - Система управления версиями. VCS/DVSC. - Ресурсы: @@ -47,7 +47,7 @@ Java Enterprise Online Project - [Git - для новичков](https://www.youtube.com/watch?list=PLY4rE9dstrJyTdVJpv7FibSaXB4BHPInb&v=PEKN8NtBDQ0) - [Руководство по написанию комментариев в коммитах](https://techrocks.ru/2019/12/02/writing-good-commit-messages) -## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. Работа с проектом (выполнять инструкции) +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 3. Работа с проектом (выполнять инструкции) - **ВНИМАНИЕ: выбирайте для проекта простой пусть без пробелов и русских букв, например (Windows) `c:\projects\topjava\`. Иначе впоследствии будут проблемы** - **Плагин уже Git Intergation не требуется и вкладку `Version control` в IDEA переименовали в `Git`** @@ -80,7 +80,7 @@ Java Enterprise Online Project - Выполнить задание и залить на GitHub (commit + push) - Переключиться в основную ветку проекта master. -## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Тех.задание: библия или допускаются изменения. Полуоткрытый интервал.](https://drive.google.com/file/d/1BpTzjNFjS0TSekCyt_xvt6YoLvuw5KTZ/view) +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Тех.задание: библия или допускаются изменения. Полуоткрытый интервал.](https://drive.google.com/file/d/1BpTzjNFjS0TSekCyt_xvt6YoLvuw5KTZ/view?usp=sharing) - [Типы промежутков](https://ru.wikipedia.org/wiki/Промежуток_(математика)) ## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Домашнее задание HW0 From b612a114ab979f08d04613f9d00e090a13fc4553 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 26 Sep 2021 23:40:19 +0300 Subject: [PATCH 074/226] Update lesson07.md --- doc/lesson07.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/lesson07.md b/doc/lesson07.md index 2b46394101bf..1a3b1fe72692 100644 --- a/doc/lesson07.md +++ b/doc/lesson07.md @@ -2,7 +2,7 @@ ## [Почему мы?](http://javaops.ru/#why) ## REST, REST контроллеры, тестирование Spring MVC контроллеров -# Для просмотра открыты видео [4](#--4-миграция-на-junit-5), [5](#-5-принципы-rest-rest-контроллеры), [6](#-6-тестирование-rest-контроллеров-jackson), [7](#-7-кастомизация-jackson-object-mapper), [8](#-8-тестирование-rest-контроллеров-через-jsonassert) +# Для просмотра открыты видео [4](#--4-миграция-на-junit-5), [5](#-5-принципы-rest-rest-контроллеры), [6](#-6-тестирование-rest-контроллеров-jackson), [7](#-7-кастомизация-jackson-object-mapper), [8](#user-content--8-тестирование-rest-контроллеров-через-jsonassert-и-матчеры) - Не стоит стремиться прочитать все ссылки урока, их можно использовать как справочник. Гораздо важнее пройти основной материал урока и сделать Домашнее Задание - Обязательно посмотри правила работы с патчами на проекте - Делать Apply Patch лучше по одному, непосредственно перед видео на эту тему, а при просмотре видео сразу отслеживать все изменения кода проекта по изменению в патче (`Version Control->Local Changes-> Ctrl+D`) From 1cba20e1c6a1bd876cc25cf0e38fe55b2388b0c6 Mon Sep 17 00:00:00 2001 From: "admin@javaops.ru" Date: Mon, 27 Sep 2021 22:33:40 +0300 Subject: [PATCH 075/226] fix closed google disk urls --- README.md | 2 +- cv.md | 4 ++-- description.md | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e4cdd4bbb95f..f1545d04f5f2 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ Java Enterprise Online Project - Java 8 Date and Time API - Алгоритмы и структуры данных для начинающих: сложность алгоритмов - [Головач: сложность алгоритмов в теме коллекций](https://www.youtube.com/watch?v=Ek9ijOiplNE&feature=youtu.be&t=778) -- Time complexity +- Time complexity - Временная сложность алгоритма - Вычислительная сложность diff --git a/cv.md b/cv.md index 29d5aec06555..910b9ad88ab6 100644 --- a/cv.md +++ b/cv.md @@ -3,7 +3,7 @@ ![cv](https://cloud.githubusercontent.com/assets/13649199/10877471/93ea86b8-8157-11e5-9bfa-95e3fba75c58.jpg) - Научиться программировать сложнее, чем кажется -- [Собеседование. Разработка ПО. Вопросы.](https://drive.google.com/open?id=0B9Ye2auQ_NsFQVc2WUdCR0xvLWM) +- [Собеседование. Разработка ПО. Вопросы.](https://drive.google.com/file/d/0B9Ye2auQ_NsFQVc2WUdCR0xvLWM/view?usp=sharing&resourcekey=0-HaWoRxoyboMSKjg5P2I1cQ) - [Набор ссылок для тренировки и прохождения интервью](https://github.com/andreis/interview) ### Составление резюме: @@ -50,7 +50,7 @@ - Тест на знание SQL - Вопросы на собеседовании Java Junior Developer - Java вопросы с собеседований на Android -- Сборка вопросов от JavaRush +- Сборка вопросов от JavaRush > про clone и finalize объязательно прочтите Джошуа Блох: Java. Эффективное программирование (второе издание) - Cracking the Coding Interview diff --git a/description.md b/description.md index 0834140f19a7..e3626957efc7 100644 --- a/description.md +++ b/description.md @@ -13,7 +13,7 @@ Hibernate, делаем конверторы для типов LocalDateTime (Ja ## План проекта (ссылки на некоторые темы открыты для просмотра) ### Архитектура проекта. Персистентность. -- Системы управления версиями +- Системы управления версиями - Java 8: Lambda, Stream API - Обзор используемых в проекте технологий и инструментов. - Инструмент сборки Maven @@ -56,7 +56,7 @@ Hibernate, делаем конверторы для типов LocalDateTime (Ja - Spring Binding/Validation - Работа с datatables через Ajax. - Spring Security Test -- [Кастомизация JSON (@JsonView) и валидации (groups)](https://drive.google.com/open?id=0B9Ye2auQ_NsFRTFsTjVHR2dXczA) +- [Кастомизация JSON (@JsonView) и валидации (groups)](https://drive.google.com/file/d/0B9Ye2auQ_NsFRTFsTjVHR2dXczA/view?usp=sharing&resourcekey=0-Ou4A_gRor5HaRho4Fciqdw) - Encoding password - CSRF (добавление в проект защиты от межсайтовой подделки запроса) - form-login. Spring Security Taglib @@ -65,11 +65,11 @@ Hibernate, делаем конверторы для типов LocalDateTime (Ja - Смена локали - Фильтрация JSON с помощью @JsonView - Защита от XSS (Cross Site Scripting) -- Деплой в Heroku +- Деплой в Heroku - Локализация datatables, ошибок валидации - Обработка ошибок 404 (NotFound) - Доступ к AuthorizedUser -- Собеседование. Разработка ПО +- Собеседование. Разработка ПО ### Миграция на Spring Boot - Основы Spring Boot. Spring Boot maven plugin From b72af3345aed61ce3316a87924c29940a0613b48 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 28 Sep 2021 15:21:27 +0300 Subject: [PATCH 076/226] Update graduation.md --- graduation.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/graduation.md b/graduation.md index b42a9cce210b..250ce62ab04e 100644 --- a/graduation.md +++ b/graduation.md @@ -57,23 +57,23 @@ _Антуан де Сент-Экзюпери_ - **[10 Best Practices for Better RESTful API](https://medium.com/@mwaysolutions/10-best-practices-for-better-restful-api-cbe81b06f291)** - [REST resource hierarchy](https://stackoverflow.com/questions/20951419/what-are-best-practices-for-rest-nested-resources) - [Лучшие практики разработки REST API: правила 1-7,15-17](https://tproger.ru/translations/luchshie-praktiki-razrabotki-rest-api-20-sovetov/) -- 2.5: Разделение на роли я предпочитаю на уровне URL. Сразу и однозначно видно, какой API у админа, какое у юзера. +- 2.5: Разделение на роли я предпочитаю на уровне URL. Сразу и однозначно видно, какой API у админа, какое у пользователя (API админа начинается, например, с */admin/...*). - 2.6: На управление (CRUD) ресторанами и едой должны быть ОТДЕЛЬНЫЕ контроллеры. Не надо все, что может админ, сваливать в одну кучу! -- 2.7: Проверьте в Swagger, что в POST и GET нет ничего лишнего, а в GET есть все необходимые данные. Например, при запросе голоса должен быть `id` ресторана, а при +- 2.7: Проверьте в Swagger, что в POST и PUT нет ничего лишнего, а в GET есть все необходимые данные. Например, при запросе голоса должен быть `id` ресторана, а при создании-редактировании ресторана не должно быть меню и еды. - 2.8: `Profile` означает, что данные принадлежат профилю пользователя. Все остальное называйте по-другому. ### 3: Код: -- 5.1: Строго соблюдайте соглашения Java по именованию: пакеты ТОЛЬКО маленькими буквами, методы начинаются с маленькой буквы, классы с большой. Незнания Java Core - тестовое задание сразу в корзину. -- 5.2 В проекте (и тестовом задании на работу), в отличие от нашего учебного topjava, оставляйте только необходимый для работы по ТЗ приложения код, ничего лишнего - - 5.2.1: НЕ надо делать разные профили базы и работы с ней - - 5.2.2: НЕ надо делать абстрактных контроллеров на всякий случай - - 5.2.3: НЕ надо делать сервисов, если там нет ничего, кроме делегирования - - 5.2.4: НЕ нужны локализация, UI, типы ошибок, Json View -- 5.3: Название пакетов, имен классов для `model/to/web` стандартные (например `model/domain`). НЕ надо придумывать своих собственных правил -- 5.4: Проверьте, не торчат ли из кода учебные уши TopJava, типа `ProfileRestController.testUTF()`, `AbstractServiceTest.printResult()` или закомментированные `JdbcTemplate`. Назначение выпускного +- 3.1: Строго соблюдайте соглашения Java по именованию: пакеты ТОЛЬКО маленькими буквами, методы начинаются с маленькой буквы, классы с большой. Незнания Java Core - тестовое задание сразу в корзину. +- 3.2 В проекте (и тестовом задании на работу), в отличие от нашего учебного topjava, оставляйте только необходимый для работы по ТЗ приложения код, ничего лишнего + - 3.2.1: НЕ надо делать разные профили базы и работы с ней + - 3.2.2: НЕ надо делать абстрактных контроллеров на всякий случай + - 3.2.3: НЕ надо делать сервисов, если там нет ничего, кроме делегирования + - 3.2.4: НЕ нужны локализация, UI, типы ошибок, Json View +- 3.3: Название пакетов, имен классов для `model/to/web` стандартные (например `model/domain`). НЕ надо придумывать своих собственных правил +- 3.4: Проверьте, не торчат ли из кода учебные уши TopJava, типа `ProfileRestController.testUTF()`, `AbstractServiceTest.printResult()` или закомментированные `JdbcTemplate`. Назначение выпускного совсем другое -- 5.5: Вместо `return ResponseEntity.ok(object)` в контроллерах пишите `return object`. Проще! +- 3.5: Вместо `return ResponseEntity.ok(object)` в контроллерах пишите `return object`. Проще! ### 4: Модель @@ -103,7 +103,7 @@ _Антуан де Сент-Экзюпери_ - 6.1: Берите без установки (H2 или HSQLDB). Одну и **в памяти**! Ваше приложение должно сразу запуститься, без всяких настроек и переменных окружения - 6.2: Тщательно считайте количество обращений в базу на каждый запрос. Особенно при запросах от юзеров, которых очень много! Также на сложность запросов от них, чтобы не положить базу -- 6.3: Сделайте индексы к таблицам. Попробуйте обеспечить UNIQUE (один голос пользователя в день, один уникальный пункт меню в день). Следите за порядком полей в индексе +- 6.3: Сделайте индексы к таблицам. Попробуйте обеспечить UNIQUE (один голос пользователя в день, один уникальный пункт меню в день). Следите за порядком полей в индексе, от этого зависит индексирование запросов. - 6.4: При популировании добавь записи за сегодняшний день - `now()`, чтобы всегда были актуальные исходные данные - 6.5: Поля базы case insensitive, на пишите camelStyle. - 6.6: Таблицы обычно именуются в единственном числе. Исключение - users, т. к. user - зарезервированное слово. @@ -122,7 +122,7 @@ _Антуан де Сент-Экзюпери_ ### 9: Валидация данных желательна -- 9.1: Одних аннотаций недостаточно. Должны быть `@Valid/@Validation` +- 9.1: Одних аннотаций валидации недостаточно. Должны быть `@Valid/@Validation` - 9.2: Проверяйте входные данные при `create/update` в контроллерах! В TopJava это `ValidationUtil.checkNew()/assureIdConsistent()` ### 10: Дополнительно @@ -132,8 +132,8 @@ _Антуан де Сент-Экзюпери_ ### 11: `readme.md`: -- 11.1: Поместите вначале `readme` ТЗ - будет понятно о чем он проект -- 11.2: Если задание на English, описание пишите также на English (тоже самое относится к языку резюме: вакансия на English предполагает ваше резюме на English) +- 11.1: Поместите вначале `readme` ТЗ или ссылку на него - будет понятно о чем твой проект +- 11.2: Если задание на English, описание пиши также на English (то же самое относится к языку резюме: вакансия на English предполагает резюме на English) - 11.3: Требуемые примеры `curl` не прячьте, а пишите здесь! Оптимально здесь должна быть ссылка на `Swagger UI` с креденшелами для выполнения запросов - 11.4: Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven:) From 47ee7be0f072f1be9c7f66fe58bab8a33cb8a41c Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 28 Sep 2021 15:27:24 +0300 Subject: [PATCH 077/226] Update README.md --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f1545d04f5f2..b61b2f02e0a7 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ Java Enterprise Online Project - [Типы промежутков](https://ru.wikipedia.org/wiki/Промежуток_(математика)) ## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Домашнее задание HW0 -``` + Реализовать метод `UserMealsUtil.filteredByCycles` через циклы (`forEach`): - должны возвращаться только записи между `startTime` и `endTime` - поле `UserMealWithExcess.excess` должно показывать, @@ -92,9 +92,10 @@ Java Enterprise Online Project Т.е `UserMealWithExcess` - это запись одной еды, но поле `excess` будет одинаково для всех записей за этот день. -- Проверьте результат выполнения ДЗ (можно проверить логику в http://topjava.herokuapp.com , список еды) -- Оцените Time complexity алгоритма. Если она больше O(N), например O(N*N) или N*log(N), сделайте O(N). -``` +> - Проверьте результат выполнения ДЗ (можно проверить логику в http://topjava.herokuapp.com , список еды) +> - Оцените Time complexity алгоритма. Если она больше O(N), например O(N*N) или N*log(N), сделайте O(N). +> **Внимание: внимательно прочитайте про O(N). O - это любой коэффициент, 2*N это тоже O(N).** + - Java 8 Date and Time API - Алгоритмы и структуры данных для начинающих: сложность алгоритмов - [Головач: сложность алгоритмов в теме коллекций](https://www.youtube.com/watch?v=Ek9ijOiplNE&feature=youtu.be&t=778) From a46c887b788b7a4d58f6aced16c16c2341f420c9 Mon Sep 17 00:00:00 2001 From: "admin@javaops.ru" Date: Thu, 30 Sep 2021 12:38:25 +0300 Subject: [PATCH 078/226] Update resources --- README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b61b2f02e0a7..6cb380d182a2 100644 --- a/README.md +++ b/README.md @@ -168,13 +168,10 @@ Java Enterprise Online Project ----- ## [Пример 7-го занятия онлайн стажировки, несколько видео открыто](https://github.com/JavaOPs/topjava/blob/master/doc/lesson07.md) -### Полезные ресурсы -> ВНИМАНИЕ: -> - **ДЗ первого урока будет связано с [созданием небольшого CRUD приложения (в памяти, без DB) на JSP и сервлетах](https://danielniko.wordpress.com/2012/04/17/simple-crud-using-jsp-servlet-and-mysql/)**. Введение будет, но предварительное знакомство не помешает. -> - основы JavaSсript необходимы для понимания проекта, начиная с 8-го занятия! - -Все остальное - опционально. +> - ДЗ первого урока будет связано с созданием небольшого [CRUD](https://ru.wikipedia.org/wiki/CRUD) приложения (в памяти, без базы данных) на JSP и сервлетах +> - основы JavaSсript необходимы для понимания проекта, начиная с 8-го занятия +### Полезные ресурсы #### HTML, JavaScript, CSS - [Basic HTML and HTML5](https://learn.freecodecamp.org/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements/) - [Справочник по WEB](https://developer.mozilla.org/ru/) From fbc880486f2548a73af766143294fc095b8be566 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Fri, 1 Oct 2021 17:06:44 +0300 Subject: [PATCH 079/226] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6cb380d182a2..8c4b373298d1 100644 --- a/README.md +++ b/README.md @@ -128,11 +128,12 @@ Java Enterprise Online Project ### Optional 2 (+5 бонусов, только после выполнения базового и Optional задания!) Сделать реализацию со сложностью O(N) (обратите внимание на п.13 замечаний): - циклом за 1 проход по `List` + - нельзя 2 раза проходить по исходному списку (в том числе его отфильтрованной или преобразованной копии) - без циклов по другим коллекциям/массивам (к ним также относим методы коллекций `addAll()/removeAll()`) - решение должно быть рабочим в общем случае (работать в приложении с многими пользователями, не только при запуске main) - через Stream API за 1 проход по исходному списку `meals.stream()` - - нельзя использовать внешние коллекции, не являющиеся частью коллектора - нельзя 2 раза проходить по исходному списку (в том числе его отфильтрованной или преобразованной копии) + - нельзя использовать внешние коллекции, не являющиеся частью коллектора - возможно дополнительные проходы по частям списка, при этом превышение должно считаться один раз для всего подсписка. Те например нельзя разбить список на на 2 подсписка с четными и нечетными датами и затем их объединить, с подсчетом превышения для каждого элемента. From cf0f38a1210258d1de5052aec492e0cb79bc273d Mon Sep 17 00:00:00 2001 From: "admin@javaops.ru" Date: Sat, 2 Oct 2021 20:38:13 +0300 Subject: [PATCH 080/226] Update graduation --- graduation.md | 114 +++++++++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 52 deletions(-) diff --git a/graduation.md b/graduation.md index 250ce62ab04e..aa42f2982643 100644 --- a/graduation.md +++ b/graduation.md @@ -30,21 +30,21 @@ P.P.S.: Assume that your API will be used by a frontend developer to build front **Пишем выпускной проект как тестовое задание на работу** - **Не изобретай велосипедов!** Грубая ошибка - пытаться сделать стандартные вещи по-своему, чаще всего криво. На проекте все должно быть единообразно! Ваш проект TopJava - сделай все МАКСИМАЛЬНО в этом - стиле. Если тебе кажется, что у тебя есть лучшее решение, чем в TopJava - пишите мне в личку, я всегда открыт для улучшений. -- **Рекомендую писать проект современно**: Spring Boot + Swagger/OpenAPI 3.0. Оптимально подойдет код миграции TopJava на Spring Boot в конце стажировки. + стиле. Если тебе кажется, что есть лучшее решение, чем в TopJava - пишите мне в личку, я всегда открыт для улучшений. +- **Рекомендую писать проект на востребованном на рынке стеке**: Spring Boot + Spring Data JPA (работа с БД) + Swagger/OpenAPI 3.0 (REST документация). **Оптимально подойдет код миграции TopJava на Spring Boot в конце стажировки**. *Представьте себе, что ПМ (лид, архитектор) дал вам ТЗ и некоторое время недоступен. У вас, конечно, есть много мыслей, для чего нужно приложение, как исправить ТЗ, дополнить его и сделать правильно. -НО НЕ НАДО ИХ РЕАЛИЗОВЫВАТЬ В КОДЕ. Нужно сделать все максимально просто, удобно для доработок и для использования со стороны клиента (если, конечно, в ТЗ нет оговорок).* +НО НЕ НАДО ИХ РЕАЛИЗОВЫВАТЬ В КОДЕ. Нужно сделать все строго по ТЗ, максимально просто, удобно для доработок и для использования со стороны клиента.* > Совершенство достигнуто не тогда, когда нечего добавить, а тогда, когда нечего отнять _Антуан де Сент-Экзюпери_ -### 1: ТЗ +### 1: ТЗ (Тех.задание) - 1.1: Читай ТЗ ОЧЕНЬ внимательно, НЕ надо ничего своего туда домысливать и творчески изменять - 1.2: Учитывай, что пользователей может быть ОООЧЕНЬ много, а админов - МАЛО -- 1.3: Сначала сделай основной сценарий по ТЗ. Все остальное (если очень хочется, 3 раза подумай) - потом. +- 1.3: Сначала сделай основные сценарии по ТЗ. Все остальное (если очень хочется, 3 раза подумай) - потом. ### 2. API @@ -77,8 +77,7 @@ _Антуан де Сент-Экзюпери_ ### 4: Модель -- 4.1: Историю еды и голосований делать НУЖНО (история означает, что в БД хранятся и не удаляются голоса пользователей и меню на любой день. Есть базовые вещи, которые закладываются в архитектуру - приложения и неочевидные доработки к ТЗ, которых лучше не делать. +- 4.1: В БД обычно хранятся все введенные пользователем и админом данные (история). Они не удаляются и не переписываются заново. Есть базовые вещи, которые закладываются в архитектуру приложения, и есть неочевидные доработки к ТЗ, делать не надо. - 4.2: Не делайте в модели объектов, которые не будут использоваться в коде (например, не надо двунаправленных связей, если достаточно однонаправленных) - 4.3: еще раз про [hashCode/equals в Entity](https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma): не делайте в модели сравнение по полям! - 4.4: ORM работает с объектами. [Иногда, для упрощения логики, fk_id как поля допустимы](https://stackoverflow.com/questions/6311776/hibernate-foreign-keys-instead-of-entities) @@ -86,70 +85,81 @@ _Антуан де Сент-Экзюпери_ ### 5: Архитектура - 5.1: Можно: - или подключить DATA-REST (см.курс [Spring Boot 2.x + HATEOAS](https://javaops.ru/view/bootjava)). Контроллеры генерируются автоматически по репозиториям, требуется настройка ресурсов в кастомных контроллерах - - или делать на основе миграции TopJava / кода [TopJava-2](https://github.com/JavaOPs/topjava2) - -Нельзя смешивать эти подходы вместе! Я рекомендую 2-й вариант, без data-rest. Обязательно посмотрите, что у вас получилось в результате в swagger. + - или делать на основе миграции TopJava / кода [TopJava-2](https://github.com/JavaOPs/topjava2) + +Нельзя смешивать эти подходы вместе! Я рекомендую 2-й вариант, без data-rest. Обязательно посмотрите в Swagger, какие контроллеры получились в результате. - 5.2: Не размещайте бизнес-логику приложения и преобразования в TO в слое доступа к DB - 5.3: Не смешивайте TO и Entity вместе. Они должны быть независимыми друг от друга. На TopJava мы смотрели разные варианты [c использованием TO и без](https://stackoverflow.com/a/21569720/548473). Делаем максимально просто. -- 5.4: Репозитории - - 5.4.1: Используйте DATA-JPA (без лишней делегации). Из сервиса/контроллера напрямую вызывайте Repository - - 5.4.2: Если приложению в объекте требуется только его id, используйте reference (`getById`) - - 5.4.3: В DATA-JPA 2.x используются `Optional`. Попробуйте работать с ними, это безопасный способ работать с null-значениями (используйте `orElseThrow`) - - 5.4.4: Обновление в базе делается через `update`, даже если `delete/insert` сократит java-код на несколько строк -- 5.5: [Use for money in java app](http://stackoverflow.com/a/43051227/548473) +- 5.4: [Use for money in java app](http://stackoverflow.com/a/43051227/548473) + +### 6: Доступ к БД + +- 6.1: Используйте Spring Data JPA (без лишней делегации). Методы Repository можно вызывать напрямую из сервиса или из контроллера. +- 6.2: Если приложению в объекте требуется только его id, используйте reference (`getById`) +- 6.3: В DATA-JPA 2.x используются `Optional`. Попробуйте работать с ними, это безопасный способ работать с null-значениями (используйте `orElseThrow`) +- 6.4: Не делайте при обновлении записи ради экономии пары строчек кода так: +``` +if(updateCondition) + repository.delete(entity) +} +repository.save(entity) +``` +Обновление записи базы должно быть через `UPDATE`. -### 6: База Данных +### 7: База Данных -- 6.1: Берите без установки (H2 или HSQLDB). Одну и **в памяти**! Ваше приложение должно сразу запуститься, без всяких настроек и переменных окружения -- 6.2: Тщательно считайте количество обращений в базу на каждый запрос. Особенно при запросах от юзеров, которых очень много! Также на сложность запросов от них, чтобы не положить базу -- 6.3: Сделайте индексы к таблицам. Попробуйте обеспечить UNIQUE (один голос пользователя в день, один уникальный пункт меню в день). Следите за порядком полей в индексе, от этого зависит индексирование запросов. -- 6.4: При популировании добавь записи за сегодняшний день - `now()`, чтобы всегда были актуальные исходные данные -- 6.5: Поля базы case insensitive, на пишите camelStyle. -- 6.6: Таблицы обычно именуются в единственном числе. Исключение - users, т. к. user - зарезервированное слово. -- 6.7: `date`/`timestamp` - зарезервированное слово, лучше избегать их при именовании полей +- 7.1: Берите без установки (H2 или HSQLDB). Одну и **в памяти**! Ваше приложение должно сразу запуститься, без всяких настроек и переменных окружения +- 7.2: Тщательно считайте количество обращений в базу на каждый запрос. Особенно при запросах от юзеров, которых очень много! Также на сложность запросов от них, чтобы не положить базу +- 7.3: Сделайте [индексы к таблицам](https://ru.wikipedia.org/wiki/Индекс_(базы_данных)). Попробуйте обеспечить UNIQUE (один голос пользователя в день, один уникальный пункт меню в день). +Следите за **порядком полей в индексе**, от этого зависит индексирование запросов. +- 7.4: При популировании добавь записи за сегодняшний день - `now()`, чтобы всегда были актуальные исходные данные +- 7.5: Поля базы case insensitive, не пишите camelStyle (для которых нужны кавычки) +- 7.6: Таблицы обычно именуются в единственном числе. Исключение - `users`, `orders` и другие зарезервированные слова +- 7.7: `date`/`timestamp` - зарезервированное слово, лучше избегать их при именовании полей -### 7: Security +### 8: Security -- 7.1: Проверьте, станет ли код проще с `@AuthenticationPrincipal` (урок 11, Доступ к AuthorizedUser). -- 7.2: Я предпочитаю четкое разделение ролей на основе URL. Для админа URL содержит `/admin` -- 7.3: Еще раз - призываю не менять код TopJava +- 8.1: Проверьте, станет ли код проще с `@AuthenticationPrincipal` (урок 11, Доступ к AuthorizedUser). +- 8.2: Я предпочитаю четкое разделение ролей на основе URL. Для админа URL содержит `/admin` +- 8.3: Еще раз - призываю не менять код TopJava -### 8: Кэширование необязательно, но желательно. Старайтесь сделать реализацию попроще. +### 9: Кэширование -- 8.1: Тщательно продумайте, что надо кэшировать (самые частые запросы), а что нет (большие или редко запрашиваемые данные)! -- 8.2: Проверьте соответствие ключей к кэшу (параметры кэшируемого метода) с конфигурацией (например в singleNonExpiryCache, heap=1 в кэше может содержаться только ОДНО значение). +- 9.1: Кэширование желательно для частых и редко меняющихся запросов от пользователей. +Тщательно продумайте, что надо кэшировать (самые частые запросы), а что нет (большие или редко запрашиваемые данные) +- 9.2: Проверьте соответствие ключей к кэшу (параметры кэшируемого метода) с конфигурацией (например в singleNonExpiryCache, heap=1 в кэше может содержаться только ОДНО значение). -### 9: Валидация данных желательна +### 10: Валидация -- 9.1: Одних аннотаций валидации недостаточно. Должны быть `@Valid/@Validation` -- 9.2: Проверяйте входные данные при `create/update` в контроллерах! В TopJava это `ValidationUtil.checkNew()/assureIdConsistent()` +- 10.1: Одних аннотаций валидации недостаточно. Должны быть `@Valid/@Validation` +- 10.2: Проверяйте входные данные при `create/update` в контроллерах! В TopJava это `ValidationUtil.checkNew()/assureIdConsistent()` -### 10: Дополнительно +### 11: Дополнительно -- 10.1: По возможности сделать JUnit-тесты. Можно не делать 100% покрытие, только основные сценарии -- 10.2: Уделяйте внимание обработке ошибок +- 11.1: По возможности сделать JUnit-тесты. Можно не делать 100% покрытие, только основные сценарии +- 11.2: Уделяйте внимание обработке ошибок. -### 11: `readme.md`: +### 12: `readme.md`: -- 11.1: Поместите вначале `readme` ТЗ или ссылку на него - будет понятно о чем твой проект -- 11.2: Если задание на English, описание пиши также на English (то же самое относится к языку резюме: вакансия на English предполагает резюме на English) -- 11.3: Требуемые примеры `curl` не прячьте, а пишите здесь! Оптимально здесь должна быть ссылка на `Swagger UI` с креденшелами для выполнения запросов -- 11.4: Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven:) +- 12.1: Поместите вначале `readme` ТЗ или **ссылку на него** - будет понятно о чем твой проект +- 12.2: Если задание на English, описание пиши также на English (то же самое относится к языку резюме: вакансия на English предполагает резюме на English) +- 12.3: Требуемые примеры `curl` не прячьте, а пишите здесь! Оптимально здесь должна быть ссылка на `Swagger UI` с креденшелами для выполнения запросов +- 12.4: Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven -### 12: Git +### 13: Git -- Должна быть история ваших комитов с внятными комментариями. Это смотрят. -- Не комить служенбые файлы: логи, DB, настройки IDEA и пр., это сразу - уровень Junior. -- Все служебные файлы должны быть в `.gitignore` +- 13.1: Должна быть история ваших комитов с внятными комментариями. Это смотрят. +- 13.2: Не комить служенбые файлы: логи, DB, настройки IDEA и пр., это сразу - уровень Junior. +- 13.3: Все служебные файлы должны быть в `.gitignore` -### 13: Проверка +## Проверка -- 13.1: Попробуйте подергать свое API по всем типичным сценариям ТЗ! - - 13.1.2: Удобно использовать? Можно сделать проще? Например, чтобы проголосовать за ресторан залогиненному юзеру, достаточно `restorauntId`. - - 13.1.3: Сколько раз пришлось его вызвать API для типичного сценария (например посмотреть рестораны с едой на сегодня)? - - 13.1.4: Сколько запросов к базе было сделано? Можно ли сократить (например с `FETCH/Graph` или через кэширование)? - - 13.1.5: **Еще раз - проверьте все запросы в Sawgger, смотрите на формат запросов и данные в ответе. Все должно работать, есть все данные и нет ничего лишнего** +- Попробуй подергать свое API по всем типичным сценариям ТЗ! + - Удобно использовать? Можно сделать проще? Например, чтобы проголосовать за ресторан залогиненному юзеру, достаточно `restorauntId`. + - Сколько раз пришлось его вызвать API для типичного сценария (например посмотреть рестораны с едой на сегодня)? + - Сколько запросов к базе было сделано? Можно ли сократить (например с `FETCH/Graph` или через кэширование)? + - **Еще раз - проверь все запросы в Sawgger, смотри на формат запросов и данные в ответе. Все должно работать, есть все данные и нет ничего лишнего** - 13.2: API ДОЛЖЕН соответствовать принципам REST (см. ссылки выше) - 13.3: ОБЯЗАТЕЛЬНО: запустите `mvn test` - ошибок быть не должно - 13.4: ОБЯЗАТЕЛЬНО: запустите приложение без всяких предварительных настроек (базы, переменных окружения, ..), лучше на другом компьютере. Приложение должно запускаться и работать! From 570ebeba4db3aa3ffa8d8354d1f12d37d4481875 Mon Sep 17 00:00:00 2001 From: "admin@javaops.ru" Date: Tue, 5 Oct 2021 13:35:32 +0300 Subject: [PATCH 081/226] Update Optional2 --- README.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 8c4b373298d1..fff4d41c9f20 100644 --- a/README.md +++ b/README.md @@ -126,16 +126,14 @@ Java Enterprise Online Project - [Сергей Куксенко — Stream API, часть 2](https://www.youtube.com/watch?v=i0Jr2l3jrDA) ### Optional 2 (+5 бонусов, только после выполнения базового и Optional задания!) -Сделать реализацию со сложностью O(N) (обратите внимание на п.13 замечаний): +Сделать реализацию со сложностью O(N) (обратите внимание на п.13 замечаний) +Решение должно быть рабочим в общем случае (работать в приложении с многими пользователями, не только при запуске main) +Нельзя 2 раза проходить по исходному списку (в том числе его отфильтрованной или преобразованной копии) - циклом за 1 проход по `List` - - нельзя 2 раза проходить по исходному списку (в том числе его отфильтрованной или преобразованной копии) - - без циклов по другим коллекциям/массивам (к ним также относим методы коллекций `addAll()/removeAll()`) - - решение должно быть рабочим в общем случае (работать в приложении с многими пользователями, не только при запуске main) + - без циклов по другим коллекциям/массивам (к ним также относим методы коллекций `addAll()/removeAll()`) - через Stream API за 1 проход по исходному списку `meals.stream()` - - нельзя 2 раза проходить по исходному списку (в том числе его отфильтрованной или преобразованной копии) - - нельзя использовать внешние коллекции, не являющиеся частью коллектора - - возможно дополнительные проходы по частям списка, при этом превышение должно считаться один раз для всего подсписка. Те например нельзя разбить список на на 2 подсписка с четными и нечетными датами и затем их объединить, с подсчетом превышения для каждого элемента. - + - нельзя использовать внешние коллекции, не являющиеся частью коллектора + - возможно дополнительные проходы по частям списка, при этом превышение должно считаться один раз для всего подсписка. Те например нельзя разбить список на на 2 подсписка с четными и нечетными датами и затем их объединить, с подсчетом превышения для каждого элемента. Ресурсы: - [Java 8 Stream API, часть шестая: собственный коллектор](https://easyjava.ru/java/language/java-8-stream-api-chast-shestaya-sobstvennyj-kollektor) From ef9126f53a38397885623a69e681e17683bcd580 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sat, 30 Oct 2021 12:39:58 +0300 Subject: [PATCH 082/226] Update cv.md --- cv.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cv.md b/cv.md index 910b9ad88ab6..0e06750068ab 100644 --- a/cv.md +++ b/cv.md @@ -39,6 +39,7 @@ - Михаил Портнов. Собеседование на работу: жизненный путь - [Лёша Корепанов. Признаки плохих компаний для программиста](https://www.youtube.com/watch?v=Sj-WSWr-n7U) - [Лёша Корепанов. Как отвечать на вопросы, которые ты не знаешь. Техническое интервью для программиста](https://www.youtube.com/watch?v=Beoh3tfgPEk) +- [Виталием Карнаух. Топ 7 ошибок на собеседование в it компанию](https://www.youtube.com/watch?v=IcFBsPN2U2g) - Канал: Резюме, поиск работы, интервью - Яков Файн: Как стать профессиональным Java разработчиком - Ответы на вопросы на собеседовании Junior Java Developer @@ -121,4 +122,6 @@ - [Часть 1](https://javarush.ru/groups/posts/3044-razbor-tipichnihkh-oshibok-nachinajujshikh-programmistov-chastjh-1) - [Часть 2](https://javarush.ru/groups/posts/3055-razbor-tipichnihkh-oshibok-nachinajujshikh-programmistov-chastjh-2) - [От джуна к миддлу: практические советы](https://tproger.ru/articles/ot-dzhuna-k-middlu-prakticheskie-sovety) +- [Виталием Карнаух. Ошибки, которых лучше избежать начинающим](https://www.youtube.com/watch?v=GNeyP7lAHAY) +- [Лёша Корепанов. 12 вещей о ПРОГРАММИРОВАНИИ, которые я хотел бы знать в 20 лет](https://www.youtube.com/watch?v=Z9FvlPpSS3U) ## [Отзывы по стажировке Topjava](https://vk.com/topic-74381644_30447246) From db7fb68b0586d19ef55659750532b99cb93f6c22 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 29 Nov 2021 13:44:34 +0300 Subject: [PATCH 083/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fff4d41c9f20..b72ef9203bc7 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,11 @@ Java Enterprise Online Project ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. Осваиваем Java Enterprise. Трудоустройство. Ответы на вопросы. - Слайды презентации - [Как стать профессиональным Java разработчиком](https://www.youtube.com/watch?v=ft0Nj8Cm9kk) -- [Популярность Java-технологий в 2019 году](https://topjava.ru/blog/sostoyanie-java-v-2019-godu) - [Java Technology Report 2021](https://www.jrebel.com/blog/2021-java-technology-report) - [The State of Developer Ecosystem 2020](https://www.jetbrains.com/lp/devecosystem-2020/java/) - [JVM Ecosystem Report 2021](https://snyk.io/jvm-ecosystem-report-2021/) - [Быть программистом: от детства к зрелости](https://www.youtube.com/watch?v=D5Hej0TyLaU) +- Ссылки по темам интервью, тестовое интервью - [Литература](https://javaops.ru/view/books) #### Spring Pet-Clinic From 8cc13b10f6b06674c5ece6afaae4214a8ea0add0 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 27 Dec 2021 18:10:02 +0300 Subject: [PATCH 084/226] Update cv.md --- cv.md | 1 + 1 file changed, 1 insertion(+) diff --git a/cv.md b/cv.md index 0e06750068ab..0bfd88a3e7f0 100644 --- a/cv.md +++ b/cv.md @@ -8,6 +8,7 @@ ### Составление резюме: - [VisualCV: create resume in minutes](https://www.visualcv.com/) +- [Build a job-winning resume for free](https://flowcv.io/start-resume) - Выбрать шаблон для резюме - [GitHub Pages](https://pages.github.com/), Resume template - Как продать свое резюме в 2 раза дороже From 8ba06715943ba2a5b9cb703beda618a3e93b530f Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 2 Jan 2022 20:54:47 +0300 Subject: [PATCH 085/226] Update ReleaseNotes.md --- ReleaseNotes.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 68ebc2ef69d7..4f53be1388f9 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,5 +1,11 @@ # TopJava Release Notes +### Topjava 24 +- migrate to JDK 17 +- добавил логирование в `RootController` +- в `AbstractServiceTest` популирование БД делаю после теста (`executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD`). Если последние тесты на сервисы портят БД, тесты на контроллеры могут упасть +- в `ActiveDbProfileResolver` добавил парсинг `profiles` + ### Topjava 23 - migrate to JDK 16 - в новой spring-data-jpa `getOne` заменили на `getById` From 6f6ffe8ff8676dd570f37b83979954922721e9e3 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 2 Jan 2022 20:57:36 +0300 Subject: [PATCH 086/226] Update ReleaseNotes.md --- ReleaseNotes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 4f53be1388f9..8bbae45f55f6 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -5,6 +5,7 @@ - добавил логирование в `RootController` - в `AbstractServiceTest` популирование БД делаю после теста (`executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD`). Если последние тесты на сервисы портят БД, тесты на контроллеры могут упасть - в `ActiveDbProfileResolver` добавил парсинг `profiles` +- добавил `@QueryHint HINT_PASS_DISTINCT_THROUGH` в реализацию Data JPA ### Topjava 23 - migrate to JDK 16 From efce3975293cbf47e99e16a238eec518413c1f83 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 6 Jan 2022 15:09:53 +0300 Subject: [PATCH 087/226] Update graduation.md --- graduation.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/graduation.md b/graduation.md index aa42f2982643..7fda5bf6916b 100644 --- a/graduation.md +++ b/graduation.md @@ -82,7 +82,7 @@ _Антуан де Сент-Экзюпери_ - 4.3: еще раз про [hashCode/equals в Entity](https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma): не делайте в модели сравнение по полям! - 4.4: ORM работает с объектами. [Иногда, для упрощения логики, fk_id как поля допустимы](https://stackoverflow.com/questions/6311776/hibernate-foreign-keys-instead-of-entities) -### 5: Архитектура +### 5: Архитектура / pom - 5.1: Можно: - или подключить DATA-REST (см.курс [Spring Boot 2.x + HATEOAS](https://javaops.ru/view/bootjava)). Контроллеры генерируются автоматически по репозиториям, требуется настройка ресурсов в кастомных контроллерах - или делать на основе миграции TopJava / кода [TopJava-2](https://github.com/JavaOPs/topjava2) @@ -92,6 +92,7 @@ _Антуан де Сент-Экзюпери_ - 5.3: Не смешивайте TO и Entity вместе. Они должны быть независимыми друг от друга. На TopJava мы смотрели разные варианты [c использованием TO и без](https://stackoverflow.com/a/21569720/548473). Делаем максимально просто. - 5.4: [Use for money in java app](http://stackoverflow.com/a/43051227/548473) +- 5.5 Не надо явно указывать версии зависимостей в `pom`, если они наследуются от `spring-boot-starter-parent` ### 6: Доступ к БД From ba314f22028ef71154e6e04d42d946025b46a591 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Fri, 7 Jan 2022 01:32:46 +0300 Subject: [PATCH 088/226] Update cv.md --- cv.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cv.md b/cv.md index 0bfd88a3e7f0..161f50329244 100644 --- a/cv.md +++ b/cv.md @@ -104,7 +104,7 @@ - Учись инвестигировать проблему. Внимательное чтение логов и умение дебажить - основные навыки разработчика. В логах надо читать верх самого нижнего эксепшена - там причина всей портянки. - Грамотно уделяй время каждой проблеме. Две крайности - сразу бросаться за помощью и - бится нам ней часами. + биться нам ней часами. Пробуй решить ее сам и в зависимости от проблемы выделяй на это разумное время. - Если тебе что-то объясняют по проекту - обязательно записывай. - Когда получаешь задачу - уточни все очень подробно. From 74fd1fe894fe8ed160c8cc5369a136c21e3a4780 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sat, 8 Jan 2022 16:42:59 +0300 Subject: [PATCH 089/226] Update graduation.md --- graduation.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/graduation.md b/graduation.md index 7fda5bf6916b..ff5c9e104354 100644 --- a/graduation.md +++ b/graduation.md @@ -58,10 +58,9 @@ _Антуан де Сент-Экзюпери_ - [REST resource hierarchy](https://stackoverflow.com/questions/20951419/what-are-best-practices-for-rest-nested-resources) - [Лучшие практики разработки REST API: правила 1-7,15-17](https://tproger.ru/translations/luchshie-praktiki-razrabotki-rest-api-20-sovetov/) - 2.5: Разделение на роли я предпочитаю на уровне URL. Сразу и однозначно видно, какой API у админа, какое у пользователя (API админа начинается, например, с */admin/...*). -- 2.6: На управление (CRUD) ресторанами и едой должны быть ОТДЕЛЬНЫЕ контроллеры. Не надо все, что может админ, сваливать в одну кучу! -- 2.7: Проверьте в Swagger, что в POST и PUT нет ничего лишнего, а в GET есть все необходимые данные. Например, при запросе голоса должен быть `id` ресторана, а при +- 2.6: Проверьте в Swagger, что в POST и PUT нет ничего лишнего, а в GET есть все необходимые данные. Например, при запросе голоса должен быть `id` ресторана, а при создании-редактировании ресторана не должно быть меню и еды. -- 2.8: `Profile` означает, что данные принадлежат профилю пользователя. Все остальное называйте по-другому. +- 2.7: `Profile` означает, что данные принадлежат профилю пользователя. Все остальное называйте по-другому. ### 3: Код: - 3.1: Строго соблюдайте соглашения Java по именованию: пакеты ТОЛЬКО маленькими буквами, методы начинаются с маленькой буквы, классы с большой. Незнания Java Core - тестовое задание сразу в корзину. @@ -93,6 +92,7 @@ _Антуан де Сент-Экзюпери_ Делаем максимально просто. - 5.4: [Use for money in java app](http://stackoverflow.com/a/43051227/548473) - 5.5 Не надо явно указывать версии зависимостей в `pom`, если они наследуются от `spring-boot-starter-parent` +- 5.6: На управление (CRUD) ресторанами и едой должны быть ОТДЕЛЬНЫЕ контроллеры. Не надо все, что может админ, сваливать в одну кучу! ### 6: Доступ к БД From b83aa46abb2353371a1fce7b6bc6699e95e877cd Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Fri, 14 Jan 2022 23:33:17 +0300 Subject: [PATCH 090/226] Update cv.md --- cv.md | 1 + 1 file changed, 1 insertion(+) diff --git a/cv.md b/cv.md index 161f50329244..50b292550d89 100644 --- a/cv.md +++ b/cv.md @@ -41,6 +41,7 @@ - [Лёша Корепанов. Признаки плохих компаний для программиста](https://www.youtube.com/watch?v=Sj-WSWr-n7U) - [Лёша Корепанов. Как отвечать на вопросы, которые ты не знаешь. Техническое интервью для программиста](https://www.youtube.com/watch?v=Beoh3tfgPEk) - [Виталием Карнаух. Топ 7 ошибок на собеседование в it компанию](https://www.youtube.com/watch?v=IcFBsPN2U2g) +- [Почему молчит интервьюер: 11 неочевидных фактов о собеседованиях в IT](https://highload.today/pochemu-molchit-intervyuer-11-neochevidnyh-faktov-o-sobesedovaniyah-v-it/) - Канал: Резюме, поиск работы, интервью - Яков Файн: Как стать профессиональным Java разработчиком - Ответы на вопросы на собеседовании Junior Java Developer From 7e422cbe976fb6cd520ae70e3ed7643bf73a002b Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sat, 22 Jan 2022 23:01:19 +0300 Subject: [PATCH 091/226] Update graduation.md --- graduation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graduation.md b/graduation.md index ff5c9e104354..5d8d287a205b 100644 --- a/graduation.md +++ b/graduation.md @@ -76,7 +76,7 @@ _Антуан де Сент-Экзюпери_ ### 4: Модель -- 4.1: В БД обычно хранятся все введенные пользователем и админом данные (история). Они не удаляются и не переписываются заново. Есть базовые вещи, которые закладываются в архитектуру приложения, и есть неочевидные доработки к ТЗ, делать не надо. +- 4.1: В БД сделайте историю голосования и историю меню/еды. Не надо их перетирать каждый день. - 4.2: Не делайте в модели объектов, которые не будут использоваться в коде (например, не надо двунаправленных связей, если достаточно однонаправленных) - 4.3: еще раз про [hashCode/equals в Entity](https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma): не делайте в модели сравнение по полям! - 4.4: ORM работает с объектами. [Иногда, для упрощения логики, fk_id как поля допустимы](https://stackoverflow.com/questions/6311776/hibernate-foreign-keys-instead-of-entities) From 9e3cd7ee985fea40b6d6d46ee5d29f90302bdef0 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 26 Jan 2022 15:51:45 +0300 Subject: [PATCH 092/226] Update graduation.md --- graduation.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/graduation.md b/graduation.md index 5d8d287a205b..4b1ad72f296f 100644 --- a/graduation.md +++ b/graduation.md @@ -127,9 +127,10 @@ repository.save(entity) ### 9: Кэширование -- 9.1: Кэширование желательно для частых и редко меняющихся запросов от пользователей. -Тщательно продумайте, что надо кэшировать (самые частые запросы), а что нет (большие или редко запрашиваемые данные) +- 9.1: Кэширование нужно для частых и редко меняющихся запросов от пользователей. +Тщательно продумайте, что надо кэшировать (самые частые запросы), а что нет (большие или редко запрашиваемые данные). **Лучше меньше, да лучше!** - 9.2: Проверьте соответствие ключей к кэшу (параметры кэшируемого метода) с конфигурацией (например в singleNonExpiryCache, heap=1 в кэше может содержаться только ОДНО значение). +- 9.3: Ключем к кэшу по умолчанию являются параметры метода. Следите, чтобы разные данные не попали в один и тот же кэш. ### 10: Валидация From c463011e1429989c1d4e55b5af5a624cff4dac56 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sat, 29 Jan 2022 18:06:57 +0300 Subject: [PATCH 093/226] Update graduation.md --- graduation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graduation.md b/graduation.md index 4b1ad72f296f..18e16aee10b8 100644 --- a/graduation.md +++ b/graduation.md @@ -58,7 +58,7 @@ _Антуан де Сент-Экзюпери_ - [REST resource hierarchy](https://stackoverflow.com/questions/20951419/what-are-best-practices-for-rest-nested-resources) - [Лучшие практики разработки REST API: правила 1-7,15-17](https://tproger.ru/translations/luchshie-praktiki-razrabotki-rest-api-20-sovetov/) - 2.5: Разделение на роли я предпочитаю на уровне URL. Сразу и однозначно видно, какой API у админа, какое у пользователя (API админа начинается, например, с */admin/...*). -- 2.6: Проверьте в Swagger, что в POST и PUT нет ничего лишнего, а в GET есть все необходимые данные. Например, при запросе голоса должен быть `id` ресторана, а при +- 2.6: **Очень частая ошибка: проверьте в Swagger, что в POST/PUT Example Value нет ничего лишнего**, а в GET есть все необходимые данные. Например, при запросе голоса должен быть `id` ресторана, а при создании-редактировании ресторана не должно быть меню и еды. - 2.7: `Profile` означает, что данные принадлежат профилю пользователя. Все остальное называйте по-другому. From 1ecf4d146beee22bce86f54117e8af393237f6b4 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sat, 29 Jan 2022 18:49:47 +0300 Subject: [PATCH 094/226] Update graduation.md --- graduation.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/graduation.md b/graduation.md index 18e16aee10b8..2b084617216f 100644 --- a/graduation.md +++ b/graduation.md @@ -40,6 +40,9 @@ P.P.S.: Assume that your API will be used by a frontend developer to build front _Антуан де Сент-Экзюпери_ +### 0: +Корневой пакет - доменное имя компании или разработчика. Если нет своего доменного имени, можно использовать com.github.{accountname}. И потом идет пакет - имя проекта. В pom.xml groupId обычно совпадает с корневым пакетом + ### 1: ТЗ (Тех.задание) - 1.1: Читай ТЗ ОЧЕНЬ внимательно, НЕ надо ничего своего туда домысливать и творчески изменять From 93c076d45c61c0142cb29b70c8f6c38f66b6121b Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sat, 29 Jan 2022 18:50:35 +0300 Subject: [PATCH 095/226] Update graduation.md --- graduation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graduation.md b/graduation.md index 2b084617216f..3fccbc9cdb50 100644 --- a/graduation.md +++ b/graduation.md @@ -40,8 +40,8 @@ P.P.S.: Assume that your API will be used by a frontend developer to build front _Антуан де Сент-Экзюпери_ -### 0: -Корневой пакет - доменное имя компании или разработчика. Если нет своего доменного имени, можно использовать com.github.{accountname}. И потом идет пакет - имя проекта. В pom.xml groupId обычно совпадает с корневым пакетом +### 0: Корневой пакет и `groupId` +Корневой пакет - доменное имя компании или разработчика. Если нет своего доменного имени, можно использовать com.github.{accountname}. И потом идет пакет - имя проекта. В `pom.xml` `groupId` обычно совпадает с корневым пакетом ### 1: ТЗ (Тех.задание) From 32915c3325eb8ba7e213b85c28e0c9d1bd908fd0 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 1 Feb 2022 12:36:17 +0300 Subject: [PATCH 096/226] Update cv.md --- cv.md | 1 + 1 file changed, 1 insertion(+) diff --git a/cv.md b/cv.md index 50b292550d89..f2dce5a5b464 100644 --- a/cv.md +++ b/cv.md @@ -10,6 +10,7 @@ - [VisualCV: create resume in minutes](https://www.visualcv.com/) - [Build a job-winning resume for free](https://flowcv.io/start-resume) - Выбрать шаблон для резюме +- [Как разработчику составить резюме. Инструкция и примеры](https://highload.today/blogs/dazhe-tsveta-mogut-sygrat-protiv-vas-kak-razrabotchiku-sostavit-rezyume-kotoroe-ustroit-na-rabotu-mechty-instruktsiya-i-primery/) - [GitHub Pages](https://pages.github.com/), Resume template - Как продать свое резюме в 2 раза дороже - Как правильно составить резюме From 57bb385405e549f436f16f30e769c601e04dc52a Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 3 Feb 2022 21:26:44 +0300 Subject: [PATCH 097/226] Update graduation.md --- graduation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graduation.md b/graduation.md index 3fccbc9cdb50..93080b8bc5b6 100644 --- a/graduation.md +++ b/graduation.md @@ -86,8 +86,8 @@ _Антуан де Сент-Экзюпери_ ### 5: Архитектура / pom - 5.1: Можно: - - или подключить DATA-REST (см.курс [Spring Boot 2.x + HATEOAS](https://javaops.ru/view/bootjava)). Контроллеры генерируются автоматически по репозиториям, требуется настройка ресурсов в кастомных контроллерах - - или делать на основе миграции TopJava / кода [TopJava-2](https://github.com/JavaOPs/topjava2) + - или подключить DATA-REST (см.курс [Spring Boot 2.x + HATEOAS](https://javaops.ru/view/bootjava)). Контроллеры генерируются автоматически по репозиториям, требуется настройка ресурсов в кастомных контроллерах. + - или делать на основе миграции TopJava / кода [TopJava-2](https://github.com/JavaOPs/topjava2). В pom **не должно быть `spring-boot-starter-data-rest` и `springdoc-openapi-data-rest`** Нельзя смешивать эти подходы вместе! Я рекомендую 2-й вариант, без data-rest. Обязательно посмотрите в Swagger, какие контроллеры получились в результате. - 5.2: Не размещайте бизнес-логику приложения и преобразования в TO в слое доступа к DB From a98107b13567529d893da491c5a0b44257df8446 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 7 Feb 2022 16:47:26 +0300 Subject: [PATCH 098/226] Update README.md --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b72ef9203bc7..44a10222d191 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,21 @@ Java Enterprise Online Project - Выполнить задание и залить на GitHub (commit + push) - Переключиться в основную ветку проекта master. -## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Тех.задание: библия или допускаются изменения. Полуоткрытый интервал.](https://drive.google.com/file/d/1BpTzjNFjS0TSekCyt_xvt6YoLvuw5KTZ/view?usp=sharing) +### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Maven](https://drive.google.com/file/d/1qEJTwv9FNUQjx-y9MSydH01xaAne0-hu/view?usp=sharing) +- Wiki: [Apache Maven](https://ru.wikipedia.org/wiki/Apache_Maven) +- [The Central Repository](http://search.maven.org) +- Дополнительно: + - [Мое Wiki Maven](https://github.com/JavaOPs/topjava/wiki/Maven) + - [Основы Maven](https://www.youtube.com/watch?v=0uwMKktzixU) + - JavaRush: [Основы Maven](https://javarush.ru/groups/posts/2523-chastjh-4osnovih-maven) + - Инструмент сборки проектов [Maven](https://www.examclouds.com/ru/java/java-core-russian/lesson20) + - [Maven Getting Started Guide](https://maven.apache.org/guides/getting-started/index.html) + - [Видео: Maven vs Gradle vs SBT (Архипов, Борисов, Садогурский)](https://www.youtube.com/watch?v=21qdRgFsTy0) + - [Build Lifecycle](http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html) + - [Dependency Mechanism](http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html) + + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 5. [Тех.задание: библия или допускаются изменения. Полуоткрытый интервал.](https://drive.google.com/file/d/1BpTzjNFjS0TSekCyt_xvt6YoLvuw5KTZ/view?usp=sharing) - [Типы промежутков](https://ru.wikipedia.org/wiki/Промежуток_(математика)) ## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Домашнее задание HW0 From dc5f3ffdbdce5d56b1e3e7c52cc4727adf572f89 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 7 Feb 2022 16:47:51 +0300 Subject: [PATCH 099/226] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 44a10222d191..b52bd15a0ec3 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ Java Enterprise Online Project - Выполнить задание и залить на GitHub (commit + push) - Переключиться в основную ветку проекта master. -### ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Maven](https://drive.google.com/file/d/1qEJTwv9FNUQjx-y9MSydH01xaAne0-hu/view?usp=sharing) +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 4. [Maven](https://drive.google.com/file/d/1qEJTwv9FNUQjx-y9MSydH01xaAne0-hu/view?usp=sharing) - Wiki: [Apache Maven](https://ru.wikipedia.org/wiki/Apache_Maven) - [The Central Repository](http://search.maven.org) - Дополнительно: From 1345409c342841ddfe48d643f43f6ad77d34b812 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 9 Feb 2022 13:18:02 +0300 Subject: [PATCH 100/226] Update README.md --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index b52bd15a0ec3..882721fe72f8 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,20 @@ Java Enterprise Online Project ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 5. [Тех.задание: библия или допускаются изменения. Полуоткрытый интервал.](https://drive.google.com/file/d/1BpTzjNFjS0TSekCyt_xvt6YoLvuw5KTZ/view?usp=sharing) - [Типы промежутков](https://ru.wikipedia.org/wiki/Промежуток_(математика)) +### ![question](https://cloud.githubusercontent.com/assets/13649199/13672858/9cd58692-e6e7-11e5-905d-c295d2a456f1.png) Ваши вопросы + +> Используются ли сервлеты на реальных проектах сегодня? + +1. Сервлеты лежат в основе любого Java web фреймворка, если взаимодействие не асинхронное и не nio (например Spring MVC). Работать с таким фреймворком и не знать, что такое сервлеты, все равно что работать с JPA/Hibarnate/любым ORM без знания JDBC. +2. Бывают легаси проекты, бывают современные, где не подтягивается сторонний web фреймворк. При этом, даже работая с фреймворком, приходится иметь дело с Servlet API (часто с `HttpServletRequest/HttpServletResponse`) - обработка ошибок, валидаторы, фильтры, пре/пост обработка зарпосов, получение ip, работа с сессией и пр. + +> Используются ли еще где-то в реальной разработке JSP, или это уже устаревшая технология? Заменит ли ее JSF (https://javatalks.ru/topics/38037)? + +JSF и JSP- разные ниши и задачи. +JSP- шаблонизатор, JSF - МVС фреймворк. Из моего опыта- с JSP сталкивался в 60% проектов. Его прямая замена: http://www.thymeleaf.org (в Spring-Boot по умолчанию), но в уже запущенных проектах встречается достаточно редко. JSP не умирает, потому что просто и дешево. Кроме того он по умолчанию включен в большинство веб-контейнеров (в Tomcat его реализация Jasper). Зная принципы JSP можно без труда освоить любой другой шаблонизатор. + +JSF- JavaEE веб фреймворк, с которым я ни разу не сталкивался и особого желания нет. Вот он как раз, по статистике, активно замещается хотя бы javascript фреймворками (Angular, React, Vue.js). + ## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Домашнее задание HW0 Реализовать метод `UserMealsUtil.filteredByCycles` через циклы (`forEach`): From ab52f8e6759c3a235e7614c64c1aa6a714dea153 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 26 Apr 2022 14:27:35 +0300 Subject: [PATCH 101/226] Update ReleaseNotes.md --- ReleaseNotes.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 8bbae45f55f6..d4c004f62935 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,5 +1,10 @@ # TopJava Release Notes +### Topjava 25 +- в `NoHtmlValidator` делаю проверку через `Jsoup.isValid` +- в `user_roles.role` добавил `NOT NULL` +- в тестах добавил 3-го пользователя `Guset` без ролей и еды + ### Topjava 24 - migrate to JDK 17 - добавил логирование в `RootController` From c78739665509051bbcd6c1d4d786e12b0aacec58 Mon Sep 17 00:00:00 2001 From: StringerDM <103386227+StringerDM@users.noreply.github.com> Date: Thu, 5 May 2022 19:04:10 +0300 Subject: [PATCH 102/226] prepare to HW_0 patch applied --- .../javawebinar/topjava/model/UserMeal.java | 29 ++++++++++++++ .../topjava/model/UserMealWithExcess.java | 30 ++++++++++++++ .../ru/javawebinar/topjava/util/TimeUtil.java | 9 +++++ .../topjava/util/UserMealsUtil.java | 39 +++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 src/main/java/ru/javawebinar/topjava/model/UserMeal.java create mode 100644 src/main/java/ru/javawebinar/topjava/model/UserMealWithExcess.java create mode 100644 src/main/java/ru/javawebinar/topjava/util/TimeUtil.java create mode 100644 src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java new file mode 100644 index 000000000000..d8f91b127f6a --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java @@ -0,0 +1,29 @@ +package ru.javawebinar.topjava.model; + +import java.time.LocalDateTime; + +public class UserMeal { + private final LocalDateTime dateTime; + + private final String description; + + private final int calories; + + public UserMeal(LocalDateTime dateTime, String description, int calories) { + this.dateTime = dateTime; + this.description = description; + this.calories = calories; + } + + public LocalDateTime getDateTime() { + return dateTime; + } + + public String getDescription() { + return description; + } + + public int getCalories() { + return calories; + } +} diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExcess.java b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExcess.java new file mode 100644 index 000000000000..d0aa431a35d9 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExcess.java @@ -0,0 +1,30 @@ +package ru.javawebinar.topjava.model; + +import java.time.LocalDateTime; + +public class UserMealWithExcess { + private final LocalDateTime dateTime; + + private final String description; + + private final int calories; + + private final boolean excess; + + public UserMealWithExcess(LocalDateTime dateTime, String description, int calories, boolean excess) { + this.dateTime = dateTime; + this.description = description; + this.calories = calories; + this.excess = excess; + } + + @Override + public String toString() { + return "UserMealWithExcess{" + + "dateTime=" + dateTime + + ", description='" + description + '\'' + + ", calories=" + calories + + ", excess=" + excess + + '}'; + } +} diff --git a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java new file mode 100644 index 000000000000..0ebfdb5fcdcb --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java @@ -0,0 +1,9 @@ +package ru.javawebinar.topjava.util; + +import java.time.LocalTime; + +public class TimeUtil { + public static boolean isBetweenHalfOpen(LocalTime lt, LocalTime startTime, LocalTime endTime) { + return lt.compareTo(startTime) >= 0 && lt.compareTo(endTime) < 0; + } +} diff --git a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java new file mode 100644 index 000000000000..3c171b4a5972 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java @@ -0,0 +1,39 @@ +package ru.javawebinar.topjava.util; + +import ru.javawebinar.topjava.model.UserMeal; +import ru.javawebinar.topjava.model.UserMealWithExcess; + +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +import java.util.Arrays; +import java.util.List; + +public class UserMealsUtil { + public static void main(String[] args) { + List meals = Arrays.asList( + new UserMeal(LocalDateTime.of(2020, Month.JANUARY, 30, 10, 0), "Завтрак", 500), + new UserMeal(LocalDateTime.of(2020, Month.JANUARY, 30, 13, 0), "Обед", 1000), + new UserMeal(LocalDateTime.of(2020, Month.JANUARY, 30, 20, 0), "Ужин", 500), + new UserMeal(LocalDateTime.of(2020, Month.JANUARY, 31, 0, 0), "Еда на граничное значение", 100), + new UserMeal(LocalDateTime.of(2020, Month.JANUARY, 31, 10, 0), "Завтрак", 1000), + new UserMeal(LocalDateTime.of(2020, Month.JANUARY, 31, 13, 0), "Обед", 500), + new UserMeal(LocalDateTime.of(2020, Month.JANUARY, 31, 20, 0), "Ужин", 410) + ); + + List mealsTo = filteredByCycles(meals, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); + mealsTo.forEach(System.out::println); + +// System.out.println(filteredByStreams(meals, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000)); + } + + public static List filteredByCycles(List meals, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + // TODO return filtered list with excess. Implement by cycles + return null; + } + + public static List filteredByStreams(List meals, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + // TODO Implement by streams + return null; + } +} From 67bf0ba9e74be0c046dfc56dc048220be6d14432 Mon Sep 17 00:00:00 2001 From: StringerDM <103386227+StringerDM@users.noreply.github.com> Date: Thu, 2 Jun 2022 11:00:44 +0300 Subject: [PATCH 103/226] Apply 1_0_rename.patch --- .../model/{UserMeal.java => Meal.java} | 4 +- .../{UserMealWithExcess.java => MealTo.java} | 6 +-- .../javawebinar/topjava/util/MealsUtil.java | 39 +++++++++++++++++++ .../topjava/util/UserMealsUtil.java | 39 ------------------- 4 files changed, 44 insertions(+), 44 deletions(-) rename src/main/java/ru/javawebinar/topjava/model/{UserMeal.java => Meal.java} (83%) rename src/main/java/ru/javawebinar/topjava/model/{UserMealWithExcess.java => MealTo.java} (77%) create mode 100644 src/main/java/ru/javawebinar/topjava/util/MealsUtil.java delete mode 100644 src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java b/src/main/java/ru/javawebinar/topjava/model/Meal.java similarity index 83% rename from src/main/java/ru/javawebinar/topjava/model/UserMeal.java rename to src/main/java/ru/javawebinar/topjava/model/Meal.java index d8f91b127f6a..f546cef0f74a 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java +++ b/src/main/java/ru/javawebinar/topjava/model/Meal.java @@ -2,14 +2,14 @@ import java.time.LocalDateTime; -public class UserMeal { +public class Meal { private final LocalDateTime dateTime; private final String description; private final int calories; - public UserMeal(LocalDateTime dateTime, String description, int calories) { + public Meal(LocalDateTime dateTime, String description, int calories) { this.dateTime = dateTime; this.description = description; this.calories = calories; diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExcess.java b/src/main/java/ru/javawebinar/topjava/model/MealTo.java similarity index 77% rename from src/main/java/ru/javawebinar/topjava/model/UserMealWithExcess.java rename to src/main/java/ru/javawebinar/topjava/model/MealTo.java index d0aa431a35d9..07f04f8dbb9f 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExcess.java +++ b/src/main/java/ru/javawebinar/topjava/model/MealTo.java @@ -2,7 +2,7 @@ import java.time.LocalDateTime; -public class UserMealWithExcess { +public class MealTo { private final LocalDateTime dateTime; private final String description; @@ -11,7 +11,7 @@ public class UserMealWithExcess { private final boolean excess; - public UserMealWithExcess(LocalDateTime dateTime, String description, int calories, boolean excess) { + public MealTo(LocalDateTime dateTime, String description, int calories, boolean excess) { this.dateTime = dateTime; this.description = description; this.calories = calories; @@ -20,7 +20,7 @@ public UserMealWithExcess(LocalDateTime dateTime, String description, int calori @Override public String toString() { - return "UserMealWithExcess{" + + return "MealTo{" + "dateTime=" + dateTime + ", description='" + description + '\'' + ", calories=" + calories + diff --git a/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java new file mode 100644 index 000000000000..bb5ddbf5ccc5 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java @@ -0,0 +1,39 @@ +package ru.javawebinar.topjava.util; + +import ru.javawebinar.topjava.model.Meal; +import ru.javawebinar.topjava.model.MealTo; + +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +import java.util.Arrays; +import java.util.List; + +public class MealsUtil { + public static void main(String[] args) { + List meals = Arrays.asList( + new Meal(LocalDateTime.of(2020, Month.JANUARY, 30, 10, 0), "Завтрак", 500), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 30, 13, 0), "Обед", 1000), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 30, 20, 0), "Ужин", 500), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 0, 0), "Еда на граничное значение", 100), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 10, 0), "Завтрак", 1000), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 13, 0), "Обед", 500), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 20, 0), "Ужин", 410) + ); + + List mealsTo = filteredByCycles(meals, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); + mealsTo.forEach(System.out::println); + +// System.out.println(filteredByStreams(meals, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000)); + } + + public static List filteredByCycles(List meals, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + // TODO return filtered list with excess. Implement by cycles + return null; + } + + public static List filteredByStreams(List meals, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + // TODO Implement by streams + return null; + } +} diff --git a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java deleted file mode 100644 index 3c171b4a5972..000000000000 --- a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java +++ /dev/null @@ -1,39 +0,0 @@ -package ru.javawebinar.topjava.util; - -import ru.javawebinar.topjava.model.UserMeal; -import ru.javawebinar.topjava.model.UserMealWithExcess; - -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.Month; -import java.util.Arrays; -import java.util.List; - -public class UserMealsUtil { - public static void main(String[] args) { - List meals = Arrays.asList( - new UserMeal(LocalDateTime.of(2020, Month.JANUARY, 30, 10, 0), "Завтрак", 500), - new UserMeal(LocalDateTime.of(2020, Month.JANUARY, 30, 13, 0), "Обед", 1000), - new UserMeal(LocalDateTime.of(2020, Month.JANUARY, 30, 20, 0), "Ужин", 500), - new UserMeal(LocalDateTime.of(2020, Month.JANUARY, 31, 0, 0), "Еда на граничное значение", 100), - new UserMeal(LocalDateTime.of(2020, Month.JANUARY, 31, 10, 0), "Завтрак", 1000), - new UserMeal(LocalDateTime.of(2020, Month.JANUARY, 31, 13, 0), "Обед", 500), - new UserMeal(LocalDateTime.of(2020, Month.JANUARY, 31, 20, 0), "Ужин", 410) - ); - - List mealsTo = filteredByCycles(meals, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); - mealsTo.forEach(System.out::println); - -// System.out.println(filteredByStreams(meals, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000)); - } - - public static List filteredByCycles(List meals, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { - // TODO return filtered list with excess. Implement by cycles - return null; - } - - public static List filteredByStreams(List meals, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { - // TODO Implement by streams - return null; - } -} From 03a4a14f1c17a4502d005fcb11d430cef815da4c Mon Sep 17 00:00:00 2001 From: StringerDM <103386227+StringerDM@users.noreply.github.com> Date: Thu, 2 Jun 2022 11:04:15 +0300 Subject: [PATCH 104/226] Apply 1_1_HW0_streams.patch --- .../ru/javawebinar/topjava/model/Meal.java | 10 +++++++ .../javawebinar/topjava/util/MealsUtil.java | 26 ++++++++++++------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/model/Meal.java b/src/main/java/ru/javawebinar/topjava/model/Meal.java index f546cef0f74a..943ff5cd59fa 100644 --- a/src/main/java/ru/javawebinar/topjava/model/Meal.java +++ b/src/main/java/ru/javawebinar/topjava/model/Meal.java @@ -1,6 +1,8 @@ package ru.javawebinar.topjava.model; +import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; public class Meal { private final LocalDateTime dateTime; @@ -26,4 +28,12 @@ public String getDescription() { public int getCalories() { return calories; } + + public LocalDate getDate() { + return dateTime.toLocalDate(); + } + + public LocalTime getTime() { + return dateTime.toLocalTime(); + } } diff --git a/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java index bb5ddbf5ccc5..c29e1fbbb077 100644 --- a/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java @@ -3,11 +3,14 @@ import ru.javawebinar.topjava.model.Meal; import ru.javawebinar.topjava.model.MealTo; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; public class MealsUtil { public static void main(String[] args) { @@ -21,19 +24,24 @@ public static void main(String[] args) { new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 20, 0), "Ужин", 410) ); - List mealsTo = filteredByCycles(meals, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); + List mealsTo = filteredByStreams(meals, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); mealsTo.forEach(System.out::println); - -// System.out.println(filteredByStreams(meals, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000)); } - public static List filteredByCycles(List meals, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { - // TODO return filtered list with excess. Implement by cycles - return null; + public static List filteredByStreams(List meals, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + Map caloriesSumByDate = meals.stream() + .collect( + Collectors.groupingBy(Meal::getDate, Collectors.summingInt(Meal::getCalories)) +// Collectors.toMap(Meal::getDate, Meal::getCalories, Integer::sum) + ); + + return meals.stream() + .filter(meal -> TimeUtil.isBetweenHalfOpen(meal.getTime(), startTime, endTime)) + .map(meal -> createTo(meal, caloriesSumByDate.get(meal.getDate()) > caloriesPerDay)) + .collect(Collectors.toList()); } - public static List filteredByStreams(List meals, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { - // TODO Implement by streams - return null; + private static MealTo createTo(Meal meal, boolean excess) { + return new MealTo(meal.getDateTime(), meal.getDescription(), meal.getCalories(), excess); } } From 39045634c96222b9bc9392da28fd7a3685259b0c Mon Sep 17 00:00:00 2001 From: StringerDM <103386227+StringerDM@users.noreply.github.com> Date: Thu, 2 Jun 2022 17:31:52 +0300 Subject: [PATCH 105/226] Apply 1_2_switch_to_war.patch --- pom.xml | 2 +- src/main/webapp/WEB-INF/web.xml | 19 +++++++++++++++++++ src/main/webapp/index.html | 13 +++++++++++++ src/main/webapp/users.jsp | 11 +++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/main/webapp/WEB-INF/web.xml create mode 100644 src/main/webapp/index.html create mode 100644 src/main/webapp/users.jsp diff --git a/pom.xml b/pom.xml index 0b1c2896da5b..b4426c1aa2d6 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ ru.javawebinar topjava - jar + war 1.0-SNAPSHOT diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000000..c63810c43593 --- /dev/null +++ b/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,19 @@ + + + Topjava + + + userServlet + ru.javawebinar.topjava.web.UserServlet + 0 + + + userServlet + /users + + + diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html new file mode 100644 index 000000000000..58d8d5ab6aec --- /dev/null +++ b/src/main/webapp/index.html @@ -0,0 +1,13 @@ + + + + Java Enterprise (Topjava) + + +

Проект Java Enterprise (Topjava)

+
+ + + diff --git a/src/main/webapp/users.jsp b/src/main/webapp/users.jsp new file mode 100644 index 000000000000..650c8dda479c --- /dev/null +++ b/src/main/webapp/users.jsp @@ -0,0 +1,11 @@ +<%@ page contentType="text/html;charset=UTF-8" %> + + + Users + + +

Home

+
+

Users

+ + \ No newline at end of file From d0588e3fc05f57d0f02de8b5bd0600c32dbf6a46 Mon Sep 17 00:00:00 2001 From: StringerDM <103386227+StringerDM@users.noreply.github.com> Date: Thu, 2 Jun 2022 17:43:46 +0300 Subject: [PATCH 106/226] Apply 1_3_add_servlet_api.patch --- pom.xml | 7 +++++++ .../ru/javawebinar/topjava/web/UserServlet.java | 15 +++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/main/java/ru/javawebinar/topjava/web/UserServlet.java diff --git a/pom.xml b/pom.xml index b4426c1aa2d6..3cd703f93681 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,13 @@ + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + diff --git a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java new file mode 100644 index 000000000000..76056e06c019 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java @@ -0,0 +1,15 @@ +package ru.javawebinar.topjava.web; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class UserServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + request.getRequestDispatcher("/users.jsp").forward(request, response); + } +} From ee182dde454c021aecdebd4ac5464f05d0f9b466 Mon Sep 17 00:00:00 2001 From: StringerDM <103386227+StringerDM@users.noreply.github.com> Date: Thu, 2 Jun 2022 20:15:26 +0300 Subject: [PATCH 107/226] Apply 1_4_forward_to_redirect.patch --- pom.xml | 2 +- src/main/java/ru/javawebinar/topjava/web/UserServlet.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3cd703f93681..f7abfea2b739 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ topjava - install + package org.apache.maven.plugins diff --git a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java index 76056e06c019..11f282bac482 100644 --- a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java @@ -10,6 +10,7 @@ public class UserServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - request.getRequestDispatcher("/users.jsp").forward(request, response); +// request.getRequestDispatcher("/users.jsp").forward(request, response); + response.sendRedirect("users.jsp"); } } From 8bfc3ac27dd1990c578760f6dcba2cf07261bda1 Mon Sep 17 00:00:00 2001 From: StringerDM <103386227+StringerDM@users.noreply.github.com> Date: Fri, 3 Jun 2022 06:54:27 +0300 Subject: [PATCH 108/226] Apply 1_5_logging.patch --- pom.xml | 19 ++++++++++++ .../javawebinar/topjava/web/UserServlet.java | 7 +++++ src/main/resources/logback.xml | 29 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 src/main/resources/logback.xml diff --git a/pom.xml b/pom.xml index f7abfea2b739..e8dc01d332cf 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,10 @@ 1.8 UTF-8 UTF-8 + + + 1.2.11 + 1.7.36 @@ -34,6 +38,21 @@ + + + org.slf4j + slf4j-api + ${slf4j.version} + compile + + + + ch.qos.logback + logback-classic + ${logback.version} + runtime + + javax.servlet diff --git a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java index 11f282bac482..ef52d67576c0 100644 --- a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java @@ -1,15 +1,22 @@ package ru.javawebinar.topjava.web; +import org.slf4j.Logger; + import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import static org.slf4j.LoggerFactory.getLogger; + public class UserServlet extends HttpServlet { + private static final Logger log = getLogger(UserServlet.class); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + log.debug("redirect to users"); + // request.getRequestDispatcher("/users.jsp").forward(request, response); response.sendRedirect("users.jsp"); } diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 000000000000..e9b900b26669 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,29 @@ + + + + + + + + ${TOPJAVA_ROOT}/log/topjava.log + + + UTF-8 + %date %-5level %logger{0} [%file:%line] %msg%n + + + + + + UTF-8 + %-5level %logger{0} [%file:%line] %msg%n + + + + + + + + + + From 52e00aadca5b10f4c96582cb98f8f1407212bbc2 Mon Sep 17 00:00:00 2001 From: StringerDM <103386227+StringerDM@users.noreply.github.com> Date: Thu, 9 Jun 2022 07:38:00 +0300 Subject: [PATCH 109/226] implement Lesson1 patches. --- src/main/java/ru/javawebinar/topjava/model/MealTo.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/ru/javawebinar/topjava/model/MealTo.java b/src/main/java/ru/javawebinar/topjava/model/MealTo.java index 07f04f8dbb9f..1fc4f09d9295 100644 --- a/src/main/java/ru/javawebinar/topjava/model/MealTo.java +++ b/src/main/java/ru/javawebinar/topjava/model/MealTo.java @@ -28,3 +28,4 @@ public String toString() { '}'; } } + From 108674e58ebebefb2a0d43e240575def643cb339 Mon Sep 17 00:00:00 2001 From: StringerDM <103386227+StringerDM@users.noreply.github.com> Date: Thu, 9 Jun 2022 08:46:47 +0300 Subject: [PATCH 110/226] Apply 2_1_HW1 patch --- .gitignore | 1 + pom.xml | 6 +++ .../java/ru/javawebinar/topjava/Main.java | 11 ----- .../ru/javawebinar/topjava/model/MealTo.java | 17 ++++++- .../topjava/util/DateTimeUtil.java | 18 +++++++ .../javawebinar/topjava/util/MealsUtil.java | 36 ++++++++------ .../ru/javawebinar/topjava/util/TimeUtil.java | 9 ---- .../javawebinar/topjava/web/MealServlet.java | 22 +++++++++ .../javawebinar/topjava/web/UserServlet.java | 6 +-- src/main/webapp/WEB-INF/tld/functions.tld | 16 +++++++ src/main/webapp/WEB-INF/web.xml | 10 ++++ src/main/webapp/index.html | 3 +- src/main/webapp/meals.jsp | 48 +++++++++++++++++++ 13 files changed, 162 insertions(+), 41 deletions(-) delete mode 100644 src/main/java/ru/javawebinar/topjava/Main.java create mode 100644 src/main/java/ru/javawebinar/topjava/util/DateTimeUtil.java delete mode 100644 src/main/java/ru/javawebinar/topjava/util/TimeUtil.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/MealServlet.java create mode 100644 src/main/webapp/WEB-INF/tld/functions.tld create mode 100644 src/main/webapp/meals.jsp diff --git a/.gitignore b/.gitignore index 73e6d9e3dd11..42ff323f7d38 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .idea out target +path_arhive *.iml log *.patch diff --git a/pom.xml b/pom.xml index e8dc01d332cf..60bfdb5bd4a3 100644 --- a/pom.xml +++ b/pom.xml @@ -60,6 +60,12 @@ 4.0.1 provided + + + javax.servlet + jstl + 1.2 + diff --git a/src/main/java/ru/javawebinar/topjava/Main.java b/src/main/java/ru/javawebinar/topjava/Main.java deleted file mode 100644 index c2f9cc618f7c..000000000000 --- a/src/main/java/ru/javawebinar/topjava/Main.java +++ /dev/null @@ -1,11 +0,0 @@ -package ru.javawebinar.topjava; - -/** - * @see Demo application - * @see Initial project - */ -public class Main { - public static void main(String[] args) { - System.out.format("Hello TopJava Enterprise!"); - } -} diff --git a/src/main/java/ru/javawebinar/topjava/model/MealTo.java b/src/main/java/ru/javawebinar/topjava/model/MealTo.java index 1fc4f09d9295..800b1fcbb5c3 100644 --- a/src/main/java/ru/javawebinar/topjava/model/MealTo.java +++ b/src/main/java/ru/javawebinar/topjava/model/MealTo.java @@ -18,6 +18,22 @@ public MealTo(LocalDateTime dateTime, String description, int calories, boolean this.excess = excess; } + public LocalDateTime getDateTime() { + return dateTime; + } + + public String getDescription() { + return description; + } + + public int getCalories() { + return calories; + } + + public boolean isExcess() { + return excess; + } + @Override public String toString() { return "MealTo{" + @@ -28,4 +44,3 @@ public String toString() { '}'; } } - diff --git a/src/main/java/ru/javawebinar/topjava/util/DateTimeUtil.java b/src/main/java/ru/javawebinar/topjava/util/DateTimeUtil.java new file mode 100644 index 000000000000..3f23f83fde65 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/util/DateTimeUtil.java @@ -0,0 +1,18 @@ +package ru.javawebinar.topjava.util; + +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; + +public class DateTimeUtil { + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + + public static boolean isBetweenHalfOpen(LocalTime lt, LocalTime startTime, LocalTime endTime) { + return lt.compareTo(startTime) >= 0 && lt.compareTo(endTime) < 0; + } + + public static String toString(LocalDateTime ldt) { + return ldt == null ? "" : ldt.format(DATE_TIME_FORMATTER); + } +} + diff --git a/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java index c29e1fbbb077..ac9c815959c5 100644 --- a/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java @@ -10,25 +10,31 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.function.Predicate; import java.util.stream.Collectors; public class MealsUtil { - public static void main(String[] args) { - List meals = Arrays.asList( - new Meal(LocalDateTime.of(2020, Month.JANUARY, 30, 10, 0), "Завтрак", 500), - new Meal(LocalDateTime.of(2020, Month.JANUARY, 30, 13, 0), "Обед", 1000), - new Meal(LocalDateTime.of(2020, Month.JANUARY, 30, 20, 0), "Ужин", 500), - new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 0, 0), "Еда на граничное значение", 100), - new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 10, 0), "Завтрак", 1000), - new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 13, 0), "Обед", 500), - new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 20, 0), "Ужин", 410) - ); - - List mealsTo = filteredByStreams(meals, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); - mealsTo.forEach(System.out::println); + public static final int DEFAULT_CALORIES_PER_DAY = 2000; + + public static final List meals = Arrays.asList( + new Meal(LocalDateTime.of(2020, Month.JANUARY, 30, 10, 0), "Завтрак", 500), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 30, 13, 0), "Обед", 1000), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 30, 20, 0), "Ужин", 500), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 0, 0), "Еда на граничное значение", 100), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 10, 0), "Завтрак", 1000), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 13, 0), "Обед", 500), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 20, 0), "Ужин", 410) + ); + + public static List getTos(List meals, int caloriesPerDay) { + return filterByPredicate(meals, caloriesPerDay, meal -> true); + } + + public static List getFilteredTos(List meals, int caloriesPerDay, LocalTime startTime, LocalTime endTime) { + return filterByPredicate(meals, caloriesPerDay, meal -> DateTimeUtil.isBetweenHalfOpen(meal.getTime(), startTime, endTime)); } - public static List filteredByStreams(List meals, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + private static List filterByPredicate(List meals, int caloriesPerDay, Predicate filter) { Map caloriesSumByDate = meals.stream() .collect( Collectors.groupingBy(Meal::getDate, Collectors.summingInt(Meal::getCalories)) @@ -36,7 +42,7 @@ public static List filteredByStreams(List meals, LocalTime startTi ); return meals.stream() - .filter(meal -> TimeUtil.isBetweenHalfOpen(meal.getTime(), startTime, endTime)) + .filter(filter) .map(meal -> createTo(meal, caloriesSumByDate.get(meal.getDate()) > caloriesPerDay)) .collect(Collectors.toList()); } diff --git a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java deleted file mode 100644 index 0ebfdb5fcdcb..000000000000 --- a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java +++ /dev/null @@ -1,9 +0,0 @@ -package ru.javawebinar.topjava.util; - -import java.time.LocalTime; - -public class TimeUtil { - public static boolean isBetweenHalfOpen(LocalTime lt, LocalTime startTime, LocalTime endTime) { - return lt.compareTo(startTime) >= 0 && lt.compareTo(endTime) < 0; - } -} diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java new file mode 100644 index 000000000000..8b47dd35450e --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -0,0 +1,22 @@ +package ru.javawebinar.topjava.web; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.javawebinar.topjava.util.MealsUtil; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class MealServlet extends HttpServlet { + private static final Logger log = LoggerFactory.getLogger(MealServlet.class); + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + log.info("forward to meals"); + request.setAttribute("meals", MealsUtil.getTos(MealsUtil.meals, MealsUtil.DEFAULT_CALORIES_PER_DAY)); + request.getRequestDispatcher("/meals.jsp").forward(request, response); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java index ef52d67576c0..f6cf12e69976 100644 --- a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java @@ -15,9 +15,7 @@ public class UserServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - log.debug("redirect to users"); - -// request.getRequestDispatcher("/users.jsp").forward(request, response); - response.sendRedirect("users.jsp"); + log.debug("forward to users"); + request.getRequestDispatcher("/users.jsp").forward(request, response); } } diff --git a/src/main/webapp/WEB-INF/tld/functions.tld b/src/main/webapp/WEB-INF/tld/functions.tld new file mode 100644 index 000000000000..d138fecdbfb5 --- /dev/null +++ b/src/main/webapp/WEB-INF/tld/functions.tld @@ -0,0 +1,16 @@ + + + + 1.0 + functions + http://topjava.javawebinar.ru/functions + + + formatDateTime + ru.javawebinar.topjava.util.DateTimeUtil + java.lang.String toString(java.time.LocalDateTime) + + diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index c63810c43593..bd98d3bf3f6a 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -16,4 +16,14 @@ /users + + mealServlet + ru.javawebinar.topjava.web.MealServlet + 0 + + + mealServlet + /meals + + diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html index 58d8d5ab6aec..714683bd3856 100644 --- a/src/main/webapp/index.html +++ b/src/main/webapp/index.html @@ -6,8 +6,9 @@

Проект Java Enterprise (Topjava)


-