diff --git a/README.md b/README.md
index 228b708b7094..8a58f7f11632 100644
--- a/README.md
+++ b/README.md
@@ -41,9 +41,16 @@ 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)
##  3. Работа с проектом (выполнять инструкции)
-**ВНИМАНИЕ: выбирайте для проекта простой пусть без пробелов и русских букв, например (Windows) `c:\projects\topjava\`. Иначе впоследствии будут проблемы**
+- **ВНИМАНИЕ: выбирайте для проекта простой пусть без пробелов и русских букв, например (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`:
+
+ 
+
### Патч [prepare_to_HW0.patch](https://drive.google.com/file/d/1LNPpu9OkuCpfpD8ZJHO-o0vwu49p2i5M) (скачать и положить в каталог вашего проекта)
> Проект постоянно улучшается, поэтому видео иногда отличается от кода проекта. Изменения указываю после видео:
@@ -51,7 +58,7 @@ Java Enterprise Online Project
> - в `UserMeals/UserMealWithExcess` поля изменились на `private`
> - обновил данные `UserMealsUtil.meals` и переименовал некоторые пременные, поля и методы
> - добавил `UserMealWithExcess.toString()` и метод для выполнения _Optional домашнего задания_
-
+> - метод фильтрации в `TimeUtil` переименовали в `isBetweenHalfOpen` (также изменилась логика сравнения - `startTime` включается в интервал)
## Инструкция по шагам (из видео):
- Установить ПО (git, JDK8, IntelliJ IDEA, Maven)
@@ -69,6 +76,9 @@ Java Enterprise Online Project
- Выполнить задание и залить на GitHub (commit + push)
- Переключиться в основную ветку проекта master.
+##  4. [Тех.задание: библия или допускаются изменения. Полуоткрытый интервал.](https://drive.google.com/file/d/1BpTzjNFjS0TSekCyt_xvt6YoLvuw5KTZ/view)
+- [Типы промежутков](https://ru.wikipedia.org/wiki/Промежуток_(математика))
+
##  Домашнее задание HW0
```
Реализовать метод `UserMealsUtil.filteredByCycles` через циклы (`forEach`):
@@ -82,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
- Временная сложность алгоритма
@@ -98,27 +108,32 @@ 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
- Шпаргалка Java Stream API
- Алексея Владыкин: Элементы функционального программирования в Java
- Yakov Fain о новом в Java 8
-- stream.map vs forEach
+- stream.map vs forEach`
- - без циклов по другим коллекциям
- - решение должно быть рабочим в общем случае (не только при запуске main)
+ - без циклов по другим коллекциям/массивам (к ним также относим методы коллекций `addAll()/removeAll()`)
+ - решение должно быть рабочим в общем случае (работать в приложении с многими пользователями, не только при запуске main)
- через Stream API за 1 проход по исходному списку `meals.streem()`
- - нельзя использовать внешние коллекции, не являющиеся частью коллектора или 2 раза проходить по исходному списку (его копиям).
- Т.е. в решении не должно быть 2 раза `meal.stream()` (в том числе неявно, в составных коллекторах)
- - возможно дополнительные проходы по частям списка
+ - нельзя использовать внешние коллекции, не являющиеся частью коллектора
+ - нельзя 2 раза проходить по исходному списку (в том числе его отфильтрованной или преобразованной копии)
+ - возможно дополнительные проходы по частям списка, при этом превышение должно считаться один раз для всего подсписка. Те например нельзя разбить список на на 2 подсписка с четными и нечетными датами и затем их объединить, с подсчетом превышения для каждого элемента.
+
+
+Ресурсы:
+- [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:
- Когда встречаешь что-то непривычное, приходится перестраивать мозги. Например, переход с процедурного на ООП программирование дается непросто. Те, кто не знает шаблонов (и не хотят учить) также их встречают плохо. Хорошая новость в том, что если это принять и начать использовать, то начинаешь получать от этого удовольствие. И тут главное не впасть в другую крайность:
@@ -133,7 +148,7 @@ Java Enterprise Online Project
##  Замечания к 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(..)`**
@@ -144,13 +159,13 @@ 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)
### Полезные ресурсы
> ВНИМАНИЕ:
-> - **ДЗ первого урока будет связано с [созданием небольшого 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-го занятия!
Все остальное - опционально.
@@ -172,7 +187,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
- Структуры данных в картинках
@@ -183,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/)
diff --git a/ReleaseNotes.md b/ReleaseNotes.md
index f4e7412eb816..7c03206fe59c 100644
--- a/ReleaseNotes.md
+++ b/ReleaseNotes.md
@@ -1,8 +1,45 @@
# 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`)
+- в `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
+- Изменилась логика для интервалов времени (исключаем `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`
-- В PostgreSQL обнаружилась бага: граничное значение `0:00` из за ошибок округления попадает в предыдущий интервал.
+- В PostgreSQL обнаружилась бага: граничное значение `0:00` из-за ошибок округления попадает в предыдущий интервал.
Мораль: всегда в тестах проверяйте граничные значения. Добавил этот случай в тестовые данные.
- Изменил `MealRepository.getBetween` (принимаю `@Nullable LocalDate`). Изменились реализации.
- Выделил метод `UserService.prepareAndSave`
diff --git a/cv.md b/cv.md
index a24d881fdeba..73ca6a62be71 100644
--- a/cv.md
+++ b/cv.md
@@ -20,6 +20,7 @@
### Наши истории (делимся опытом и успехом)
### Тесты/задачи онлайн:
+- [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
@@ -28,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)
@@ -88,8 +88,11 @@
- Яндекс агрегатор
- HH
- LinkedIn
+- ХабрКарьера
+- [headz.io](https://app.headz.io/candidates/new)
- djinni.co (более актуально для Украины)
+
## Как выжить на испытательном сроке
- Учись грамотно формулировать проблему. Проблема "у меня не работает" может иметь тысячи причин. В
процессе формулирования очень часто приходит ее решение.
@@ -106,6 +109,11 @@
- Выдели самое главное путем опроса босса и важных коллег. Не распыляйся на мелочи.
- [**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://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)
+ - [Часть 2](https://javarush.ru/groups/posts/3055-razbor-tipichnihkh-oshibok-nachinajujshikh-programmistov-chastjh-2)
## [Отзывы по стажировке Topjava](https://vk.com/topic-74381644_30447246)
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 6e4af3e023cc..442ce82b8c47 100644
--- a/graduation.md
+++ b/graduation.md
@@ -11,61 +11,77 @@ 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.
-----------------------------
###  Рекомендации
-- Если ты закончил [стажировку Topjava](http://javaops.ru/reg/topjava/grd), **cделай новый проект и добавляй туда из Topjava только то что нужно!** Локализация, типы ошибок, BeanMatcher, Json View, излишние делегирования и наследования - **не нужны!**
+- **Сделай новый проект и добавляй туда из Topjava только то что нужно! Локализация, типы ошибок, BeanMatcher, Json View, излишние делегирования и наследования - не нужны!**
- **API продумывай с точки зрения не программиста и объектов, а с точки зрения того, кто им будет пользоваться (frontend)**
- **Сначала сделай основной сценарий по ТЗ. Все остальное (если очень хочется, 3 раза подумай) - потом.**
-*Представьте себе, что ПМ (лид, архитектор) дал вам ТЗ и некоторое время недоступен. У вас конечно есть много мыслей, для чего нужно приложение, как исправить ТЗ, дополнить его и сделать правильно. НО НЕ НАДО ИХ РЕАЛИЗОВЫВАТЬ В КОДЕ. Нужно сделать все максимально просто, удобно для доработок и для использования со стороны клиента (если конечно в ТЗ нет оговорок). Все свои вопросы и предложения и хотелки оформляйете отдельно (в `read.me` например). Если делаете что-то сложнее простейшего случая (например справочник еды)- обязательно напишите в read.me. Как и выбор стратегии кэширования.*
+*Представьте себе, что ПМ (лид, архитектор) дал вам ТЗ и некоторое время недоступен. У вас, конечно, есть много мыслей, для чего нужно приложение, как исправить ТЗ, дополнить его и сделать правильно. НО НЕ НАДО ИХ РЕАЛИЗОВЫВАТЬ В КОДЕ. Нужно сделать все максимально просто, удобно для доработок и для использования со стороны клиента (если, конечно, в ТЗ нет оговорок). Все свои вопросы, предложения и хотелки оформляйте отдельно (в `read.me` например). Если делаете что-то сложнее простейшего случая (например, справочник еды) - обязательно напишите в read.me. Как и выбор стратегии кэширования.*
> Совершенство достигнуто не тогда, когда нечего добавить, а тогда, когда нечего отнять
_Антуан де Сент-Экзюпери_
- 1: **читаем ТЗ ОЧЕНЬ внимательно, НЕ надо ничего своего туда домысливать и творчески изменять**
-- 2: **тщательно считайте количество обращений в базу на каждый запрос. Особенно при запросах от юзеров, которых очень много! Также на сложность запросов от них, чтобы не положить базу**
+- 2: **тщательно считайте количество обращений в базу на каждый запрос. Особенно при запросах от юзеров, которых очень много! Также на сложность запросов от них, чтобы не положить базу**. Самое худшее в коде - обращение в базу в цикле.
- 3: **тщательно считайте количество запросов в вашем API для отображения нужной информации**
-- 4: **учитывайте, что пользователей может быть ооочень много, а админов- мало**
-- 5: в проекте (и тестовом задании на работу) в отличие от нашего учебного topjava оставляйте только необходимый для работы приложения код, ничего лишнего:
- - 5.1 НЕ надо делать разные профили базы и работы с ней.
- - 5.2 НЕ надо делать абстрактных контроллеров на всякий случай.
- - 5.3 НЕ надо делать **классов репозиториев и сервисов**, если там нет ничего, кроме делегирования.
- - 5.4 Из потребностей приложения (которую надо самим придумать) реализовывать только очевидные сценарии. Те.- НИЧЕГО ЛИШНЕГО.
-- 6: базу лучше взять без установки (H2 или HSQLDB). Ваше приложение должно сразу запуститься, **без всяких настроек и переменных окружения**
+- 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
- - [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`). НЕ надо придумывать своих собственных правил.
-- 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 в коде обязательна!
-- 21: Проверьте, станет ли код проще с `@AuthenticationPrincipal` (урок 11, Доступ к AuthorizedUser).
-- 22: Не размещайте логику приложения и преобразования в TO в слое доступа к DB
-- 23: Если используете кэширование, **тщательно продумайте, что надо кэшировать (самые частые запросы)**, а что нет (большие или редкозапрашиваемые данные)!
+- 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`. Назначение этого проекта совсем другое
+- 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` не прячьте, а пишите здесь!
+ - Проверяют люди с опытом в Java: не надо писать инструкций, как устанавливать Java и Maven:)
## Попробуйте подергать свое API по всем типичным сценариям ТЗ!
- Удобно использовать? Можно сделать проще? Например чтобы проголосовать за ресторан залогиненному юзеру достаточно `restorauntId`.
diff --git a/pom.xml b/pom.xml
index 0b1c2896da5b..101a64479a25 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
ru.javawebinartopjava
- jar
+ war1.0-SNAPSHOT
@@ -15,16 +15,20 @@
1.8UTF-8UTF-8
+
+
+ 1.2.3
+ 1.7.30topjava
- install
+ packageorg.apache.maven.pluginsmaven-compiler-plugin
- 3.8.1
+
${java.version}${java.version}
@@ -34,6 +38,28 @@
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+ compile
+
+
+
+ ch.qos.logback
+ logback-classic
+ ${logback.version}
+ runtime
+
+
+
+
+ javax.servlet
+ javax.servlet-api
+ 4.0.1
+ provided
+
diff --git a/src/main/java/ru/javawebinar/topjava/model/Meal.java b/src/main/java/ru/javawebinar/topjava/model/Meal.java
new file mode 100644
index 000000000000..943ff5cd59fa
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/model/Meal.java
@@ -0,0 +1,39 @@
+package ru.javawebinar.topjava.model;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
+public class Meal {
+ private final LocalDateTime dateTime;
+
+ private final String description;
+
+ private final int calories;
+
+ public Meal(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;
+ }
+
+ public LocalDate getDate() {
+ return dateTime.toLocalDate();
+ }
+
+ public LocalTime getTime() {
+ return dateTime.toLocalTime();
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/model/MealTo.java b/src/main/java/ru/javawebinar/topjava/model/MealTo.java
new file mode 100644
index 000000000000..07f04f8dbb9f
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/model/MealTo.java
@@ -0,0 +1,30 @@
+package ru.javawebinar.topjava.model;
+
+import java.time.LocalDateTime;
+
+public class MealTo {
+ private final LocalDateTime dateTime;
+
+ private final String description;
+
+ private final int calories;
+
+ private final boolean excess;
+
+ public MealTo(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 "MealTo{" +
+ "dateTime=" + dateTime +
+ ", description='" + description + '\'' +
+ ", calories=" + calories +
+ ", excess=" + excess +
+ '}';
+ }
+}
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..c29e1fbbb077
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java
@@ -0,0 +1,47 @@
+package ru.javawebinar.topjava.util;
+
+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) {
+ 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 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());
+ }
+
+ private static MealTo createTo(Meal meal, boolean excess) {
+ return new MealTo(meal.getDateTime(), meal.getDescription(), meal.getCalories(), 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/web/UserServlet.java b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java
new file mode 100644
index 000000000000..ef52d67576c0
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java
@@ -0,0 +1,23 @@
+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
+
+
+
+
+
+
+
+
+
+
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)
+
+
+