From aa6c1516297fccba768a22b0a029c28ef26a24d5 Mon Sep 17 00:00:00 2001 From: Grigory Kislin Date: Sat, 13 Feb 2016 17:02:55 +0300 Subject: [PATCH 01/32] Add description --- README.md | 106 +++++++++++++++++++++++++++++++++++++++++++++++++ cv.md | 55 +++++++++++++++++++++++++ description.md | 67 +++++++++++++++++++++++++++++++ 3 files changed, 228 insertions(+) create mode 100644 README.md create mode 100644 cv.md create mode 100644 description.md diff --git a/README.md b/README.md new file mode 100644 index 000000000000..786ec1b557bb --- /dev/null +++ b/README.md @@ -0,0 +1,106 @@ +Java Enterprise Online Project +=============================== +Наиболее востребованные технологии /инструменты / фреймворки Java Enterprise: +Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + plugins. + + Когда вы слышите что-то, вы забываете это. + Когда вы видите что-то, вы запоминаете это. + Но только когда вы начинаете делать это, + вы начинаете понимать это + + Старинная китайская поговорка + +## Описание и план проекта +### Демо разрабатываемого приложения +### Требования к участникам, Wiki + +Вводное занятие +=============== +## ![video](http://s.ytimg.com/yts/img/favicon-vflz7uhzw.ico) Системы управления версиями. Git. + +- Система управления версиями. VCS/DVSC. +- Ресурсы: + - Интерактивная Git обучалка + - Основы Git + - Working with remote repositories + - Видео по обучению Git + - Как начать работать с GitHub: быстрый старт + - Справочник в графическом виде + - Git Overview + - Видеокурс по Git + +## ![video](http://s.ytimg.com/yts/img/favicon-vflz7uhzw.ico) Работа с проектом (выполнять инструкции) +- **Prepare_ to_ HW0.patch (скачать и положить в каталог вашего проекта)** +- Доступно о Java 8 Lambda + +## Инструкция по шагам (из видео): +- Установить ПО (git, JDK8, IntelliJ IDEA, Maven) +- Создать аккаунт на GitHub +- Сделать Fork ЭТОГО проекта (https://github.com/JavaOPs/topjava) +- Сделать локальный репозиторий проекта: +
git clone https://github.com/[Ваш аккаунт]/topjava.git
+- Открыть и настроить проект в IDEA +- По ходу видео сделать Apply Patch... скаченного патча Prepare_ to_ HW0.patch +- Закоммитить и запушить изменения (commit + push) +- Сделать ветку домашнего задания +- Выполнить задание и залить на GitHub (commit + push) +- Переключиться в основную ветку проекта master. + +## Домашнее задание HW0 + +- Java 8 Date and Time API +- Time complexity +- Временная сложность алгоритма +- Вычислительная сложность +``` +Реализовать UserMealsUtil.getFilteredMealsWithExceeded: +- должны возвращаться только записи между startTime и endTime +- поле UserMealWithExceed.exceed должно показывать, + превышает ли сумма калорий за весь день параметра метода caloriesPerDay + +Т.е UserMealWithExceed - это запись одной еды, но поле exceeded будет одинаково для всех записей за этот день. + +- Проверте результат выполнения ДЗ (можно проверить логику в http://topjava.herokuapp.com , список еды) +- Оцените Time complexity вашего алгоритма (если он O(N*N)- попробуйте сделать O(N). +``` +Optional + +- Java 8: Lambda выражения +- Java 8: Потоки +- Pуководство по Java 8 Stream +- Лямбда-выражения в Java 8 +- Шпаргалка Java Stream API +- stream.map vs forEach + +``` +Сделать реализация через Java 8 Stream API. Заменяйте forEach оператором stream.map(..) +``` +### Составление резюме, подготовка к интервью, поиск работы +### Ресурсы для подготовки к проекту +#### (желательно иметь представление для лучшего усвоения материала) + +#### Java Web (Servlets, JSP) +- Введение в сетевое программирование +- Основы Java на реальном примере (Servlets, JSP) +- Как создать Servlet? Полное руководство. +- Технологии Java для разработки веб-приложений + +#### HTML, JavaScript, CSS +- Основы работы с HTML/CSS/JavaScript +- jQuery для начинающих +- Уроки Bootstrap 3 + +#### Java Core (Reflection API, JUnit) +- Введение в Java Reflection API +- Java JUnit + +#### JDBC, SQL +- Уроки по JDBC +- Learn SQL +- Try SQL + +#### Разное +- Интуит. Программирование на Java +- Oracle Java tutorial на русском. +- Эффективная работа с кодом в IntelliJ IDEA diff --git a/cv.md b/cv.md new file mode 100644 index 000000000000..95a53c28f61a --- /dev/null +++ b/cv.md @@ -0,0 +1,55 @@ +## Составление резюме, подготовка к интервью, поиск работы + +![cv](https://cloud.githubusercontent.com/assets/13649199/10877471/93ea86b8-8157-11e5-9bfa-95e3fba75c58.jpg) + +- Научиться программировать сложнее, чем кажется + +### Составление резюме: +- Идеальное резюме Junior’а +- Как продать свое резюме в 2 раза дороже +- Как правильно составить резюме +- Резюме программистов. Часть 1 (плохие) +- Резюме программистов. Часть 2 (хорошие) +- Как составить резюме на английском + +### Интервью: +- Михаил Портнов. Собеседование на работу: как продать себя грамотно +- Михаил Портнов. Какие вопросы мы задаем на собеседовании? +- Канал: Резюме, поиск работы, интервью +- Яков Файн: Как стать профессиональным Java разработчиком +- Quizful- тесты онлайн +- Сборка по вопросам на интервью +- Тест на знание SQL +- Сборка вопросов от JavaRush +> про clone и finalize объязательно прочтите Джошуа Блох: Java. Эффективное программирование (второе издание) + +- Cracking the Coding Interview +> Особенно обратите внимание на раздел: Часть VIII. Вопросы собеседования + +### От себя: +- email, skype - очень желательно, чтобы по ним вы были узнаваемы. Заведите рабочие, если не так. +- написать ВЕСЬ IT опыт (исключая опыт пользователя: Windows, MS Word, Photophop, Yandex disk, Google docs, ..): технологии, какие задачи решали (конкретные), какие инструменты использовали, VCS, DB, инструменты сборки, ... включая опыт в ВУЗе. +- на English иметь желательно. Если вакансия опублинована на Englsih - шлите на нем. Часто могут на нем попросить, если работодатель иностранный. +- удобно иметь резюме где то в инете (hh, linkedin, google doc, чтобы им было удобно делиться). + +### Позиционирование проекта Topjava: +- После завершения проекта вы освоите все заявленные в нем технологии - вставьте в квалификацию (включая java 8 Stream and Time API) +- Делайте упор не на обучение, а на *участие в проекте*. Выполнение домашних заданий - это полноценное участие с написанием функционала по всем этим технологиям. Например: + + Участие в разработке Spring/JPA Enterprise приложения c авторизацией и правами доступа на основе ролей + на стеке Maven/ Spring MVC/ Security/ REST(Jackson)/ Java 8 Stream API: + - реализация сохранения в базы Postgres и HSQLDB на основе Spring JBDC, JPA(Hibernate) и Spring-Data-JPA + - реализация и тестирование REST и AJAX контроллеров + - реализация клиента на Bootstrap (css/js), datatables, jQuery + plugins. + - отлично будет, если вы его еще как то сами доработаете + +- По поводу обучения на курсах- можно упомянуть в разделе образования. Но на собеседовании меньше смотрят на то, что вы заканчивали, больше - на ваш опыт и то что вы знаете. + +### В течении проекта заполните форму соискателя "Разработчик Java" +Я ее рассылаю всем знакомым HR, уже есть пинги и трудоустройство. + +### Основные сайты поиска работы: +- HH +- LinkedIn +- djinni.co (более актуально для Украины) +- moikrug diff --git a/description.md b/description.md new file mode 100644 index 000000000000..0133bf3c83e8 --- /dev/null +++ b/description.md @@ -0,0 +1,67 @@ +#### Разработка полнофункционального 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 +- Основное внимание будет уделяться способам решения многочисленных проблем разработки в Spring/JPA, а также структурному (красивому и надежному) java кодированию и архитектуре приложения. +- Каждая итерация проекта в закрепляется домашним заданием по реализации схожей функциональности. Следующее занятие начинается с разбора домашних заданий. +- Большое внимание уделяется тестированию кода: в проекте 88 JUnit тестов. +- Несмотря на относительно небольшой размер, приложение разрабатывается с нуля как большой проект (например мы используем кэш 2-го уровня Hibernate, настраиваем Jenkins для работы с ленивой загрузкой +Hibernate, делаем конверторы для типов LocalDateTime (Java 8 time API), которые еще не поддерживаются ни JPA/Hibernate, ни Jackson/json). + Разбираются архитектурные паттерны: слои приложения и как правильно разбивать логику по слоям, когда нужно применят 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. +- Поддержка 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. Datatables. +- AJAX. jQuery. Notifications. +- Spring Security +- Spring Binding/Validation +- Работа с Datatables через Ajax. +- Spring Security Test +- Encoding password +- CSRF (добавление в Spring проект защиты от межсайтовой подделки запроса) +- form-login. Spring Security Taglib +- Handler interceptor +- Spring Exception Handling +- Деплой в Heroku From 67eb1c848fc88ad95568e1ef772fd7ff7cdb8cce Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 17 Feb 2016 01:24:38 +0300 Subject: [PATCH 02/32] Update description.md --- description.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/description.md b/description.md index 0133bf3c83e8..f12cc888bf75 100644 --- a/description.md +++ b/description.md @@ -17,8 +17,8 @@ Hibernate, делаем конверторы для типов LocalDateTime (Ja ## План проекта (ссылки на некоторые темы открыты для просмотра) ### Архитектура проекта. Персистентность. -- Системы управления версиями -- Java 8: Lambda, Stream API +- Системы управления версиями +- Java 8: Lambda, Stream API - Обзор используемых в проекте технологий и инструментов. - Инструмент сборки Maven. - WAR. Веб-контейнер Tomcat. Сервлеты. From 53793a82849a3b864f863aa4244beff038f5030e Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sat, 20 Feb 2016 00:39:41 +0300 Subject: [PATCH 03/32] Update description.md --- description.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/description.md b/description.md index f12cc888bf75..cbb102fa72aa 100644 --- a/description.md +++ b/description.md @@ -1,10 +1,10 @@ -#### Разработка полнофункционального 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 +#### Разработка полнофункционального 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 - Основное внимание будет уделяться способам решения многочисленных проблем разработки в Spring/JPA, а также структурному (красивому и надежному) java кодированию и архитектуре приложения. - Каждая итерация проекта в закрепляется домашним заданием по реализации схожей функциональности. Следующее занятие начинается с разбора домашних заданий. - Большое внимание уделяется тестированию кода: в проекте 88 JUnit тестов. - Несмотря на относительно небольшой размер, приложение разрабатывается с нуля как большой проект (например мы используем кэш 2-го уровня Hibernate, настраиваем Jenkins для работы с ленивой загрузкой Hibernate, делаем конверторы для типов LocalDateTime (Java 8 time API), которые еще не поддерживаются ни JPA/Hibernate, ни Jackson/json). - Разбираются архитектурные паттерны: слои приложения и как правильно разбивать логику по слоям, когда нужно применят Data Transfer Object. + Разбираются архитектурные паттерны: слои приложения и как правильно разбивать логику по слоям, когда нужно применять Data Transfer Object. Т.е на выходе получается не учебный проект, а хорошо маштабируемый шаблон для большого проекта на всех пройденных технологиях. - Большое внимание уделяется деталям: популяция базы, использование транзакционности, тесты сервисов и REST контроллеров, насторойка EntityManagerFactory, @@ -60,7 +60,7 @@ Hibernate, делаем конверторы для типов LocalDateTime (Ja - Работа с Datatables через Ajax. - Spring Security Test - Encoding password -- CSRF (добавление в Spring проект защиты от межсайтовой подделки запроса) +- CSRF (добавление в проект защиты от межсайтовой подделки запроса) - form-login. Spring Security Taglib - Handler interceptor - Spring Exception Handling From eaf48feb81efb5cce0b2a712b7c024d1edee6aa7 Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Fri, 26 Feb 2016 17:01:40 +0300 Subject: [PATCH 04/32] Prepare to HW0 --- .../javawebinar/topjava/model/UserMeal.java | 33 +++++++++++++++++ .../topjava/model/UserMealWithExceed.java | 24 +++++++++++++ .../ru/javawebinar/topjava/util/TimeUtil.java | 13 +++++++ .../topjava/util/UserMealsUtil.java | 35 +++++++++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 src/main/java/ru/javawebinar/topjava/model/UserMeal.java create mode 100644 src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.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..fde5448b93d8 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java @@ -0,0 +1,33 @@ +package ru.javawebinar.topjava.model; + +import java.time.LocalDateTime; + +/** + * GKislin + * 11.01.2015. + */ +public class UserMeal { + protected final LocalDateTime dateTime; + + protected final String description; + + protected 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/UserMealWithExceed.java b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java new file mode 100644 index 000000000000..dab6c9468c5e --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java @@ -0,0 +1,24 @@ +package ru.javawebinar.topjava.model; + +import java.time.LocalDateTime; + +/** + * GKislin + * 11.01.2015. + */ +public class UserMealWithExceed { + protected final LocalDateTime dateTime; + + protected final String description; + + protected final int calories; + + protected final boolean exceed; + + public UserMealWithExceed(LocalDateTime dateTime, String description, int calories, boolean exceed) { + this.dateTime = dateTime; + this.description = description; + this.calories = calories; + this.exceed = exceed; + } +} 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..02399b7288cf --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java @@ -0,0 +1,13 @@ +package ru.javawebinar.topjava.util; + +import java.time.LocalTime; + +/** + * GKislin + * 07.01.2015. + */ +public class TimeUtil { + public static boolean isBetween(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..2cb426400fa5 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java @@ -0,0 +1,35 @@ +package ru.javawebinar.topjava.util; + +import ru.javawebinar.topjava.model.UserMeal; +import ru.javawebinar.topjava.model.UserMealWithExceed; + +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +import java.util.Arrays; +import java.util.List; + +/** + * GKislin + * 31.05.2015. + */ +public class UserMealsUtil { + public static void main(String[] args) { + List mealList = Arrays.asList( + new UserMeal(LocalDateTime.of(2015, Month.MAY, 30,10,0), "Завтрак", 500), + new UserMeal(LocalDateTime.of(2015, Month.MAY, 30,13,0), "Обед", 1000), + new UserMeal(LocalDateTime.of(2015, Month.MAY, 30,20,0), "Ужин", 500), + new UserMeal(LocalDateTime.of(2015, Month.MAY, 31,10,0), "Завтрак", 1000), + new UserMeal(LocalDateTime.of(2015, Month.MAY, 31,13,0), "Обед", 500), + new UserMeal(LocalDateTime.of(2015, Month.MAY, 31,20,0), "Ужин", 510) + ); + getFilteredMealsWithExceeded(mealList, LocalTime.of(7, 0), LocalTime.of(12,0), 2000); +// .toLocalDate(); +// .toLocalTime(); + } + + public static List getFilteredMealsWithExceeded(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + // TODO return filtered list with correctly exceeded field + return null; + } +} From 5d5835c6d05e4ac8f5e941c98c6786f73022f468 Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Fri, 4 Mar 2016 11:03:16 +0300 Subject: [PATCH 05/32] Applied: 1-1-HW0-stream.patch --- .../topjava/model/UserMealWithExceed.java | 10 ++++++ .../topjava/util/UserMealsUtil.java | 36 ++++++++++++------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java index dab6c9468c5e..66c356922f6b 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java @@ -21,4 +21,14 @@ public UserMealWithExceed(LocalDateTime dateTime, String description, int calori this.calories = calories; this.exceed = exceed; } + + @Override + public String toString() { + return "UserMealWithExceed{" + + "dateTime=" + dateTime + + ", description='" + description + '\'' + + ", calories=" + calories + + ", exceed=" + exceed + + '}'; + } } diff --git a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java index 2cb426400fa5..8252485855f3 100644 --- a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java @@ -3,11 +3,14 @@ import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.model.UserMealWithExceed; +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; /** * GKislin @@ -16,20 +19,29 @@ public class UserMealsUtil { public static void main(String[] args) { List mealList = Arrays.asList( - new UserMeal(LocalDateTime.of(2015, Month.MAY, 30,10,0), "Завтрак", 500), - new UserMeal(LocalDateTime.of(2015, Month.MAY, 30,13,0), "Обед", 1000), - new UserMeal(LocalDateTime.of(2015, Month.MAY, 30,20,0), "Ужин", 500), - new UserMeal(LocalDateTime.of(2015, Month.MAY, 31,10,0), "Завтрак", 1000), - new UserMeal(LocalDateTime.of(2015, Month.MAY, 31,13,0), "Обед", 500), - new UserMeal(LocalDateTime.of(2015, Month.MAY, 31,20,0), "Ужин", 510) + new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 10, 0), "Завтрак", 500), + new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 13, 0), "Обед", 1000), + new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 20, 0), "Ужин", 500), + new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 10, 0), "Завтрак", 1000), + new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 13, 0), "Обед", 500), + new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 20, 0), "Ужин", 510) ); - getFilteredMealsWithExceeded(mealList, LocalTime.of(7, 0), LocalTime.of(12,0), 2000); -// .toLocalDate(); -// .toLocalTime(); + List filteredMealsWithExceeded = getFilteredMealsWithExceeded(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); + filteredMealsWithExceeded.forEach(System.out::println); } - public static List getFilteredMealsWithExceeded(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { - // TODO return filtered list with correctly exceeded field - return null; + public static List getFilteredMealsWithExceeded(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + Map caloriesSumByDate = mealList.stream() + .collect( + Collectors.groupingBy(um -> um.getDateTime().toLocalDate(), + Collectors.summingInt(UserMeal::getCalories)) + ); + + return mealList.stream() + .filter(um -> TimeUtil.isBetween(um.getDateTime().toLocalTime(), startTime, endTime)) + .map(um -> + new UserMealWithExceed(um.getDateTime(), um.getDescription(), um.getCalories(), + caloriesSumByDate.get(um.getDateTime().toLocalDate()) > caloriesPerDay)) + .collect(Collectors.toList()); } } From bdae0a34986a899ad9c6e31d95f15b644cf541e9 Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Fri, 4 Mar 2016 11:10:43 +0300 Subject: [PATCH 06/32] Applied: 1-2-HW0-cycle.patch --- .../topjava/util/UserMealsUtil.java | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java index 8252485855f3..ed7fef004529 100644 --- a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java @@ -7,9 +7,7 @@ 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.*; import java.util.stream.Collectors; /** @@ -28,6 +26,8 @@ public static void main(String[] args) { ); List filteredMealsWithExceeded = getFilteredMealsWithExceeded(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); filteredMealsWithExceeded.forEach(System.out::println); + + System.out.println(getFilteredMealsWithExceededByCycle(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000)); } public static List getFilteredMealsWithExceeded(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { @@ -39,9 +39,26 @@ public static List getFilteredMealsWithExceeded(List TimeUtil.isBetween(um.getDateTime().toLocalTime(), startTime, endTime)) - .map(um -> - new UserMealWithExceed(um.getDateTime(), um.getDescription(), um.getCalories(), - caloriesSumByDate.get(um.getDateTime().toLocalDate()) > caloriesPerDay)) + .map(um -> createWithExceed(um, caloriesSumByDate.get(um.getDateTime().toLocalDate()) > caloriesPerDay)) .collect(Collectors.toList()); } -} + + public static List getFilteredMealsWithExceededByCycle(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + + final Map caloriesSumPerDate = new HashMap<>(); + mealList.forEach(meal -> caloriesSumPerDate.merge(meal.getDateTime().toLocalDate(), meal.getCalories(), Integer::sum)); + + final List mealExceeded = new ArrayList<>(); + mealList.forEach(meal -> { + final LocalDateTime dateTime = meal.getDateTime(); + if (TimeUtil.isBetween(dateTime.toLocalTime(), startTime, endTime)) { + mealExceeded.add(createWithExceed(meal, caloriesSumPerDate.get(dateTime.toLocalDate()) > caloriesPerDay)); + } + }); + return mealExceeded; + } + + public static UserMealWithExceed createWithExceed(UserMeal um, boolean exceeded) { + return new UserMealWithExceed(um.getDateTime(), um.getDescription(), um.getCalories(), exceeded); + } +} \ No newline at end of file From 56bace2854c5cd2dda2d8f8c338078382162fece Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 7 Mar 2016 23:47:42 +0300 Subject: [PATCH 07/32] Applied: 1-3-switch-to-war.patch --- pom.xml | 2 +- src/main/webapp/WEB-INF/web.xml | 18 ++++++++++++++++++ src/main/webapp/index.html | 10 ++++++++++ src/main/webapp/userList.jsp | 9 +++++++++ 4 files changed, 38 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/userList.jsp diff --git a/pom.xml b/pom.xml index c8a1c78f3b29..6f0e7fd7cf47 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..edca9575b44b --- /dev/null +++ b/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,18 @@ + + + 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..1937333f0dbe --- /dev/null +++ b/src/main/webapp/index.html @@ -0,0 +1,10 @@ + + + + + Codestin Search App + + +

Приложение вебинара "Top Java."

+ + \ No newline at end of file diff --git a/src/main/webapp/userList.jsp b/src/main/webapp/userList.jsp new file mode 100644 index 000000000000..c6b12052a263 --- /dev/null +++ b/src/main/webapp/userList.jsp @@ -0,0 +1,9 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + Codestin Search App + + +

User list

+ + From 23a19da564d918ed6ba8d5710462f4359ce232c8 Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 7 Mar 2016 23:50:00 +0300 Subject: [PATCH 08/32] Applied: 1-4-add-servlet-api.patch --- pom.xml | 8 ++++++++ .../javawebinar/topjava/web/UserServlet.java | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 src/main/java/ru/javawebinar/topjava/web/UserServlet.java diff --git a/pom.xml b/pom.xml index 6f0e7fd7cf47..8f53790c10fe 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,14 @@ + + + + javax.servlet + servlet-api + 2.5 + 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..389759e504ad --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java @@ -0,0 +1,18 @@ +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; + +/** + * User: gkislin + * Date: 19.08.2014 + */ +public class UserServlet extends HttpServlet { + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + request.getRequestDispatcher("/userList.jsp").forward(request, response); + } +} From ef0bf6c3a451b151fbf0e36bfa8abe1b70331317 Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 7 Mar 2016 23:51:51 +0300 Subject: [PATCH 09/32] Applied: 1-5-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 8f53790c10fe..70d34d406c59 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 389759e504ad..70ce24c6c494 100644 --- a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java @@ -13,6 +13,7 @@ public class UserServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - request.getRequestDispatcher("/userList.jsp").forward(request, response); +// request.getRequestDispatcher("/userList.jsp").forward(request, response); + response.sendRedirect("userList.jsp"); } } From 7dee9436071c2eac84b47b0d17cde6a80b750d7f Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 7 Mar 2016 23:54:35 +0300 Subject: [PATCH 10/32] Applied: 1-6-logging.patch --- pom.xml | 32 ++++++++++++++++++ .../javawebinar/topjava/web/UserServlet.java | 8 +++++ src/main/resources/logback.xml | 33 +++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 src/main/resources/logback.xml diff --git a/pom.xml b/pom.xml index 70d34d406c59..c56f716d4cbf 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,10 @@ 1.8 UTF-8 UTF-8 + + + 1.1.6 + 1.7.18 @@ -34,6 +38,34 @@ + + + org.slf4j + slf4j-api + ${slf4j.version} + compile + + + + org.slf4j + jcl-over-slf4j + ${slf4j.version} + runtime + + + + org.slf4j + jul-to-slf4j + ${slf4j.version} + runtime + + + + ch.qos.logback + logback-classic + ${logback.version} + runtime + diff --git a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java index 70ce24c6c494..0b6611f24666 100644 --- a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java @@ -1,18 +1,26 @@ package ru.javawebinar.topjava.web; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + 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; + /** * User: gkislin * Date: 19.08.2014 */ public class UserServlet extends HttpServlet { + private static final Logger LOG = getLogger(UserServlet.class); protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + LOG.debug("redirect to userList"); + // request.getRequestDispatcher("/userList.jsp").forward(request, response); response.sendRedirect("userList.jsp"); } diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 000000000000..8ee5f21b023e --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,33 @@ + + + + + true + + + + + + + ${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 4f645245fa3e2a0b6e51152d1b890fe4a72b931f Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 7 Mar 2016 23:55:43 +0300 Subject: [PATCH 11/32] Applied: 1-7-remote-jmx.patch --- config/setenv.bat | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 config/setenv.bat diff --git a/config/setenv.bat b/config/setenv.bat new file mode 100644 index 000000000000..ebbd659386f6 --- /dev/null +++ b/config/setenv.bat @@ -0,0 +1,4 @@ +rem run tomcat with JMX ability +rem Run Tomcat as admin +rem for remote connection add -Djava.rmi.server.hostname=TomcatServer_IP +set CATALINA_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false From eb1e73e2e566d8b6d3b8e75e73ccb42fb0e61aff Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 10 Mar 2016 10:27:29 +0300 Subject: [PATCH 12/32] Applied: 2-1-HW1.patch --- pom.xml | 5 +++ .../topjava/model/UserMealWithExceed.java | 24 ++++++++-- .../ru/javawebinar/topjava/util/TimeUtil.java | 8 ++++ .../topjava/util/UserMealsUtil.java | 31 ++++++++----- .../javawebinar/topjava/web/MealServlet.java | 25 +++++++++++ src/main/webapp/WEB-INF/web.xml | 10 +++++ src/main/webapp/index.html | 9 +++- src/main/webapp/mealList.jsp | 45 +++++++++++++++++++ src/main/webapp/userList.jsp | 3 +- 9 files changed, 141 insertions(+), 19 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/web/MealServlet.java create mode 100644 src/main/webapp/mealList.jsp diff --git a/pom.xml b/pom.xml index c56f716d4cbf..af41b1894a11 100644 --- a/pom.xml +++ b/pom.xml @@ -67,6 +67,11 @@ runtime + + javax.servlet + jstl + 1.2 + javax.servlet diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java index 66c356922f6b..935b943afeb6 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java @@ -7,13 +7,13 @@ * 11.01.2015. */ public class UserMealWithExceed { - protected final LocalDateTime dateTime; + private final LocalDateTime dateTime; - protected final String description; + private final String description; - protected final int calories; + private final int calories; - protected final boolean exceed; + private final boolean exceed; public UserMealWithExceed(LocalDateTime dateTime, String description, int calories, boolean exceed) { this.dateTime = dateTime; @@ -22,6 +22,22 @@ public UserMealWithExceed(LocalDateTime dateTime, String description, int calori this.exceed = exceed; } + public LocalDateTime getDateTime() { + return dateTime; + } + + public String getDescription() { + return description; + } + + public int getCalories() { + return calories; + } + + public boolean isExceed() { + return exceed; + } + @Override public String toString() { return "UserMealWithExceed{" + diff --git a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java index 02399b7288cf..115311fad6b7 100644 --- a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java @@ -1,13 +1,21 @@ package ru.javawebinar.topjava.util; +import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.format.DateTimeFormatter; /** * GKislin * 07.01.2015. */ public class TimeUtil { + public static final DateTimeFormatter DATE_TME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + public static boolean isBetween(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_TME_FORMATTER); + } } diff --git a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java index ed7fef004529..6ea1f206d9e7 100644 --- a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java @@ -15,22 +15,29 @@ * 31.05.2015. */ public class UserMealsUtil { + public static final List MEAL_LIST = Arrays.asList( + new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 10, 0), "Завтрак", 500), + new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 13, 0), "Обед", 1000), + new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 20, 0), "Ужин", 500), + new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 10, 0), "Завтрак", 1000), + new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 13, 0), "Обед", 500), + new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 20, 0), "Ужин", 510) + ); + + public static final int DEFAULT_CALORIES_PER_DAY = 2000; + public static void main(String[] args) { - List mealList = Arrays.asList( - new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 10, 0), "Завтрак", 500), - new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 13, 0), "Обед", 1000), - new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 20, 0), "Ужин", 500), - new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 10, 0), "Завтрак", 1000), - new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 13, 0), "Обед", 500), - new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 20, 0), "Ужин", 510) - ); - List filteredMealsWithExceeded = getFilteredMealsWithExceeded(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); + List filteredMealsWithExceeded = getFilteredWithExceeded(MEAL_LIST, LocalTime.of(7, 0), LocalTime.of(12, 0), DEFAULT_CALORIES_PER_DAY); filteredMealsWithExceeded.forEach(System.out::println); - System.out.println(getFilteredMealsWithExceededByCycle(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000)); + System.out.println(getFilteredWithExceededByCycle(MEAL_LIST, LocalTime.of(7, 0), LocalTime.of(12, 0), DEFAULT_CALORIES_PER_DAY)); + } + + public static List getWithExceeded(List mealList, int caloriesPerDay) { + return getFilteredWithExceeded(mealList, LocalTime.MIN, LocalTime.MAX, caloriesPerDay); } - public static List getFilteredMealsWithExceeded(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + public static List getFilteredWithExceeded(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { Map caloriesSumByDate = mealList.stream() .collect( Collectors.groupingBy(um -> um.getDateTime().toLocalDate(), @@ -43,7 +50,7 @@ public static List getFilteredMealsWithExceeded(List getFilteredMealsWithExceededByCycle(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + public static List getFilteredWithExceededByCycle(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { final Map caloriesSumPerDate = new HashMap<>(); mealList.forEach(meal -> caloriesSumPerDate.merge(meal.getDateTime().toLocalDate(), meal.getCalories(), Integer::sum)); 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..9e6ae04d69b2 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -0,0 +1,25 @@ +package ru.javawebinar.topjava.web; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.javawebinar.topjava.util.UserMealsUtil; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * User: gkislin + * Date: 19.08.2014 + */ +public class MealServlet extends HttpServlet { + private static final Logger LOG = LoggerFactory.getLogger(MealServlet.class); + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + LOG.info("getAll"); + request.setAttribute("mealList", UserMealsUtil.getWithExceeded(UserMealsUtil.MEAL_LIST, UserMealsUtil.DEFAULT_CALORIES_PER_DAY)); + request.getRequestDispatcher("/mealList.jsp").forward(request, response); + } +} diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index edca9575b44b..6306688d0998 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -15,4 +15,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 1937333f0dbe..e85ec56ddf0d 100644 --- a/src/main/webapp/index.html +++ b/src/main/webapp/index.html @@ -5,6 +5,11 @@ Codestin Search App -

Приложение вебинара "Top Java."

+

Проект "Top Java"

+
+ - \ No newline at end of file + diff --git a/src/main/webapp/mealList.jsp b/src/main/webapp/mealList.jsp new file mode 100644 index 000000000000..1d1f66d87f7f --- /dev/null +++ b/src/main/webapp/mealList.jsp @@ -0,0 +1,45 @@ +<%@ page import="ru.javawebinar.topjava.util.TimeUtil" %> +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> + + + Codestin Search App + + + +
+

Home

+

Meal list

+
+ + + + + + + + + + + + + + + + +
DateDescriptionCalories
+ ${meal.dateTime.toLocalDate()} ${meal.dateTime.toLocalTime()} + <%--<%=TimeUtil.toString(meal.getDateTime())%>--%> + ${meal.description}${meal.calories}
+
+ + \ No newline at end of file diff --git a/src/main/webapp/userList.jsp b/src/main/webapp/userList.jsp index c6b12052a263..eae4726d4400 100644 --- a/src/main/webapp/userList.jsp +++ b/src/main/webapp/userList.jsp @@ -4,6 +4,7 @@ Codestin Search App -

User list

+

Home

+

User list

From 9cb684cea16260edcb38405c79c655172548d58a Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 10 Mar 2016 11:11:51 +0300 Subject: [PATCH 13/32] Applied: 2-2-HW1-optional.patch --- .../javawebinar/topjava/model/UserMeal.java | 35 ++++++++++-- .../topjava/model/UserMealWithExceed.java | 14 ++++- .../InMemoryUserMealRepositoryImpl.java | 47 ++++++++++++++++ .../repository/UserMealRepository.java | 19 +++++++ .../topjava/util/UserMealsUtil.java | 8 +-- .../javawebinar/topjava/web/MealServlet.java | 53 +++++++++++++++++-- src/main/webapp/mealEdit.jsp | 51 ++++++++++++++++++ src/main/webapp/mealList.jsp | 7 +++ 8 files changed, 223 insertions(+), 11 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/repository/InMemoryUserMealRepositoryImpl.java create mode 100644 src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java create mode 100644 src/main/webapp/mealEdit.jsp diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java index fde5448b93d8..fc43ba8b8b32 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java @@ -7,18 +7,29 @@ * 11.01.2015. */ public class UserMeal { - protected final LocalDateTime dateTime; + private Integer id; - protected final String description; + private final LocalDateTime dateTime; - protected final int calories; + private final String description; + + private final int calories; public UserMeal(LocalDateTime dateTime, String description, int calories) { + this(null, dateTime, description, calories); + } + + public UserMeal(Integer id, LocalDateTime dateTime, String description, int calories) { + this.id = id; this.dateTime = dateTime; this.description = description; this.calories = calories; } + public void setId(int id) { + this.id = id; + } + public LocalDateTime getDateTime() { return dateTime; } @@ -30,4 +41,22 @@ public String getDescription() { public int getCalories() { return calories; } + + public Integer getId() { + return id; + } + + public boolean isNew() { + return id == null; + } + + @Override + public String toString() { + return "UserMeal{" + + "id=" + id + + ", dateTime=" + dateTime + + ", description='" + description + '\'' + + ", calories=" + calories + + '}'; + } } diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java index 935b943afeb6..4f1fe2f6ae0f 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java @@ -7,6 +7,8 @@ * 11.01.2015. */ public class UserMealWithExceed { + protected final Integer id; + private final LocalDateTime dateTime; private final String description; @@ -16,12 +18,21 @@ public class UserMealWithExceed { private final boolean exceed; public UserMealWithExceed(LocalDateTime dateTime, String description, int calories, boolean exceed) { + this(null, dateTime, description, calories, exceed); + } + + public UserMealWithExceed(Integer id, LocalDateTime dateTime, String description, int calories, boolean exceed) { + this.id = id; this.dateTime = dateTime; this.description = description; this.calories = calories; this.exceed = exceed; } + public Integer getId() { + return id; + } + public LocalDateTime getDateTime() { return dateTime; } @@ -41,7 +52,8 @@ public boolean isExceed() { @Override public String toString() { return "UserMealWithExceed{" + - "dateTime=" + dateTime + + "id=" + id + + ", dateTime=" + dateTime + ", description='" + description + '\'' + ", calories=" + calories + ", exceed=" + exceed + diff --git a/src/main/java/ru/javawebinar/topjava/repository/InMemoryUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/InMemoryUserMealRepositoryImpl.java new file mode 100644 index 000000000000..4da0792bb19d --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/InMemoryUserMealRepositoryImpl.java @@ -0,0 +1,47 @@ +package ru.javawebinar.topjava.repository; + +import ru.javawebinar.topjava.model.UserMeal; +import ru.javawebinar.topjava.util.UserMealsUtil; + +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * GKislin + * 15.09.2015. + */ +public class InMemoryUserMealRepositoryImpl implements UserMealRepository { + private Map repository = new ConcurrentHashMap<>(); + private AtomicInteger counter = new AtomicInteger(0); + + { + UserMealsUtil.MEAL_LIST.forEach(this::save); + } + + @Override + public UserMeal save(UserMeal userMeal) { + if (userMeal.isNew()) { + userMeal.setId(counter.incrementAndGet()); + } + repository.put(userMeal.getId(), userMeal); + return userMeal; + } + + @Override + public void delete(int id) { + repository.remove(id); + } + + @Override + public UserMeal get(int id) { + return repository.get(id); + } + + @Override + public Collection getAll() { + return repository.values(); + } +} + diff --git a/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java new file mode 100644 index 000000000000..ad656ea6cd19 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java @@ -0,0 +1,19 @@ +package ru.javawebinar.topjava.repository; + +import ru.javawebinar.topjava.model.UserMeal; + +import java.util.Collection; + +/** + * GKislin + * 06.03.2015. + */ +public interface UserMealRepository { + UserMeal save(UserMeal userMeal); + + void delete(int id); + + UserMeal get(int id); + + Collection getAll(); +} diff --git a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java index 6ea1f206d9e7..6f22256c7807 100644 --- a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java @@ -33,11 +33,11 @@ public static void main(String[] args) { System.out.println(getFilteredWithExceededByCycle(MEAL_LIST, LocalTime.of(7, 0), LocalTime.of(12, 0), DEFAULT_CALORIES_PER_DAY)); } - public static List getWithExceeded(List mealList, int caloriesPerDay) { + public static List getWithExceeded(Collection mealList, int caloriesPerDay) { return getFilteredWithExceeded(mealList, LocalTime.MIN, LocalTime.MAX, caloriesPerDay); } - public static List getFilteredWithExceeded(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + public static List getFilteredWithExceeded(Collection mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { Map caloriesSumByDate = mealList.stream() .collect( Collectors.groupingBy(um -> um.getDateTime().toLocalDate(), @@ -66,6 +66,6 @@ public static List getFilteredWithExceededByCycle(List +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + Codestin Search App + + + +
+

Home

+

Edit meal

+
+ +
+ +
+
DateTime:
+
+
+
+
Description:
+
+
+
+
Calories:
+
+
+ + +
+
+ + diff --git a/src/main/webapp/mealList.jsp b/src/main/webapp/mealList.jsp index 1d1f66d87f7f..e0e1d234f6bc 100644 --- a/src/main/webapp/mealList.jsp +++ b/src/main/webapp/mealList.jsp @@ -1,3 +1,5 @@ + ${meal.dateTime.toLocalDate()} ${meal.dateTime.toLocalTime()} + <%--<%=TimeUtil.toString(meal.getDateTime())%>--%> <%@ page import="ru.javawebinar.topjava.util.TimeUtil" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> @@ -19,6 +21,7 @@

Home

Meal list

+ Add Meal
@@ -26,6 +29,8 @@ + + @@ -37,6 +42,8 @@ + +
Date Description Calories
${meal.description} ${meal.calories}UpdateDelete
From 6df3291f8f148120181130b7a12dcefd10104892 Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 10 Mar 2016 11:27:04 +0300 Subject: [PATCH 14/32] Applied: 2-3-app-layers.patch --- .../ru/javawebinar/topjava/LoggedUser.java | 18 ++++ .../javawebinar/topjava/model/BaseEntity.java | 28 ++++++ .../topjava/model/NamedEntity.java | 31 ++++++ .../ru/javawebinar/topjava/model/Role.java | 10 ++ .../ru/javawebinar/topjava/model/User.java | 98 +++++++++++++++++++ .../topjava/repository/UserRepository.java | 24 +++++ .../topjava/service/UserMealService.java | 8 ++ .../topjava/service/UserMealServiceImpl.java | 13 +++ .../topjava/service/UserService.java | 26 +++++ .../topjava/service/UserServiceImpl.java | 41 ++++++++ .../topjava/util/exception/ExceptionUtil.java | 25 +++++ .../util/exception/NotFoundException.java | 11 +++ .../web/meal/UserMealRestController.java | 12 +++ .../web/user/AbstractUserController.java | 49 ++++++++++ .../topjava/web/user/AdminRestController.java | 36 +++++++ .../web/user/ProfileRestController.java | 23 +++++ 16 files changed, 453 insertions(+) create mode 100644 src/main/java/ru/javawebinar/topjava/LoggedUser.java create mode 100644 src/main/java/ru/javawebinar/topjava/model/BaseEntity.java create mode 100644 src/main/java/ru/javawebinar/topjava/model/NamedEntity.java create mode 100644 src/main/java/ru/javawebinar/topjava/model/Role.java create mode 100644 src/main/java/ru/javawebinar/topjava/model/User.java create mode 100644 src/main/java/ru/javawebinar/topjava/repository/UserRepository.java create mode 100644 src/main/java/ru/javawebinar/topjava/service/UserMealService.java create mode 100644 src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java create mode 100644 src/main/java/ru/javawebinar/topjava/service/UserService.java create mode 100644 src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java create mode 100644 src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java create mode 100644 src/main/java/ru/javawebinar/topjava/util/exception/NotFoundException.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java diff --git a/src/main/java/ru/javawebinar/topjava/LoggedUser.java b/src/main/java/ru/javawebinar/topjava/LoggedUser.java new file mode 100644 index 000000000000..eb68d99a0d6e --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/LoggedUser.java @@ -0,0 +1,18 @@ +package ru.javawebinar.topjava; + +import ru.javawebinar.topjava.util.UserMealsUtil; + +/** + * GKislin + * 06.03.2015. + */ +public class LoggedUser { + + public static int id() { + return 1; + } + + public static int getCaloriesPerDay() { + return UserMealsUtil.DEFAULT_CALORIES_PER_DAY; + } +} diff --git a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java new file mode 100644 index 000000000000..60f4b46f1d8e --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java @@ -0,0 +1,28 @@ +package ru.javawebinar.topjava.model; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +public class BaseEntity { + protected Integer id; + + public BaseEntity() { + } + + protected BaseEntity(Integer id) { + this.id = id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public boolean isNew() { + return (this.id == null); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/model/NamedEntity.java b/src/main/java/ru/javawebinar/topjava/model/NamedEntity.java new file mode 100644 index 000000000000..ca92e394dc98 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/model/NamedEntity.java @@ -0,0 +1,31 @@ +package ru.javawebinar.topjava.model; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +public class NamedEntity extends BaseEntity { + + protected String name; + + public NamedEntity() { + } + + protected NamedEntity(Integer id, String name) { + super(id); + this.name = name; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/src/main/java/ru/javawebinar/topjava/model/Role.java b/src/main/java/ru/javawebinar/topjava/model/Role.java new file mode 100644 index 000000000000..f0de2b4c4a81 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/model/Role.java @@ -0,0 +1,10 @@ +package ru.javawebinar.topjava.model; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +public enum Role { + ROLE_USER, + ROLE_ADMIN +} diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java new file mode 100644 index 000000000000..34b5977a5917 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -0,0 +1,98 @@ +package ru.javawebinar.topjava.model; + +import ru.javawebinar.topjava.util.UserMealsUtil; + +import java.util.Date; +import java.util.EnumSet; +import java.util.Set; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +public class User extends NamedEntity { + + protected String email; + + protected String password; + + protected boolean enabled = true; + + protected Date registered = new Date(); + + protected Set roles; + + protected int caloriesPerDay = UserMealsUtil.DEFAULT_CALORIES_PER_DAY; + + public User() { + } + + public User(Integer id, String name, String email, String password, Role role, Role... roles) { + this(id, name, email, password, UserMealsUtil.DEFAULT_CALORIES_PER_DAY, true, EnumSet.of(role, roles)); + } + + public User(Integer id, String name, String email, String password, int caloriesPerDay, boolean enabled, Set roles) { + super(id, name); + this.email = email; + this.password = password; + this.caloriesPerDay = caloriesPerDay; + this.enabled = enabled; + this.roles = roles; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public void setPassword(String password) { + this.password = password; + } + + public Date getRegistered() { + return registered; + } + + public void setRegistered(Date registered) { + this.registered = registered; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public int getCaloriesPerDay() { + return caloriesPerDay; + } + + public void setCaloriesPerDay(int caloriesPerDay) { + this.caloriesPerDay = caloriesPerDay; + } + + public boolean isEnabled() { + return enabled; + } + + public Set getRoles() { + return roles; + } + + public String getPassword() { + return password; + } + + @Override + public String toString() { + return "User (" + + "id=" + id + + ", email=" + email + + ", name=" + name + + ", enabled=" + enabled + + ", roles=" + roles + + ", caloriesPerDay=" + caloriesPerDay + + ')'; + } +} diff --git a/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java new file mode 100644 index 000000000000..24c1c45beca6 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java @@ -0,0 +1,24 @@ +package ru.javawebinar.topjava.repository; + +import ru.javawebinar.topjava.model.User; + +import java.util.List; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +public interface UserRepository { + User save(User user); + + // false if not found + boolean delete(int id); + + // null if not found + User get(int id); + + // null if not found + User getByEmail(String email); + + List getAll(); +} diff --git a/src/main/java/ru/javawebinar/topjava/service/UserMealService.java b/src/main/java/ru/javawebinar/topjava/service/UserMealService.java new file mode 100644 index 000000000000..b17fec811065 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/service/UserMealService.java @@ -0,0 +1,8 @@ +package ru.javawebinar.topjava.service; + +/** + * GKislin + * 15.06.2015. + */ +public interface UserMealService { +} diff --git a/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java new file mode 100644 index 000000000000..5730b8bfb130 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java @@ -0,0 +1,13 @@ +package ru.javawebinar.topjava.service; + +import ru.javawebinar.topjava.repository.UserMealRepository; + +/** + * GKislin + * 06.03.2015. + */ +public class UserMealServiceImpl implements UserMealService { + + private UserMealRepository repository; + +} diff --git a/src/main/java/ru/javawebinar/topjava/service/UserService.java b/src/main/java/ru/javawebinar/topjava/service/UserService.java new file mode 100644 index 000000000000..85c15e48f951 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/service/UserService.java @@ -0,0 +1,26 @@ +package ru.javawebinar.topjava.service; + + +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.util.exception.NotFoundException; + +import java.util.List; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +public interface UserService { + + User save(User user); + + void delete(int id) throws NotFoundException; + + User get(int id) throws NotFoundException; + + User getByEmail(String email) throws NotFoundException; + + List getAll(); + + void update(User user); +} diff --git a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java new file mode 100644 index 000000000000..27a4b171c406 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java @@ -0,0 +1,41 @@ +package ru.javawebinar.topjava.service; + +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.repository.UserRepository; +import ru.javawebinar.topjava.util.exception.ExceptionUtil; +import ru.javawebinar.topjava.util.exception.NotFoundException; + +import java.util.List; + +/** + * GKislin + * 06.03.2015. + */ +public class UserServiceImpl implements UserService { + + private UserRepository repository; + + public User save(User user) { + return repository.save(user); + } + + public void delete(int id) { + ExceptionUtil.check(repository.delete(id), id); + } + + public User get(int id) throws NotFoundException { + return ExceptionUtil.check(repository.get(id), id); + } + + public User getByEmail(String email) throws NotFoundException { + return ExceptionUtil.check(repository.getByEmail(email), "email=" + email); + } + + public List getAll() { + return repository.getAll(); + } + + public void update(User user) { + repository.save(user); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java b/src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java new file mode 100644 index 000000000000..de97182f9d87 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java @@ -0,0 +1,25 @@ +package ru.javawebinar.topjava.util.exception; + + +/** + * User: gkislin + * Date: 14.05.2014 + */ +public class ExceptionUtil { + public static void check(boolean found, int id) { + check(found, "id=" + id); + } + + public static T check(T object, int id) { + return check(object, "id=" + id); + } + + public static T check(T object, String msg) { + check(object != null, msg); + return object; + } + + public static void check(boolean found, String msg) { + if (!found) throw new NotFoundException("Not found entity with " + msg); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/util/exception/NotFoundException.java b/src/main/java/ru/javawebinar/topjava/util/exception/NotFoundException.java new file mode 100644 index 000000000000..7a770f0db834 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/util/exception/NotFoundException.java @@ -0,0 +1,11 @@ +package ru.javawebinar.topjava.util.exception; + +/** + * User: gkislin + * Date: 19.08.2014 + */ +public class NotFoundException extends RuntimeException { + public NotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java b/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java new file mode 100644 index 000000000000..b3c1008f1d00 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java @@ -0,0 +1,12 @@ +package ru.javawebinar.topjava.web.meal; + +import ru.javawebinar.topjava.service.UserMealService; + +/** + * GKislin + * 06.03.2015. + */ +public class UserMealRestController { + private UserMealService service; + +} diff --git a/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java b/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java new file mode 100644 index 000000000000..aac911f5864d --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java @@ -0,0 +1,49 @@ +package ru.javawebinar.topjava.web.user; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.service.UserService; + +import java.util.List; + +/** + * User: gkislin + */ +public abstract class AbstractUserController { + protected final Logger LOG = LoggerFactory.getLogger(getClass()); + + private UserService service; + + public List getAll() { + LOG.info("getAll"); + return service.getAll(); + } + + public User get(int id) { + LOG.info("get " + id); + return service.get(id); + } + + public User create(User user) { + user.setId(null); + LOG.info("create " + user); + return service.save(user); + } + + public void delete(int id) { + LOG.info("delete " + id); + service.delete(id); + } + + public void update(User user, int id) { + user.setId(id); + LOG.info("update " + user); + service.update(user); + } + + public User getByMail(String email) { + LOG.info("getByEmail " + email); + return service.getByEmail(email); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java b/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java new file mode 100644 index 000000000000..cdd1e6bf11f8 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java @@ -0,0 +1,36 @@ +package ru.javawebinar.topjava.web.user; + +import ru.javawebinar.topjava.model.User; + +import java.util.List; + +/** + * GKislin + * 06.03.2015. + */ +public class AdminRestController extends AbstractUserController { + + public List getAll() { + return super.getAll(); + } + + public User get(int id) { + return super.get(id); + } + + public User create(User user) { + return super.create(user); + } + + public void delete(int id) { + super.delete(id); + } + + public void update(User user, int id) { + super.update(user, id); + } + + public User getByMail(String email) { + return super.getByMail(email); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java new file mode 100644 index 000000000000..6f0c970152af --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java @@ -0,0 +1,23 @@ +package ru.javawebinar.topjava.web.user; + +import ru.javawebinar.topjava.LoggedUser; +import ru.javawebinar.topjava.model.User; + +/** + * GKislin + * 06.03.2015. + */ +public class ProfileRestController extends AbstractUserController { + + public User get() { + return super.get(LoggedUser.id()); + } + + public void delete() { + super.delete(LoggedUser.id()); + } + + public void update(User user) { + super.update(user, LoggedUser.id()); + } +} \ No newline at end of file From 104a0566b206f3a3737b33df89183c550f06a797 Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 10 Mar 2016 12:03:14 +0300 Subject: [PATCH 15/32] Applied: 2-4-add-spring-context.patch --- pom.xml | 14 ++++++ .../ru/javawebinar/topjava/SpringMain.java | 23 +++++++++ .../InMemoryUserMealRepositoryImpl.java | 3 +- .../mock/MockUserRepositoryImpl.java | 47 +++++++++++++++++++ .../javawebinar/topjava/web/MealServlet.java | 2 +- src/main/resources/spring/spring-app.xml | 8 ++++ 6 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/SpringMain.java rename src/main/java/ru/javawebinar/topjava/repository/{ => mock}/InMemoryUserMealRepositoryImpl.java (90%) create mode 100644 src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java create mode 100644 src/main/resources/spring/spring-app.xml diff --git a/pom.xml b/pom.xml index af41b1894a11..ec49eea1e524 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,8 @@ UTF-8 UTF-8 + 4.2.5.RELEASE + 1.1.6 1.7.18 @@ -67,6 +69,18 @@ runtime + + + org.springframework + spring-context + ${spring.version} + + + commons-logging + commons-logging + + + javax.servlet jstl diff --git a/src/main/java/ru/javawebinar/topjava/SpringMain.java b/src/main/java/ru/javawebinar/topjava/SpringMain.java new file mode 100644 index 000000000000..6699bb27ca33 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/SpringMain.java @@ -0,0 +1,23 @@ +package ru.javawebinar.topjava; + +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import ru.javawebinar.topjava.repository.UserRepository; + +import java.util.Arrays; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +public class SpringMain { + public static void main(String[] args) { + ConfigurableApplicationContext appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml"); + System.out.println(Arrays.toString(appCtx.getBeanDefinitionNames())); + +// UserRepository userRepository = (UserRepository) appCtx.getBean("mockUserRepository"); + UserRepository userRepository = appCtx.getBean(UserRepository.class); + userRepository.getAll(); + appCtx.close(); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/repository/InMemoryUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java similarity index 90% rename from src/main/java/ru/javawebinar/topjava/repository/InMemoryUserMealRepositoryImpl.java rename to src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java index 4da0792bb19d..ab4e99c5993c 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/InMemoryUserMealRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java @@ -1,6 +1,7 @@ -package ru.javawebinar.topjava.repository; +package ru.javawebinar.topjava.repository.mock; import ru.javawebinar.topjava.model.UserMeal; +import ru.javawebinar.topjava.repository.UserMealRepository; import ru.javawebinar.topjava.util.UserMealsUtil; import java.util.Collection; diff --git a/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java new file mode 100644 index 000000000000..8a014233b855 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java @@ -0,0 +1,47 @@ +package ru.javawebinar.topjava.repository.mock; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.repository.UserRepository; + +import java.util.Collections; +import java.util.List; + +/** + * GKislin + * 15.06.2015. + */ +public class MockUserRepositoryImpl implements UserRepository { + private static final Logger LOG = LoggerFactory.getLogger(MockUserRepositoryImpl.class); + + @Override + public boolean delete(int id) { + LOG.info("delete " + id); + return true; + } + + @Override + public User save(User user) { + LOG.info("save " + user); + return user; + } + + @Override + public User get(int id) { + LOG.info("get " + id); + return null; + } + + @Override + public List getAll() { + LOG.info("getAll"); + return Collections.emptyList(); + } + + @Override + public User getByEmail(String email) { + LOG.info("getByEmail " + email); + return null; + } +} diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java index 614c2a6d44bd..d66f4c4301df 100644 --- a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -3,7 +3,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ru.javawebinar.topjava.model.UserMeal; -import ru.javawebinar.topjava.repository.InMemoryUserMealRepositoryImpl; +import ru.javawebinar.topjava.repository.mock.InMemoryUserMealRepositoryImpl; import ru.javawebinar.topjava.repository.UserMealRepository; import ru.javawebinar.topjava.util.UserMealsUtil; diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml new file mode 100644 index 000000000000..19632d5645ac --- /dev/null +++ b/src/main/resources/spring/spring-app.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file From e523980bbac35a69c2d74c25c72f938e26d98c42 Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 10 Mar 2016 12:06:18 +0300 Subject: [PATCH 16/32] Applied: 2-5-add-dependency-injection.patch --- src/main/java/ru/javawebinar/topjava/SpringMain.java | 7 +++++++ .../ru/javawebinar/topjava/service/UserServiceImpl.java | 4 ++++ src/main/resources/spring/spring-app.xml | 6 ++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/SpringMain.java b/src/main/java/ru/javawebinar/topjava/SpringMain.java index 6699bb27ca33..fcf9372812b9 100644 --- a/src/main/java/ru/javawebinar/topjava/SpringMain.java +++ b/src/main/java/ru/javawebinar/topjava/SpringMain.java @@ -2,7 +2,10 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; +import ru.javawebinar.topjava.model.Role; +import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.repository.UserRepository; +import ru.javawebinar.topjava.service.UserService; import java.util.Arrays; @@ -18,6 +21,10 @@ public static void main(String[] args) { // UserRepository userRepository = (UserRepository) appCtx.getBean("mockUserRepository"); UserRepository userRepository = appCtx.getBean(UserRepository.class); userRepository.getAll(); + + UserService userService = appCtx.getBean(UserService.class); + System.out.println(userService.save(new User(1, "userName", "email", "password", Role.ROLE_ADMIN))); + appCtx.close(); } } diff --git a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java index 27a4b171c406..066ae95037be 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java @@ -15,6 +15,10 @@ public class UserServiceImpl implements UserService { private UserRepository repository; + public void setRepository(UserRepository repository) { + this.repository = repository; + } + public User save(User user) { return repository.save(user); } diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml index 19632d5645ac..7b4fa1689425 100644 --- a/src/main/resources/spring/spring-app.xml +++ b/src/main/resources/spring/spring-app.xml @@ -1,8 +1,10 @@ + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> + + + \ No newline at end of file From 72e0681857ade20e1273ddb8a592d49482330935 Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 10 Mar 2016 12:16:58 +0300 Subject: [PATCH 17/32] Applied: 2-6-add-annotation-processing.patch --- .../ru/javawebinar/topjava/SpringMain.java | 20 ++++++---------- .../mock/MockUserRepositoryImpl.java | 2 ++ .../topjava/service/UserServiceImpl.java | 8 +++---- .../web/user/AbstractUserController.java | 2 ++ .../topjava/web/user/AdminRestController.java | 2 ++ .../web/user/ProfileRestController.java | 2 ++ src/main/resources/spring/spring-app.xml | 23 +++++++++++++++---- 7 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/SpringMain.java b/src/main/java/ru/javawebinar/topjava/SpringMain.java index fcf9372812b9..9b14ec645a08 100644 --- a/src/main/java/ru/javawebinar/topjava/SpringMain.java +++ b/src/main/java/ru/javawebinar/topjava/SpringMain.java @@ -4,8 +4,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; import ru.javawebinar.topjava.model.Role; import ru.javawebinar.topjava.model.User; -import ru.javawebinar.topjava.repository.UserRepository; -import ru.javawebinar.topjava.service.UserService; +import ru.javawebinar.topjava.web.user.AdminRestController; import java.util.Arrays; @@ -15,16 +14,11 @@ */ public class SpringMain { public static void main(String[] args) { - ConfigurableApplicationContext appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml"); - System.out.println(Arrays.toString(appCtx.getBeanDefinitionNames())); - -// UserRepository userRepository = (UserRepository) appCtx.getBean("mockUserRepository"); - UserRepository userRepository = appCtx.getBean(UserRepository.class); - userRepository.getAll(); - - UserService userService = appCtx.getBean(UserService.class); - System.out.println(userService.save(new User(1, "userName", "email", "password", Role.ROLE_ADMIN))); - - appCtx.close(); + // java 7 Automatic resource management + try (ConfigurableApplicationContext appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml")) { + System.out.println(Arrays.toString(appCtx.getBeanDefinitionNames())); + AdminRestController adminUserController = appCtx.getBean(AdminRestController.class); + System.out.println(adminUserController.create(new User(1, "userName", "email", "password", Role.ROLE_ADMIN))); + } } } diff --git a/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java index 8a014233b855..6231e4c74521 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java @@ -1,5 +1,6 @@ package ru.javawebinar.topjava.repository.mock; +import org.springframework.stereotype.Repository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ru.javawebinar.topjava.model.User; @@ -12,6 +13,7 @@ * GKislin * 15.06.2015. */ +@Repository public class MockUserRepositoryImpl implements UserRepository { private static final Logger LOG = LoggerFactory.getLogger(MockUserRepositoryImpl.class); diff --git a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java index 066ae95037be..f83d039b7fbc 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java @@ -1,5 +1,7 @@ package ru.javawebinar.topjava.service; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.repository.UserRepository; import ru.javawebinar.topjava.util.exception.ExceptionUtil; @@ -11,14 +13,12 @@ * GKislin * 06.03.2015. */ +@Service public class UserServiceImpl implements UserService { + @Autowired private UserRepository repository; - public void setRepository(UserRepository repository) { - this.repository = repository; - } - public User save(User user) { return repository.save(user); } diff --git a/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java b/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java index aac911f5864d..e2b847678af2 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java @@ -1,5 +1,6 @@ package ru.javawebinar.topjava.web.user; +import org.springframework.beans.factory.annotation.Autowired; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ru.javawebinar.topjava.model.User; @@ -13,6 +14,7 @@ public abstract class AbstractUserController { protected final Logger LOG = LoggerFactory.getLogger(getClass()); + @Autowired private UserService service; public List getAll() { diff --git a/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java b/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java index cdd1e6bf11f8..d6b8bb420803 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java @@ -1,5 +1,6 @@ package ru.javawebinar.topjava.web.user; +import org.springframework.stereotype.Controller; import ru.javawebinar.topjava.model.User; import java.util.List; @@ -8,6 +9,7 @@ * GKislin * 06.03.2015. */ +@Controller public class AdminRestController extends AbstractUserController { public List getAll() { diff --git a/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java index 6f0c970152af..1114e57eeb1e 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java @@ -1,5 +1,6 @@ package ru.javawebinar.topjava.web.user; +import org.springframework.stereotype.Controller; import ru.javawebinar.topjava.LoggedUser; import ru.javawebinar.topjava.model.User; @@ -7,6 +8,7 @@ * GKislin * 06.03.2015. */ +@Controller public class ProfileRestController extends AbstractUserController { public User get() { diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml index 7b4fa1689425..96e40e902b66 100644 --- a/src/main/resources/spring/spring-app.xml +++ b/src/main/resources/spring/spring-app.xml @@ -1,10 +1,23 @@ + xmlns:context="http://www.springframework.org/schema/context" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> - + + + + + + + + + - - - \ No newline at end of file From 10c37585a6451937751d5f7c9f6e93947d8773d9 Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 10 Mar 2016 13:36:03 +0300 Subject: [PATCH 18/32] fix: mealList.jsp --- src/main/webapp/mealList.jsp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/webapp/mealList.jsp b/src/main/webapp/mealList.jsp index e0e1d234f6bc..5d6a5dbfc9ef 100644 --- a/src/main/webapp/mealList.jsp +++ b/src/main/webapp/mealList.jsp @@ -1,5 +1,3 @@ - ${meal.dateTime.toLocalDate()} ${meal.dateTime.toLocalTime()} - <%--<%=TimeUtil.toString(meal.getDateTime())%>--%> <%@ page import="ru.javawebinar.topjava.util.TimeUtil" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> From 17d150cc38851903ada6e146ced6a4a474eb869b Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 17 Mar 2016 09:50:53 +0300 Subject: [PATCH 19/32] Applied: 3-01-HW2-repository.patch --- .../repository/UserMealRepository.java | 16 +++-- .../mock/InMemoryUserMealRepositoryImpl.java | 64 +++++++++++++++---- .../mock/InMemoryUserRepositoryImpl.java | 59 +++++++++++++++++ .../mock/MockUserRepositoryImpl.java | 49 -------------- .../ru/javawebinar/topjava/util/TimeUtil.java | 5 +- .../javawebinar/topjava/web/MealServlet.java | 11 ++-- 6 files changed, 129 insertions(+), 75 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java delete mode 100644 src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java diff --git a/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java index ad656ea6cd19..8a7687fb85cb 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java @@ -2,6 +2,7 @@ import ru.javawebinar.topjava.model.UserMeal; +import java.time.LocalDateTime; import java.util.Collection; /** @@ -9,11 +10,18 @@ * 06.03.2015. */ public interface UserMealRepository { - UserMeal save(UserMeal userMeal); + // null if updated meal do not belong to userId + UserMeal save(UserMeal userMeal, int userId); - void delete(int id); + // false if meal do not belong to userId + boolean delete(int id, int userId); - UserMeal get(int id); + // null if meal do not belong to userId + UserMeal get(int id, int userId); - Collection getAll(); + // ORDERED dateTime + Collection getAll(int userId); + + // ORDERED dateTime + Collection getBetween(LocalDateTime startDate, LocalDateTime endDate, int userId); } diff --git a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java index ab4e99c5993c..8e5df520c7b7 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java @@ -1,48 +1,84 @@ package ru.javawebinar.topjava.repository.mock; +import org.springframework.stereotype.Repository; import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.repository.UserMealRepository; +import ru.javawebinar.topjava.util.TimeUtil; import ru.javawebinar.topjava.util.UserMealsUtil; -import java.util.Collection; -import java.util.Map; +import java.time.LocalDateTime; +import java.time.Month; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import static ru.javawebinar.topjava.repository.mock.InMemoryUserRepositoryImpl.ADMIN_ID; +import static ru.javawebinar.topjava.repository.mock.InMemoryUserRepositoryImpl.USER_ID; /** * GKislin * 15.09.2015. */ +@Repository public class InMemoryUserMealRepositoryImpl implements UserMealRepository { - private Map repository = new ConcurrentHashMap<>(); + + public static final Comparator USER_MEAL_COMPARATOR = Comparator.comparing(UserMeal::getDateTime).reversed(); + + // Map userId -> (mealId-> meal) + private Map> repository = new ConcurrentHashMap<>(); private AtomicInteger counter = new AtomicInteger(0); { - UserMealsUtil.MEAL_LIST.forEach(this::save); + UserMealsUtil.MEAL_LIST.forEach(um -> save(um, USER_ID)); + + save(new UserMeal(LocalDateTime.of(2015, Month.JUNE, 1, 14, 0), "Админ ланч", 510), ADMIN_ID); + save(new UserMeal(LocalDateTime.of(2015, Month.JUNE, 1, 21, 0), "Админ ужин", 1500), ADMIN_ID); } @Override - public UserMeal save(UserMeal userMeal) { + public UserMeal save(UserMeal userMeal, int userId) { + Objects.requireNonNull(userMeal); + + Integer mealId = userMeal.getId(); + if (userMeal.isNew()) { - userMeal.setId(counter.incrementAndGet()); + mealId = counter.incrementAndGet(); + userMeal.setId(mealId); + } else if (get(mealId, userId) == null) { + return null; } - repository.put(userMeal.getId(), userMeal); + Map userMeals = repository.computeIfAbsent(userId, ConcurrentHashMap::new); + userMeals.put(mealId, userMeal); return userMeal; } @Override - public void delete(int id) { - repository.remove(id); + public boolean delete(int id, int userId) { + Map userMeals = repository.get(userId); + return userMeals != null && userMeals.remove(id) != null; } @Override - public UserMeal get(int id) { - return repository.get(id); + public UserMeal get(int id, int userId) { + Map userMeals = repository.get(userId); + return userMeals == null ? null : userMeals.get(id); } @Override - public Collection getAll() { - return repository.values(); + public Collection getAll(int userId) { + Map userMeals = repository.get(userId); + return userMeals == null ? + Collections.emptyList() : + userMeals.values().stream().sorted(USER_MEAL_COMPARATOR).collect(Collectors.toList()); } -} + @Override + public Collection getBetween(LocalDateTime startDateTime, LocalDateTime endDateTime, int userId) { + Objects.requireNonNull(startDateTime); + Objects.requireNonNull(endDateTime); + return getAll(userId).stream() + .filter(um -> TimeUtil.isBetween(um.getDateTime(), startDateTime, endDateTime)) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java new file mode 100644 index 000000000000..fe8b12bdc3ff --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java @@ -0,0 +1,59 @@ +package ru.javawebinar.topjava.repository.mock; + +import org.springframework.stereotype.Repository; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.repository.UserRepository; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * GKislin + * 15.06.2015. + */ +@Repository +public class InMemoryUserRepositoryImpl implements UserRepository { + private Map repository = new ConcurrentHashMap<>(); + private AtomicInteger counter = new AtomicInteger(0); + + public static final Comparator USER_COMPARATOR = Comparator.comparing(User::getName); + + public static final int USER_ID = 1; + public static final int ADMIN_ID = 2; + + @Override + public User save(User user) { + Objects.requireNonNull(user); + if (user.isNew()) { + user.setId(counter.incrementAndGet()); + } + repository.put(user.getId(), user); + return user; + } + + @Override + public boolean delete(int id) { + return repository.remove(id) != null; + } + + @Override + public User get(int id) { + return repository.get(id); + } + + @Override + public List getAll() { + return repository.values().stream().sorted(USER_COMPARATOR).collect(Collectors.toList()); + } + + @Override + public User getByEmail(String email) { + Objects.requireNonNull(email); + return repository.values().stream().filter(u -> email.equals(u.getEmail())).findFirst().orElse(null); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java deleted file mode 100644 index 6231e4c74521..000000000000 --- a/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -package ru.javawebinar.topjava.repository.mock; - -import org.springframework.stereotype.Repository; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import ru.javawebinar.topjava.model.User; -import ru.javawebinar.topjava.repository.UserRepository; - -import java.util.Collections; -import java.util.List; - -/** - * GKislin - * 15.06.2015. - */ -@Repository -public class MockUserRepositoryImpl implements UserRepository { - private static final Logger LOG = LoggerFactory.getLogger(MockUserRepositoryImpl.class); - - @Override - public boolean delete(int id) { - LOG.info("delete " + id); - return true; - } - - @Override - public User save(User user) { - LOG.info("save " + user); - return user; - } - - @Override - public User get(int id) { - LOG.info("get " + id); - return null; - } - - @Override - public List getAll() { - LOG.info("getAll"); - return Collections.emptyList(); - } - - @Override - public User getByEmail(String email) { - LOG.info("getByEmail " + email); - return null; - } -} diff --git a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java index 115311fad6b7..74df07dec309 100644 --- a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java @@ -1,7 +1,6 @@ package ru.javawebinar.topjava.util; import java.time.LocalDateTime; -import java.time.LocalTime; import java.time.format.DateTimeFormatter; /** @@ -11,8 +10,8 @@ public class TimeUtil { public static final DateTimeFormatter DATE_TME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); - public static boolean isBetween(LocalTime lt, LocalTime startTime, LocalTime endTime) { - return lt.compareTo(startTime) >= 0 && lt.compareTo(endTime) <= 0; + public static > boolean isBetween(T value, T start, T end) { + return value.compareTo(start) >= 0 && value.compareTo(end) <= 0; } public static String toString(LocalDateTime ldt) { diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java index d66f4c4301df..db61311a371d 100644 --- a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -1,10 +1,11 @@ package ru.javawebinar.topjava.web; +import ru.javawebinar.topjava.LoggedUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ru.javawebinar.topjava.model.UserMeal; -import ru.javawebinar.topjava.repository.mock.InMemoryUserMealRepositoryImpl; import ru.javawebinar.topjava.repository.UserMealRepository; +import ru.javawebinar.topjava.repository.mock.InMemoryUserMealRepositoryImpl; import ru.javawebinar.topjava.util.UserMealsUtil; import javax.servlet.ServletConfig; @@ -39,7 +40,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) request.getParameter("description"), Integer.valueOf(request.getParameter("calories"))); LOG.info(userMeal.isNew() ? "Create {}" : "Update {}", userMeal); - repository.save(userMeal); + repository.save(userMeal, LoggedUser.id()); response.sendRedirect("meals"); } @@ -49,17 +50,17 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t if (action == null) { LOG.info("getAll"); request.setAttribute("mealList", - UserMealsUtil.getWithExceeded(repository.getAll(), UserMealsUtil.DEFAULT_CALORIES_PER_DAY)); + UserMealsUtil.getWithExceeded(repository.getAll(LoggedUser.id()), UserMealsUtil.DEFAULT_CALORIES_PER_DAY)); request.getRequestDispatcher("/mealList.jsp").forward(request, response); } else if (action.equals("delete")) { int id = getId(request); LOG.info("Delete {}", id); - repository.delete(id); + repository.delete(id, LoggedUser.id()); response.sendRedirect("meals"); } else { final UserMeal meal = action.equals("create") ? new UserMeal(LocalDateTime.now(), "", 1000) : - repository.get(getId(request)); + repository.get(getId(request), LoggedUser.id()); request.setAttribute("meal", meal); request.getRequestDispatcher("mealEdit.jsp").forward(request, response); } From 33204359499c2a7ea6b5bcf46669821cee9b60a0 Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 17 Mar 2016 10:22:22 +0300 Subject: [PATCH 20/32] Applied: 3-02-HW2-meal-layers.patch --- .../ru/javawebinar/topjava/SpringMain.java | 14 +++++ .../javawebinar/topjava/model/UserMeal.java | 17 +----- .../topjava/service/UserMealService.java | 23 +++++++ .../topjava/service/UserMealServiceImpl.java | 38 ++++++++++++ .../{model => to}/UserMealWithExceed.java | 2 +- .../ru/javawebinar/topjava/util/TimeUtil.java | 3 + .../topjava/util/UserMealsUtil.java | 2 +- .../web/meal/UserMealRestController.java | 61 ++++++++++++++++++- src/main/webapp/mealList.jsp | 6 +- 9 files changed, 145 insertions(+), 21 deletions(-) rename src/main/java/ru/javawebinar/topjava/{model => to}/UserMealWithExceed.java (97%) diff --git a/src/main/java/ru/javawebinar/topjava/SpringMain.java b/src/main/java/ru/javawebinar/topjava/SpringMain.java index 9b14ec645a08..a50dc23ecee7 100644 --- a/src/main/java/ru/javawebinar/topjava/SpringMain.java +++ b/src/main/java/ru/javawebinar/topjava/SpringMain.java @@ -4,9 +4,15 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; import ru.javawebinar.topjava.model.Role; import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.to.UserMealWithExceed; +import ru.javawebinar.topjava.web.meal.UserMealRestController; import ru.javawebinar.topjava.web.user.AdminRestController; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.Month; import java.util.Arrays; +import java.util.List; /** * User: gkislin @@ -19,6 +25,14 @@ public static void main(String[] args) { System.out.println(Arrays.toString(appCtx.getBeanDefinitionNames())); AdminRestController adminUserController = appCtx.getBean(AdminRestController.class); System.out.println(adminUserController.create(new User(1, "userName", "email", "password", Role.ROLE_ADMIN))); + System.out.println(); + + UserMealRestController mealController = appCtx.getBean(UserMealRestController.class); + List filteredMealsWithExceeded = + mealController.getBetween( + LocalDate.of(2015, Month.MAY, 30), LocalTime.of(7, 0), + LocalDate.of(2015, Month.MAY, 31), LocalTime.of(11, 0)); + filteredMealsWithExceeded.forEach(System.out::println); } } } diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java index fc43ba8b8b32..5fc41074a979 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java @@ -6,8 +6,7 @@ * GKislin * 11.01.2015. */ -public class UserMeal { - private Integer id; +public class UserMeal extends BaseEntity { private final LocalDateTime dateTime; @@ -20,16 +19,12 @@ public UserMeal(LocalDateTime dateTime, String description, int calories) { } public UserMeal(Integer id, LocalDateTime dateTime, String description, int calories) { - this.id = id; + super(id); this.dateTime = dateTime; this.description = description; this.calories = calories; } - public void setId(int id) { - this.id = id; - } - public LocalDateTime getDateTime() { return dateTime; } @@ -42,14 +37,6 @@ public int getCalories() { return calories; } - public Integer getId() { - return id; - } - - public boolean isNew() { - return id == null; - } - @Override public String toString() { return "UserMeal{" + diff --git a/src/main/java/ru/javawebinar/topjava/service/UserMealService.java b/src/main/java/ru/javawebinar/topjava/service/UserMealService.java index b17fec811065..9e4ea6413504 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserMealService.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserMealService.java @@ -1,8 +1,31 @@ package ru.javawebinar.topjava.service; +import ru.javawebinar.topjava.model.UserMeal; +import ru.javawebinar.topjava.util.exception.NotFoundException; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Collection; + /** * GKislin * 15.06.2015. */ public interface UserMealService { + UserMeal get(int id, int userId) throws NotFoundException; + + void delete(int id, int userId) throws NotFoundException; + + default Collection getBetweenDates(LocalDate startDate, LocalDate endDate, int userId) { + return getBetweenDateTimes(LocalDateTime.of(startDate, LocalTime.MIN), LocalDateTime.of(endDate, LocalTime.MAX), userId); + } + + Collection getBetweenDateTimes(LocalDateTime startDateTime, LocalDateTime endDateTime, int userId); + + Collection getAll(int userId); + + UserMeal update(UserMeal meal, int userId) throws NotFoundException; + + UserMeal save(UserMeal meal, int userId); } diff --git a/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java index 5730b8bfb130..fe2aa873de5c 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java @@ -1,13 +1,51 @@ package ru.javawebinar.topjava.service; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.repository.UserMealRepository; +import ru.javawebinar.topjava.util.exception.ExceptionUtil; + +import java.time.LocalDateTime; +import java.util.Collection; /** * GKislin * 06.03.2015. */ +@Service public class UserMealServiceImpl implements UserMealService { + @Autowired private UserMealRepository repository; + @Override + public UserMeal get(int id, int userId) { + return ExceptionUtil.check(repository.get(id, userId), id); + } + + @Override + public void delete(int id, int userId) { + ExceptionUtil.check(repository.delete(id, userId), id); + } + + @Override + public Collection getBetweenDateTimes(LocalDateTime startDateTime, LocalDateTime endDateTime, int userId) { + return repository.getBetween(startDateTime, endDateTime, userId); + } + + @Override + public Collection getAll(int userId) { + return repository.getAll(userId); + } + + @Override + public UserMeal update(UserMeal meal, int userId) { + return ExceptionUtil.check(repository.save(meal, userId), meal.getId()); + } + + @Override + public UserMeal save(UserMeal meal, int userId) { + return repository.save(meal, userId); + } } diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java b/src/main/java/ru/javawebinar/topjava/to/UserMealWithExceed.java similarity index 97% rename from src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java rename to src/main/java/ru/javawebinar/topjava/to/UserMealWithExceed.java index 4f1fe2f6ae0f..3dcc17d30b2f 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java +++ b/src/main/java/ru/javawebinar/topjava/to/UserMealWithExceed.java @@ -1,4 +1,4 @@ -package ru.javawebinar.topjava.model; +package ru.javawebinar.topjava.to; import java.time.LocalDateTime; diff --git a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java index 74df07dec309..0e9b13eab977 100644 --- a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java @@ -1,5 +1,6 @@ package ru.javawebinar.topjava.util; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -9,6 +10,8 @@ */ public class TimeUtil { public static final DateTimeFormatter DATE_TME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + public static final LocalDate MIN_DATE = LocalDate.of(0, 1, 1); + public static final LocalDate MAX_DATE = LocalDate.of(3000, 1, 1); public static > boolean isBetween(T value, T start, T end) { return value.compareTo(start) >= 0 && value.compareTo(end) <= 0; diff --git a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java index 6f22256c7807..dea298e4cf4c 100644 --- a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java @@ -1,7 +1,7 @@ package ru.javawebinar.topjava.util; import ru.javawebinar.topjava.model.UserMeal; -import ru.javawebinar.topjava.model.UserMealWithExceed; +import ru.javawebinar.topjava.to.UserMealWithExceed; import java.time.LocalDate; import java.time.LocalDateTime; diff --git a/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java b/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java index b3c1008f1d00..ac5e90232670 100644 --- a/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java @@ -1,12 +1,71 @@ package ru.javawebinar.topjava.web.meal; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import ru.javawebinar.topjava.LoggedUser; +import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.service.UserMealService; +import ru.javawebinar.topjava.to.UserMealWithExceed; +import ru.javawebinar.topjava.util.TimeUtil; +import ru.javawebinar.topjava.util.UserMealsUtil; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; /** * GKislin * 06.03.2015. */ +@Controller public class UserMealRestController { + private static final Logger LOG = LoggerFactory.getLogger(UserMealRestController.class); + + @Autowired private UserMealService service; -} + public UserMeal get(int id) { + int userId = LoggedUser.id(); + LOG.info("get meal {} for User {}", id, userId); + return service.get(id, userId); + } + + public void delete(int id) { + int userId = LoggedUser.id(); + LOG.info("delete meal {} for User {}", id, userId); + service.delete(id, userId); + } + + public List getAll() { + int userId = LoggedUser.id(); + LOG.info("getAll for User {}", userId); + return UserMealsUtil.getWithExceeded(service.getAll(userId), LoggedUser.getCaloriesPerDay()); + } + + public void update(UserMeal meal, int id) { + meal.setId(id); + int userId = LoggedUser.id(); + LOG.info("update {} for User {}", meal, userId); + service.update(meal, userId); + } + + public UserMeal create(UserMeal meal) { + meal.setId(null); + int userId = LoggedUser.id(); + LOG.info("create {} for User {}", meal, userId); + return service.save(meal, userId); + } + + public List getBetween(LocalDate startDate, LocalTime startTime, LocalDate endDate, LocalTime endTime) { + int userId = LoggedUser.id(); + LOG.info("getBetween dates {} - {} for time {} - {} for User {}", startDate, endDate, startTime, endTime, userId); + + return UserMealsUtil.getFilteredWithExceeded( + service.getBetweenDates( + startDate != null ? startDate : TimeUtil.MIN_DATE, endDate != null ? endDate : TimeUtil.MAX_DATE, userId), + startTime != null ? startTime : LocalTime.MIN, endTime != null ? endTime : LocalTime.MAX, LoggedUser.getCaloriesPerDay() + ); + } +} \ No newline at end of file diff --git a/src/main/webapp/mealList.jsp b/src/main/webapp/mealList.jsp index 5d6a5dbfc9ef..cacd403218e9 100644 --- a/src/main/webapp/mealList.jsp +++ b/src/main/webapp/mealList.jsp @@ -32,11 +32,11 @@ - + - ${meal.dateTime.toLocalDate()} ${meal.dateTime.toLocalTime()} - <%--<%=TimeUtil.toString(meal.getDateTime())%>--%> + <%--${meal.dateTime.toLocalDate()} ${meal.dateTime.toLocalTime()}--%> + <%=TimeUtil.toString(meal.getDateTime())%> ${meal.description} ${meal.calories} From 25469c1ab7481c778de5d763c312b0118e5c5fbd Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 17 Mar 2016 10:25:25 +0300 Subject: [PATCH 21/32] Applied: 3-03-HW2-optional-MealServlet.patch --- .../javawebinar/topjava/web/MealServlet.java | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java index db61311a371d..80cd67d1d781 100644 --- a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -1,12 +1,11 @@ package ru.javawebinar.topjava.web; -import ru.javawebinar.topjava.LoggedUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; import ru.javawebinar.topjava.model.UserMeal; -import ru.javawebinar.topjava.repository.UserMealRepository; -import ru.javawebinar.topjava.repository.mock.InMemoryUserMealRepositoryImpl; -import ru.javawebinar.topjava.util.UserMealsUtil; +import ru.javawebinar.topjava.web.meal.UserMealRestController; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -24,23 +23,37 @@ public class MealServlet extends HttpServlet { private static final Logger LOG = LoggerFactory.getLogger(MealServlet.class); - private UserMealRepository repository; + private ConfigurableApplicationContext springContext; + private UserMealRestController mealController; @Override public void init(ServletConfig config) throws ServletException { super.init(config); - repository = new InMemoryUserMealRepositoryImpl(); + springContext = new ClassPathXmlApplicationContext("spring/spring-app.xml"); + mealController = springContext.getBean(UserMealRestController.class); + } + + @Override + public void destroy() { + springContext.close(); + super.destroy(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException { request.setCharacterEncoding("UTF-8"); - String id = request.getParameter("id"); - UserMeal userMeal = new UserMeal(id.isEmpty() ? null : Integer.valueOf(id), + + final UserMeal userMeal = new UserMeal( LocalDateTime.parse(request.getParameter("dateTime")), request.getParameter("description"), Integer.valueOf(request.getParameter("calories"))); - LOG.info(userMeal.isNew() ? "Create {}" : "Update {}", userMeal); - repository.save(userMeal, LoggedUser.id()); + + if (request.getParameter("id").isEmpty()) { + LOG.info("Create {}", userMeal); + mealController.create(userMeal); + } else { + LOG.info("Update {}", userMeal); + mealController.update(userMeal, getId(request)); + } response.sendRedirect("meals"); } @@ -49,18 +62,17 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t if (action == null) { LOG.info("getAll"); - request.setAttribute("mealList", - UserMealsUtil.getWithExceeded(repository.getAll(LoggedUser.id()), UserMealsUtil.DEFAULT_CALORIES_PER_DAY)); - request.getRequestDispatcher("/mealList.jsp").forward(request, response); + request.setAttribute("mealList", mealController.getAll()); + request.getRequestDispatcher("mealList.jsp").forward(request, response); } else if (action.equals("delete")) { int id = getId(request); LOG.info("Delete {}", id); - repository.delete(id, LoggedUser.id()); + mealController.delete(id); response.sendRedirect("meals"); } else { final UserMeal meal = action.equals("create") ? - new UserMeal(LocalDateTime.now(), "", 1000) : - repository.get(getId(request), LoggedUser.id()); + new UserMeal(LocalDateTime.now(), "", 1000) : // create + mealController.get(getId(request)); // update request.setAttribute("meal", meal); request.getRequestDispatcher("mealEdit.jsp").forward(request, response); } From b8aeccf8006827112f3dd5161faa529fa01345b5 Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 17 Mar 2016 10:31:12 +0300 Subject: [PATCH 22/32] Applied: 3-04-HW2-optional-filter.patch --- .../ru/javawebinar/topjava/util/TimeUtil.java | 11 +++++ .../javawebinar/topjava/web/MealServlet.java | 43 ++++++++++++++----- .../web/meal/UserMealRestController.java | 1 - src/main/webapp/css/style.css | 24 +++++++++++ src/main/webapp/mealEdit.jsp | 19 +------- src/main/webapp/mealList.jsp | 30 +++++++++---- 6 files changed, 89 insertions(+), 39 deletions(-) create mode 100644 src/main/webapp/css/style.css diff --git a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java index 0e9b13eab977..872dbd411e06 100644 --- a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java @@ -1,7 +1,10 @@ package ru.javawebinar.topjava.util; +import org.springframework.util.StringUtils; + import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.format.DateTimeFormatter; /** @@ -20,4 +23,12 @@ public static > boolean isBetween(T value, T sta public static String toString(LocalDateTime ldt) { return ldt == null ? "" : ldt.format(DATE_TME_FORMATTER); } + + public static LocalDate parseLocalDate(String str) { + return StringUtils.isEmpty(str) ? null : LocalDate.parse(str); + } + + public static LocalTime parseLocalTime(String str) { + return StringUtils.isEmpty(str) ? null : LocalTime.parse(str); + } } diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java index 80cd67d1d781..9355c1432ffb 100644 --- a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -5,6 +5,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import ru.javawebinar.topjava.model.UserMeal; +import ru.javawebinar.topjava.util.TimeUtil; import ru.javawebinar.topjava.web.meal.UserMealRestController; import javax.servlet.ServletConfig; @@ -13,7 +14,9 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.util.Objects; /** @@ -41,20 +44,30 @@ public void destroy() { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException { request.setCharacterEncoding("UTF-8"); + String action = request.getParameter("action"); + if (action == null) { + final UserMeal userMeal = new UserMeal( + LocalDateTime.parse(request.getParameter("dateTime")), + request.getParameter("description"), + Integer.valueOf(request.getParameter("calories"))); - final UserMeal userMeal = new UserMeal( - LocalDateTime.parse(request.getParameter("dateTime")), - request.getParameter("description"), - Integer.valueOf(request.getParameter("calories"))); + if (request.getParameter("id").isEmpty()) { + LOG.info("Create {}", userMeal); + mealController.create(userMeal); + } else { + LOG.info("Update {}", userMeal); + mealController.update(userMeal, getId(request)); + } + response.sendRedirect("meals"); - if (request.getParameter("id").isEmpty()) { - LOG.info("Create {}", userMeal); - mealController.create(userMeal); - } else { - LOG.info("Update {}", userMeal); - mealController.update(userMeal, getId(request)); + } else if (action.equals("filter")) { + LocalDate startDate = TimeUtil.parseLocalDate(resetParam("startDate", request)); + LocalDate endDate = TimeUtil.parseLocalDate(resetParam("endDate", request)); + LocalTime startTime = TimeUtil.parseLocalTime(resetParam("startTime", request)); + LocalTime endTime = TimeUtil.parseLocalTime(resetParam("endTime", request)); + request.setAttribute("mealList", mealController.getBetween(startDate, startTime, endDate, endTime)); + request.getRequestDispatcher("/mealList.jsp").forward(request, response); } - response.sendRedirect("meals"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { @@ -78,6 +91,14 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t } } + + private String resetParam(String param, HttpServletRequest request) { + String value = request.getParameter(param); + request.setAttribute(param, value); + return value; + } + + private int getId(HttpServletRequest request) { String paramId = Objects.requireNonNull(request.getParameter("id")); return Integer.valueOf(paramId); diff --git a/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java b/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java index ac5e90232670..305604f46144 100644 --- a/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java @@ -61,7 +61,6 @@ public UserMeal create(UserMeal meal) { public List getBetween(LocalDate startDate, LocalTime startTime, LocalDate endDate, LocalTime endTime) { int userId = LoggedUser.id(); LOG.info("getBetween dates {} - {} for time {} - {} for User {}", startDate, endDate, startTime, endTime, userId); - return UserMealsUtil.getFilteredWithExceeded( service.getBetweenDates( startDate != null ? startDate : TimeUtil.MIN_DATE, endDate != null ? endDate : TimeUtil.MAX_DATE, userId), diff --git a/src/main/webapp/css/style.css b/src/main/webapp/css/style.css new file mode 100644 index 000000000000..0c9fc667371c --- /dev/null +++ b/src/main/webapp/css/style.css @@ -0,0 +1,24 @@ +dl { + background: none repeat scroll 0 0 #FAFAFA; + margin: 8px 0; + padding: 0; +} + +dt { + display: inline-block; + width: 170px; +} + +dd { + display: inline-block; + margin-left: 8px; + vertical-align: top; +} + +.normal { + color: green; +} + +.exceeded { + color: red; +} diff --git a/src/main/webapp/mealEdit.jsp b/src/main/webapp/mealEdit.jsp index 443933549130..d71aeb3a6bbd 100644 --- a/src/main/webapp/mealEdit.jsp +++ b/src/main/webapp/mealEdit.jsp @@ -4,24 +4,7 @@ Codestin Search App - +
diff --git a/src/main/webapp/mealList.jsp b/src/main/webapp/mealList.jsp index cacd403218e9..0f198569b67f 100644 --- a/src/main/webapp/mealList.jsp +++ b/src/main/webapp/mealList.jsp @@ -5,20 +5,32 @@ Codestin Search App - +

Home

Meal list

+
+
+
From Date:
+
+
+
+
To Date:
+
+
+
+
From Time:
+
+
+
+
To Time:
+
+
+ +
+
Add Meal
From 5790b2049aec3112fb2e4d4913e5d18985fdce6c Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 17 Mar 2016 10:34:38 +0300 Subject: [PATCH 23/32] Applied: 3-05-HW2-optional-select-user.patch --- src/main/java/ru/javawebinar/topjava/LoggedUser.java | 7 ++++++- .../java/ru/javawebinar/topjava/web/UserServlet.java | 10 +++++++--- src/main/webapp/index.html | 11 +++++++++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/LoggedUser.java b/src/main/java/ru/javawebinar/topjava/LoggedUser.java index eb68d99a0d6e..115866e29f99 100644 --- a/src/main/java/ru/javawebinar/topjava/LoggedUser.java +++ b/src/main/java/ru/javawebinar/topjava/LoggedUser.java @@ -7,9 +7,14 @@ * 06.03.2015. */ public class LoggedUser { + public static int id = 1; public static int id() { - return 1; + return id; + } + + public static void setId(int id) { + LoggedUser.id = id; } public static int getCaloriesPerDay() { diff --git a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java index 0b6611f24666..543b1e1e5200 100644 --- a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java @@ -1,7 +1,7 @@ package ru.javawebinar.topjava.web; import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import ru.javawebinar.topjava.LoggedUser; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -18,10 +18,14 @@ public class UserServlet extends HttpServlet { private static final Logger LOG = getLogger(UserServlet.class); + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + int userId = Integer.valueOf(request.getParameter("userId")); + LoggedUser.setId(userId); + response.sendRedirect("meals"); + } + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { LOG.debug("redirect to userList"); - -// request.getRequestDispatcher("/userList.jsp").forward(request, response); response.sendRedirect("userList.jsp"); } } diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html index e85ec56ddf0d..b178fa0eeba4 100644 --- a/src/main/webapp/index.html +++ b/src/main/webapp/index.html @@ -7,9 +7,16 @@

Проект "Top Java"


+
+ Login as: + + From b82e61734c22bb3165779fe8767caa1b6c04fec5 Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 17 Mar 2016 10:36:00 +0300 Subject: [PATCH 24/32] Applied: 3-06-bean-life-cycle.patch --- .../mock/InMemoryUserRepositoryImpl.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java index fe8b12bdc3ff..dbbef77704d1 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java @@ -1,9 +1,13 @@ package ru.javawebinar.topjava.repository.mock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Repository; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.repository.UserRepository; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import java.util.Comparator; import java.util.List; import java.util.Map; @@ -18,6 +22,8 @@ */ @Repository public class InMemoryUserRepositoryImpl implements UserRepository { + private static final Logger LOG = LoggerFactory.getLogger(InMemoryUserRepositoryImpl.class); + private Map repository = new ConcurrentHashMap<>(); private AtomicInteger counter = new AtomicInteger(0); @@ -36,6 +42,16 @@ public User save(User user) { return user; } + @PostConstruct + public void postConstruct() { + LOG.info("+++ PostConstruct"); + } + + @PreDestroy + public void preDestroy() { + LOG.info("+++ PreDestroy"); + } + @Override public boolean delete(int id) { return repository.remove(id) != null; From 19b891fd9e9fdd443fc8940c7cddc70760c09fa0 Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 17 Mar 2016 14:10:22 +0300 Subject: [PATCH 25/32] Applied: 3-07-add-junit.patch --- pom.xml | 11 ++++ .../ru/javawebinar/topjava/SpringMain.java | 4 +- .../ru/javawebinar/topjava/UserTestData.java | 16 ++++++ .../mock/InMemoryUserMealRepositoryImpl.java | 4 +- .../mock/InMemoryUserRepositoryImpl.java | 3 - .../web/InMemoryAdminRestControllerTest.java | 55 +++++++++++++++++++ 6 files changed, 85 insertions(+), 8 deletions(-) rename src/{main => test}/java/ru/javawebinar/topjava/SpringMain.java (87%) create mode 100644 src/test/java/ru/javawebinar/topjava/UserTestData.java rename src/{main => test}/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java (94%) rename src/{main => test}/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java (95%) create mode 100644 src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerTest.java diff --git a/pom.xml b/pom.xml index ec49eea1e524..533516297105 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,9 @@ 1.1.6 1.7.18 + + + 4.12 @@ -81,6 +84,14 @@ + + + + junit + junit + ${junit.version} + test + javax.servlet jstl diff --git a/src/main/java/ru/javawebinar/topjava/SpringMain.java b/src/test/java/ru/javawebinar/topjava/SpringMain.java similarity index 87% rename from src/main/java/ru/javawebinar/topjava/SpringMain.java rename to src/test/java/ru/javawebinar/topjava/SpringMain.java index a50dc23ecee7..1e61564819e0 100644 --- a/src/main/java/ru/javawebinar/topjava/SpringMain.java +++ b/src/test/java/ru/javawebinar/topjava/SpringMain.java @@ -2,8 +2,6 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; -import ru.javawebinar.topjava.model.Role; -import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.to.UserMealWithExceed; import ru.javawebinar.topjava.web.meal.UserMealRestController; import ru.javawebinar.topjava.web.user.AdminRestController; @@ -24,7 +22,7 @@ public static void main(String[] args) { try (ConfigurableApplicationContext appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml")) { System.out.println(Arrays.toString(appCtx.getBeanDefinitionNames())); AdminRestController adminUserController = appCtx.getBean(AdminRestController.class); - System.out.println(adminUserController.create(new User(1, "userName", "email", "password", Role.ROLE_ADMIN))); + System.out.println(adminUserController.create(UserTestData.USER)); System.out.println(); UserMealRestController mealController = appCtx.getBean(UserMealRestController.class); diff --git a/src/test/java/ru/javawebinar/topjava/UserTestData.java b/src/test/java/ru/javawebinar/topjava/UserTestData.java new file mode 100644 index 000000000000..bb8a9fb19788 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/UserTestData.java @@ -0,0 +1,16 @@ +package ru.javawebinar.topjava; + +import ru.javawebinar.topjava.model.Role; +import ru.javawebinar.topjava.model.User; + +/** + * GKislin + * 24.09.2015. + */ +public class UserTestData { + public static final int USER_ID = 1; + public static final int ADMIN_ID = 2; + + public static final User USER = new User(USER_ID, "User", "user@yandex.ru", "password", Role.ROLE_USER); + public static final User ADMIN = new User(ADMIN_ID, "Admin", "admin@gmail.com", "admin", Role.ROLE_ADMIN); +} diff --git a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java b/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java similarity index 94% rename from src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java rename to src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java index 8e5df520c7b7..d68c3e3555b7 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java +++ b/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java @@ -13,8 +13,8 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; -import static ru.javawebinar.topjava.repository.mock.InMemoryUserRepositoryImpl.ADMIN_ID; -import static ru.javawebinar.topjava.repository.mock.InMemoryUserRepositoryImpl.USER_ID; +import static ru.javawebinar.topjava.UserTestData.ADMIN_ID; +import static ru.javawebinar.topjava.UserTestData.USER_ID; /** * GKislin diff --git a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java b/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java similarity index 95% rename from src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java rename to src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java index dbbef77704d1..a76cfe226c06 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java +++ b/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java @@ -29,9 +29,6 @@ public class InMemoryUserRepositoryImpl implements UserRepository { public static final Comparator USER_COMPARATOR = Comparator.comparing(User::getName); - public static final int USER_ID = 1; - public static final int ADMIN_ID = 2; - @Override public User save(User user) { Objects.requireNonNull(user); diff --git a/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerTest.java b/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerTest.java new file mode 100644 index 000000000000..fe08ae623eec --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerTest.java @@ -0,0 +1,55 @@ +package ru.javawebinar.topjava.web; + +import org.junit.*; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import ru.javawebinar.topjava.UserTestData; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.repository.UserRepository; +import ru.javawebinar.topjava.util.exception.NotFoundException; +import ru.javawebinar.topjava.web.user.AdminRestController; + +import java.util.Arrays; +import java.util.Collection; + +import static ru.javawebinar.topjava.UserTestData.ADMIN; +import static ru.javawebinar.topjava.UserTestData.USER; + +public class InMemoryAdminRestControllerTest { + private static ConfigurableApplicationContext appCtx; + private static AdminRestController controller; + + @BeforeClass + public static void beforeClass() { + appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml"); + System.out.println("\n" + Arrays.toString(appCtx.getBeanDefinitionNames()) + "\n"); + controller = appCtx.getBean(AdminRestController.class); + } + + @Before + public void setUp() throws Exception { + // Re-initialize + UserRepository repository = appCtx.getBean(UserRepository.class); + repository.getAll().forEach(u -> repository.delete(u.getId())); + repository.save(USER); + repository.save(ADMIN); + } + + @AfterClass + public static void afterClass() { + appCtx.close(); + } + + @Test + public void testDelete() throws Exception { + controller.delete(UserTestData.USER_ID); + Collection users = controller.getAll(); + Assert.assertEquals(users.size(), 1); + Assert.assertEquals(users.iterator().next(), ADMIN); + } + + @Test(expected = NotFoundException.class) + public void testDeleteNotFound() throws Exception { + controller.delete(10); + } +} \ No newline at end of file From cd1d24de54d7b2c598bbcf509fbb3dadbd02695b Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 17 Mar 2016 14:11:20 +0300 Subject: [PATCH 26/32] Applied: 3-08-add-spring-test.patch --- pom.xml | 7 +++ ...InMemoryAdminRestControllerSpringTest.java | 54 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerSpringTest.java diff --git a/pom.xml b/pom.xml index 533516297105..63e4368b02bd 100644 --- a/pom.xml +++ b/pom.xml @@ -104,6 +104,13 @@ 2.5 provided + + org.springframework + spring-test + ${spring.version} + test + + diff --git a/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerSpringTest.java b/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerSpringTest.java new file mode 100644 index 000000000000..9396810afe48 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerSpringTest.java @@ -0,0 +1,54 @@ +package ru.javawebinar.topjava.web; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import ru.javawebinar.topjava.UserTestData; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.repository.UserRepository; +import ru.javawebinar.topjava.util.exception.NotFoundException; +import ru.javawebinar.topjava.web.user.AdminRestController; + +import java.util.Collection; + +import static ru.javawebinar.topjava.UserTestData.ADMIN; +import static ru.javawebinar.topjava.UserTestData.USER; + +/** + * GKislin + * 13.03.2015. + */ +@ContextConfiguration("classpath:spring/spring-app.xml") +@RunWith(SpringJUnit4ClassRunner.class) +public class InMemoryAdminRestControllerSpringTest { + + @Autowired + private AdminRestController controller; + + @Autowired + private UserRepository repository; + + @Before + public void setUp() throws Exception { + repository.getAll().forEach(u -> repository.delete(u.getId())); + repository.save(USER); + repository.save(ADMIN); + } + + @Test + public void testDelete() throws Exception { + controller.delete(UserTestData.USER_ID); + Collection users = controller.getAll(); + Assert.assertEquals(users.size(), 1); + Assert.assertEquals(users.iterator().next(), ADMIN); + } + + @Test(expected = NotFoundException.class) + public void testDeleteNotFound() throws Exception { + controller.delete(10); + } +} From b6ea6ce49aba5da75f1a279684e5c61a5676b3dc Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 17 Mar 2016 14:12:26 +0300 Subject: [PATCH 27/32] Applied: 3-09-add-postgresql.patch --- pom.xml | 9 +++++++++ src/main/resources/db/postgres.properties | 7 +++++++ 2 files changed, 16 insertions(+) create mode 100644 src/main/resources/db/postgres.properties diff --git a/pom.xml b/pom.xml index 63e4368b02bd..07cfa1c089ba 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,8 @@ 1.1.6 1.7.18 + + 9.4.1208 4.12 @@ -85,6 +87,13 @@ + + + org.postgresql + postgresql + ${postgresql.version} + + junit diff --git a/src/main/resources/db/postgres.properties b/src/main/resources/db/postgres.properties new file mode 100644 index 000000000000..44dd64eb26b8 --- /dev/null +++ b/src/main/resources/db/postgres.properties @@ -0,0 +1,7 @@ +#database.url=jdbc:postgresql://ec2-54-217-202-110.eu-west-1.compute.amazonaws.com:5432/dehm6lvm8bink0?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory +#database.username=wegxlfzjjgxaxy +#database.password=SSQyKKE_e93kiUCR-ehzMcKCxZ + +database.url=jdbc:postgresql://localhost:5432/topjava +database.username=user +database.password=password From 9b7f22edee212e777b35870c00a192628ebdb8d3 Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 17 Mar 2016 14:13:14 +0300 Subject: [PATCH 28/32] Applied: 3-10-populate-and-init-db.patch --- src/main/resources/db/initDB.sql | 25 +++++++++++++++++++++++++ src/main/resources/db/populateDB.sql | 13 +++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/main/resources/db/initDB.sql create mode 100644 src/main/resources/db/populateDB.sql diff --git a/src/main/resources/db/initDB.sql b/src/main/resources/db/initDB.sql new file mode 100644 index 000000000000..a0631c79567b --- /dev/null +++ b/src/main/resources/db/initDB.sql @@ -0,0 +1,25 @@ +DROP TABLE IF EXISTS user_roles; +DROP TABLE IF EXISTS users; +DROP SEQUENCE IF EXISTS global_seq; + +CREATE SEQUENCE global_seq START 100000; + +CREATE TABLE users +( + id INTEGER PRIMARY KEY DEFAULT nextval('global_seq'), + name VARCHAR NOT NULL, + email VARCHAR NOT NULL, + password VARCHAR NOT NULL, + registered TIMESTAMP DEFAULT now(), + enabled BOOL DEFAULT TRUE, + calories_per_day INTEGER DEFAULT 2000 NOT NULL +); +CREATE UNIQUE INDEX users_unique_email_idx ON users (email); + +CREATE TABLE user_roles +( + user_id INTEGER NOT NULL, + role VARCHAR, + CONSTRAINT user_roles_idx UNIQUE (user_id, role), + FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE +); diff --git a/src/main/resources/db/populateDB.sql b/src/main/resources/db/populateDB.sql new file mode 100644 index 000000000000..199e2ace615d --- /dev/null +++ b/src/main/resources/db/populateDB.sql @@ -0,0 +1,13 @@ +DELETE FROM user_roles; +DELETE FROM users; +ALTER SEQUENCE global_seq RESTART WITH 100000; + +INSERT INTO users (name, email, password) +VALUES ('User', 'user@yandex.ru', 'password'); + +INSERT INTO users (name, email, password) +VALUES ('Admin', 'admin@gmail.com', 'admin'); + +INSERT INTO user_roles (role, user_id) VALUES + ('ROLE_USER', 100000), + ('ROLE_ADMIN', 100001); From 50121b94a2c5f1c2d76ab4593f48bc770859395a Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Thu, 17 Mar 2016 14:18:05 +0300 Subject: [PATCH 29/32] Applied: 3-11-impl-JdbcUserRepository.patch --- pom.xml | 5 ++ .../jdbc/JdbcUserRepositoryImpl.java | 84 +++++++++++++++++++ src/main/resources/spring/spring-db.xml | 25 ++++++ 3 files changed, 114 insertions(+) create mode 100644 src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepositoryImpl.java create mode 100644 src/main/resources/spring/spring-db.xml diff --git a/pom.xml b/pom.xml index 07cfa1c089ba..47231f550ac1 100644 --- a/pom.xml +++ b/pom.xml @@ -119,6 +119,11 @@ ${spring.version} test + + org.springframework + spring-jdbc + ${spring.version} + diff --git a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepositoryImpl.java new file mode 100644 index 000000000000..5646bad071ed --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepositoryImpl.java @@ -0,0 +1,84 @@ +package ru.javawebinar.topjava.repository.jdbc; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.support.DataAccessUtils; +import org.springframework.jdbc.core.BeanPropertyRowMapper; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.stereotype.Repository; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.repository.UserRepository; + +import javax.sql.DataSource; +import java.util.List; + +/** + * User: gkislin + * Date: 26.08.2014 + */ + +@Repository +public class JdbcUserRepositoryImpl implements UserRepository { + + private static final BeanPropertyRowMapper ROW_MAPPER = BeanPropertyRowMapper.newInstance(User.class); + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Autowired + private NamedParameterJdbcTemplate namedParameterJdbcTemplate; + + private SimpleJdbcInsert insertUser; + + @Autowired + public JdbcUserRepositoryImpl(DataSource dataSource) { + this.insertUser = new SimpleJdbcInsert(dataSource) + .withTableName("USERS") + .usingGeneratedKeyColumns("id"); + } + + @Override + public User save(User user) { + MapSqlParameterSource map = new MapSqlParameterSource() + .addValue("id", user.getId()) + .addValue("name", user.getName()) + .addValue("email", user.getEmail()) + .addValue("password", user.getPassword()) + .addValue("registered", user.getRegistered()) + .addValue("enabled", user.isEnabled()) + .addValue("caloriesPerDay", user.getCaloriesPerDay()); + + if (user.isNew()) { + Number newKey = insertUser.executeAndReturnKey(map); + user.setId(newKey.intValue()); + } else { + namedParameterJdbcTemplate.update( + "UPDATE users SET name=:name, email=:email, password=:password, " + + "registered=:registered, enabled=:enabled, calories_per_day=:caloriesPerDay WHERE id=:id", map); + } + return user; + } + + @Override + public boolean delete(int id) { + return jdbcTemplate.update("DELETE FROM users WHERE id=?", id) != 0; + } + + @Override + public User get(int id) { + List users = jdbcTemplate.query("SELECT * FROM users WHERE id=?", ROW_MAPPER, id); + return DataAccessUtils.singleResult(users); + } + + @Override + public User getByEmail(String email) { + return jdbcTemplate.queryForObject("SELECT * FROM users WHERE email=?", ROW_MAPPER, email); + } + + @Override + public List getAll() { + return jdbcTemplate.query("SELECT * FROM users ORDER BY name, email", ROW_MAPPER); + } +} diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml new file mode 100644 index 000000000000..a1f6b09a7464 --- /dev/null +++ b/src/main/resources/spring/spring-db.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 3a29d600191bed161a800290a5b0209eca007438 Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Fri, 18 Mar 2016 17:38:57 +0300 Subject: [PATCH 30/32] Applied: 3-12-test-UserService.patch --- .../javawebinar/topjava/model/BaseEntity.java | 23 +++++ .../ru/javawebinar/topjava/model/User.java | 4 + .../jdbc/JdbcUserMealRepositoryImpl.java | 42 ++++++++ .../javawebinar/topjava/util/DbPopulator.java | 28 ++++++ src/main/resources/spring/spring-app.xml | 2 +- src/main/resources/spring/spring-db.xml | 4 + .../ru/javawebinar/topjava/MealTestData.java | 14 +++ .../ru/javawebinar/topjava/UserTestData.java | 63 +++++++++++- .../topjava/matcher/ModelMatcher.java | 34 +++++++ .../topjava/service/UserServiceTest.java | 95 +++++++++++++++++++ 10 files changed, 306 insertions(+), 3 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserMealRepositoryImpl.java create mode 100644 src/main/java/ru/javawebinar/topjava/util/DbPopulator.java create mode 100644 src/test/java/ru/javawebinar/topjava/MealTestData.java create mode 100644 src/test/java/ru/javawebinar/topjava/matcher/ModelMatcher.java create mode 100644 src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java diff --git a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java index 60f4b46f1d8e..892beb4c6281 100644 --- a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java +++ b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java @@ -5,6 +5,8 @@ * Date: 22.08.2014 */ public class BaseEntity { + public static final int START_SEQ = 100000; + protected Integer id; public BaseEntity() { @@ -25,4 +27,25 @@ public Integer getId() { public boolean isNew() { return (this.id == null); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + BaseEntity that = (BaseEntity) o; + if (id == null || that.id == null) { + return false; + } + return id.equals(that.id); + } + + @Override + public int hashCode() { + return (id == null) ? 0 : id; + } + } diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index 34b5977a5917..22d746307bf4 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -27,6 +27,10 @@ public class User extends NamedEntity { public User() { } + public User(User u) { + this(u.getId(), u.getName(), u.getEmail(), u.getPassword(), u.getCaloriesPerDay(), u.isEnabled(), u.getRoles()); + } + public User(Integer id, String name, String email, String password, Role role, Role... roles) { this(id, name, email, password, UserMealsUtil.DEFAULT_CALORIES_PER_DAY, true, EnumSet.of(role, roles)); } diff --git a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserMealRepositoryImpl.java new file mode 100644 index 000000000000..77c0ba8f639d --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserMealRepositoryImpl.java @@ -0,0 +1,42 @@ +package ru.javawebinar.topjava.repository.jdbc; + +import org.springframework.stereotype.Repository; +import ru.javawebinar.topjava.model.UserMeal; +import ru.javawebinar.topjava.repository.UserMealRepository; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * User: gkislin + * Date: 26.08.2014 + */ + +@Repository +public class JdbcUserMealRepositoryImpl implements UserMealRepository { + + @Override + public UserMeal save(UserMeal UserMeal, int userId) { + return null; + } + + @Override + public boolean delete(int id, int userId) { + return false; + } + + @Override + public UserMeal get(int id, int userId) { + return null; + } + + @Override + public List getAll(int userId) { + return null; + } + + @Override + public List getBetween(LocalDateTime startDate, LocalDateTime endDate, int userId) { + return null; + } +} diff --git a/src/main/java/ru/javawebinar/topjava/util/DbPopulator.java b/src/main/java/ru/javawebinar/topjava/util/DbPopulator.java new file mode 100644 index 000000000000..8d4a6cc3c719 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/util/DbPopulator.java @@ -0,0 +1,28 @@ +package ru.javawebinar.topjava.util; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.ResourceLoader; +import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; + +import javax.sql.DataSource; + +/** + * User: gkislin + * Date: 26.08.2014 + */ +public class DbPopulator extends ResourceDatabasePopulator { + private static final ResourceLoader RESOURCE_LOADER = new DefaultResourceLoader(); + + @Autowired + private DataSource dataSource; + + public DbPopulator(String scriptLocation) { + super(RESOURCE_LOADER.getResource(scriptLocation)); + } + + public void execute() { + DatabasePopulatorUtils.execute(this, dataSource); + } +} diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml index 96e40e902b66..04810da82e92 100644 --- a/src/main/resources/spring/spring-app.xml +++ b/src/main/resources/spring/spring-app.xml @@ -14,7 +14,7 @@ - + diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index a1f6b09a7464..051f225300cd 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -6,6 +6,10 @@ + + + + diff --git a/src/test/java/ru/javawebinar/topjava/MealTestData.java b/src/test/java/ru/javawebinar/topjava/MealTestData.java new file mode 100644 index 000000000000..ac44047caa52 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/MealTestData.java @@ -0,0 +1,14 @@ +package ru.javawebinar.topjava; + +import ru.javawebinar.topjava.matcher.ModelMatcher; +import ru.javawebinar.topjava.model.UserMeal; + +/** + * GKislin + * 13.03.2015. + */ +public class MealTestData { + + public static final ModelMatcher MATCHER = new ModelMatcher<>(UserMeal::toString); + +} diff --git a/src/test/java/ru/javawebinar/topjava/UserTestData.java b/src/test/java/ru/javawebinar/topjava/UserTestData.java index bb8a9fb19788..c6855207f44e 100644 --- a/src/test/java/ru/javawebinar/topjava/UserTestData.java +++ b/src/test/java/ru/javawebinar/topjava/UserTestData.java @@ -1,16 +1,75 @@ package ru.javawebinar.topjava; +import ru.javawebinar.topjava.matcher.ModelMatcher; import ru.javawebinar.topjava.model.Role; import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.util.UserMealsUtil; + +import java.util.EnumSet; +import java.util.Objects; +import java.util.Set; + +import static ru.javawebinar.topjava.model.BaseEntity.START_SEQ; /** * GKislin * 24.09.2015. */ public class UserTestData { - public static final int USER_ID = 1; - public static final int ADMIN_ID = 2; + public static final int USER_ID = START_SEQ; + public static final int ADMIN_ID = START_SEQ + 1; public static final User USER = new User(USER_ID, "User", "user@yandex.ru", "password", Role.ROLE_USER); public static final User ADMIN = new User(ADMIN_ID, "Admin", "admin@gmail.com", "admin", Role.ROLE_ADMIN); + + public static final ModelMatcher MATCHER = new ModelMatcher<>(u -> ((u instanceof TestUser) ? (TestUser) u : new TestUser(u))); + + public static class TestUser extends User { + + public TestUser(User u) { + this(u.getId(), u.getName(), u.getEmail(), u.getPassword(), u.getCaloriesPerDay(), u.isEnabled(), u.getRoles()); + } + + public TestUser(String name, String email, String password, Role role, Role... roles) { + this(null, name, email, password, UserMealsUtil.DEFAULT_CALORIES_PER_DAY, true, EnumSet.of(role, roles)); + } + + public TestUser(Integer id, String name, String email, String password, int caloriesPerDay, boolean enabled, Set roles) { + super(id, name, email, password, caloriesPerDay, enabled, roles); + } + + public User asUser() { + return new User(this); + } + + @Override + public String toString() { + return "User (" + + "id=" + id + + ", email=" + email + + ", name=" + name + + ", enabled=" + enabled + + ", password=" + password + + ", authorities=" + roles + + ')'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + TestUser that = (TestUser) o; + return Objects.equals(this.password, that.password) + && Objects.equals(this.id, that.id) + && Objects.equals(this.name, that.name) + && Objects.equals(this.email, that.email) + && Objects.equals(this.caloriesPerDay, that.caloriesPerDay) + && Objects.equals(this.enabled, that.enabled); + } + } } diff --git a/src/test/java/ru/javawebinar/topjava/matcher/ModelMatcher.java b/src/test/java/ru/javawebinar/topjava/matcher/ModelMatcher.java new file mode 100644 index 000000000000..f2b18b2e34bd --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/matcher/ModelMatcher.java @@ -0,0 +1,34 @@ +package ru.javawebinar.topjava.matcher; + +import org.junit.Assert; + +import java.util.Collection; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * GKislin + * 06.01.2015. + * + * @param : entity + * @param : testEntity, converter result for compare + */ +public class ModelMatcher { + protected Function entityConverter; + + public ModelMatcher(Function entityConverter) { + this.entityConverter = entityConverter; + } + + public void assertEquals(T expected, T actual) { + Assert.assertEquals(entityConverter.apply(expected), entityConverter.apply(actual)); + } + + public void assertCollectionEquals(Collection expected, Collection actual) { + Assert.assertEquals(map(expected, entityConverter), map(actual, entityConverter)); + } + + public static Collection map(Collection collection, Function converter) { + return collection.stream().map(converter).collect(Collectors.toList()); + } +} diff --git a/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java new file mode 100644 index 000000000000..c9c6eb8fd0f0 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java @@ -0,0 +1,95 @@ +package ru.javawebinar.topjava.service; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import ru.javawebinar.topjava.UserTestData.*; +import ru.javawebinar.topjava.model.Role; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.util.DbPopulator; +import ru.javawebinar.topjava.util.exception.NotFoundException; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +import static ru.javawebinar.topjava.UserTestData.*; + +@ContextConfiguration({ + "classpath:spring/spring-app.xml", + "classpath:spring/spring-db.xml" +}) +@RunWith(SpringJUnit4ClassRunner.class) +public class UserServiceTest { + + @Autowired + protected UserService service; + + @Autowired + private DbPopulator dbPopulator; + + @Before + public void setUp() throws Exception { + dbPopulator.execute(); + } + + @Test + public void testSave() throws Exception { + TestUser tu = new TestUser(null, "New", "new@gmail.com", "newPass", 1555, false, Collections.singleton(Role.ROLE_USER)); + User created = service.save(tu.asUser()); + tu.setId(created.getId()); + MATCHER.assertCollectionEquals(Arrays.asList(ADMIN, tu, USER), service.getAll()); + } + + @Test(expected = DataAccessException.class) + public void testDuplicateMailSave() throws Exception { + service.save(new TestUser("Duplicate", "user@yandex.ru", "newPass", Role.ROLE_USER).asUser()); + } + + @Test + public void testDelete() throws Exception { + service.delete(USER_ID); + MATCHER.assertCollectionEquals(Collections.singletonList(ADMIN), service.getAll()); + } + + @Test(expected = NotFoundException.class) + public void testNotFoundDelete() throws Exception { + service.delete(1); + } + + @Test + public void testGet() throws Exception { + User user = service.get(USER_ID); + MATCHER.assertEquals(USER, user); + } + + @Test(expected = NotFoundException.class) + public void testGetNotFound() throws Exception { + service.get(1); + } + + @Test + public void testGetByEmail() throws Exception { + User user = service.getByEmail("user@yandex.ru"); + MATCHER.assertEquals(USER, user); + } + + @Test + public void testGetAll() throws Exception { + Collection all = service.getAll(); + MATCHER.assertCollectionEquals(Arrays.asList(ADMIN, USER), all); + } + + @Test + public void testUpdate() throws Exception { + TestUser updated = new TestUser(USER); + updated.setName("UpdatedName"); + updated.setCaloriesPerDay(330); + service.update(updated.asUser()); + MATCHER.assertEquals(updated, service.get(USER_ID)); + } +} \ No newline at end of file From a2d4c470429aaa30a61049bfbde02351ae33b77e Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Fri, 18 Mar 2016 17:41:19 +0300 Subject: [PATCH 31/32] Applied: 3-13-test-logging.patch --- src/test/resources/logback-test.xml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/resources/logback-test.xml diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml new file mode 100644 index 000000000000..80c38026d409 --- /dev/null +++ b/src/test/resources/logback-test.xml @@ -0,0 +1,21 @@ + + + + true + + + + + UTF-8 + %-5level %logger{0} - %msg%n + + + + + + + + + + + \ No newline at end of file From 6a0bcf8f8a69d793a44bfb281d0124ad6ce2e01e Mon Sep 17 00:00:00 2001 From: Artem Dvinin Date: Fri, 18 Mar 2016 17:51:05 +0300 Subject: [PATCH 32/32] Applied: 3-14-fix-servlet.patch --- src/main/java/ru/javawebinar/topjava/LoggedUser.java | 4 +++- src/main/java/ru/javawebinar/topjava/web/MealServlet.java | 2 +- src/main/webapp/index.html | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/LoggedUser.java b/src/main/java/ru/javawebinar/topjava/LoggedUser.java index 115866e29f99..813658a2b4c9 100644 --- a/src/main/java/ru/javawebinar/topjava/LoggedUser.java +++ b/src/main/java/ru/javawebinar/topjava/LoggedUser.java @@ -2,12 +2,14 @@ import ru.javawebinar.topjava.util.UserMealsUtil; +import ru.javawebinar.topjava.model.BaseEntity; + /** * GKislin * 06.03.2015. */ public class LoggedUser { - public static int id = 1; + public static int id = BaseEntity.START_SEQ; public static int id() { return id; diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java index 9355c1432ffb..2e9481ddb26d 100644 --- a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -32,7 +32,7 @@ public class MealServlet extends HttpServlet { @Override public void init(ServletConfig config) throws ServletException { super.init(config); - springContext = new ClassPathXmlApplicationContext("spring/spring-app.xml"); + springContext = new ClassPathXmlApplicationContext("spring/spring-app.xml", "spring/spring-db.xml"); mealController = springContext.getBean(UserMealRestController.class); } diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html index b178fa0eeba4..f3c54386a713 100644 --- a/src/main/webapp/index.html +++ b/src/main/webapp/index.html @@ -9,8 +9,8 @@

Проект " Login as: