From d8cd3741df392ca24b7df77f47709118e0f19426 Mon Sep 17 00:00:00 2001 From: Grigory Kislin Date: Sat, 14 May 2016 00:01:16 +0300 Subject: [PATCH 01/76] Add description --- README.md | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ cv.md | 62 +++++++++++++++++++++++++ description.md | 67 +++++++++++++++++++++++++++ 3 files changed, 251 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..9f951c067876 --- /dev/null +++ b/README.md @@ -0,0 +1,122 @@ +Java Enterprise Online Project +=============================== +Наиболее востребованные технологии /инструменты / фреймворки Java Enterprise: +Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + plugins. + + Когда вы слышите что-то, вы забываете это. + Когда вы видите что-то, вы запоминаете это. + Но только когда вы начинаете делать это, + вы начинаете понимать это + + Старинная китайская поговорка + +## Описание и план проекта +### Демо разрабатываемого приложения +### Требования к участникам, Wiki +### Составление резюме, подготовка к интервью, поиск работы + +Вводное занятие +=============== +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) Системы управления версиями. Git. + +- Система управления версиями. VCS/DVSC. +- Ресурсы: + - Интерактивная Git обучалка + - Книга Git + - Working with remote repositories + - Видео по обучению Git + - Git Overview + - Видеокурс по Git + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) Работа с проектом (выполнять инструкции) +- **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. + +## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Домашнее задание 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 +- A Guide to Java 8 +- Шпаргалка Java Stream API +- Stream API. Видеурок от Алексея Владыкина +- stream.map vs forEach + +``` +Сделать реализация через Java 8 Stream API. Заменяйте forEach оператором stream.map(..) +``` +### Ресурсы для подготовки к проекту +желательно иметь представление для лучшего усвоения материала + +#### Git +- Книга Git +- Видео: продвинутый Git + +#### Java (базовые вещи) +- Интуит. Программирование на Java +- Основы Java garbage collection +- Размер Java объектов +- Блог о памяти, сборщике мусора, многопоточности и производительности в JAVA +- Введение в Java Reflection API +- Структуры данных в картинках +- Обзор java.util.concurrent.* +- Синхронизация потоков +- String literal pool +- Маленькие хитрости Java +- Как создать Servlet? Полное руководство. +- A Guide to Java 8 +- Java JUnit + +#### HTML, JavaScript, CSS +- Основы работы с HTML/CSS/JavaScript +- JavaScript - Основы +- Bootstrap 3 - Основы +- jQuery для начинающих + +#### JDBC, SQL +- Уроки по JDBC +- Learn SQL +- Try SQL + +#### Разное +- Эффективная работа с кодом в IntelliJ IDEA +- Quizful- тесты онлайн + +#### Книги +- Джошуа Блох: Java. Эффективное программирование. Второе издание +- Гамма, Хелм, Джонсон: Приемы объектно-ориентированного проектирования. Паттерны проектирования +- Редмонд Э.: Семь баз данных за семь недель. Введение в современные базы данных и идеологию NoSQL +- Brian Goetz: Java Concurrency in Practice +- G.L. McDowell: Cracking the Coding Interview diff --git a/cv.md b/cv.md new file mode 100644 index 000000000000..42f5a2644243 --- /dev/null +++ b/cv.md @@ -0,0 +1,62 @@ +## Составление резюме, подготовка к интервью, поиск работы + +![cv](https://cloud.githubusercontent.com/assets/13649199/10877471/93ea86b8-8157-11e5-9bfa-95e3fba75c58.jpg) + +- Научиться программировать сложнее, чем кажется + +### Составление резюме: +- ОФОРМЛЕНИЕ IT-РЕЗЮМЕ для USA +- Идеальное резюме Junior’а +- Как продать свое резюме в 2 раза дороже +- Как правильно составить резюме +- Резюме программистов. Часть 1 (плохие) +- Резюме программистов. Часть 2 (хорошие) +- Как составить резюме на английском + +### Наши истории (делимся опытом и успехом) + +### Интервью: +- Михаил Портнов. Собеседование на работу: как продать себя грамотно +- Михаил Портнов. Какие вопросы мы задаем на собеседовании? +- Канал: Резюме, поиск работы, интервью +- Яков Файн: Как стать профессиональным Java разработчиком +- Quizful- тесты онлайн +- Сборка по вопросам на интервью +- Сборка вопросов-ответов от JavaStudy +- Тест на знание SQL +- Вопросы на собеседовании Java Junior Developer +- Сборка вопросов от 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, уже есть пинги и трудоустройство. + +### Группа в skype: Online Projects. +Общение на все темы IT, обсуждение вступительных заданий, вакансии, цены на рынке труда, события, помощь, интересные видео по теме и пр. + +### Основные сайты поиска работы: +- HH +- LinkedIn +- djinni.co (более актуально для Украины) diff --git a/description.md b/description.md new file mode 100644 index 000000000000..cbb102fa72aa --- /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 (добавление в проект защиты от межсайтовой подделки запроса) +- form-login. Spring Security Taglib +- Handler interceptor +- Spring Exception Handling +- Деплой в Heroku From 32ffd17cb7deab043db9033ec9947fec9763d928 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 18 May 2016 12:22:48 +0300 Subject: [PATCH 02/76] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9f951c067876..7ae0bcb58ccd 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ Optional - Java JUnit #### HTML, JavaScript, CSS +- Введение в программирование на JavaScript - Основы работы с HTML/CSS/JavaScript - JavaScript - Основы - Bootstrap 3 - Основы From f5a5fefdce094c08eb21bbe252ea3d43c4a70480 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 19 May 2016 07:45:01 +0300 Subject: [PATCH 03/76] Update cv.md --- cv.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cv.md b/cv.md index 42f5a2644243..ae5697cc2d7d 100644 --- a/cv.md +++ b/cv.md @@ -25,12 +25,14 @@ - Сборка вопросов-ответов от JavaStudy - Тест на знание SQL - Вопросы на собеседовании Java Junior Developer +- Java вопросы с собеседований на Android - Сборка вопросов от JavaRush > про clone и finalize объязательно прочтите Джошуа Блох: Java. Эффективное программирование (второе издание) - Cracking the Coding Interview > Особенно обратите внимание на раздел: Часть VIII. Вопросы собеседования + ### От себя: - email, skype - очень желательно, чтобы по ним вы были узнаваемы. Заведите рабочие, если не так. - написать ВЕСЬ IT опыт (исключая опыт пользователя: Windows, MS Word, Photophop, Yandex disk, Google docs, ..): технологии, какие задачи решали (конкретные), какие инструменты использовали, VCS, DB, инструменты сборки, ... включая опыт в ВУЗе. From 740690fb5dab9afa3a76a132f1ab570f1b19b2df Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 19 May 2016 23:19:18 +0300 Subject: [PATCH 04/76] Update cv.md --- cv.md | 1 + 1 file changed, 1 insertion(+) diff --git a/cv.md b/cv.md index ae5697cc2d7d..4d55421230fc 100644 --- a/cv.md +++ b/cv.md @@ -21,6 +21,7 @@ - Канал: Резюме, поиск работы, интервью - Яков Файн: Как стать профессиональным Java разработчиком - Quizful- тесты онлайн +- Список вопросов с ответами для собеседования по Java - Сборка по вопросам на интервью - Сборка вопросов-ответов от JavaStudy - Тест на знание SQL From bc2d18213026b4346ced76cd8ef7f3dbd938e07e Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Fri, 20 May 2016 13:03:57 +0300 Subject: [PATCH 05/76] 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 0d75333eca4a7bdd4e0bea3d97b68b289d2fa9f8 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 2 Jun 2016 18:31:29 +0300 Subject: [PATCH 06/76] prepare to HW1 --- .../topjava/model/UserMealWithExceed.java | 18 +++++++--- .../topjava/util/UserMealsUtil.java | 36 ++++++++++++------- 2 files changed, 38 insertions(+), 16 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..d240ff3d2d6e 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; @@ -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..d005598f159b 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 = getFilteredWithExceeded(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 getFilteredWithExceeded(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 22d7306718ce901132b351ed20f8d6906a6b431a Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 2 Jun 2016 21:00:32 +0300 Subject: [PATCH 07/76] prepare to HW1 --- config/setenv.bat | 4 ++ pom.xml | 44 ++++++++++++++++++- .../topjava/util/UserMealsUtil.java | 31 ++++++++++--- .../javawebinar/topjava/web/UserServlet.java | 27 ++++++++++++ src/main/resources/logback.xml | 33 ++++++++++++++ src/main/webapp/WEB-INF/web.xml | 18 ++++++++ src/main/webapp/index.html | 14 ++++++ src/main/webapp/userList.jsp | 10 +++++ 8 files changed, 172 insertions(+), 9 deletions(-) create mode 100644 config/setenv.bat create mode 100644 src/main/java/ru/javawebinar/topjava/web/UserServlet.java create mode 100644 src/main/resources/logback.xml 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/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 diff --git a/pom.xml b/pom.xml index c8a1c78f3b29..b7c2974eaea8 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ ru.javawebinar topjava - jar + war 1.0-SNAPSHOT @@ -15,11 +15,15 @@ 1.8 UTF-8 UTF-8 + + + 1.1.7 + 1.7.21 topjava - install + package org.apache.maven.plugins @@ -34,6 +38,42 @@ + + + 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 + + + + + javax.servlet + servlet-api + 2.5 + provided + diff --git a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java index d005598f159b..70cfdef41983 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 = getFilteredWithExceeded(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); filteredMealsWithExceeded.forEach(System.out::println); + + System.out.println(getFilteredWithExceededByCycle(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000)); } public static List getFilteredWithExceeded(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { @@ -39,9 +39,26 @@ public static List getFilteredWithExceeded(List me 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)) + .map(um -> createWithExceed(um, caloriesSumByDate.get(um.getDateTime().toLocalDate()) > caloriesPerDay)) .collect(Collectors.toList()); } -} + + 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)); + + 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 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..0b6611f24666 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java @@ -0,0 +1,27 @@ +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 + + + + + + + + + + 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..83b186ee233a --- /dev/null +++ b/src/main/webapp/index.html @@ -0,0 +1,14 @@ + + + + + Java Enterprise (Topjava) + + +

Проект "Java Enterprise (Topjava)"

+
+ + + diff --git a/src/main/webapp/userList.jsp b/src/main/webapp/userList.jsp new file mode 100644 index 000000000000..fbd40d3d7219 --- /dev/null +++ b/src/main/webapp/userList.jsp @@ -0,0 +1,10 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + User list + + +

Home

+

User list

+ + From 07f84ea14a27ba3cecd1c6a1c62246e1707cdee3 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 2 Jun 2016 21:17:51 +0300 Subject: [PATCH 08/76] prepare to HW1 --- .../topjava/util/UserMealsUtil.java | 64 ------------------- 1 file changed, 64 deletions(-) delete mode 100644 src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java diff --git a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java deleted file mode 100644 index 70cfdef41983..000000000000 --- a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java +++ /dev/null @@ -1,64 +0,0 @@ -package ru.javawebinar.topjava.util; - -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.*; -import java.util.stream.Collectors; - -/** - * 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) - ); - List filteredMealsWithExceeded = getFilteredWithExceeded(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); - filteredMealsWithExceeded.forEach(System.out::println); - - System.out.println(getFilteredWithExceededByCycle(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000)); - } - - public static List getFilteredWithExceeded(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 -> createWithExceed(um, caloriesSumByDate.get(um.getDateTime().toLocalDate()) > caloriesPerDay)) - .collect(Collectors.toList()); - } - - 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)); - - 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 aa7c0b8afd67d2b9e3221a05cfc8608ceafdbcd7 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 2 Jun 2016 21:27:44 +0300 Subject: [PATCH 09/76] prepare to HW1 --- config/setenv.bat | 4 - cv.md | 65 -------------- description.md | 67 --------------- pom.xml | 84 ------------------- .../javawebinar/topjava/model/UserMeal.java | 33 -------- .../topjava/model/UserMealWithExceed.java | 34 -------- .../ru/javawebinar/topjava/util/TimeUtil.java | 13 --- .../javawebinar/topjava/web/UserServlet.java | 27 ------ src/main/resources/logback.xml | 33 -------- src/main/webapp/WEB-INF/web.xml | 18 ---- src/main/webapp/index.html | 14 ---- src/main/webapp/userList.jsp | 10 --- 12 files changed, 402 deletions(-) delete mode 100644 config/setenv.bat delete mode 100644 cv.md delete mode 100644 description.md delete mode 100644 pom.xml delete mode 100644 src/main/java/ru/javawebinar/topjava/model/UserMeal.java delete mode 100644 src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java delete mode 100644 src/main/java/ru/javawebinar/topjava/util/TimeUtil.java delete mode 100644 src/main/java/ru/javawebinar/topjava/web/UserServlet.java delete mode 100644 src/main/resources/logback.xml delete mode 100644 src/main/webapp/WEB-INF/web.xml delete mode 100644 src/main/webapp/index.html delete mode 100644 src/main/webapp/userList.jsp diff --git a/config/setenv.bat b/config/setenv.bat deleted file mode 100644 index ebbd659386f6..000000000000 --- a/config/setenv.bat +++ /dev/null @@ -1,4 +0,0 @@ -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 diff --git a/cv.md b/cv.md deleted file mode 100644 index 4d55421230fc..000000000000 --- a/cv.md +++ /dev/null @@ -1,65 +0,0 @@ -## Составление резюме, подготовка к интервью, поиск работы - -![cv](https://cloud.githubusercontent.com/assets/13649199/10877471/93ea86b8-8157-11e5-9bfa-95e3fba75c58.jpg) - -- Научиться программировать сложнее, чем кажется - -### Составление резюме: -- ОФОРМЛЕНИЕ IT-РЕЗЮМЕ для USA -- Идеальное резюме Junior’а -- Как продать свое резюме в 2 раза дороже -- Как правильно составить резюме -- Резюме программистов. Часть 1 (плохие) -- Резюме программистов. Часть 2 (хорошие) -- Как составить резюме на английском - -### Наши истории (делимся опытом и успехом) - -### Интервью: -- Михаил Портнов. Собеседование на работу: как продать себя грамотно -- Михаил Портнов. Какие вопросы мы задаем на собеседовании? -- Канал: Резюме, поиск работы, интервью -- Яков Файн: Как стать профессиональным Java разработчиком -- Quizful- тесты онлайн -- Список вопросов с ответами для собеседования по Java -- Сборка по вопросам на интервью -- Сборка вопросов-ответов от JavaStudy -- Тест на знание SQL -- Вопросы на собеседовании Java Junior Developer -- Java вопросы с собеседований на Android -- Сборка вопросов от 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, уже есть пинги и трудоустройство. - -### Группа в skype: Online Projects. -Общение на все темы IT, обсуждение вступительных заданий, вакансии, цены на рынке труда, события, помощь, интересные видео по теме и пр. - -### Основные сайты поиска работы: -- HH -- LinkedIn -- djinni.co (более актуально для Украины) diff --git a/description.md b/description.md deleted file mode 100644 index cbb102fa72aa..000000000000 --- a/description.md +++ /dev/null @@ -1,67 +0,0 @@ -#### Разработка полнофункционального 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 (добавление в проект защиты от межсайтовой подделки запроса) -- form-login. Spring Security Taglib -- Handler interceptor -- Spring Exception Handling -- Деплой в Heroku diff --git a/pom.xml b/pom.xml deleted file mode 100644 index b7c2974eaea8..000000000000 --- a/pom.xml +++ /dev/null @@ -1,84 +0,0 @@ - - 4.0.0 - - ru.javawebinar - topjava - war - - 1.0-SNAPSHOT - - Calories Management - http://topjava.herokuapp.com/ - - - 1.8 - UTF-8 - UTF-8 - - - 1.1.7 - 1.7.21 - - - - topjava - package - - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - ${java.version} - ${java.version} - - - - - - - - - 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 - - - - - javax.servlet - servlet-api - 2.5 - provided - - - - - - - - - diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java deleted file mode 100644 index fde5448b93d8..000000000000 --- a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java +++ /dev/null @@ -1,33 +0,0 @@ -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 deleted file mode 100644 index d240ff3d2d6e..000000000000 --- a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java +++ /dev/null @@ -1,34 +0,0 @@ -package ru.javawebinar.topjava.model; - -import java.time.LocalDateTime; - -/** - * GKislin - * 11.01.2015. - */ -public class UserMealWithExceed { - private final LocalDateTime dateTime; - - private final String description; - - private final int calories; - - private 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; - } - - @Override - public String toString() { - return "UserMealWithExceed{" + - "dateTime=" + dateTime + - ", description='" + description + '\'' + - ", calories=" + calories + - ", exceed=" + exceed + - '}'; - } -} diff --git a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java deleted file mode 100644 index 02399b7288cf..000000000000 --- a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java +++ /dev/null @@ -1,13 +0,0 @@ -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/web/UserServlet.java b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java deleted file mode 100644 index 0b6611f24666..000000000000 --- a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index 8ee5f21b023e..000000000000 --- a/src/main/resources/logback.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - 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 - - - - - - - - - - diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index edca9575b44b..000000000000 --- a/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - Topjava - - - userServlet - ru.javawebinar.topjava.web.UserServlet - 0 - - - userServlet - /users - - - diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html deleted file mode 100644 index 83b186ee233a..000000000000 --- a/src/main/webapp/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - Java Enterprise (Topjava) - - -

Проект "Java Enterprise (Topjava)"

-
- - - diff --git a/src/main/webapp/userList.jsp b/src/main/webapp/userList.jsp deleted file mode 100644 index fbd40d3d7219..000000000000 --- a/src/main/webapp/userList.jsp +++ /dev/null @@ -1,10 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" %> - - - User list - - -

Home

-

User list

- - From 8e0344ed6e2ca9af70bcb1e5fce681da9222de65 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 2 Jun 2016 21:29:00 +0300 Subject: [PATCH 10/76] prepare to HW1 --- pom.xml | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 pom.xml diff --git a/pom.xml b/pom.xml new file mode 100644 index 000000000000..deff2fbb83df --- /dev/null +++ b/pom.xml @@ -0,0 +1,44 @@ + + 4.0.0 + + ru.javawebinar + topjava + jar + + 1.0-SNAPSHOT + + Calories Management + http://topjava.herokuapp.com/ + + + 1.8 + UTF-8 + UTF-8 + + + + topjava + install + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + ${java.version} + ${java.version} + + + + + + + + + + + + + + \ No newline at end of file From c649d6c9be6bb17b7a1252cd56922f313c1e089d Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 2 Jun 2016 21:29:30 +0300 Subject: [PATCH 11/76] prepare to HW1 --- .../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 fff3c636b774603423b6270172d6960fa53357be Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 2 Jun 2016 21:30:11 +0300 Subject: [PATCH 12/76] prepare to HW1 --- .../topjava/model/UserMealWithExceed.java | 18 +++++++--- .../topjava/util/UserMealsUtil.java | 36 ++++++++++++------- 2 files changed, 38 insertions(+), 16 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..d240ff3d2d6e 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; @@ -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..d005598f159b 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 = getFilteredWithExceeded(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 getFilteredWithExceeded(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 242b20ea274d5ace66ce393e096fdfd3f02dfdd2 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 2 Jun 2016 21:30:31 +0300 Subject: [PATCH 13/76] prepare to HW1 --- .../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 d005598f159b..70cfdef41983 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 = getFilteredWithExceeded(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); filteredMealsWithExceeded.forEach(System.out::println); + + System.out.println(getFilteredWithExceededByCycle(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000)); } public static List getFilteredWithExceeded(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { @@ -39,9 +39,26 @@ public static List getFilteredWithExceeded(List me 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)) + .map(um -> createWithExceed(um, caloriesSumByDate.get(um.getDateTime().toLocalDate()) > caloriesPerDay)) .collect(Collectors.toList()); } -} + + 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)); + + 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 b373614ffe35eec133e40d4ff20bafd75290d665 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 2 Jun 2016 21:30:59 +0300 Subject: [PATCH 14/76] prepare to HW1 --- pom.xml | 4 ++-- src/main/webapp/WEB-INF/web.xml | 18 ++++++++++++++++++ src/main/webapp/index.html | 14 ++++++++++++++ src/main/webapp/userList.jsp | 10 ++++++++++ 4 files changed, 44 insertions(+), 2 deletions(-) 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 deff2fbb83df..6f0e7fd7cf47 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ ru.javawebinar topjava - jar + war 1.0-SNAPSHOT @@ -41,4 +41,4 @@ - \ No newline at end of file + 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..83b186ee233a --- /dev/null +++ b/src/main/webapp/index.html @@ -0,0 +1,14 @@ + + + + + Java Enterprise (Topjava) + + +

Проект "Java Enterprise (Topjava)"

+
+ + + diff --git a/src/main/webapp/userList.jsp b/src/main/webapp/userList.jsp new file mode 100644 index 000000000000..fbd40d3d7219 --- /dev/null +++ b/src/main/webapp/userList.jsp @@ -0,0 +1,10 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + User list + + +

Home

+

User list

+ + From 1de1dfc57cd31a0715464d182fb512b080747685 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 2 Jun 2016 21:31:31 +0300 Subject: [PATCH 15/76] prepare to HW1 --- 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 f0b482bb91601f69b66cf4a9097527188a135f1d Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 2 Jun 2016 21:31:59 +0300 Subject: [PATCH 16/76] prepare to HW1 --- 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 4beb880fa5dafb7bc6171fb1b226b9e2d7358822 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 2 Jun 2016 21:32:22 +0300 Subject: [PATCH 17/76] prepare to HW1 --- 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..b7c2974eaea8 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,10 @@ 1.8 UTF-8 UTF-8 + + + 1.1.7 + 1.7.21 @@ -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 aa72044daa284297179f1e77a4597203f1430135 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 2 Jun 2016 21:32:47 +0300 Subject: [PATCH 18/76] prepare to HW1 --- 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 fde7b35036f389771cf44e5165bfaa6fe9835254 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Fri, 10 Jun 2016 12:30:33 +0300 Subject: [PATCH 19/76] prepare to HW2 --- pom.xml | 5 ++ .../topjava/model/UserMealWithExceed.java | 16 +++++++ .../ru/javawebinar/topjava/util/TimeUtil.java | 8 ++++ .../topjava/util/UserMealsUtil.java | 27 +++++++---- .../javawebinar/topjava/web/MealServlet.java | 25 ++++++++++ src/main/webapp/WEB-INF/tld/functions.tld | 16 +++++++ src/main/webapp/WEB-INF/web.xml | 10 ++++ src/main/webapp/index.html | 1 + src/main/webapp/mealList.jsp | 46 +++++++++++++++++++ 9 files changed, 144 insertions(+), 10 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/web/MealServlet.java create mode 100644 src/main/webapp/WEB-INF/tld/functions.tld create mode 100644 src/main/webapp/mealList.jsp diff --git a/pom.xml b/pom.xml index b7c2974eaea8..f79727654639 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 d240ff3d2d6e..935b943afeb6 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java @@ -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 70cfdef41983..6ea1f206d9e7 100644 --- a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java @@ -15,19 +15,26 @@ * 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 = getFilteredWithExceeded(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(getFilteredWithExceededByCycle(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 getFilteredWithExceeded(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { 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/tld/functions.tld b/src/main/webapp/WEB-INF/tld/functions.tld new file mode 100644 index 000000000000..7921d2914838 --- /dev/null +++ b/src/main/webapp/WEB-INF/tld/functions.tld @@ -0,0 +1,16 @@ + + + + 1.0 + functions + http://topjava.javawebinar.ru/functions + + + formatDateTime + ru.javawebinar.topjava.util.TimeUtil + java.lang.String toString(java.time.LocalDateTime) + + diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 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 83b186ee233a..131319c33c41 100644 --- a/src/main/webapp/index.html +++ b/src/main/webapp/index.html @@ -9,6 +9,7 @@

Проект "User List +
  • Meal List
  • diff --git a/src/main/webapp/mealList.jsp b/src/main/webapp/mealList.jsp new file mode 100644 index 000000000000..1bc6112dc341 --- /dev/null +++ b/src/main/webapp/mealList.jsp @@ -0,0 +1,46 @@ +<%@ 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" %> +<%@ taglib prefix="fn" uri="http://topjava.javawebinar.ru/functions" %> + + + Meal list + + + +
    +

    Home

    +

    Meal list

    +
    + + + + + + + + + + + + + + + + +
    DateDescriptionCalories
    + <%--${meal.dateTime.toLocalDate()} ${meal.dateTime.toLocalTime()}--%> + <%--<%=TimeUtil.toString(meal.getDateTime())%>--%> + ${fn:formatDateTime(meal.dateTime)} + ${meal.description}${meal.calories}
    +
    + + \ No newline at end of file From 5f5e7533803c95f25eec8ddfc1da371823376320 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Fri, 10 Jun 2016 13:56:44 +0300 Subject: [PATCH 20/76] prepare to HW2 --- .../javawebinar/topjava/model/UserMeal.java | 35 ++++++++++-- .../topjava/model/UserMealWithExceed.java | 14 ++++- .../InMemoryUserMealRepositoryImpl.java | 47 ++++++++++++++++ .../repository/UserMealRepository.java | 19 +++++++ .../topjava/util/UserMealsUtil.java | 6 +-- .../javawebinar/topjava/web/MealServlet.java | 53 +++++++++++++++++-- src/main/webapp/mealEdit.jsp | 51 ++++++++++++++++++ src/main/webapp/mealList.jsp | 5 ++ 8 files changed, 220 insertions(+), 10 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..6b18770bbb7f 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 { + private 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..8d6d4484fa62 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" %> + + + + Meal + + + +
    +

    Home

    +

    Edit meal

    +
    + +
    + +
    +
    DateTime:
    +
    +
    +
    +
    Description:
    +
    +
    +
    +
    Calories:
    +
    +
    + + +
    +
    + + diff --git a/src/main/webapp/mealList.jsp b/src/main/webapp/mealList.jsp index 1bc6112dc341..f128a01282f9 100644 --- a/src/main/webapp/mealList.jsp +++ b/src/main/webapp/mealList.jsp @@ -19,6 +19,7 @@

    Home

    Meal list

    + Add Meal
    @@ -26,6 +27,8 @@ + + @@ -38,6 +41,8 @@ + +
    Date Description Calories
    ${meal.description} ${meal.calories}UpdateDelete
    From 0ab91633229fcbc540239dfc216651bb450dee1a Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 14 Jun 2016 13:19:03 +0300 Subject: [PATCH 21/76] prepare to HW3 --- pom.xml | 14 +++ .../ru/javawebinar/topjava/LoggedUser.java | 18 ++++ .../ru/javawebinar/topjava/SpringMain.java | 24 +++++ .../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 +++++ .../InMemoryUserMealRepositoryImpl.java | 3 +- .../mock/MockUserRepositoryImpl.java | 49 ++++++++++ .../topjava/service/UserMealService.java | 8 ++ .../topjava/service/UserMealServiceImpl.java | 13 +++ .../topjava/service/UserService.java | 26 +++++ .../topjava/service/UserServiceImpl.java | 45 +++++++++ .../topjava/util/exception/ExceptionUtil.java | 25 +++++ .../util/exception/NotFoundException.java | 11 +++ .../javawebinar/topjava/web/MealServlet.java | 2 +- .../web/meal/UserMealRestController.java | 12 +++ .../web/user/AbstractUserController.java | 51 ++++++++++ .../topjava/web/user/AdminRestController.java | 38 +++++++ .../web/user/ProfileRestController.java | 25 +++++ src/main/resources/spring/spring-app.xml | 23 +++++ 22 files changed, 576 insertions(+), 2 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/LoggedUser.java create mode 100644 src/main/java/ru/javawebinar/topjava/SpringMain.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 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/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 create mode 100644 src/main/resources/spring/spring-app.xml diff --git a/pom.xml b/pom.xml index f79727654639..9e17b4a5669a 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,8 @@ UTF-8 UTF-8 + 4.2.6.RELEASE + 1.1.7 1.7.21 @@ -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/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/SpringMain.java b/src/main/java/ru/javawebinar/topjava/SpringMain.java new file mode 100644 index 000000000000..9b14ec645a08 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/SpringMain.java @@ -0,0 +1,24 @@ +package ru.javawebinar.topjava; + +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.web.user.AdminRestController; + +import java.util.Arrays; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +public class SpringMain { + public static void main(String[] args) { + // 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/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/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..6231e4c74521 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java @@ -0,0 +1,49 @@ +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/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..77782de1784e --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java @@ -0,0 +1,45 @@ +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; +import ru.javawebinar.topjava.util.exception.NotFoundException; + +import java.util.List; + +/** + * GKislin + * 06.03.2015. + */ +@Service +public class UserServiceImpl implements UserService { + + @Autowired + private UserRepository repository; + + public User save(User user) { + return repository.save(user); + } + + public void delete(int id) { + ExceptionUtil.checkNotFoundWithId(repository.delete(id), id); + } + + public User get(int id) throws NotFoundException { + return ExceptionUtil.checkNotFoundWithId(repository.get(id), id); + } + + public User getByEmail(String email) throws NotFoundException { + return ExceptionUtil.checkNotFound(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..254a7dba2b00 --- /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 checkNotFoundWithId(boolean found, int id) { + checkNotFound(found, "id=" + id); + } + + public static T checkNotFoundWithId(T object, int id) { + return checkNotFound(object, "id=" + id); + } + + public static T checkNotFound(T object, String msg) { + checkNotFound(object != null, msg); + return object; + } + + public static void checkNotFound(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/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java index aabe64eb8aae..364635b68fcd 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/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..e2b847678af2 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java @@ -0,0 +1,51 @@ +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; +import ru.javawebinar.topjava.service.UserService; + +import java.util.List; + +/** + * User: gkislin + */ +public abstract class AbstractUserController { + protected final Logger LOG = LoggerFactory.getLogger(getClass()); + + @Autowired + 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..d6b8bb420803 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java @@ -0,0 +1,38 @@ +package ru.javawebinar.topjava.web.user; + +import org.springframework.stereotype.Controller; +import ru.javawebinar.topjava.model.User; + +import java.util.List; + +/** + * GKislin + * 06.03.2015. + */ +@Controller +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..1114e57eeb1e --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java @@ -0,0 +1,25 @@ +package ru.javawebinar.topjava.web.user; + +import org.springframework.stereotype.Controller; +import ru.javawebinar.topjava.LoggedUser; +import ru.javawebinar.topjava.model.User; + +/** + * GKislin + * 06.03.2015. + */ +@Controller +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 diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml new file mode 100644 index 000000000000..96e40e902b66 --- /dev/null +++ b/src/main/resources/spring/spring-app.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + \ No newline at end of file From 98792ec0279614792760dbe7a679b3a921822710 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 16 Jun 2016 13:07:52 +0300 Subject: [PATCH 22/76] prepare to HW3 --- .../repository/UserMealRepository.java | 16 +++-- .../mock/InMemoryUserMealRepositoryImpl.java | 64 +++++++++++++++---- .../mock/InMemoryUserRepositoryImpl.java | 64 +++++++++++++++++++ .../mock/MockUserRepositoryImpl.java | 49 -------------- .../ru/javawebinar/topjava/util/TimeUtil.java | 7 +- .../javawebinar/topjava/web/MealServlet.java | 11 ++-- 6 files changed, 135 insertions(+), 76 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..e8c5245c1df4 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<>(); + + private 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..74b4cb84326f --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java @@ -0,0 +1,64 @@ +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); + + private 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..4fbe9dc16de3 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; /** @@ -9,10 +8,10 @@ * 07.01.2015. */ public class TimeUtil { - public static final DateTimeFormatter DATE_TME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + private 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 364635b68fcd..915830f39b3c 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 if (action.equals("create") || action.equals("update")) { final UserMeal meal = action.equals("create") ? new UserMeal(LocalDateTime.now().withNano(0).withSecond(0), "", 1000) : - repository.get(getId(request)); + repository.get(getId(request), LoggedUser.id()); request.setAttribute("meal", meal); request.getRequestDispatcher("mealEdit.jsp").forward(request, response); } From eee0333a24dbfa5802fe057d828d83bea55c4763 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Fri, 17 Jun 2016 17:55:15 +0300 Subject: [PATCH 23/76] prepare to HW4 --- src/main/webapp/mealEdit.jsp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/webapp/mealEdit.jsp b/src/main/webapp/mealEdit.jsp index 443933549130..e579ecc4845a 100644 --- a/src/main/webapp/mealEdit.jsp +++ b/src/main/webapp/mealEdit.jsp @@ -25,8 +25,8 @@
    -

    Home

    -

    Edit meal

    +

    Home

    +

    ${param.action == 'create' ? 'Create meal' : 'Edit meal'}


    From 346daa8bcb2c55f56a5def75a8a09f1a1431ff8c Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Fri, 17 Jun 2016 19:00:13 +0300 Subject: [PATCH 24/76] prepare to HW4 --- .../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 | 4 ++ .../topjava/util/UserMealsUtil.java | 2 +- .../javawebinar/topjava/web/MealServlet.java | 42 ++++++++----- .../web/meal/UserMealRestController.java | 61 ++++++++++++++++++- src/main/webapp/mealList.jsp | 2 +- 10 files changed, 171 insertions(+), 34 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..356a21447d63 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.checkNotFoundWithId(repository.get(id, userId), id); + } + + @Override + public void delete(int id, int userId) { + ExceptionUtil.checkNotFoundWithId(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.checkNotFoundWithId(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 6b18770bbb7f..47a843c58724 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 4fbe9dc16de3..0419eb0a4793 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; @@ -10,6 +11,9 @@ public class TimeUtil { private static final DateTimeFormatter DATE_TME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + public static final LocalDate MIN_DATE = LocalDate.of(1, 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 8d6d4484fa62..31656ae96b20 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/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java index 915830f39b3c..20c1d3a51c9b 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 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 if (action.equals("create") || action.equals("update")) { final UserMeal meal = action.equals("create") ? new UserMeal(LocalDateTime.now().withNano(0).withSecond(0), "", 1000) : - repository.get(getId(request), LoggedUser.id()); + mealController.get(getId(request)); // update request.setAttribute("meal", meal); request.getRequestDispatcher("mealEdit.jsp").forward(request, response); } 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 f128a01282f9..64926a4fd4c0 100644 --- a/src/main/webapp/mealList.jsp +++ b/src/main/webapp/mealList.jsp @@ -32,7 +32,7 @@ - + <%--${meal.dateTime.toLocalDate()} ${meal.dateTime.toLocalTime()}--%> From fe92c05493215c90de2a21b36bf43642d3c8d236 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Fri, 17 Jun 2016 19:06:51 +0300 Subject: [PATCH 25/76] prepare to HW4 --- .../ru/javawebinar/topjava/util/TimeUtil.java | 11 +++++ .../javawebinar/topjava/web/MealServlet.java | 41 ++++++++++++++----- src/main/webapp/css/style.css | 24 +++++++++++ src/main/webapp/mealEdit.jsp | 19 +-------- src/main/webapp/mealList.jsp | 30 ++++++++++---- 5 files changed, 87 insertions(+), 38 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 0419eb0a4793..9657c46ec949 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; /** @@ -21,4 +24,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 20c1d3a51c9b..9b724fc10bd4 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 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,12 @@ 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/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 e579ecc4845a..993610e746a7 100644 --- a/src/main/webapp/mealEdit.jsp +++ b/src/main/webapp/mealEdit.jsp @@ -4,24 +4,7 @@ Meal - +
    diff --git a/src/main/webapp/mealList.jsp b/src/main/webapp/mealList.jsp index 64926a4fd4c0..84a31cac352b 100644 --- a/src/main/webapp/mealList.jsp +++ b/src/main/webapp/mealList.jsp @@ -5,20 +5,32 @@ Meal list - +

    Home

    Meal list

    + +
    +
    From Date:
    +
    +
    +
    +
    To Date:
    +
    +
    +
    +
    From Time:
    +
    +
    +
    +
    To Time:
    +
    +
    + + +
    Add Meal
    From 00a59f6e2c7949d305beca99683800e1898c662c Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Fri, 17 Jun 2016 19:09:26 +0300 Subject: [PATCH 26/76] prepare to HW4 --- src/main/java/ru/javawebinar/topjava/LoggedUser.java | 7 ++++++- .../java/ru/javawebinar/topjava/web/UserServlet.java | 10 +++++++--- src/main/webapp/index.html | 12 ++++++++---- 3 files changed, 21 insertions(+), 8 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 131319c33c41..472858c37ffc 100644 --- a/src/main/webapp/index.html +++ b/src/main/webapp/index.html @@ -7,9 +7,13 @@

    Проект "Java Enterprise (Topjava)"


    - +
    + Meal list of + + + From 15a9fe7a1b0d41f4af2567df6bd4cbef4fa9da61 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Sat, 18 Jun 2016 14:54:34 +0300 Subject: [PATCH 27/76] prepare to HW4 --- .../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 74b4cb84326f..57716837f553 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 1bf0432ef82d4c7442654a896e4a40cbb030b485 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Mon, 20 Jun 2016 14:11:09 +0300 Subject: [PATCH 28/76] prepare to HW4 --- 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 (96%) create mode 100644 src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerTest.java diff --git a/pom.xml b/pom.xml index 9e17b4a5669a..d4bb43e8b66d 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,9 @@ 1.1.7 1.7.21 + + + 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 e8c5245c1df4..16fd3422e59a 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 96% 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 57716837f553..6b1e658d5739 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 { private 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..becff75a3425 --- /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); + } + + @AfterClass + public static void afterClass() { + appCtx.close(); + } + + @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); + } + + @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 49a111cbee4efb4b914476992bf7ab75a74852a4 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Mon, 20 Jun 2016 17:34:00 +0300 Subject: [PATCH 29/76] prepare to HW4 --- 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 d4bb43e8b66d..0585bb36384a 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 8eb2b57cf0d6a5050b64d27f503acbebc3d0eae3 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 21 Jun 2016 13:23:42 +0300 Subject: [PATCH 30/76] prepare to HW4 --- 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 0585bb36384a..a1a7a863fa69 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,8 @@ 1.1.7 1.7.21 + + 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 ec8ff5a81444aacd30c738486af6869ec309a59a Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 21 Jun 2016 15:04:40 +0300 Subject: [PATCH 31/76] prepare to HW4 --- 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 99df854d7b692061e05e6a8476458b7847f20e00 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 21 Jun 2016 15:05:10 +0300 Subject: [PATCH 32/76] prepare to HW4 --- 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 a1a7a863fa69..9d5fb076404b 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 bc196fec3a58a92541bba78bf7d1d3c64b079f9f Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 21 Jun 2016 19:01:33 +0300 Subject: [PATCH 33/76] prepare to HW4 --- .../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 c9640992fc0a811aa889ee1de33069c87aab1094 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 21 Jun 2016 19:05:56 +0300 Subject: [PATCH 34/76] prepare to HW4 --- .../ru/javawebinar/topjava/LoggedUser.java | 4 +++- .../javawebinar/topjava/web/MealServlet.java | 2 +- src/main/webapp/index.html | 4 ++-- src/test/resources/logback-test.xml | 21 +++++++++++++++++++ 4 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 src/test/resources/logback-test.xml 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 9b724fc10bd4..2873eb2f1d40 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 472858c37ffc..2ac7fd93bf1d 100644 --- a/src/main/webapp/index.html +++ b/src/main/webapp/index.html @@ -10,8 +10,8 @@

    Проект " Meal list of 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 0a1fc0ee82d2a9415d75a2c6605952360a7465ec Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Fri, 24 Jun 2016 20:30:41 +0300 Subject: [PATCH 35/76] prepare to HW4 --- .../javawebinar/topjava/model/UserMeal.java | 21 +++++- .../jdbc/JdbcUserMealRepositoryImpl.java | 65 ++++++++++++++++--- src/main/resources/db/initDB.sql | 11 ++++ src/main/resources/db/populateDB.sql | 11 ++++ 4 files changed, 97 insertions(+), 11 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java index 5fc41074a979..28f585dbeb57 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java @@ -8,11 +8,14 @@ */ public class UserMeal extends BaseEntity { - private final LocalDateTime dateTime; + private LocalDateTime dateTime; - private final String description; + private String description; - private final int calories; + private int calories; + + public UserMeal() { + } public UserMeal(LocalDateTime dateTime, String description, int calories) { this(null, dateTime, description, calories); @@ -37,6 +40,18 @@ public int getCalories() { return calories; } + public void setDateTime(LocalDateTime dateTime) { + this.dateTime = dateTime; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setCalories(int calories) { + this.calories = calories; + } + @Override public String toString() { return "UserMeal{" + diff --git a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserMealRepositoryImpl.java index 77c0ba8f639d..f0366d4c8564 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserMealRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserMealRepositoryImpl.java @@ -1,9 +1,18 @@ 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.RowMapper; +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.UserMeal; import ru.javawebinar.topjava.repository.UserMealRepository; +import javax.sql.DataSource; import java.time.LocalDateTime; import java.util.List; @@ -15,28 +24,68 @@ @Repository public class JdbcUserMealRepositoryImpl implements UserMealRepository { + private static final RowMapper ROW_MAPPER = BeanPropertyRowMapper.newInstance(UserMeal.class); + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Autowired + private NamedParameterJdbcTemplate namedParameterJdbcTemplate; + + private SimpleJdbcInsert insertUserMeal; + + @Autowired + public JdbcUserMealRepositoryImpl(DataSource dataSource) { + this.insertUserMeal = new SimpleJdbcInsert(dataSource) + .withTableName("meals") + .usingGeneratedKeyColumns("id"); + } + @Override - public UserMeal save(UserMeal UserMeal, int userId) { - return null; + public UserMeal save(UserMeal userMeal, int userId) { + MapSqlParameterSource map = new MapSqlParameterSource() + .addValue("id", userMeal.getId()) + .addValue("description", userMeal.getDescription()) + .addValue("calories", userMeal.getCalories()) + .addValue("date_time", userMeal.getDateTime()) + .addValue("user_id", userId); + + if (userMeal.isNew()) { + Number newId = insertUserMeal.executeAndReturnKey(map); + userMeal.setId(newId.intValue()); + } else { + if (namedParameterJdbcTemplate.update("" + + "UPDATE meals " + + " SET description=:description, calories=:calories, date_time=:date_time " + + " WHERE id=:id AND user_id=:user_id" + , map) == 0) { + return null; + } + } + return userMeal; } @Override public boolean delete(int id, int userId) { - return false; + return jdbcTemplate.update("DELETE FROM meals WHERE id=? AND user_id=?", id, userId) != 0; } @Override public UserMeal get(int id, int userId) { - return null; + List userMeals = jdbcTemplate.query( + "SELECT * FROM meals WHERE id = ? AND user_id = ?", ROW_MAPPER, id, userId); + return DataAccessUtils.singleResult(userMeals); } - @Override public List getAll(int userId) { - return null; + return jdbcTemplate.query( + "SELECT * FROM meals WHERE user_id=? ORDER BY date_time DESC", ROW_MAPPER, userId); } @Override public List getBetween(LocalDateTime startDate, LocalDateTime endDate, int userId) { - return null; + return jdbcTemplate.query( + "SELECT * FROM meals WHERE user_id=? AND date_time BETWEEN ? AND ? ORDER BY date_time DESC", + ROW_MAPPER, userId, startDate, endDate); } -} +} \ No newline at end of file diff --git a/src/main/resources/db/initDB.sql b/src/main/resources/db/initDB.sql index a0631c79567b..aede3736c9d0 100644 --- a/src/main/resources/db/initDB.sql +++ b/src/main/resources/db/initDB.sql @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS user_roles; +DROP TABLE IF EXISTS meals; DROP TABLE IF EXISTS users; DROP SEQUENCE IF EXISTS global_seq; @@ -23,3 +24,13 @@ CREATE TABLE user_roles CONSTRAINT user_roles_idx UNIQUE (user_id, role), FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE ); + +CREATE TABLE meals ( + id INTEGER PRIMARY KEY DEFAULT nextval('global_seq'), + user_id INTEGER NOT NULL, + date_time TIMESTAMP NOT NULL, + description TEXT NOT NULL, + calories INT NOT NULL, + FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE +); +CREATE UNIQUE INDEX meals_unique_user_datetime_idx ON meals(user_id, date_time) \ No newline at end of file diff --git a/src/main/resources/db/populateDB.sql b/src/main/resources/db/populateDB.sql index 199e2ace615d..0fbffd0dfb58 100644 --- a/src/main/resources/db/populateDB.sql +++ b/src/main/resources/db/populateDB.sql @@ -1,4 +1,5 @@ DELETE FROM user_roles; +DELETE FROM meals; DELETE FROM users; ALTER SEQUENCE global_seq RESTART WITH 100000; @@ -11,3 +12,13 @@ VALUES ('Admin', 'admin@gmail.com', 'admin'); INSERT INTO user_roles (role, user_id) VALUES ('ROLE_USER', 100000), ('ROLE_ADMIN', 100001); + +INSERT INTO meals (date_time, description, calories, user_id) VALUES + ('2015-05-30 10:00:00', 'Завтрак', 500, 100000), + ('2015-05-30 13:00:00', 'Обед', 1000, 100000), + ('2015-05-30 20:00:00', 'Ужин', 500, 100000), + ('2015-05-31 10:00:00', 'Завтрак', 500, 100000), + ('2015-05-31 13:00:00', 'Обед', 1000, 100000), + ('2015-05-31 20:00:00', 'Ужин', 510, 100000), + ('2015-06-01 14:00:00', 'Админ ланч', 510, 100001), + ('2015-06-01 21:00:00', 'Админ ужин', 1500, 100001); From 2b0489f4d8853f02bc64f5f1a4dba6b9ec7b367d Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Fri, 24 Jun 2016 20:33:19 +0300 Subject: [PATCH 36/76] prepare to HW4 --- pom.xml | 7 ++ .../ru/javawebinar/topjava/MealTestData.java | 28 ++++++ .../topjava/service/UserMealServiceTest.java | 92 +++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java diff --git a/pom.xml b/pom.xml index 9d5fb076404b..8eaca7d556c5 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,13 @@ ${java.version} + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + -Dfile.encoding=UTF-8 + + diff --git a/src/test/java/ru/javawebinar/topjava/MealTestData.java b/src/test/java/ru/javawebinar/topjava/MealTestData.java index ac44047caa52..997184b17814 100644 --- a/src/test/java/ru/javawebinar/topjava/MealTestData.java +++ b/src/test/java/ru/javawebinar/topjava/MealTestData.java @@ -3,6 +3,13 @@ import ru.javawebinar.topjava.matcher.ModelMatcher; import ru.javawebinar.topjava.model.UserMeal; +import java.time.Month; +import java.util.Arrays; +import java.util.List; + +import static java.time.LocalDateTime.of; +import static ru.javawebinar.topjava.model.BaseEntity.START_SEQ; + /** * GKislin * 13.03.2015. @@ -11,4 +18,25 @@ public class MealTestData { public static final ModelMatcher MATCHER = new ModelMatcher<>(UserMeal::toString); + public static final int MEAL1_ID = START_SEQ + 2; + public static final int ADMIN_MEAL_ID = START_SEQ + 8; + + public static final UserMeal MEAL1 = new UserMeal(MEAL1_ID, of(2015, Month.MAY, 30, 10, 0), "Завтрак", 500); + public static final UserMeal MEAL2 = new UserMeal(MEAL1_ID + 1, of(2015, Month.MAY, 30, 13, 0), "Обед", 1000); + public static final UserMeal MEAL3 = new UserMeal(MEAL1_ID + 2, of(2015, Month.MAY, 30, 20, 0), "Ужин", 500); + public static final UserMeal MEAL4 = new UserMeal(MEAL1_ID + 3, of(2015, Month.MAY, 31, 10, 0), "Завтрак", 500); + public static final UserMeal MEAL5 = new UserMeal(MEAL1_ID + 4, of(2015, Month.MAY, 31, 13, 0), "Обед", 1000); + public static final UserMeal MEAL6 = new UserMeal(MEAL1_ID + 5, of(2015, Month.MAY, 31, 20, 0), "Ужин", 510); + public static final UserMeal ADMIN_MEAL = new UserMeal(ADMIN_MEAL_ID, of(2015, Month.JUNE, 1, 14, 0), "Админ ланч", 510); + public static final UserMeal ADMIN_MEAL2 = new UserMeal(ADMIN_MEAL_ID + 1, of(2015, Month.JUNE, 1, 21, 0), "Админ ужин", 1500); + + public static final List USER_MEALS = Arrays.asList(MEAL6, MEAL5, MEAL4, MEAL3, MEAL2, MEAL1); + + public static UserMeal getCreated() { + return new UserMeal(null, of(2015, Month.JUNE, 1, 18, 0), "Созданный ужин", 300); + } + + public static UserMeal getUpdated() { + return new UserMeal(MEAL1_ID, MEAL1.getDateTime(), "Обновленный завтрак", 200); + } } diff --git a/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java new file mode 100644 index 000000000000..91ba08d6c015 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java @@ -0,0 +1,92 @@ +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.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import ru.javawebinar.topjava.MealTestData; +import ru.javawebinar.topjava.model.UserMeal; +import ru.javawebinar.topjava.util.DbPopulator; +import ru.javawebinar.topjava.util.exception.NotFoundException; + +import java.time.LocalDate; +import java.time.Month; +import java.util.Arrays; + +import static ru.javawebinar.topjava.MealTestData.*; +import static ru.javawebinar.topjava.UserTestData.ADMIN_ID; +import static ru.javawebinar.topjava.UserTestData.USER_ID; + +@ContextConfiguration({ + "classpath:spring/spring-app.xml", + "classpath:spring/spring-db.xml" +}) +@RunWith(SpringJUnit4ClassRunner.class) +public class UserMealServiceTest { + + @Autowired + protected UserMealService service; + + @Autowired + private DbPopulator dbPopulator; + + @Before + public void setUp() throws Exception { + dbPopulator.execute(); + } + + @Test + public void testDelete() throws Exception { + service.delete(MealTestData.MEAL1_ID, USER_ID); + MATCHER.assertCollectionEquals(Arrays.asList(MEAL6, MEAL5, MEAL4, MEAL3, MEAL2), service.getAll(USER_ID)); + } + + @Test(expected = NotFoundException.class) + public void testDeleteNotFound() throws Exception { + service.delete(MEAL1_ID, 1); + } + + @Test + public void testSave() throws Exception { + UserMeal created = getCreated(); + service.save(created, USER_ID); + MATCHER.assertCollectionEquals(Arrays.asList(created, MEAL6, MEAL5, MEAL4, MEAL3, MEAL2, MEAL1), service.getAll(USER_ID)); + } + + @Test + public void testGet() throws Exception { + UserMeal actual = service.get(ADMIN_MEAL_ID, ADMIN_ID); + MATCHER.assertEquals(ADMIN_MEAL, actual); + } + + @Test(expected = NotFoundException.class) + public void testGetNotFound() throws Exception { + service.get(MEAL1_ID, ADMIN_ID); + } + + @Test + public void testUpdate() throws Exception { + UserMeal updated = getUpdated(); + service.update(updated, USER_ID); + MATCHER.assertEquals(updated, service.get(MEAL1_ID, USER_ID)); + } + + @Test(expected = NotFoundException.class) + public void testNotFoundUpdate() throws Exception { + UserMeal item = service.get(MEAL1_ID, USER_ID); + service.update(item, ADMIN_ID); + } + + @Test + public void testGetAll() throws Exception { + MATCHER.assertCollectionEquals(USER_MEALS, service.getAll(USER_ID)); + } + + @Test + public void testGetBetween() throws Exception { + MATCHER.assertCollectionEquals(Arrays.asList(MEAL3, MEAL2, MEAL1), + service.getBetweenDates(LocalDate.of(2015, Month.MAY, 30), LocalDate.of(2015, Month.MAY, 30), USER_ID)); + } +} \ No newline at end of file From 5e0042f6cd077c3c33a1956adc76596ffe4c4c6d Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Sat, 25 Jun 2016 12:30:18 +0300 Subject: [PATCH 37/76] prepare to HW4 --- README.md | 2 ++ .../{LoggedUser.java => AuthorizedUser.java} | 4 ++-- .../ru/javawebinar/topjava/util/TimeUtil.java | 7 +++++-- .../topjava/util/exception/ExceptionUtil.java | 7 ++++++- .../javawebinar/topjava/web/UserServlet.java | 4 ++-- .../web/meal/UserMealRestController.java | 18 +++++++++--------- .../web/user/AbstractUserController.java | 14 +++++++------- .../web/user/ProfileRestController.java | 8 ++++---- .../mock/InMemoryUserMealRepositoryImpl.java | 7 ++++--- .../mock/InMemoryUserRepositoryImpl.java | 5 +++-- 10 files changed, 44 insertions(+), 32 deletions(-) rename src/main/java/ru/javawebinar/topjava/{LoggedUser.java => AuthorizedUser.java} (87%) diff --git a/README.md b/README.md index 7ae0bcb58ccd..95e35e52d3ae 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ Java Enterprise Online Project =============================== + +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/fd10a882fc3048a2bbdc5c347fa4fac3)](https://www.codacy.com/app/javawebinar/topjava07) Наиболее востребованные технологии /инструменты / фреймворки Java Enterprise: Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + plugins. diff --git a/src/main/java/ru/javawebinar/topjava/LoggedUser.java b/src/main/java/ru/javawebinar/topjava/AuthorizedUser.java similarity index 87% rename from src/main/java/ru/javawebinar/topjava/LoggedUser.java rename to src/main/java/ru/javawebinar/topjava/AuthorizedUser.java index 813658a2b4c9..d820cb585446 100644 --- a/src/main/java/ru/javawebinar/topjava/LoggedUser.java +++ b/src/main/java/ru/javawebinar/topjava/AuthorizedUser.java @@ -8,7 +8,7 @@ * GKislin * 06.03.2015. */ -public class LoggedUser { +public class AuthorizedUser { public static int id = BaseEntity.START_SEQ; public static int id() { @@ -16,7 +16,7 @@ public static int id() { } public static void setId(int id) { - LoggedUser.id = id; + AuthorizedUser.id = id; } public static int getCaloriesPerDay() { diff --git a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java index 9657c46ec949..c6951ab73506 100644 --- a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java @@ -12,17 +12,20 @@ * 07.01.2015. */ public class TimeUtil { - private static final DateTimeFormatter DATE_TME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); public static final LocalDate MIN_DATE = LocalDate.of(1, 1, 1); public static final LocalDate MAX_DATE = LocalDate.of(3000, 1, 1); + private TimeUtil() { + } + 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) { - return ldt == null ? "" : ldt.format(DATE_TME_FORMATTER); + return ldt == null ? "" : ldt.format(DATE_TIME_FORMATTER); } public static LocalDate parseLocalDate(String str) { diff --git a/src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java b/src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java index 254a7dba2b00..db860486466f 100644 --- a/src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java @@ -6,6 +6,9 @@ * Date: 14.05.2014 */ public class ExceptionUtil { + private ExceptionUtil() { + } + public static void checkNotFoundWithId(boolean found, int id) { checkNotFound(found, "id=" + id); } @@ -20,6 +23,8 @@ public static T checkNotFound(T object, String msg) { } public static void checkNotFound(boolean found, String msg) { - if (!found) throw new NotFoundException("Not found entity with " + msg); + if (!found) { + throw new NotFoundException("Not found entity with " + msg); + } } } diff --git a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java index 543b1e1e5200..9a528bfe5231 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 ru.javawebinar.topjava.LoggedUser; +import ru.javawebinar.topjava.AuthorizedUser; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -20,7 +20,7 @@ public class UserServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int userId = Integer.valueOf(request.getParameter("userId")); - LoggedUser.setId(userId); + AuthorizedUser.setId(userId); response.sendRedirect("meals"); } 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..919a7f92453d 100644 --- a/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java @@ -4,7 +4,7 @@ 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.AuthorizedUser; import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.service.UserMealService; import ru.javawebinar.topjava.to.UserMealWithExceed; @@ -27,45 +27,45 @@ public class UserMealRestController { private UserMealService service; public UserMeal get(int id) { - int userId = LoggedUser.id(); + int userId = AuthorizedUser.id(); LOG.info("get meal {} for User {}", id, userId); return service.get(id, userId); } public void delete(int id) { - int userId = LoggedUser.id(); + int userId = AuthorizedUser.id(); LOG.info("delete meal {} for User {}", id, userId); service.delete(id, userId); } public List getAll() { - int userId = LoggedUser.id(); + int userId = AuthorizedUser.id(); LOG.info("getAll for User {}", userId); - return UserMealsUtil.getWithExceeded(service.getAll(userId), LoggedUser.getCaloriesPerDay()); + return UserMealsUtil.getWithExceeded(service.getAll(userId), AuthorizedUser.getCaloriesPerDay()); } public void update(UserMeal meal, int id) { meal.setId(id); - int userId = LoggedUser.id(); + int userId = AuthorizedUser.id(); LOG.info("update {} for User {}", meal, userId); service.update(meal, userId); } public UserMeal create(UserMeal meal) { meal.setId(null); - int userId = LoggedUser.id(); + int userId = AuthorizedUser.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(); + int userId = AuthorizedUser.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() + startTime != null ? startTime : LocalTime.MIN, endTime != null ? endTime : LocalTime.MAX, AuthorizedUser.getCaloriesPerDay() ); } } \ No newline at end of file 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 e2b847678af2..c519e53e6bee 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java @@ -12,40 +12,40 @@ * User: gkislin */ public abstract class AbstractUserController { - protected final Logger LOG = LoggerFactory.getLogger(getClass()); + protected final Logger log = LoggerFactory.getLogger(getClass()); @Autowired private UserService service; public List getAll() { - LOG.info("getAll"); + log.info("getAll"); return service.getAll(); } public User get(int id) { - LOG.info("get " + id); + log.info("get " + id); return service.get(id); } public User create(User user) { user.setId(null); - LOG.info("create " + user); + log.info("create " + user); return service.save(user); } public void delete(int id) { - LOG.info("delete " + id); + log.info("delete " + id); service.delete(id); } public void update(User user, int id) { user.setId(id); - LOG.info("update " + user); + log.info("update " + user); service.update(user); } public User getByMail(String email) { - LOG.info("getByEmail " + email); + log.info("getByEmail " + email); return service.getByEmail(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 index 1114e57eeb1e..443db9c53263 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java @@ -1,7 +1,7 @@ package ru.javawebinar.topjava.web.user; import org.springframework.stereotype.Controller; -import ru.javawebinar.topjava.LoggedUser; +import ru.javawebinar.topjava.AuthorizedUser; import ru.javawebinar.topjava.model.User; /** @@ -12,14 +12,14 @@ public class ProfileRestController extends AbstractUserController { public User get() { - return super.get(LoggedUser.id()); + return super.get(AuthorizedUser.id()); } public void delete() { - super.delete(LoggedUser.id()); + super.delete(AuthorizedUser.id()); } public void update(User user) { - super.update(user, LoggedUser.id()); + super.update(user, AuthorizedUser.id()); } } \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java b/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java index 16fd3422e59a..89fca47e7f76 100644 --- a/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java +++ b/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java @@ -1,6 +1,7 @@ package ru.javawebinar.topjava.repository.mock; import org.springframework.stereotype.Repository; +import org.springframework.util.Assert; import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.repository.UserMealRepository; import ru.javawebinar.topjava.util.TimeUtil; @@ -38,7 +39,7 @@ public class InMemoryUserMealRepositoryImpl implements UserMealRepository { @Override public UserMeal save(UserMeal userMeal, int userId) { - Objects.requireNonNull(userMeal); + Assert.notNull(userMeal, "userMeal must not be null"); Integer mealId = userMeal.getId(); @@ -75,8 +76,8 @@ public Collection getAll(int userId) { @Override public Collection getBetween(LocalDateTime startDateTime, LocalDateTime endDateTime, int userId) { - Objects.requireNonNull(startDateTime); - Objects.requireNonNull(endDateTime); + Assert.notNull(startDateTime, "startDateTime must not be null"); + Assert.notNull(endDateTime, "endDateTime must not be null"); return getAll(userId).stream() .filter(um -> TimeUtil.isBetween(um.getDateTime(), startDateTime, endDateTime)) .collect(Collectors.toList()); diff --git a/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java b/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java index 6b1e658d5739..6dc64f249a8f 100644 --- a/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java +++ b/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java @@ -3,6 +3,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Repository; +import org.springframework.util.Assert; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.repository.UserRepository; @@ -31,7 +32,7 @@ public class InMemoryUserRepositoryImpl implements UserRepository { @Override public User save(User user) { - Objects.requireNonNull(user); + Assert.notNull(user, "user must not be null"); if (user.isNew()) { user.setId(counter.incrementAndGet()); } @@ -68,7 +69,7 @@ public List getAll() { @Override public User getByEmail(String email) { - Objects.requireNonNull(email); + Assert.notNull(email, "email must not be null"); return repository.values().stream() .filter(u -> email.equals(u.getEmail())) .findFirst() From c2174ce73c4a85e25775cbf32e340568d52a251d Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Sat, 25 Jun 2016 14:37:36 +0300 Subject: [PATCH 38/76] prepare to HW4 --- .../javawebinar/topjava/util/DbPopulator.java | 28 ------------------- src/main/resources/db/postgres.properties | 2 ++ src/main/resources/spring/spring-db.xml | 11 ++++---- .../topjava/service/UserMealServiceTest.java | 13 ++------- .../topjava/service/UserServiceTest.java | 13 ++------- 5 files changed, 14 insertions(+), 53 deletions(-) delete mode 100644 src/main/java/ru/javawebinar/topjava/util/DbPopulator.java diff --git a/src/main/java/ru/javawebinar/topjava/util/DbPopulator.java b/src/main/java/ru/javawebinar/topjava/util/DbPopulator.java deleted file mode 100644 index 8d4a6cc3c719..000000000000 --- a/src/main/java/ru/javawebinar/topjava/util/DbPopulator.java +++ /dev/null @@ -1,28 +0,0 @@ -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/db/postgres.properties b/src/main/resources/db/postgres.properties index 44dd64eb26b8..1b5ffc9c73b1 100644 --- a/src/main/resources/db/postgres.properties +++ b/src/main/resources/db/postgres.properties @@ -5,3 +5,5 @@ database.url=jdbc:postgresql://localhost:5432/topjava database.username=user database.password=password + +database.init=true diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index 051f225300cd..0e228352bad7 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -1,14 +1,15 @@ + http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd"> - - - + + + + Date: Sat, 25 Jun 2016 14:50:16 +0300 Subject: [PATCH 39/76] prepare to HW4 --- src/main/resources/spring/spring-app.xml | 2 -- src/main/resources/spring/spring-db.xml | 2 ++ src/test/java/ru/javawebinar/topjava/SpringMain.java | 2 +- .../topjava/web/InMemoryAdminRestControllerSpringTest.java | 2 +- .../topjava/web/InMemoryAdminRestControllerTest.java | 2 +- src/test/resources/spring/mock.xml | 7 +++++++ 6 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 src/test/resources/spring/mock.xml diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml index 04810da82e92..eff98648bc5a 100644 --- a/src/main/resources/spring/spring-app.xml +++ b/src/main/resources/spring/spring-app.xml @@ -14,8 +14,6 @@ - - diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index 0e228352bad7..a2c9da98e9f8 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -6,6 +6,8 @@ + + diff --git a/src/test/java/ru/javawebinar/topjava/SpringMain.java b/src/test/java/ru/javawebinar/topjava/SpringMain.java index 1e61564819e0..5a7e86e9751c 100644 --- a/src/test/java/ru/javawebinar/topjava/SpringMain.java +++ b/src/test/java/ru/javawebinar/topjava/SpringMain.java @@ -19,7 +19,7 @@ public class SpringMain { public static void main(String[] args) { // java 7 Automatic resource management - try (ConfigurableApplicationContext appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml")) { + try (ConfigurableApplicationContext appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml","spring/mock.xml")) { System.out.println(Arrays.toString(appCtx.getBeanDefinitionNames())); AdminRestController adminUserController = appCtx.getBean(AdminRestController.class); System.out.println(adminUserController.create(UserTestData.USER)); diff --git a/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerSpringTest.java b/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerSpringTest.java index 9396810afe48..a9125c6e4d96 100644 --- a/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerSpringTest.java +++ b/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerSpringTest.java @@ -22,7 +22,7 @@ * GKislin * 13.03.2015. */ -@ContextConfiguration("classpath:spring/spring-app.xml") +@ContextConfiguration({"classpath:spring/spring-app.xml", "classpath:spring/mock.xml"}) @RunWith(SpringJUnit4ClassRunner.class) public class InMemoryAdminRestControllerSpringTest { diff --git a/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerTest.java b/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerTest.java index becff75a3425..f7006200f781 100644 --- a/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerTest.java +++ b/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerTest.java @@ -21,7 +21,7 @@ public class InMemoryAdminRestControllerTest { @BeforeClass public static void beforeClass() { - appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml"); + appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml", "spring/mock.xml"); System.out.println("\n" + Arrays.toString(appCtx.getBeanDefinitionNames()) + "\n"); controller = appCtx.getBean(AdminRestController.class); } diff --git a/src/test/resources/spring/mock.xml b/src/test/resources/spring/mock.xml new file mode 100644 index 000000000000..c7c9f62cc5d8 --- /dev/null +++ b/src/test/resources/spring/mock.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file From 21bf37cdb006b2f38788634838a156d9d9ad21ed Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Wed, 29 Jun 2016 13:05:13 +0300 Subject: [PATCH 40/76] prepare to HW4 --- pom.xml | 28 +++++++- .../javawebinar/topjava/model/BaseEntity.java | 7 ++ .../topjava/model/NamedEntity.java | 8 +++ .../ru/javawebinar/topjava/model/User.java | 22 +++++++ .../javawebinar/topjava/model/UserMeal.java | 15 ++++- .../jpa/JpaUserMealRepositoryImpl.java | 42 ++++++++++++ .../repository/jpa/JpaUserRepositoryImpl.java | 65 +++++++++++++++++++ src/main/resources/db/postgres.properties | 4 ++ src/main/resources/spring/spring-db.xml | 29 ++++++++- 9 files changed, 215 insertions(+), 5 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserMealRepositoryImpl.java create mode 100644 src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java diff --git a/pom.xml b/pom.xml index 8eaca7d556c5..b054e57ca376 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,10 @@ 9.4.1208 4.12 + + + 5.1.0.Final + 5.2.4.Final @@ -128,10 +132,30 @@ org.springframework - spring-jdbc + spring-orm ${spring.version} - + + org.hibernate + hibernate-entitymanager + ${hibernate.version} + + + javax.transaction + jta + 1.1 + runtime + + + org.hibernate + hibernate-validator + ${hibernate-validator.version} + + + javax.el + javax.el-api + 2.2.5 + diff --git a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java index 892beb4c6281..007e260dcb68 100644 --- a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java +++ b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java @@ -1,12 +1,19 @@ package ru.javawebinar.topjava.model; +import javax.persistence.*; + /** * User: gkislin * Date: 22.08.2014 */ +@MappedSuperclass +@Access(AccessType.FIELD) public class BaseEntity { public static final int START_SEQ = 100000; + @Id + @SequenceGenerator(name = "global_seq", sequenceName = "global_seq", allocationSize = 1) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "global_seq") protected Integer id; public BaseEntity() { diff --git a/src/main/java/ru/javawebinar/topjava/model/NamedEntity.java b/src/main/java/ru/javawebinar/topjava/model/NamedEntity.java index ca92e394dc98..e593d37981e7 100644 --- a/src/main/java/ru/javawebinar/topjava/model/NamedEntity.java +++ b/src/main/java/ru/javawebinar/topjava/model/NamedEntity.java @@ -1,11 +1,19 @@ package ru.javawebinar.topjava.model; +import org.hibernate.validator.constraints.NotEmpty; + +import javax.persistence.Column; +import javax.persistence.MappedSuperclass; + /** * User: gkislin * Date: 22.08.2014 */ +@MappedSuperclass public class NamedEntity extends BaseEntity { + @NotEmpty + @Column(name = "name", nullable = false) protected String name; public NamedEntity() { diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index 22d746307bf4..2b6e4e0c25d7 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -2,6 +2,12 @@ import ru.javawebinar.topjava.util.UserMealsUtil; +import org.hibernate.validator.constraints.Email; +import org.hibernate.validator.constraints.Length; +import org.hibernate.validator.constraints.NotEmpty; + +import javax.persistence.*; +import javax.validation.constraints.Digits; import java.util.Date; import java.util.EnumSet; import java.util.Set; @@ -10,18 +16,34 @@ * User: gkislin * Date: 22.08.2014 */ +@Entity +@Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = "email", name = "users_unique_email_idx")}) public class User extends NamedEntity { + @Column(name = "email", nullable = false, unique = true) + @Email + @NotEmpty protected String email; + @Column(name = "password", nullable = false) + @NotEmpty + @Length(min = 5) protected String password; + @Column(name = "enabled", nullable = false) protected boolean enabled = true; + @Column(name = "registered", columnDefinition = "timestamp default now()") protected Date registered = new Date(); + @Enumerated(EnumType.STRING) + @CollectionTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id")) + @Column(name = "role") + @ElementCollection(fetch = FetchType.EAGER) protected Set roles; + @Column(name = "calories_per_day", columnDefinition = "default 2000") + @Digits(fraction = 0, integer = 4) protected int caloriesPerDay = UserMealsUtil.DEFAULT_CALORIES_PER_DAY; public User() { diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java index 28f585dbeb57..fd4bd3f481a3 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java @@ -1,5 +1,7 @@ package ru.javawebinar.topjava.model; +import javax.persistence.FetchType; +import javax.persistence.ManyToOne; import java.time.LocalDateTime; /** @@ -12,7 +14,10 @@ public class UserMeal extends BaseEntity { private String description; - private int calories; + protected int calories; + + @ManyToOne(fetch = FetchType.LAZY) + private User user; public UserMeal() { } @@ -52,6 +57,14 @@ public void setCalories(int calories) { this.calories = calories; } + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + @Override public String toString() { return "UserMeal{" + diff --git a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserMealRepositoryImpl.java new file mode 100644 index 000000000000..647a24eef180 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserMealRepositoryImpl.java @@ -0,0 +1,42 @@ +package ru.javawebinar.topjava.repository.jpa; + +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: gkisline + * Date: 26.08.2014 + */ + +@Repository +public class JpaUserMealRepositoryImpl 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; + } +} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java new file mode 100644 index 000000000000..b662bea948ba --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java @@ -0,0 +1,65 @@ +package ru.javawebinar.topjava.repository.jpa; + +import org.springframework.stereotype.Repository; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.repository.UserRepository; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.Query; +import java.util.List; + +/** + * User: gkislin + * Date: 29.08.2014 + */ +@Repository +public class JpaUserRepositoryImpl implements UserRepository { + +/* + @Autowired + private SessionFactory sessionFactory; + + private Session openSession() { + return sessionFactory.getCurrentSession(); + } +*/ + + @PersistenceContext + private EntityManager em; + + @Override + public User save(User user) { + if (user.isNew()) { + em.persist(user); + return user; + } else { + return em.merge(user); + } + } + + @Override + public User get(int id) { + return em.find(User.class, id); + } + + @Override + public boolean delete(int id) { + +/* User ref = em.getReference(User.class, id); + em.remove(ref); +*/ + Query query = em.createQuery("DELETE FROM User u WHERE u.id=:id"); + return query.setParameter("id", id).executeUpdate() != 0; + } + + @Override + public User getByEmail(String email) { + return null; + } + + @Override + public List getAll() { + return null; + } +} diff --git a/src/main/resources/db/postgres.properties b/src/main/resources/db/postgres.properties index 1b5ffc9c73b1..8fd375f6d74b 100644 --- a/src/main/resources/db/postgres.properties +++ b/src/main/resources/db/postgres.properties @@ -7,3 +7,7 @@ database.username=user database.password=password database.init=true + +jpa.showSql=true +hibernate.format_sql=true +hibernate.use_sql_comments=true diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index a2c9da98e9f8..250ed31cbc13 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -1,12 +1,14 @@ - + @@ -22,6 +24,28 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file From e7668306fa8c9d9ea35581477ac36a6fc3e3dba0 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Wed, 29 Jun 2016 13:08:25 +0300 Subject: [PATCH 41/76] prepare to HW4 --- .../ru/javawebinar/topjava/model/User.java | 9 ++++++ .../repository/jpa/JpaUserRepositoryImpl.java | 15 ++++++--- src/main/resources/spring/spring-db.xml | 31 ++++++++++++------- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index 2b6e4e0c25d7..8fc29ca0a4ce 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -16,10 +16,19 @@ * User: gkislin * Date: 22.08.2014 */ +@NamedQueries({ + @NamedQuery(name = User.DELETE, query = "DELETE FROM User u WHERE u.id=:id"), + @NamedQuery(name = User.BY_EMAIL, query = "SELECT u FROM User u LEFT JOIN FETCH u.roles WHERE u.email=?1"), + @NamedQuery(name = User.ALL_SORTED, query = "SELECT u FROM User u LEFT JOIN FETCH u.roles ORDER BY u.name, u.email"), +}) @Entity @Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = "email", name = "users_unique_email_idx")}) public class User extends NamedEntity { + public static final String DELETE = "User.delete"; + public static final String ALL_SORTED = "User.getAllSorted"; + public static final String BY_EMAIL = "User.getByEmail"; + @Column(name = "email", nullable = false, unique = true) @Email @NotEmpty diff --git a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java index b662bea948ba..2b4057f3a4b4 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java @@ -1,12 +1,12 @@ package ru.javawebinar.topjava.repository.jpa; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.repository.UserRepository; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; -import javax.persistence.Query; import java.util.List; /** @@ -14,6 +14,7 @@ * Date: 29.08.2014 */ @Repository +@Transactional(readOnly = true) public class JpaUserRepositoryImpl implements UserRepository { /* @@ -29,6 +30,7 @@ private Session openSession() { private EntityManager em; @Override + @Transactional public User save(User user) { if (user.isNew()) { em.persist(user); @@ -44,22 +46,25 @@ public User get(int id) { } @Override + @Transactional public boolean delete(int id) { /* User ref = em.getReference(User.class, id); em.remove(ref); -*/ - Query query = em.createQuery("DELETE FROM User u WHERE u.id=:id"); + + Query query = em.createQuery("DELETE FROM User u WHERE u.id=:id"); return query.setParameter("id", id).executeUpdate() != 0; +*/ + return em.createNamedQuery(User.DELETE).setParameter("id", id).executeUpdate() != 0; } @Override public User getByEmail(String email) { - return null; + return em.createNamedQuery(User.BY_EMAIL, User.class).setParameter(1, email).getSingleResult(); } @Override public List getAll() { - return null; + return em.createNamedQuery(User.ALL_SORTED, User.class).getResultList(); } } diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index 250ed31cbc13..bb44b36cb5f7 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -3,8 +3,11 @@ xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" - 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 http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd"> + xmlns:tx="http://www.springframework.org/schema/tx" + 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 + http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> @@ -44,14 +47,20 @@ - + + + + \ No newline at end of file From 10b18d42653fa693ec20246f5d1e302c07c500d5 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Wed, 29 Jun 2016 13:23:00 +0300 Subject: [PATCH 42/76] prepare to HW4 --- pom.xml | 6 ++++ src/main/resources/db/hsqldb.properties | 13 ++++++++ src/main/resources/db/initDB_hsql.sql | 37 +++++++++++++++++++++++ src/main/resources/db/postgres.properties | 2 ++ src/main/resources/spring/spring-db.xml | 7 +++-- 5 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/db/hsqldb.properties create mode 100644 src/main/resources/db/initDB_hsql.sql diff --git a/pom.xml b/pom.xml index b054e57ca376..198aa06d27ee 100644 --- a/pom.xml +++ b/pom.xml @@ -130,6 +130,12 @@ ${spring.version} test + + org.hsqldb + hsqldb + 2.3.4 + + org.springframework spring-orm diff --git a/src/main/resources/db/hsqldb.properties b/src/main/resources/db/hsqldb.properties new file mode 100644 index 000000000000..e879739f755a --- /dev/null +++ b/src/main/resources/db/hsqldb.properties @@ -0,0 +1,13 @@ +#database.url=jdbc:hsqldb:file:D:/temp/topjava +database.url=jdbc:hsqldb:mem:topjava + +database.username=sa +database.password= +database.driverClassName=org.hsqldb.jdbcDriver + +database.init=true + +jdbc.initLocation=initDB_hsql.sql +jpa.showSql=true +hibernate.format_sql=true +hibernate.use_sql_comments=true \ No newline at end of file diff --git a/src/main/resources/db/initDB_hsql.sql b/src/main/resources/db/initDB_hsql.sql new file mode 100644 index 000000000000..a2c615d7b6e7 --- /dev/null +++ b/src/main/resources/db/initDB_hsql.sql @@ -0,0 +1,37 @@ +DROP TABLE user_roles IF EXISTS; +DROP TABLE meals IF EXISTS; +DROP TABLE users IF EXISTS; +DROP SEQUENCE global_seq IF EXISTS; + +CREATE SEQUENCE GLOBAL_SEQ AS INTEGER START WITH 100000; + +CREATE TABLE users +( + id INTEGER GENERATED BY DEFAULT AS SEQUENCE GLOBAL_SEQ PRIMARY KEY, + name VARCHAR(255), + email VARCHAR(255) NOT NULL, + password VARCHAR(255) NOT NULL, + registered TIMESTAMP DEFAULT now(), + enabled BOOLEAN 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(255), + CONSTRAINT user_roles_idx UNIQUE (user_id, role), + FOREIGN KEY ( user_id ) REFERENCES USERS ( id ) ON DELETE CASCADE +); + +CREATE TABLE meals +( + id INTEGER GENERATED BY DEFAULT AS SEQUENCE GLOBAL_SEQ PRIMARY KEY, + date_time TIMESTAMP, + description VARCHAR(255), + calories INT, + user_id INTEGER NOT NULL, + FOREIGN KEY ( user_id ) REFERENCES USERS ( id ) ON DELETE CASCADE +); +CREATE UNIQUE INDEX meals_unique_user_datetime_idx ON meals(user_id, date_time) \ No newline at end of file diff --git a/src/main/resources/db/postgres.properties b/src/main/resources/db/postgres.properties index 8fd375f6d74b..9f8ed0164261 100644 --- a/src/main/resources/db/postgres.properties +++ b/src/main/resources/db/postgres.properties @@ -5,9 +5,11 @@ database.url=jdbc:postgresql://localhost:5432/topjava database.username=user database.password=password +database.driverClassName=org.postgresql.Driver database.init=true +jdbc.initLocation=initDB.sql jpa.showSql=true hibernate.format_sql=true hibernate.use_sql_comments=true diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index bb44b36cb5f7..ea1fdf6dd3b4 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -9,19 +9,22 @@ http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> + + + - + - + From 0b77128cce5e3c848f17ee2f88bbecc2a9626663 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 30 Jun 2016 14:04:20 +0300 Subject: [PATCH 43/76] prepared HW5 --- src/main/resources/db/initDB_hsql.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/db/initDB_hsql.sql b/src/main/resources/db/initDB_hsql.sql index a2c615d7b6e7..56f978ac3b03 100644 --- a/src/main/resources/db/initDB_hsql.sql +++ b/src/main/resources/db/initDB_hsql.sql @@ -28,9 +28,9 @@ CREATE TABLE user_roles CREATE TABLE meals ( id INTEGER GENERATED BY DEFAULT AS SEQUENCE GLOBAL_SEQ PRIMARY KEY, - date_time TIMESTAMP, - description VARCHAR(255), - calories INT, + date_time TIMESTAMP NOT NULL, + description VARCHAR(255) NOT NULL, + calories INT NOT NULL, user_id INTEGER NOT NULL, FOREIGN KEY ( user_id ) REFERENCES USERS ( id ) ON DELETE CASCADE ); From 27c66f9a5fc45a915e7ed5f306a3234161b7d08b Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 30 Jun 2016 15:24:01 +0300 Subject: [PATCH 44/76] prepared HW5 --- pom.xml | 5 +++ .../javawebinar/topjava/model/UserMeal.java | 30 ++++++++++++- .../jpa/JpaUserMealRepositoryImpl.java | 42 ++++++++++++++++--- .../topjava/service/UserMealServiceTest.java | 35 ++++++++++++++-- 4 files changed, 102 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index 198aa06d27ee..ad471ce8628e 100644 --- a/pom.xml +++ b/pom.xml @@ -146,6 +146,11 @@ hibernate-entitymanager ${hibernate.version} + + org.hibernate + hibernate-java8 + ${hibernate.version} + javax.transaction jta diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java index fd4bd3f481a3..efc12d6af885 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java @@ -1,22 +1,48 @@ package ru.javawebinar.topjava.model; -import javax.persistence.FetchType; -import javax.persistence.ManyToOne; +import org.hibernate.validator.constraints.NotEmpty; +import org.hibernate.validator.constraints.Range; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; import java.time.LocalDateTime; /** * GKislin * 11.01.2015. */ +@NamedQueries({ + @NamedQuery(name = UserMeal.GET, query = "SELECT m FROM UserMeal m WHERE m.id=:id AND m.user.id=:userId"), + @NamedQuery(name = UserMeal.ALL_SORTED, query = "SELECT m FROM UserMeal m WHERE m.user.id=:userId ORDER BY m.dateTime DESC"), + @NamedQuery(name = UserMeal.DELETE, query = "DELETE FROM UserMeal m WHERE m.id=:id AND m.user.id=:userId"), + @NamedQuery(name = UserMeal.GET_BETWEEN, query = "SELECT m FROM UserMeal m "+ + "WHERE m.user.id=:userId AND m.dateTime BETWEEN :startDate AND :endDate ORDER BY m.dateTime DESC"), + +// @NamedQuery(name = UserMeal.UPDATE, query = "UPDATE UserMeal m SET m.dateTime = :datetime, m.calories= :calories," + +// "m.description=:desc where m.id=:id and m.user.id=:userId") +}) +@Entity +@Table(name = "meals", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_id", "date_time"}, name = "meals_unique_user_datetime_idx")}) public class UserMeal extends BaseEntity { + public static final String GET = "UserMeal.get"; + public static final String ALL_SORTED = "UserMeal.getAll"; + public static final String DELETE = "UserMeal.delete"; + public static final String GET_BETWEEN = "UserMeal.getBetween"; + @Column(name = "date_time", nullable = false) + @NotNull private LocalDateTime dateTime; + @Column(name = "description", nullable = false) + @NotEmpty private String description; + @Column(name = "calories", nullable = false) + @Range(min = 10, max = 5000) protected int calories; @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) private User user; public UserMeal() { diff --git a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserMealRepositoryImpl.java index 647a24eef180..3e4ead5e0cda 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserMealRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserMealRepositoryImpl.java @@ -1,9 +1,14 @@ package ru.javawebinar.topjava.repository.jpa; +import org.springframework.dao.support.DataAccessUtils; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; +import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.repository.UserMealRepository; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; import java.time.LocalDateTime; import java.util.List; @@ -13,30 +18,57 @@ */ @Repository +@Transactional(readOnly = true) public class JpaUserMealRepositoryImpl implements UserMealRepository { + @PersistenceContext + private EntityManager em; + @Override + @Transactional public UserMeal save(UserMeal userMeal, int userId) { - return null; + if (!userMeal.isNew() && get(userMeal.getId(), userId) == null) { + return null; + } + userMeal.setUser(em.getReference(User.class, userId)); + if (userMeal.isNew()) { + em.persist(userMeal); + return userMeal; + } else { + return em.merge(userMeal); + } } @Override + @Transactional public boolean delete(int id, int userId) { - return false; + return em.createNamedQuery(UserMeal.DELETE) + .setParameter("id", id) + .setParameter("userId", userId) + .executeUpdate() != 0; } @Override public UserMeal get(int id, int userId) { - return null; + List userMeals = em.createNamedQuery(UserMeal.GET, UserMeal.class) + .setParameter("id", id) + .setParameter("userId", userId) + .getResultList(); + return DataAccessUtils.singleResult(userMeals); } @Override public List getAll(int userId) { - return null; + return em.createNamedQuery(UserMeal.ALL_SORTED, UserMeal.class) + .setParameter("userId", userId) + .getResultList(); } @Override public List getBetween(LocalDateTime startDate, LocalDateTime endDate, int userId) { - return null; + return em.createNamedQuery(UserMeal.GET_BETWEEN, UserMeal.class) + .setParameter("userId", userId) + .setParameter("startDate", startDate) + .setParameter("endDate", endDate).getResultList(); } } \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java index 9069c6759569..70af94e9f3ae 100644 --- a/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java @@ -1,7 +1,13 @@ package ru.javawebinar.topjava.service; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.rules.Stopwatch; +import org.junit.runner.Description; import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.jdbc.Sql; @@ -14,6 +20,7 @@ import java.time.LocalDate; import java.time.Month; import java.util.Arrays; +import java.util.concurrent.TimeUnit; import static ru.javawebinar.topjava.MealTestData.*; import static ru.javawebinar.topjava.UserTestData.ADMIN_ID; @@ -26,6 +33,24 @@ @RunWith(SpringJUnit4ClassRunner.class) @Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8")) public class UserMealServiceTest { + private static final Logger LOG = LoggerFactory.getLogger(UserMealServiceTest.class);; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Rule + // http://stackoverflow.com/questions/14892125/what-is-the-best-practice-to-determine-the-execution-time-of-the-bussiness-relev + public Stopwatch stopwatch = new Stopwatch() { + private void logInfo(Description description, long nanos) { + LOG.info(String.format("+++ Test %s spent %d ms", + description.getMethodName(), TimeUnit.NANOSECONDS.toMillis(nanos))); + } + + @Override + protected void finished(long nanos, Description description) { + logInfo(description, nanos); + } + }; @Autowired protected UserMealService service; @@ -36,8 +61,9 @@ public void testDelete() throws Exception { MATCHER.assertCollectionEquals(Arrays.asList(MEAL6, MEAL5, MEAL4, MEAL3, MEAL2), service.getAll(USER_ID)); } - @Test(expected = NotFoundException.class) + @Test public void testDeleteNotFound() throws Exception { + thrown.expect(NotFoundException.class); service.delete(MEAL1_ID, 1); } @@ -54,8 +80,9 @@ public void testGet() throws Exception { MATCHER.assertEquals(ADMIN_MEAL, actual); } - @Test(expected = NotFoundException.class) + @Test public void testGetNotFound() throws Exception { + thrown.expect(NotFoundException.class); service.get(MEAL1_ID, ADMIN_ID); } @@ -66,9 +93,11 @@ public void testUpdate() throws Exception { MATCHER.assertEquals(updated, service.get(MEAL1_ID, USER_ID)); } - @Test(expected = NotFoundException.class) + @Test public void testNotFoundUpdate() throws Exception { UserMeal item = service.get(MEAL1_ID, USER_ID); + thrown.expect(NotFoundException.class); + thrown.expectMessage("Not found entity with id=" + MEAL1_ID); service.update(item, ADMIN_ID); } From c23ff881f3e94d0a142a8f1cdacddd32fb29953f Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Mon, 4 Jul 2016 18:53:55 +0300 Subject: [PATCH 45/76] prepared HW5 --- pom.xml | 41 +++++++++++++------ .../java/ru/javawebinar/topjava/Profiles.java | 15 +++++++ src/main/resources/spring/spring-db.xml | 37 ++++++++++------- .../topjava/service/UserMealServiceTest.java | 3 ++ .../topjava/service/UserServiceTest.java | 3 ++ 5 files changed, 73 insertions(+), 26 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/Profiles.java diff --git a/pom.xml b/pom.xml index ad471ce8628e..ada5dcc52192 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,7 @@ UTF-8 UTF-8 + 8.0.33 4.2.6.RELEASE @@ -98,13 +99,6 @@ - - - org.postgresql - postgresql - ${postgresql.version} - - junit @@ -130,11 +124,6 @@ ${spring.version} test - - org.hsqldb - hsqldb - 2.3.4 - org.springframework @@ -170,6 +159,34 @@ + + hsqldb + + + org.hsqldb + hsqldb + 2.3.4 + + + + + postgres + + + org.postgresql + postgresql + ${postgresql.version} + + + org.apache.tomcat + tomcat-jdbc + ${tomcat.version} + + + + true + + diff --git a/src/main/java/ru/javawebinar/topjava/Profiles.java b/src/main/java/ru/javawebinar/topjava/Profiles.java new file mode 100644 index 000000000000..9826ef551b6a --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/Profiles.java @@ -0,0 +1,15 @@ +package ru.javawebinar.topjava; + +/** + * User: gkislin + * Date: 19.08.2014 + */ +public class Profiles { + public static final String + POSTGRES = "postgres", + HSQLDB = "hsqldb", + JDBC = "jdbc", + JPA = "jpa"; + + public static final String ACTIVE_DB = POSTGRES; +} diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index ea1fdf6dd3b4..cb1942675e8d 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -9,11 +9,6 @@ http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> - - - - - @@ -21,15 +16,6 @@ - - - - - - - - @@ -66,4 +52,27 @@ --> + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java index 70af94e9f3ae..0a613180c5f3 100644 --- a/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java @@ -9,11 +9,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.SqlConfig; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import ru.javawebinar.topjava.MealTestData; +import ru.javawebinar.topjava.Profiles; import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.util.exception.NotFoundException; @@ -32,6 +34,7 @@ }) @RunWith(SpringJUnit4ClassRunner.class) @Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8")) +@ActiveProfiles(Profiles.ACTIVE_DB) public class UserMealServiceTest { private static final Logger LOG = LoggerFactory.getLogger(UserMealServiceTest.class);; diff --git a/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java index e3e37e8dce48..591ea3b2fc9e 100644 --- a/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java @@ -4,10 +4,12 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.SqlConfig; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import ru.javawebinar.topjava.Profiles; import ru.javawebinar.topjava.UserTestData.*; import ru.javawebinar.topjava.model.Role; import ru.javawebinar.topjava.model.User; @@ -25,6 +27,7 @@ }) @RunWith(SpringJUnit4ClassRunner.class) @Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8")) +@ActiveProfiles(Profiles.ACTIVE_DB) public class UserServiceTest { @Autowired From c90b55ad18267a18ea167fcedea8ec940598d140 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 5 Jul 2016 18:17:31 +0300 Subject: [PATCH 46/76] prepared HW5 --- pom.xml | 16 +++++-- .../DataJpaUserMealRepositoryImpl.java | 40 ++++++++++++++++ .../datajpa/DataJpaUserRepositoryImpl.java | 47 +++++++++++++++++++ .../datajpa/ProxyUserRepository.java | 37 +++++++++++++++ src/main/resources/spring/spring-db.xml | 16 ++++++- 5 files changed, 151 insertions(+), 5 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserMealRepositoryImpl.java create mode 100644 src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java create mode 100644 src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java diff --git a/pom.xml b/pom.xml index ada5dcc52192..34a37b1812f6 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,7 @@ UTF-8 UTF-8 + 1.10.2.RELEASE 8.0.33 4.2.6.RELEASE @@ -126,9 +127,9 @@ - org.springframework - spring-orm - ${spring.version} + org.springframework.data + spring-data-jpa + ${spring-data-jpa.version} org.hibernate @@ -190,5 +191,14 @@ + + + org.springframework + spring-framework-bom + ${spring.version} + pom + import + + diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserMealRepositoryImpl.java new file mode 100644 index 000000000000..3069deb03861 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserMealRepositoryImpl.java @@ -0,0 +1,40 @@ +package ru.javawebinar.topjava.repository.datajpa; + +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; + +/** + * GKislin + * 27.03.2015. + */ +@Repository +public class DataJpaUserMealRepositoryImpl 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/repository/datajpa/DataJpaUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java new file mode 100644 index 000000000000..139946a33baa --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java @@ -0,0 +1,47 @@ +package ru.javawebinar.topjava.repository.datajpa; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Repository; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.repository.UserRepository; + +import java.util.List; + +/** + * GKislin + * 27.03.2015. + */ + +@Repository +public class DataJpaUserRepositoryImpl implements UserRepository { + private static final Sort SORT_NAME_EMAIL = new Sort("name", "email"); + + @Autowired + private ProxyUserRepository proxy; + + @Override + public User save(User user) { + return proxy.save(user); + } + + @Override + public boolean delete(int id) { + return proxy.delete(id) != 0; + } + + @Override + public User get(int id) { + return proxy.findOne(id); + } + + @Override + public User getByEmail(String email) { + return proxy.getByEmail(email); + } + + @Override + public List getAll() { + return proxy.findAll(SORT_NAME_EMAIL); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java new file mode 100644 index 000000000000..092d847f2bb0 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java @@ -0,0 +1,37 @@ +package ru.javawebinar.topjava.repository.datajpa; + +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.transaction.annotation.Transactional; +import ru.javawebinar.topjava.model.User; + +import java.util.List; + +/** + * GKislin + * 27.03.2015. + */ +@Transactional(readOnly = true) +public interface ProxyUserRepository extends JpaRepository { + + @Transactional + @Modifying +// @Query(name = User.DELETE) + @Query("DELETE FROM User u WHERE u.id=:id") + int delete(@Param("id") int id); + + @Override + @Transactional + User save(User user); + + @Override + User findOne(Integer id); + + @Override + List findAll(Sort sort); + + User getByEmail(String email); +} diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index cb1942675e8d..878b153f2f71 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -4,12 +4,17 @@ xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx" + xmlns:jpa="http://www.springframework.org/schema/data/jpa" 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 http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd - http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd + http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> - + + + + @@ -75,4 +80,11 @@ p:username="${database.username}" p:password="${database.password}"/> + + + + + + + \ No newline at end of file From e911fdde8225257441a162f0f5aa8f4d938c025e Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 5 Jul 2016 19:18:52 +0300 Subject: [PATCH 47/76] prepared HW5 --- pom.xml | 12 +- .../topjava/service/UserService.java | 2 + .../topjava/service/UserServiceImpl.java | 13 + src/main/resources/cache/ehcache.xml | 28 ++ src/main/resources/cache/ehcache.xsd | 419 ++++++++++++++++++ src/main/resources/spring/spring-app.xml | 1 + src/main/resources/spring/spring-tools.xml | 24 + .../topjava/service/UserServiceTest.java | 6 + 8 files changed, 504 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/cache/ehcache.xml create mode 100644 src/main/resources/cache/ehcache.xsd create mode 100644 src/main/resources/spring/spring-tools.xml diff --git a/pom.xml b/pom.xml index 34a37b1812f6..c4760b1bb18d 100644 --- a/pom.xml +++ b/pom.xml @@ -32,6 +32,9 @@ 5.1.0.Final 5.2.4.Final + + + 2.10.2.2.21 @@ -90,7 +93,7 @@ org.springframework - spring-context + spring-context-support ${spring.version} @@ -152,6 +155,13 @@ hibernate-validator ${hibernate-validator.version} + + + net.sf.ehcache + ehcache + ${ehcache.version} + + javax.el javax.el-api diff --git a/src/main/java/ru/javawebinar/topjava/service/UserService.java b/src/main/java/ru/javawebinar/topjava/service/UserService.java index 85c15e48f951..080b94b93c93 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserService.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserService.java @@ -23,4 +23,6 @@ public interface UserService { List getAll(); void update(User user); + + void evictCache(); } diff --git a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java index 77782de1784e..c9dedc20e2e4 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java @@ -1,6 +1,8 @@ package ru.javawebinar.topjava.service; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.repository.UserRepository; @@ -8,6 +10,7 @@ import ru.javawebinar.topjava.util.exception.NotFoundException; import java.util.List; +import java.util.Objects; /** * GKislin @@ -19,10 +22,12 @@ public class UserServiceImpl implements UserService { @Autowired private UserRepository repository; + @CacheEvict(value = "users", allEntries = true) public User save(User user) { return repository.save(user); } + @CacheEvict(value = "users", allEntries = true) public void delete(int id) { ExceptionUtil.checkNotFoundWithId(repository.delete(id), id); } @@ -32,14 +37,22 @@ public User get(int id) throws NotFoundException { } public User getByEmail(String email) throws NotFoundException { + Objects.requireNonNull(email, "Email must not be empty"); return ExceptionUtil.checkNotFound(repository.getByEmail(email), "email=" + email); } + @Cacheable("users") public List getAll() { return repository.getAll(); } + @CacheEvict(value = "users", allEntries = true) public void update(User user) { repository.save(user); } + + @CacheEvict(value = "users", allEntries = true) + @Override + public void evictCache() { + } } diff --git a/src/main/resources/cache/ehcache.xml b/src/main/resources/cache/ehcache.xml new file mode 100644 index 000000000000..8d420010d88d --- /dev/null +++ b/src/main/resources/cache/ehcache.xml @@ -0,0 +1,28 @@ + + + + + + + + + + diff --git a/src/main/resources/cache/ehcache.xsd b/src/main/resources/cache/ehcache.xsd new file mode 100644 index 000000000000..bfc19ddb1e7d --- /dev/null +++ b/src/main/resources/cache/ehcache.xsd @@ -0,0 +1,419 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml index eff98648bc5a..fbf54e789877 100644 --- a/src/main/resources/spring/spring-app.xml +++ b/src/main/resources/spring/spring-app.xml @@ -11,6 +11,7 @@ --> + diff --git a/src/main/resources/spring/spring-tools.xml b/src/main/resources/spring/spring-tools.xml new file mode 100644 index 000000000000..784de2d79e20 --- /dev/null +++ b/src/main/resources/spring/spring-tools.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java index 591ea3b2fc9e..e6b41bd9fd35 100644 --- a/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java @@ -1,5 +1,6 @@ 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; @@ -33,6 +34,11 @@ public class UserServiceTest { @Autowired protected UserService service; + @Before + public void setUp() throws Exception { + service.evictCache(); + } + @Test public void testSave() throws Exception { TestUser tu = new TestUser(null, "New", "new@gmail.com", "newPass", 1555, false, Collections.singleton(Role.ROLE_USER)); From 3965ecd69bf64ca9c5e5b8795fa68c4059e55633 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 7 Jul 2016 16:07:09 +0300 Subject: [PATCH 48/76] prepare to HW6 --- src/main/java/ru/javawebinar/topjava/model/User.java | 2 +- .../repository/datajpa/DataJpaUserRepositoryImpl.java | 4 +--- .../topjava/repository/datajpa/ProxyUserRepository.java | 5 ++--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index 8fc29ca0a4ce..7f48d431f522 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -48,7 +48,7 @@ public class User extends NamedEntity { @Enumerated(EnumType.STRING) @CollectionTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id")) @Column(name = "role") - @ElementCollection(fetch = FetchType.EAGER) + @ElementCollection(fetch = FetchType.LAZY) protected Set roles; @Column(name = "calories_per_day", columnDefinition = "default 2000") diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java index 139946a33baa..514dabb1e5cd 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java @@ -1,7 +1,6 @@ package ru.javawebinar.topjava.repository.datajpa; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Sort; import org.springframework.stereotype.Repository; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.repository.UserRepository; @@ -15,7 +14,6 @@ @Repository public class DataJpaUserRepositoryImpl implements UserRepository { - private static final Sort SORT_NAME_EMAIL = new Sort("name", "email"); @Autowired private ProxyUserRepository proxy; @@ -42,6 +40,6 @@ public User getByEmail(String email) { @Override public List getAll() { - return proxy.findAll(SORT_NAME_EMAIL); + return proxy.findAll(); } } diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java index 092d847f2bb0..25235734f438 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java @@ -1,6 +1,5 @@ package ru.javawebinar.topjava.repository.datajpa; -import org.springframework.data.domain.Sort; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -19,7 +18,6 @@ public interface ProxyUserRepository extends JpaRepository { @Transactional @Modifying -// @Query(name = User.DELETE) @Query("DELETE FROM User u WHERE u.id=:id") int delete(@Param("id") int id); @@ -31,7 +29,8 @@ public interface ProxyUserRepository extends JpaRepository { User findOne(Integer id); @Override - List findAll(Sort sort); + @Query("SELECT u FROM User u LEFT JOIN FETCH u.roles ORDER BY u.name, u.email") + List findAll(); User getByEmail(String email); } From d6e1fcfc6a84a43577cdfe2985b44dde6f9c65aa Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 7 Jul 2016 16:11:58 +0300 Subject: [PATCH 49/76] prepare to HW6 --- .../javawebinar/topjava/model/UserMeal.java | 3 +- .../DataJpaUserMealRepositoryImpl.java | 25 ++++++++++---- .../datajpa/ProxyUserMealRepository.java | 33 +++++++++++++++++++ src/main/resources/logback.xml | 3 ++ src/test/resources/logback-test.xml | 2 +- 5 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java index efc12d6af885..50dfb34f4259 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java @@ -11,6 +11,7 @@ * GKislin * 11.01.2015. */ +@SuppressWarnings("JpaQlInspection") @NamedQueries({ @NamedQuery(name = UserMeal.GET, query = "SELECT m FROM UserMeal m WHERE m.id=:id AND m.user.id=:userId"), @NamedQuery(name = UserMeal.ALL_SORTED, query = "SELECT m FROM UserMeal m WHERE m.user.id=:userId ORDER BY m.dateTime DESC"), @@ -100,4 +101,4 @@ public String toString() { ", calories=" + calories + '}'; } -} +} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserMealRepositoryImpl.java index 3069deb03861..520325efc76a 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserMealRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserMealRepositoryImpl.java @@ -1,6 +1,8 @@ package ru.javawebinar.topjava.repository.datajpa; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.repository.UserMealRepository; @@ -12,29 +14,40 @@ * 27.03.2015. */ @Repository -public class DataJpaUserMealRepositoryImpl implements UserMealRepository{ +public class DataJpaUserMealRepositoryImpl implements UserMealRepository { + @Autowired + private ProxyUserMealRepository proxy; + + @Autowired + private ProxyUserRepository userProxy; + @Override + @Transactional public UserMeal save(UserMeal userMeal, int userId) { - return null; + if (!userMeal.isNew() && get(userMeal.getId(), userId) == null) { + return null; + } + userMeal.setUser(userProxy.getOne(userId)); + return proxy.save(userMeal); } @Override public boolean delete(int id, int userId) { - return false; + return proxy.delete(id, userId) != 0; } @Override public UserMeal get(int id, int userId) { - return null; + return proxy.get(id, userId); } @Override public List getAll(int userId) { - return null; + return proxy.getAll(userId); } @Override public List getBetween(LocalDateTime startDate, LocalDateTime endDate, int userId) { - return null; + return proxy.getBetween(startDate, endDate, userId); } } diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java new file mode 100644 index 000000000000..6aa835840e6c --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java @@ -0,0 +1,33 @@ +package ru.javawebinar.topjava.repository.datajpa; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.transaction.annotation.Transactional; +import ru.javawebinar.topjava.model.UserMeal; + +import java.time.LocalDateTime; +import java.util.List; + +@Transactional(readOnly = true) +public interface ProxyUserMealRepository extends JpaRepository { + + @Modifying + @Transactional + @Query("DELETE FROM UserMeal m WHERE m.id=:id AND m.user.id=:userId") + int delete(@Param("id") int id, @Param("userId") int userId); + + @Override + UserMeal save(UserMeal item); + + @Query("SELECT m FROM UserMeal m WHERE m.id=:id AND m.user.id=:userId") + UserMeal get(@Param("id") int id, @Param("userId") int userId); + + @Query("SELECT m FROM UserMeal m WHERE m.user.id=:userId ORDER BY m.dateTime DESC") + List getAll(@Param("userId") int userId); + + @SuppressWarnings("JpaQlInspection") + @Query("SELECT m from UserMeal m WHERE m.user.id=:userId AND m.dateTime BETWEEN :startDate AND :endDate ORDER BY m.dateTime DESC") + List getBetween(@Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate, @Param("userId") int userId); +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 8ee5f21b023e..198d5663f852 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -26,6 +26,9 @@ + + + diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 80c38026d409..661579943554 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -11,7 +11,7 @@ - + From b95ef344185d06d2d6895214ded6b716585d0d12 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 7 Jul 2016 16:16:15 +0300 Subject: [PATCH 50/76] prepare to HW6 --- .../java/ru/javawebinar/topjava/Profiles.java | 4 +- src/main/resources/spring/spring-db.xml | 88 ++++++++++--------- 2 files changed, 48 insertions(+), 44 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/Profiles.java b/src/main/java/ru/javawebinar/topjava/Profiles.java index 9826ef551b6a..4ce31d6f690a 100644 --- a/src/main/java/ru/javawebinar/topjava/Profiles.java +++ b/src/main/java/ru/javawebinar/topjava/Profiles.java @@ -9,7 +9,9 @@ public class Profiles { POSTGRES = "postgres", HSQLDB = "hsqldb", JDBC = "jdbc", - JPA = "jpa"; + JPA = "jpa", + DATAJPA = "datajpa"; public static final String ACTIVE_DB = POSTGRES; + public static final String DB_IMPLEMENTATION = DATAJPA; } diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index 878b153f2f71..aad9a4d97418 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -11,52 +11,12 @@ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -64,7 +24,7 @@ @@ -75,16 +35,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From e962d35d6fcc2d38812866f1b1dd0e43a85aca1f Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Thu, 7 Jul 2016 16:27:13 +0300 Subject: [PATCH 51/76] prepare to HW6 --- .../topjava/service/AbstractServiceTest.java | 50 +++++++++++++++++++ ....java => AbstractUserMealServiceTest.java} | 44 +--------------- ...Test.java => AbstractUserServiceTest.java} | 18 +------ .../datajpa/DataJpaUserMealServiceTest.java | 10 ++++ .../datajpa/DataJpaUserServiceTest.java | 10 ++++ .../service/jdbc/JdbcUserMealServiceTest.java | 10 ++++ .../service/jdbc/JdbcUserServiceTest.java | 10 ++++ .../service/jpa/JpaUserMealServiceTest.java | 10 ++++ .../service/jpa/JpaUserServiceTest.java | 10 ++++ 9 files changed, 114 insertions(+), 58 deletions(-) create mode 100644 src/test/java/ru/javawebinar/topjava/service/AbstractServiceTest.java rename src/test/java/ru/javawebinar/topjava/service/{UserMealServiceTest.java => AbstractUserMealServiceTest.java} (57%) rename src/test/java/ru/javawebinar/topjava/service/{UserServiceTest.java => AbstractUserServiceTest.java} (78%) create mode 100644 src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserMealServiceTest.java create mode 100644 src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserServiceTest.java create mode 100644 src/test/java/ru/javawebinar/topjava/service/jdbc/JdbcUserMealServiceTest.java create mode 100644 src/test/java/ru/javawebinar/topjava/service/jdbc/JdbcUserServiceTest.java create mode 100644 src/test/java/ru/javawebinar/topjava/service/jpa/JpaUserMealServiceTest.java create mode 100644 src/test/java/ru/javawebinar/topjava/service/jpa/JpaUserServiceTest.java diff --git a/src/test/java/ru/javawebinar/topjava/service/AbstractServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractServiceTest.java new file mode 100644 index 000000000000..6548d1e8d644 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/service/AbstractServiceTest.java @@ -0,0 +1,50 @@ +package ru.javawebinar.topjava.service; + +import org.junit.Rule; +import org.junit.rules.ExpectedException; +import org.junit.rules.Stopwatch; +import org.junit.runner.Description; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.jdbc.SqlConfig; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.concurrent.TimeUnit; + +import static ru.javawebinar.topjava.Profiles.ACTIVE_DB; + +/** + * User: gkislin + */ +@ContextConfiguration({ + "classpath:spring/spring-app.xml", + "classpath:spring/spring-db.xml" +}) +@RunWith(SpringJUnit4ClassRunner.class) +@ActiveProfiles(ACTIVE_DB) +@Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8")) +abstract public class AbstractServiceTest { + + protected final Logger log = LoggerFactory.getLogger(getClass()); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Rule + // http://stackoverflow.com/questions/14892125/what-is-the-best-practice-to-determine-the-execution-time-of-the-bussiness-relev + public Stopwatch stopwatch = new Stopwatch() { + private void logInfo(Description description, long nanos) { + log.info(String.format("+++ Test %s spent %d microseconds", + description.getMethodName(), TimeUnit.NANOSECONDS.toMicros(nanos))); + } + + @Override + protected void finished(long nanos, Description description) { + logInfo(description, nanos); + } + }; +} diff --git a/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractUserMealServiceTest.java similarity index 57% rename from src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java rename to src/test/java/ru/javawebinar/topjava/service/AbstractUserMealServiceTest.java index 0a613180c5f3..2385804f8eb7 100644 --- a/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/AbstractUserMealServiceTest.java @@ -1,66 +1,26 @@ package ru.javawebinar.topjava.service; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.Stopwatch; -import org.junit.runner.Description; -import org.junit.runner.RunWith; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.jdbc.SqlConfig; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import ru.javawebinar.topjava.MealTestData; -import ru.javawebinar.topjava.Profiles; import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.util.exception.NotFoundException; import java.time.LocalDate; import java.time.Month; import java.util.Arrays; -import java.util.concurrent.TimeUnit; import static ru.javawebinar.topjava.MealTestData.*; import static ru.javawebinar.topjava.UserTestData.ADMIN_ID; import static ru.javawebinar.topjava.UserTestData.USER_ID; -@ContextConfiguration({ - "classpath:spring/spring-app.xml", - "classpath:spring/spring-db.xml" -}) -@RunWith(SpringJUnit4ClassRunner.class) -@Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8")) -@ActiveProfiles(Profiles.ACTIVE_DB) -public class UserMealServiceTest { - private static final Logger LOG = LoggerFactory.getLogger(UserMealServiceTest.class);; - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @Rule - // http://stackoverflow.com/questions/14892125/what-is-the-best-practice-to-determine-the-execution-time-of-the-bussiness-relev - public Stopwatch stopwatch = new Stopwatch() { - private void logInfo(Description description, long nanos) { - LOG.info(String.format("+++ Test %s spent %d ms", - description.getMethodName(), TimeUnit.NANOSECONDS.toMillis(nanos))); - } - - @Override - protected void finished(long nanos, Description description) { - logInfo(description, nanos); - } - }; +abstract public class AbstractUserMealServiceTest extends AbstractServiceTest { @Autowired protected UserMealService service; @Test public void testDelete() throws Exception { - service.delete(MealTestData.MEAL1_ID, USER_ID); + service.delete(MEAL1_ID, USER_ID); MATCHER.assertCollectionEquals(Arrays.asList(MEAL6, MEAL5, MEAL4, MEAL3, MEAL2), service.getAll(USER_ID)); } diff --git a/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java similarity index 78% rename from src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java rename to src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java index e6b41bd9fd35..0752fdbb225b 100644 --- a/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java @@ -2,15 +2,8 @@ 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.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.jdbc.SqlConfig; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import ru.javawebinar.topjava.Profiles; import ru.javawebinar.topjava.UserTestData.*; import ru.javawebinar.topjava.model.Role; import ru.javawebinar.topjava.model.User; @@ -22,14 +15,7 @@ import static ru.javawebinar.topjava.UserTestData.*; -@ContextConfiguration({ - "classpath:spring/spring-app.xml", - "classpath:spring/spring-db.xml" -}) -@RunWith(SpringJUnit4ClassRunner.class) -@Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8")) -@ActiveProfiles(Profiles.ACTIVE_DB) -public class UserServiceTest { +abstract public class AbstractUserServiceTest extends AbstractServiceTest { @Autowired protected UserService service; @@ -38,7 +24,7 @@ public class UserServiceTest { public void setUp() throws Exception { service.evictCache(); } - + @Test public void testSave() throws Exception { TestUser tu = new TestUser(null, "New", "new@gmail.com", "newPass", 1555, false, Collections.singleton(Role.ROLE_USER)); diff --git a/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserMealServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserMealServiceTest.java new file mode 100644 index 000000000000..b2252cc6cff4 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserMealServiceTest.java @@ -0,0 +1,10 @@ +package ru.javawebinar.topjava.service.datajpa; + +import org.springframework.test.context.ActiveProfiles; +import ru.javawebinar.topjava.service.AbstractUserMealServiceTest; + +import static ru.javawebinar.topjava.Profiles.DATAJPA; + +@ActiveProfiles(DATAJPA) +public class DataJpaUserMealServiceTest extends AbstractUserMealServiceTest { +} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserServiceTest.java new file mode 100644 index 000000000000..a0757e739339 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserServiceTest.java @@ -0,0 +1,10 @@ +package ru.javawebinar.topjava.service.datajpa; + +import org.springframework.test.context.ActiveProfiles; +import ru.javawebinar.topjava.service.AbstractUserServiceTest; + +import static ru.javawebinar.topjava.Profiles.DATAJPA; + +@ActiveProfiles(DATAJPA) +public class DataJpaUserServiceTest extends AbstractUserServiceTest { +} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/service/jdbc/JdbcUserMealServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/jdbc/JdbcUserMealServiceTest.java new file mode 100644 index 000000000000..d310717c67a5 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/service/jdbc/JdbcUserMealServiceTest.java @@ -0,0 +1,10 @@ +package ru.javawebinar.topjava.service.jdbc; + +import org.springframework.test.context.ActiveProfiles; +import ru.javawebinar.topjava.service.AbstractUserMealServiceTest; + +import static ru.javawebinar.topjava.Profiles.JDBC; + +@ActiveProfiles(JDBC) +public class JdbcUserMealServiceTest extends AbstractUserMealServiceTest { +} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/service/jdbc/JdbcUserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/jdbc/JdbcUserServiceTest.java new file mode 100644 index 000000000000..419f68ed1098 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/service/jdbc/JdbcUserServiceTest.java @@ -0,0 +1,10 @@ +package ru.javawebinar.topjava.service.jdbc; + +import org.springframework.test.context.ActiveProfiles; +import ru.javawebinar.topjava.service.AbstractUserServiceTest; + +import static ru.javawebinar.topjava.Profiles.JDBC; + +@ActiveProfiles(JDBC) +public class JdbcUserServiceTest extends AbstractUserServiceTest { +} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/service/jpa/JpaUserMealServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/jpa/JpaUserMealServiceTest.java new file mode 100644 index 000000000000..778235ed8ef0 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/service/jpa/JpaUserMealServiceTest.java @@ -0,0 +1,10 @@ +package ru.javawebinar.topjava.service.jpa; + +import org.springframework.test.context.ActiveProfiles; +import ru.javawebinar.topjava.service.AbstractUserMealServiceTest; + +import static ru.javawebinar.topjava.Profiles.JPA; + +@ActiveProfiles(JPA) +public class JpaUserMealServiceTest extends AbstractUserMealServiceTest { +} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/service/jpa/JpaUserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/jpa/JpaUserServiceTest.java new file mode 100644 index 000000000000..d1b3e4699785 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/service/jpa/JpaUserServiceTest.java @@ -0,0 +1,10 @@ +package ru.javawebinar.topjava.service.jpa; + +import org.springframework.test.context.ActiveProfiles; +import ru.javawebinar.topjava.service.AbstractUserServiceTest; + +import static ru.javawebinar.topjava.Profiles.JPA; + +@ActiveProfiles(JPA) +public class JpaUserServiceTest extends AbstractUserServiceTest { +} \ No newline at end of file From 91bc473978b4e94e8f5542a2220f8c756f7f8718 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Fri, 8 Jul 2016 15:24:48 +0300 Subject: [PATCH 52/76] prepare to HW6 --- ...> AbstractJdbcUserMealRepositoryImpl.java} | 25 +++++++------- .../jdbc/Java8JdbcUserMealRepositoryImpl.java | 31 +++++++++++++++++ .../TimestampJdbcUserMealRepositoryImpl.java | 34 +++++++++++++++++++ 3 files changed, 77 insertions(+), 13 deletions(-) rename src/main/java/ru/javawebinar/topjava/repository/jdbc/{JdbcUserMealRepositoryImpl.java => AbstractJdbcUserMealRepositoryImpl.java} (83%) create mode 100644 src/main/java/ru/javawebinar/topjava/repository/jdbc/Java8JdbcUserMealRepositoryImpl.java create mode 100644 src/main/java/ru/javawebinar/topjava/repository/jdbc/TimestampJdbcUserMealRepositoryImpl.java diff --git a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jdbc/AbstractJdbcUserMealRepositoryImpl.java similarity index 83% rename from src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserMealRepositoryImpl.java rename to src/main/java/ru/javawebinar/topjava/repository/jdbc/AbstractJdbcUserMealRepositoryImpl.java index f0366d4c8564..d60ffa64157a 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserMealRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/jdbc/AbstractJdbcUserMealRepositoryImpl.java @@ -2,13 +2,11 @@ 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.RowMapper; 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.UserMeal; import ru.javawebinar.topjava.repository.UserMealRepository; @@ -21,10 +19,11 @@ * Date: 26.08.2014 */ -@Repository -public class JdbcUserMealRepositoryImpl implements UserMealRepository { +public abstract class AbstractJdbcUserMealRepositoryImpl implements UserMealRepository { - private static final RowMapper ROW_MAPPER = BeanPropertyRowMapper.newInstance(UserMeal.class); + private SimpleJdbcInsert insertUserMeal; + + private final RowMapper rowMapper; @Autowired private JdbcTemplate jdbcTemplate; @@ -32,22 +31,22 @@ public class JdbcUserMealRepositoryImpl implements UserMealRepository { @Autowired private NamedParameterJdbcTemplate namedParameterJdbcTemplate; - private SimpleJdbcInsert insertUserMeal; - - @Autowired - public JdbcUserMealRepositoryImpl(DataSource dataSource) { + public AbstractJdbcUserMealRepositoryImpl(RowMapper rowMapper, DataSource dataSource) { + this.rowMapper = rowMapper; this.insertUserMeal = new SimpleJdbcInsert(dataSource) .withTableName("meals") .usingGeneratedKeyColumns("id"); } + protected abstract T toDbValue(LocalDateTime ldt); + @Override public UserMeal save(UserMeal userMeal, int userId) { MapSqlParameterSource map = new MapSqlParameterSource() .addValue("id", userMeal.getId()) .addValue("description", userMeal.getDescription()) .addValue("calories", userMeal.getCalories()) - .addValue("date_time", userMeal.getDateTime()) + .addValue("date_time", toDbValue(userMeal.getDateTime())) .addValue("user_id", userId); if (userMeal.isNew()) { @@ -73,19 +72,19 @@ public boolean delete(int id, int userId) { @Override public UserMeal get(int id, int userId) { List userMeals = jdbcTemplate.query( - "SELECT * FROM meals WHERE id = ? AND user_id = ?", ROW_MAPPER, id, userId); + "SELECT * FROM meals WHERE id = ? AND user_id = ?", rowMapper, id, userId); return DataAccessUtils.singleResult(userMeals); } public List getAll(int userId) { return jdbcTemplate.query( - "SELECT * FROM meals WHERE user_id=? ORDER BY date_time DESC", ROW_MAPPER, userId); + "SELECT * FROM meals WHERE user_id=? ORDER BY date_time DESC", rowMapper, userId); } @Override public List getBetween(LocalDateTime startDate, LocalDateTime endDate, int userId) { return jdbcTemplate.query( "SELECT * FROM meals WHERE user_id=? AND date_time BETWEEN ? AND ? ORDER BY date_time DESC", - ROW_MAPPER, userId, startDate, endDate); + rowMapper, userId, toDbValue(startDate), toDbValue(endDate)); } } \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/repository/jdbc/Java8JdbcUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jdbc/Java8JdbcUserMealRepositoryImpl.java new file mode 100644 index 000000000000..7bbb7ae02d08 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/jdbc/Java8JdbcUserMealRepositoryImpl.java @@ -0,0 +1,31 @@ +package ru.javawebinar.topjava.repository.jdbc; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.jdbc.core.BeanPropertyRowMapper; +import org.springframework.stereotype.Repository; +import ru.javawebinar.topjava.Profiles; +import ru.javawebinar.topjava.model.UserMeal; + +import javax.sql.DataSource; +import java.time.LocalDateTime; + +/** + * User: gkislin + * Date: 26.08.2014 + */ + +@Repository +@Profile(Profiles.POSTGRES) +public class Java8JdbcUserMealRepositoryImpl extends AbstractJdbcUserMealRepositoryImpl { + + @Autowired + public Java8JdbcUserMealRepositoryImpl(DataSource dataSource) { + super(BeanPropertyRowMapper.newInstance(UserMeal.class), dataSource); + } + + @Override + protected LocalDateTime toDbValue(LocalDateTime ldt) { + return ldt; + } +} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/repository/jdbc/TimestampJdbcUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jdbc/TimestampJdbcUserMealRepositoryImpl.java new file mode 100644 index 000000000000..559bd51d5169 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/jdbc/TimestampJdbcUserMealRepositoryImpl.java @@ -0,0 +1,34 @@ +package ru.javawebinar.topjava.repository.jdbc; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; +import ru.javawebinar.topjava.Profiles; +import ru.javawebinar.topjava.model.UserMeal; + +import javax.sql.DataSource; +import java.sql.Timestamp; +import java.time.LocalDateTime; + +/** + * User: gkislin + * Date: 26.08.2014 + */ + +@Repository +@Profile(Profiles.HSQLDB) +public class TimestampJdbcUserMealRepositoryImpl extends AbstractJdbcUserMealRepositoryImpl { + + @Autowired + public TimestampJdbcUserMealRepositoryImpl(DataSource dataSource) { + super((rs, rowNum) -> + new UserMeal(rs.getInt("id"), rs.getTimestamp("date_time").toLocalDateTime(), + rs.getString("description"), rs.getInt("calories")), dataSource + ); + } + + @Override + protected Timestamp toDbValue(LocalDateTime ldt) { + return Timestamp.valueOf(ldt); + } +} \ No newline at end of file From 80de9e3a64510aa97693fc79015bfe530ccb5780 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Fri, 8 Jul 2016 15:39:40 +0300 Subject: [PATCH 53/76] prepare to HW6 --- .../java/ru/javawebinar/topjava/web/MealServlet.java | 10 +++++++--- src/test/java/ru/javawebinar/topjava/SpringMain.java | 11 +++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java index 2873eb2f1d40..36155cfdd5ea 100644 --- a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -2,8 +2,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; +import ru.javawebinar.topjava.Profiles; import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.util.TimeUtil; import ru.javawebinar.topjava.web.meal.UserMealRestController; @@ -26,13 +26,17 @@ public class MealServlet extends HttpServlet { private static final Logger LOG = LoggerFactory.getLogger(MealServlet.class); - private ConfigurableApplicationContext springContext; + private ClassPathXmlApplicationContext springContext; private UserMealRestController mealController; @Override public void init(ServletConfig config) throws ServletException { super.init(config); - springContext = new ClassPathXmlApplicationContext("spring/spring-app.xml", "spring/spring-db.xml"); + springContext = new ClassPathXmlApplicationContext(new String[]{"spring/spring-app.xml", "spring/spring-db.xml"}, false); +// springContext = new ClassPathXmlApplicationContext(); + springContext.getEnvironment().setActiveProfiles(Profiles.ACTIVE_DB, Profiles.DB_IMPLEMENTATION); +// springContext.setConfigLocations("spring/spring-app.xml", "spring/spring-db.xml"); + springContext.refresh(); mealController = springContext.getBean(UserMealRestController.class); } diff --git a/src/test/java/ru/javawebinar/topjava/SpringMain.java b/src/test/java/ru/javawebinar/topjava/SpringMain.java index 5a7e86e9751c..3d1bd18eefc3 100644 --- a/src/test/java/ru/javawebinar/topjava/SpringMain.java +++ b/src/test/java/ru/javawebinar/topjava/SpringMain.java @@ -1,7 +1,6 @@ package ru.javawebinar.topjava; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.GenericXmlApplicationContext; import ru.javawebinar.topjava.to.UserMealWithExceed; import ru.javawebinar.topjava.web.meal.UserMealRestController; import ru.javawebinar.topjava.web.user.AdminRestController; @@ -19,10 +18,14 @@ public class SpringMain { public static void main(String[] args) { // java 7 Automatic resource management - try (ConfigurableApplicationContext appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml","spring/mock.xml")) { + try (GenericXmlApplicationContext appCtx = new GenericXmlApplicationContext()) { + appCtx.getEnvironment().setActiveProfiles(Profiles.ACTIVE_DB, Profiles.DB_IMPLEMENTATION); + appCtx.load("spring/spring-app.xml", "spring/spring-db.xml"); + appCtx.refresh(); + System.out.println(Arrays.toString(appCtx.getBeanDefinitionNames())); AdminRestController adminUserController = appCtx.getBean(AdminRestController.class); - System.out.println(adminUserController.create(UserTestData.USER)); + System.out.println(adminUserController.get(UserTestData.USER_ID)); System.out.println(); UserMealRestController mealController = appCtx.getBean(UserMealRestController.class); From 18a959863f3bfc22d270c08cb084d3f9908f8baa Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Fri, 8 Jul 2016 15:49:28 +0300 Subject: [PATCH 54/76] prepare to HW6 --- .../java/ru/javawebinar/topjava/model/User.java | 9 +++++++++ .../topjava/repository/UserMealRepository.java | 4 ++++ .../topjava/repository/UserRepository.java | 4 ++++ .../datajpa/DataJpaUserMealRepositoryImpl.java | 5 +++++ .../datajpa/DataJpaUserRepositoryImpl.java | 5 +++++ .../datajpa/ProxyUserMealRepository.java | 3 +++ .../repository/datajpa/ProxyUserRepository.java | 5 ++++- .../topjava/service/UserMealService.java | 2 ++ .../topjava/service/UserMealServiceImpl.java | 11 +++++++++++ .../topjava/service/UserService.java | 4 +++- .../topjava/service/UserServiceImpl.java | 5 +++++ .../datajpa/DataJpaUserMealServiceTest.java | 17 +++++++++++++++++ .../service/datajpa/DataJpaUserServiceTest.java | 17 +++++++++++++++++ 13 files changed, 89 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index 7f48d431f522..d28607bd6072 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -10,6 +10,7 @@ import javax.validation.constraints.Digits; import java.util.Date; import java.util.EnumSet; +import java.util.List; import java.util.Set; /** @@ -55,6 +56,10 @@ public class User extends NamedEntity { @Digits(fraction = 0, integer = 4) protected int caloriesPerDay = UserMealsUtil.DEFAULT_CALORIES_PER_DAY; + @OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY, mappedBy = "user") + @OrderBy("dateTime DESC") + protected List meals; + public User() { } @@ -119,6 +124,10 @@ public String getPassword() { return password; } + public List getMeals() { + return meals; + } + @Override public String toString() { return "User (" + diff --git a/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java index 8a7687fb85cb..5b283b14feac 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java @@ -24,4 +24,8 @@ public interface UserMealRepository { // ORDERED dateTime Collection getBetween(LocalDateTime startDate, LocalDateTime endDate, int userId); + + default UserMeal getWithUser(Integer id, Integer userId) { + throw new UnsupportedOperationException(); + } } diff --git a/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java index 24c1c45beca6..47ded4cec6b8 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java @@ -21,4 +21,8 @@ public interface UserRepository { User getByEmail(String email); List getAll(); + + default User getWithMeals(int id){ + throw new UnsupportedOperationException(); + } } diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserMealRepositoryImpl.java index 520325efc76a..5a633070298d 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserMealRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserMealRepositoryImpl.java @@ -50,4 +50,9 @@ public List getAll(int userId) { public List getBetween(LocalDateTime startDate, LocalDateTime endDate, int userId) { return proxy.getBetween(startDate, endDate, userId); } + + @Override + public UserMeal getWithUser(Integer id, Integer userId) { + return proxy.getWithUser(id, userId); + } } diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java index 514dabb1e5cd..af7dfa663b0a 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java @@ -42,4 +42,9 @@ public User getByEmail(String email) { public List getAll() { return proxy.findAll(); } + + @Override + public User getWithMeals(int id) { + return proxy.getWithMeals(id); + } } diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java index 6aa835840e6c..3c857a4c4880 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java @@ -30,4 +30,7 @@ public interface ProxyUserMealRepository extends JpaRepository getBetween(@Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate, @Param("userId") int userId); + + @Query("SELECT um FROM UserMeal um JOIN FETCH um.user WHERE um.id = ?1 and um.user.id = ?2") + UserMeal getWithUser(Integer id, Integer userId); } diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java index 25235734f438..badae9d6e1a3 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java @@ -33,4 +33,7 @@ public interface ProxyUserRepository extends JpaRepository { List findAll(); User getByEmail(String email); -} + + @Query("SELECT u FROM User u LEFT JOIN FETCH u.meals WHERE u.id = ?1") + User getWithMeals(Integer id); +} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/service/UserMealService.java b/src/main/java/ru/javawebinar/topjava/service/UserMealService.java index 9e4ea6413504..9cfd2f128aeb 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserMealService.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserMealService.java @@ -28,4 +28,6 @@ default Collection getBetweenDates(LocalDate startDate, LocalDate endD UserMeal update(UserMeal meal, int userId) throws NotFoundException; UserMeal save(UserMeal meal, int userId); + + UserMeal getWithUser(Integer id, Integer userId); } diff --git a/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java index 356a21447d63..d09a5a289296 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java @@ -48,4 +48,15 @@ public UserMeal update(UserMeal meal, int userId) { public UserMeal save(UserMeal meal, int userId) { return repository.save(meal, userId); } + +// @Autowired +// private UserRepository userRepository; + + // @Transactional + public UserMeal getWithUser(Integer id, Integer userId) { +// UserMeal meal = get(id, userId); +// meal.setUser(userRepository.get(userId)); +// return meal; + return ExceptionUtil.checkNotFoundWithId(repository.getWithUser(id, userId), id); + } } diff --git a/src/main/java/ru/javawebinar/topjava/service/UserService.java b/src/main/java/ru/javawebinar/topjava/service/UserService.java index 080b94b93c93..aa06ef3607f6 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserService.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserService.java @@ -23,6 +23,8 @@ public interface UserService { List getAll(); void update(User user); - + void evictCache(); + + User getWithMeals(int id); } diff --git a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java index c9dedc20e2e4..c47e207138ad 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java @@ -55,4 +55,9 @@ public void update(User user) { @Override public void evictCache() { } + + @Override + public User getWithMeals(int id) { + return ExceptionUtil.checkNotFoundWithId(repository.getWithMeals(id), id); + } } diff --git a/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserMealServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserMealServiceTest.java index b2252cc6cff4..0b85be7188e8 100644 --- a/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserMealServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserMealServiceTest.java @@ -1,10 +1,27 @@ package ru.javawebinar.topjava.service.datajpa; +import org.junit.Test; import org.springframework.test.context.ActiveProfiles; +import ru.javawebinar.topjava.UserTestData; +import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.service.AbstractUserMealServiceTest; +import ru.javawebinar.topjava.util.exception.NotFoundException; +import static ru.javawebinar.topjava.MealTestData.*; import static ru.javawebinar.topjava.Profiles.DATAJPA; +import static ru.javawebinar.topjava.UserTestData.ADMIN_ID; @ActiveProfiles(DATAJPA) public class DataJpaUserMealServiceTest extends AbstractUserMealServiceTest { + @Test + public void testGetWithUser() throws Exception { + UserMeal adminMeal = service.getWithUser(ADMIN_MEAL_ID, ADMIN_ID); + MATCHER.assertEquals(ADMIN_MEAL, adminMeal); + UserTestData.MATCHER.assertEquals(UserTestData.ADMIN, adminMeal.getUser()); + } + + @Test(expected = NotFoundException.class) + public void testGetWithUserNotFound() throws Exception { + service.getWithUser(MEAL1_ID, ADMIN_ID); + } } \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserServiceTest.java index a0757e739339..84ba35cf9032 100644 --- a/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserServiceTest.java @@ -1,10 +1,27 @@ package ru.javawebinar.topjava.service.datajpa; +import org.junit.Test; +import org.springframework.dao.DataAccessException; import org.springframework.test.context.ActiveProfiles; +import ru.javawebinar.topjava.MealTestData; +import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.service.AbstractUserServiceTest; +import ru.javawebinar.topjava.util.exception.NotFoundException; import static ru.javawebinar.topjava.Profiles.DATAJPA; +import static ru.javawebinar.topjava.UserTestData.*; @ActiveProfiles(DATAJPA) public class DataJpaUserServiceTest extends AbstractUserServiceTest { + @Test + public void testGetWithMeals() throws Exception { + User user = service.getWithMeals(USER_ID); + MATCHER.assertEquals(USER, user); + MealTestData.MATCHER.assertCollectionEquals(MealTestData.USER_MEALS, user.getMeals()); + } + + @Test(expected = NotFoundException.class) + public void testGetWithMealsNotFound() throws Exception { + service.getWithMeals(1); + } } \ No newline at end of file From 00302fd1fb7c72ff170c75fb92c512742f840a9b Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Mon, 11 Jul 2016 16:32:03 +0300 Subject: [PATCH 55/76] prepare to HW6 --- pom.xml | 5 ++++ .../ru/javawebinar/topjava/model/User.java | 4 +++ .../topjava/repository/JpaUtil.java | 25 +++++++++++++++++++ src/main/resources/cache/ehcache.xml | 3 +++ src/main/resources/spring/spring-db.xml | 8 ++++++ .../service/AbstractUserServiceTest.java | 5 ++++ 6 files changed, 50 insertions(+) create mode 100644 src/main/java/ru/javawebinar/topjava/repository/JpaUtil.java diff --git a/pom.xml b/pom.xml index c4760b1bb18d..e8e915f32d66 100644 --- a/pom.xml +++ b/pom.xml @@ -155,6 +155,11 @@ hibernate-validator ${hibernate-validator.version} + + org.hibernate + hibernate-ehcache + ${hibernate.version} + net.sf.ehcache diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index d28607bd6072..c6050d9f19d7 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -2,6 +2,8 @@ import ru.javawebinar.topjava.util.UserMealsUtil; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.validator.constraints.Email; import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.NotEmpty; @@ -22,6 +24,7 @@ @NamedQuery(name = User.BY_EMAIL, query = "SELECT u FROM User u LEFT JOIN FETCH u.roles WHERE u.email=?1"), @NamedQuery(name = User.ALL_SORTED, query = "SELECT u FROM User u LEFT JOIN FETCH u.roles ORDER BY u.name, u.email"), }) +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) @Entity @Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = "email", name = "users_unique_email_idx")}) public class User extends NamedEntity { @@ -50,6 +53,7 @@ public class User extends NamedEntity { @CollectionTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id")) @Column(name = "role") @ElementCollection(fetch = FetchType.LAZY) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) protected Set roles; @Column(name = "calories_per_day", columnDefinition = "default 2000") diff --git a/src/main/java/ru/javawebinar/topjava/repository/JpaUtil.java b/src/main/java/ru/javawebinar/topjava/repository/JpaUtil.java new file mode 100644 index 000000000000..75b3d82ba3cb --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/JpaUtil.java @@ -0,0 +1,25 @@ +package ru.javawebinar.topjava.repository; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +public class JpaUtil { + + @PersistenceContext + private EntityManager em; + + public void clear2ndLevelHibernateCache() { + Session s = (Session) em.getDelegate(); + SessionFactory sf = s.getSessionFactory(); +// sf.evict(User.class); +// sf.getCache().evictEntity(User.class, BaseEntity.START_SEQ); +// sf.getCache().evictEntityRegion(User.class); + sf.getCache().evictQueryRegions(); + sf.getCache().evictDefaultQueryRegion(); + sf.getCache().evictCollectionRegions(); + sf.getCache().evictEntityRegions(); + } +} diff --git a/src/main/resources/cache/ehcache.xml b/src/main/resources/cache/ehcache.xml index 8d420010d88d..b0275e589a4a 100644 --- a/src/main/resources/cache/ehcache.xml +++ b/src/main/resources/cache/ehcache.xml @@ -25,4 +25,7 @@ diskExpiryThreadIntervalSeconds="1" memoryStoreEvictionPolicy="LRU"/> + + diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index aad9a4d97418..8711a7077922 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -64,6 +64,12 @@ + + + + + + @@ -79,6 +85,8 @@ + + diff --git a/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java index 0752fdbb225b..c930cec28d2f 100644 --- a/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java @@ -7,6 +7,7 @@ import ru.javawebinar.topjava.UserTestData.*; import ru.javawebinar.topjava.model.Role; import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.repository.JpaUtil; import ru.javawebinar.topjava.util.exception.NotFoundException; import java.util.Arrays; @@ -20,9 +21,13 @@ abstract public class AbstractUserServiceTest extends AbstractServiceTest { @Autowired protected UserService service; + @Autowired + protected JpaUtil jpaUtil; + @Before public void setUp() throws Exception { service.evictCache(); + jpaUtil.clear2ndLevelHibernateCache(); } @Test From b35a457a692072d2841be4907b79b2c548effd1c Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Mon, 11 Jul 2016 19:23:20 +0300 Subject: [PATCH 56/76] prepare to HW6 --- pom.xml | 18 +++++++++++++++--- .../javawebinar/topjava/web/MealServlet.java | 17 +++-------------- src/main/webapp/WEB-INF/web.xml | 16 ++++++++++++++++ 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/pom.xml b/pom.xml index e8e915f32d66..6e2c7cefc7c7 100644 --- a/pom.xml +++ b/pom.xml @@ -117,11 +117,23 @@ - javax.servlet - servlet-api - 2.5 + org.apache.tomcat + tomcat-servlet-api + ${tomcat.version} provided + + + org.springframework + spring-web + ${spring.version} + + + commons-logging + commons-logging + + + org.springframework spring-test diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java index 36155cfdd5ea..a5e2ec2a0b98 100644 --- a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -2,8 +2,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.context.support.ClassPathXmlApplicationContext; -import ru.javawebinar.topjava.Profiles; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.util.TimeUtil; import ru.javawebinar.topjava.web.meal.UserMealRestController; @@ -26,26 +26,15 @@ public class MealServlet extends HttpServlet { private static final Logger LOG = LoggerFactory.getLogger(MealServlet.class); - private ClassPathXmlApplicationContext springContext; private UserMealRestController mealController; @Override public void init(ServletConfig config) throws ServletException { super.init(config); - springContext = new ClassPathXmlApplicationContext(new String[]{"spring/spring-app.xml", "spring/spring-db.xml"}, false); -// springContext = new ClassPathXmlApplicationContext(); - springContext.getEnvironment().setActiveProfiles(Profiles.ACTIVE_DB, Profiles.DB_IMPLEMENTATION); -// springContext.setConfigLocations("spring/spring-app.xml", "spring/spring-db.xml"); - springContext.refresh(); + WebApplicationContext springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); mealController = springContext.getBean(UserMealRestController.class); } - @Override - public void destroy() { - springContext.close(); - super.destroy(); - } - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); String action = request.getParameter("action"); diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 6306688d0998..e194d26d8fff 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -5,6 +5,22 @@ Topjava + + spring.profiles.default + postgres,datajpa + + + + contextConfigLocation + + classpath:spring/spring-app.xml + classpath:spring/spring-db.xml + + + + + org.springframework.web.context.ContextLoaderListener + userServlet ru.javawebinar.topjava.web.UserServlet From 234fa6e116726cbefd0aa16215fae3fb50330acd Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Mon, 11 Jul 2016 19:44:51 +0300 Subject: [PATCH 57/76] prepare to HW6 --- .../javawebinar/topjava/web/UserServlet.java | 19 ++++++++- src/main/resources/messages/app.properties | 4 ++ src/main/resources/messages/app_ru.properties | 4 ++ src/main/webapp/css/style.css | 8 ++++ src/main/webapp/fragments/bodyHeader.jsp | 5 +++ src/main/webapp/fragments/footer.jsp | 5 +++ src/main/webapp/fragments/headTag.jsp | 10 +++++ src/main/webapp/index.html | 19 --------- src/main/webapp/index.jsp | 26 ++++++++++++ src/main/webapp/mealList.jsp | 2 +- src/main/webapp/userList.jsp | 40 ++++++++++++++++--- 11 files changed, 115 insertions(+), 27 deletions(-) create mode 100644 src/main/resources/messages/app.properties create mode 100644 src/main/resources/messages/app_ru.properties create mode 100644 src/main/webapp/fragments/bodyHeader.jsp create mode 100644 src/main/webapp/fragments/footer.jsp create mode 100644 src/main/webapp/fragments/headTag.jsp delete mode 100644 src/main/webapp/index.html create mode 100644 src/main/webapp/index.jsp diff --git a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java index 9a528bfe5231..186d60c4814c 100644 --- a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java @@ -1,8 +1,12 @@ package ru.javawebinar.topjava.web; import org.slf4j.Logger; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; import ru.javawebinar.topjava.AuthorizedUser; +import ru.javawebinar.topjava.web.user.AdminRestController; +import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -18,6 +22,15 @@ public class UserServlet extends HttpServlet { private static final Logger LOG = getLogger(UserServlet.class); + private AdminRestController adminController; + + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + WebApplicationContext springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); + adminController = springContext.getBean(AdminRestController.class); + } + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int userId = Integer.valueOf(request.getParameter("userId")); AuthorizedUser.setId(userId); @@ -25,7 +38,9 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - LOG.debug("redirect to userList"); - response.sendRedirect("userList.jsp"); + LOG.debug("getAll"); + request.setAttribute("userList", adminController.getAll()); + request.getRequestDispatcher("/userList.jsp").forward(request, response); +// response.sendRedirect("userList.jsp"); } } diff --git a/src/main/resources/messages/app.properties b/src/main/resources/messages/app.properties new file mode 100644 index 000000000000..9b52a760888f --- /dev/null +++ b/src/main/resources/messages/app.properties @@ -0,0 +1,4 @@ +app.title=Calories management +app.footer=Project Maven/ Spring/ Security/ JPA(Hibernate)/ Jackson/jQuery application + +users.title=User list \ No newline at end of file diff --git a/src/main/resources/messages/app_ru.properties b/src/main/resources/messages/app_ru.properties new file mode 100644 index 000000000000..8c028c6c270e --- /dev/null +++ b/src/main/resources/messages/app_ru.properties @@ -0,0 +1,4 @@ +app.title=\u041F\u043E\u0434\u0441\u0447\u0435\u0442 \u043A\u0430\u043B\u043E\u0440\u0438\u0439 +app.footer=\u041F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043F\u043E \u043F\u0440\u043E\u0435\u043A\u0442\u0443 Maven/ Spring/ Security/ JPA(Hibernate)/ Jackson/jQuery + +users.title=\u0421\u043F\u0438\u0441\u043E\u043A \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \ No newline at end of file diff --git a/src/main/webapp/css/style.css b/src/main/webapp/css/style.css index 0c9fc667371c..36305de387ee 100644 --- a/src/main/webapp/css/style.css +++ b/src/main/webapp/css/style.css @@ -22,3 +22,11 @@ dd { .exceeded { color: red; } + +header, footer { + background: none repeat scroll 0 0 #A6C9E2; + color: #2E6E9E; + font-size: 20px; + padding: 5px 20px; + margin: 6px 0; +} \ No newline at end of file diff --git a/src/main/webapp/fragments/bodyHeader.jsp b/src/main/webapp/fragments/bodyHeader.jsp new file mode 100644 index 000000000000..c70d67914744 --- /dev/null +++ b/src/main/webapp/fragments/bodyHeader.jsp @@ -0,0 +1,5 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> + + +
    \ No newline at end of file diff --git a/src/main/webapp/fragments/footer.jsp b/src/main/webapp/fragments/footer.jsp new file mode 100644 index 000000000000..c59bff2e54bf --- /dev/null +++ b/src/main/webapp/fragments/footer.jsp @@ -0,0 +1,5 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> + +
    +
    \ No newline at end of file diff --git a/src/main/webapp/fragments/headTag.jsp b/src/main/webapp/fragments/headTag.jsp new file mode 100644 index 000000000000..c1532783af5e --- /dev/null +++ b/src/main/webapp/fragments/headTag.jsp @@ -0,0 +1,10 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> + + + + + <fmt:message key="app.title"/> + + \ No newline at end of file diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html deleted file mode 100644 index 2ac7fd93bf1d..000000000000 --- a/src/main/webapp/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Java Enterprise (Topjava) - - -

    Проект "Java Enterprise (Topjava)"

    -
    -
    - Meal list of - - - - - diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp new file mode 100644 index 000000000000..5fc24b21f049 --- /dev/null +++ b/src/main/webapp/index.jsp @@ -0,0 +1,26 @@ +<%@ 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" %> + + + + + + + +
    +
    + Login as: + + + +
    + + + \ No newline at end of file diff --git a/src/main/webapp/mealList.jsp b/src/main/webapp/mealList.jsp index 84a31cac352b..09a6b69f682f 100644 --- a/src/main/webapp/mealList.jsp +++ b/src/main/webapp/mealList.jsp @@ -9,7 +9,7 @@
    -

    Home

    +

    Home

    Meal list

    diff --git a/src/main/webapp/userList.jsp b/src/main/webapp/userList.jsp index fbd40d3d7219..4e01d64bca6e 100644 --- a/src/main/webapp/userList.jsp +++ b/src/main/webapp/userList.jsp @@ -1,10 +1,40 @@ <%@ 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" %> + + + - - User list - + -

    Home

    -

    User list

    + + +
    +

    + +

    + + + + + + + + + + + + + + + + + + + +
    NameEmailRolesActiveRegistered
    ${user.email}${user.roles}<%=user.isEnabled()%> +
    +
    + From 69a1f6c8cf2fc3fac3d7b9d4e3a3ae7babe8f53a Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 12 Jul 2016 01:34:23 +0300 Subject: [PATCH 58/76] prepare to HW6 --- pom.xml | 68 ++++++++++++++++++- src/main/resources/db/hsqldb.properties | 1 - src/main/resources/db/postgres.properties | 1 - src/main/resources/db/tomcat.properties | 7 ++ src/main/resources/messages/app_ru.properties | 2 +- src/main/resources/spring/spring-db.xml | 9 ++- src/main/resources/tomcat/context.xml | 49 +++++++++++++ 7 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/db/tomcat.properties create mode 100644 src/main/resources/tomcat/context.xml diff --git a/pom.xml b/pom.xml index 6e2c7cefc7c7..35238e372434 100644 --- a/pom.xml +++ b/pom.xml @@ -53,10 +53,75 @@ org.apache.maven.plugins maven-surefire-plugin - 2.19.1 + 2.19.1 + -Dfile.encoding=UTF-8 + + + + org.codehaus.cargo + cargo-maven2-plugin + 1.5.0 + + + tomcat8x + + UTF-8 + tomcat,datajpa + + + + org.postgresql + postgresql + + + + + + + src/main/resources/tomcat/context.xml + conf/Catalina/localhost/ + context.xml.default + + + + + + ru.javawebinar + topjava + war + + ${project.build.finalName} + + + + + + + @@ -183,6 +248,7 @@ javax.el javax.el-api 2.2.5 + provided diff --git a/src/main/resources/db/hsqldb.properties b/src/main/resources/db/hsqldb.properties index e879739f755a..aeeb57462caf 100644 --- a/src/main/resources/db/hsqldb.properties +++ b/src/main/resources/db/hsqldb.properties @@ -3,7 +3,6 @@ database.url=jdbc:hsqldb:mem:topjava database.username=sa database.password= -database.driverClassName=org.hsqldb.jdbcDriver database.init=true diff --git a/src/main/resources/db/postgres.properties b/src/main/resources/db/postgres.properties index 9f8ed0164261..b135be001a01 100644 --- a/src/main/resources/db/postgres.properties +++ b/src/main/resources/db/postgres.properties @@ -5,7 +5,6 @@ database.url=jdbc:postgresql://localhost:5432/topjava database.username=user database.password=password -database.driverClassName=org.postgresql.Driver database.init=true diff --git a/src/main/resources/db/tomcat.properties b/src/main/resources/db/tomcat.properties new file mode 100644 index 000000000000..09ed9c2548ee --- /dev/null +++ b/src/main/resources/db/tomcat.properties @@ -0,0 +1,7 @@ +database.init=false + +jdbc.initLocation=initDB.sql + +jpa.showSql=true +hibernate.format_sql=true +hibernate.use_sql_comments=true \ No newline at end of file diff --git a/src/main/resources/messages/app_ru.properties b/src/main/resources/messages/app_ru.properties index 8c028c6c270e..11ad6b652e89 100644 --- a/src/main/resources/messages/app_ru.properties +++ b/src/main/resources/messages/app_ru.properties @@ -1,4 +1,4 @@ app.title=\u041F\u043E\u0434\u0441\u0447\u0435\u0442 \u043A\u0430\u043B\u043E\u0440\u0438\u0439 -app.footer=\u041F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043F\u043E \u043F\u0440\u043E\u0435\u043A\u0442\u0443 Maven/ Spring/ Security/ JPA(Hibernate)/ Jackson/jQuery +app.footer=\u041F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043F\u043E \u043F\u0440\u043E\u0435\u043A\u0442\u0443 Maven/ Spring/ Security/ JPA(Hibernate)/ Jackson/jQuery users.title=\u0421\u043F\u0438\u0441\u043E\u043A \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \ No newline at end of file diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index 8711a7077922..31542d8900cb 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -5,11 +5,13 @@ xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" + xmlns:jee="http://www.springframework.org/schema/jee" 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 http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd - http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> + http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd + http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd"> @@ -41,6 +43,11 @@ p:password="${database.password}"/> + + + + + diff --git a/src/main/resources/tomcat/context.xml b/src/main/resources/tomcat/context.xml new file mode 100644 index 000000000000..cad687c2d4fd --- /dev/null +++ b/src/main/resources/tomcat/context.xml @@ -0,0 +1,49 @@ + + + + + + + + WEB-INF/web.xml + ${catalina.base}/conf/web.xml + + + + + + + + + From 07f3b84bce06d315ac6be3fb37695248b70ee059 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 12 Jul 2016 16:11:09 +0300 Subject: [PATCH 59/76] prepare to HW6 --- pom.xml | 2 +- .../topjava/web/RootController.java | 39 +++++++++++++++++++ src/main/resources/spring/spring-app.xml | 3 -- src/main/resources/spring/spring-mvc.xml | 18 +++++++++ .../jsp}/fragments/bodyHeader.jsp | 2 +- .../{ => WEB-INF/jsp}/fragments/footer.jsp | 2 +- .../{ => WEB-INF/jsp}/fragments/headTag.jsp | 2 +- src/main/webapp/{ => WEB-INF/jsp}/index.jsp | 2 +- .../webapp/{ => WEB-INF/jsp}/mealEdit.jsp | 0 .../webapp/{ => WEB-INF/jsp}/mealList.jsp | 2 +- .../webapp/{ => WEB-INF/jsp}/userList.jsp | 0 src/main/webapp/WEB-INF/web.xml | 17 ++++++++ src/main/webapp/{ => resources}/css/style.css | 2 +- 13 files changed, 81 insertions(+), 10 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/web/RootController.java create mode 100644 src/main/resources/spring/spring-mvc.xml rename src/main/webapp/{ => WEB-INF/jsp}/fragments/bodyHeader.jsp (98%) rename src/main/webapp/{ => WEB-INF/jsp}/fragments/footer.jsp (77%) rename src/main/webapp/{ => WEB-INF/jsp}/fragments/headTag.jsp (85%) rename src/main/webapp/{ => WEB-INF/jsp}/index.jsp (98%) rename src/main/webapp/{ => WEB-INF/jsp}/mealEdit.jsp (100%) rename src/main/webapp/{ => WEB-INF/jsp}/mealList.jsp (99%) rename src/main/webapp/{ => WEB-INF/jsp}/userList.jsp (100%) rename src/main/webapp/{ => resources}/css/style.css (99%) diff --git a/pom.xml b/pom.xml index 35238e372434..5d84a2c8ac32 100644 --- a/pom.xml +++ b/pom.xml @@ -190,7 +190,7 @@ org.springframework - spring-web + spring-webmvc ${spring.version} diff --git a/src/main/java/ru/javawebinar/topjava/web/RootController.java b/src/main/java/ru/javawebinar/topjava/web/RootController.java new file mode 100644 index 000000000000..95cff6f3eb4c --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/RootController.java @@ -0,0 +1,39 @@ +package ru.javawebinar.topjava.web; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import ru.javawebinar.topjava.AuthorizedUser; +import ru.javawebinar.topjava.service.UserService; + +import javax.servlet.http.HttpServletRequest; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +@Controller +public class RootController { + @Autowired + private UserService service; + + @RequestMapping(value = "/", method = RequestMethod.GET) + public String root() { + return "index"; + } + + @RequestMapping(value = "/users", method = RequestMethod.GET) + public String userList(Model model) { + model.addAttribute("userList", service.getAll()); + return "userList"; + } + + @RequestMapping(value = "/users", method = RequestMethod.POST) + public String setUser(HttpServletRequest request) { + int userId = Integer.valueOf(request.getParameter("userId")); + AuthorizedUser.setId(userId); + return "redirect:meals"; + } +} diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml index fbf54e789877..c3e7587cfdea 100644 --- a/src/main/resources/spring/spring-app.xml +++ b/src/main/resources/spring/spring-app.xml @@ -16,7 +16,4 @@ - - - \ No newline at end of file diff --git a/src/main/resources/spring/spring-mvc.xml b/src/main/resources/spring/spring-mvc.xml new file mode 100644 index 000000000000..7c71d5af5939 --- /dev/null +++ b/src/main/resources/spring/spring-mvc.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/webapp/fragments/bodyHeader.jsp b/src/main/webapp/WEB-INF/jsp/fragments/bodyHeader.jsp similarity index 98% rename from src/main/webapp/fragments/bodyHeader.jsp rename to src/main/webapp/WEB-INF/jsp/fragments/bodyHeader.jsp index c70d67914744..ad383f16f619 100644 --- a/src/main/webapp/fragments/bodyHeader.jsp +++ b/src/main/webapp/WEB-INF/jsp/fragments/bodyHeader.jsp @@ -2,4 +2,4 @@ <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> -
    \ No newline at end of file +
    diff --git a/src/main/webapp/fragments/footer.jsp b/src/main/webapp/WEB-INF/jsp/fragments/footer.jsp similarity index 77% rename from src/main/webapp/fragments/footer.jsp rename to src/main/webapp/WEB-INF/jsp/fragments/footer.jsp index c59bff2e54bf..6df7790c26c3 100644 --- a/src/main/webapp/fragments/footer.jsp +++ b/src/main/webapp/WEB-INF/jsp/fragments/footer.jsp @@ -2,4 +2,4 @@ <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
    -
    \ No newline at end of file +
    diff --git a/src/main/webapp/fragments/headTag.jsp b/src/main/webapp/WEB-INF/jsp/fragments/headTag.jsp similarity index 85% rename from src/main/webapp/fragments/headTag.jsp rename to src/main/webapp/WEB-INF/jsp/fragments/headTag.jsp index c1532783af5e..da40d461d76a 100644 --- a/src/main/webapp/fragments/headTag.jsp +++ b/src/main/webapp/WEB-INF/jsp/fragments/headTag.jsp @@ -6,5 +6,5 @@ <fmt:message key="app.title"/> - + \ No newline at end of file diff --git a/src/main/webapp/index.jsp b/src/main/webapp/WEB-INF/jsp/index.jsp similarity index 98% rename from src/main/webapp/index.jsp rename to src/main/webapp/WEB-INF/jsp/index.jsp index 5fc24b21f049..6177319f7252 100644 --- a/src/main/webapp/index.jsp +++ b/src/main/webapp/WEB-INF/jsp/index.jsp @@ -23,4 +23,4 @@
    - \ No newline at end of file + diff --git a/src/main/webapp/mealEdit.jsp b/src/main/webapp/WEB-INF/jsp/mealEdit.jsp similarity index 100% rename from src/main/webapp/mealEdit.jsp rename to src/main/webapp/WEB-INF/jsp/mealEdit.jsp diff --git a/src/main/webapp/mealList.jsp b/src/main/webapp/WEB-INF/jsp/mealList.jsp similarity index 99% rename from src/main/webapp/mealList.jsp rename to src/main/webapp/WEB-INF/jsp/mealList.jsp index 09a6b69f682f..9a4929604c02 100644 --- a/src/main/webapp/mealList.jsp +++ b/src/main/webapp/WEB-INF/jsp/mealList.jsp @@ -60,4 +60,4 @@
    - \ No newline at end of file + diff --git a/src/main/webapp/userList.jsp b/src/main/webapp/WEB-INF/jsp/userList.jsp similarity index 100% rename from src/main/webapp/userList.jsp rename to src/main/webapp/WEB-INF/jsp/userList.jsp diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index e194d26d8fff..330fb5bba850 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -18,9 +18,25 @@ + org.springframework.web.context.ContextLoaderListener + + mvc-dispatcher + org.springframework.web.servlet.DispatcherServlet + + contextConfigLocation + classpath:spring/spring-mvc.xml + + 1 + + + mvc-dispatcher + / + + + diff --git a/src/main/webapp/css/style.css b/src/main/webapp/resources/css/style.css similarity index 99% rename from src/main/webapp/css/style.css rename to src/main/webapp/resources/css/style.css index 36305de387ee..d4807fb38efb 100644 --- a/src/main/webapp/css/style.css +++ b/src/main/webapp/resources/css/style.css @@ -29,4 +29,4 @@ header, footer { font-size: 20px; padding: 5px 20px; margin: 6px 0; -} \ No newline at end of file +} From 3269dc2fe22cd47433593c0747f408b77b1eb782 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 12 Jul 2016 16:27:54 +0300 Subject: [PATCH 60/76] prepare to HW6 --- .../messages/app.properties | 2 +- config/messages/app_ru.properties | 4 ++++ src/main/resources/messages/app_ru.properties | 4 ---- src/main/resources/spring/spring-mvc.xml | 18 ++++++++++++++++++ .../WEB-INF/jsp/fragments/bodyHeader.jsp | 1 - .../webapp/WEB-INF/jsp/fragments/footer.jsp | 1 - .../webapp/WEB-INF/jsp/fragments/headTag.jsp | 1 - src/main/webapp/WEB-INF/jsp/index.jsp | 4 +--- src/main/webapp/WEB-INF/jsp/userList.jsp | 2 -- 9 files changed, 24 insertions(+), 13 deletions(-) rename {src/main/resources => config}/messages/app.properties (89%) create mode 100644 config/messages/app_ru.properties delete mode 100644 src/main/resources/messages/app_ru.properties diff --git a/src/main/resources/messages/app.properties b/config/messages/app.properties similarity index 89% rename from src/main/resources/messages/app.properties rename to config/messages/app.properties index 9b52a760888f..58e0b7e45d6b 100644 --- a/src/main/resources/messages/app.properties +++ b/config/messages/app.properties @@ -1,4 +1,4 @@ app.title=Calories management app.footer=Project Maven/ Spring/ Security/ JPA(Hibernate)/ Jackson/jQuery application -users.title=User list \ No newline at end of file +users.title=User list diff --git a/config/messages/app_ru.properties b/config/messages/app_ru.properties new file mode 100644 index 000000000000..95c1ca2d2b07 --- /dev/null +++ b/config/messages/app_ru.properties @@ -0,0 +1,4 @@ +app.title=Подсчет калорий +app.footer=Приложение по проекту Maven/ Spring/ Security/ JPA(Hibernate)/ Jackson/jQuery + +users.title=Список пользователей \ No newline at end of file diff --git a/src/main/resources/messages/app_ru.properties b/src/main/resources/messages/app_ru.properties deleted file mode 100644 index 11ad6b652e89..000000000000 --- a/src/main/resources/messages/app_ru.properties +++ /dev/null @@ -1,4 +0,0 @@ -app.title=\u041F\u043E\u0434\u0441\u0447\u0435\u0442 \u043A\u0430\u043B\u043E\u0440\u0438\u0439 -app.footer=\u041F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043F\u043E \u043F\u0440\u043E\u0435\u043A\u0442\u0443 Maven/ Spring/ Security/ JPA(Hibernate)/ Jackson/jQuery - -users.title=\u0421\u043F\u0438\u0441\u043E\u043A \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \ No newline at end of file diff --git a/src/main/resources/spring/spring-mvc.xml b/src/main/resources/spring/spring-mvc.xml index 7c71d5af5939..12ac233daa15 100644 --- a/src/main/resources/spring/spring-mvc.xml +++ b/src/main/resources/spring/spring-mvc.xml @@ -15,4 +15,22 @@ + + + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/fragments/bodyHeader.jsp b/src/main/webapp/WEB-INF/jsp/fragments/bodyHeader.jsp index ad383f16f619..833a84d0b2a4 100644 --- a/src/main/webapp/WEB-INF/jsp/fragments/bodyHeader.jsp +++ b/src/main/webapp/WEB-INF/jsp/fragments/bodyHeader.jsp @@ -1,5 +1,4 @@ <%@page contentType="text/html" pageEncoding="UTF-8" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> -
    diff --git a/src/main/webapp/WEB-INF/jsp/fragments/footer.jsp b/src/main/webapp/WEB-INF/jsp/fragments/footer.jsp index 6df7790c26c3..997a1677296c 100644 --- a/src/main/webapp/WEB-INF/jsp/fragments/footer.jsp +++ b/src/main/webapp/WEB-INF/jsp/fragments/footer.jsp @@ -1,5 +1,4 @@ <%@page contentType="text/html" pageEncoding="UTF-8" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> -
    diff --git a/src/main/webapp/WEB-INF/jsp/fragments/headTag.jsp b/src/main/webapp/WEB-INF/jsp/fragments/headTag.jsp index da40d461d76a..4f44c6dee4d5 100644 --- a/src/main/webapp/WEB-INF/jsp/fragments/headTag.jsp +++ b/src/main/webapp/WEB-INF/jsp/fragments/headTag.jsp @@ -1,7 +1,6 @@ <%@page contentType="text/html" pageEncoding="UTF-8" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> - diff --git a/src/main/webapp/WEB-INF/jsp/index.jsp b/src/main/webapp/WEB-INF/jsp/index.jsp index 6177319f7252..83b0110f0b83 100644 --- a/src/main/webapp/WEB-INF/jsp/index.jsp +++ b/src/main/webapp/WEB-INF/jsp/index.jsp @@ -2,8 +2,6 @@ <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> - - @@ -23,4 +21,4 @@
    - + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/userList.jsp b/src/main/webapp/WEB-INF/jsp/userList.jsp index 4e01d64bca6e..d8a8a77e57da 100644 --- a/src/main/webapp/WEB-INF/jsp/userList.jsp +++ b/src/main/webapp/WEB-INF/jsp/userList.jsp @@ -2,8 +2,6 @@ <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> - - From 16e7e1e6a641a2209f15e962c4d5b934cbda04b4 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Sat, 16 Jul 2016 17:47:15 +0300 Subject: [PATCH 61/76] prepare to HW7 --- .../ru/javawebinar/topjava/SpringMain.java | 2 +- .../mock/InMemoryUserRepositoryImpl.java | 1 - .../service/AbstractJpaUserServiceTest.java | 21 +++++++++++++++++++ .../service/AbstractUserServiceTest.java | 5 ----- .../datajpa/DataJpaUserServiceTest.java | 5 ++--- .../service/jpa/JpaUserServiceTest.java | 4 ++-- ...InMemoryAdminRestControllerSpringTest.java | 2 +- .../web/InMemoryAdminRestControllerTest.java | 6 ++++-- 8 files changed, 31 insertions(+), 15 deletions(-) create mode 100644 src/test/java/ru/javawebinar/topjava/service/AbstractJpaUserServiceTest.java diff --git a/src/test/java/ru/javawebinar/topjava/SpringMain.java b/src/test/java/ru/javawebinar/topjava/SpringMain.java index 3d1bd18eefc3..24657f3132f6 100644 --- a/src/test/java/ru/javawebinar/topjava/SpringMain.java +++ b/src/test/java/ru/javawebinar/topjava/SpringMain.java @@ -20,7 +20,7 @@ public static void main(String[] args) { // java 7 Automatic resource management try (GenericXmlApplicationContext appCtx = new GenericXmlApplicationContext()) { appCtx.getEnvironment().setActiveProfiles(Profiles.ACTIVE_DB, Profiles.DB_IMPLEMENTATION); - appCtx.load("spring/spring-app.xml", "spring/spring-db.xml"); + appCtx.load("spring/spring-app.xml", "spring/spring-db.xml", "spring/spring-mvc.xml"); appCtx.refresh(); System.out.println(Arrays.toString(appCtx.getBeanDefinitionNames())); diff --git a/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java b/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java index 6dc64f249a8f..6c4a872fb261 100644 --- a/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java +++ b/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java @@ -12,7 +12,6 @@ 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; diff --git a/src/test/java/ru/javawebinar/topjava/service/AbstractJpaUserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractJpaUserServiceTest.java new file mode 100644 index 000000000000..eb8f8e9ea70e --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/service/AbstractJpaUserServiceTest.java @@ -0,0 +1,21 @@ +package ru.javawebinar.topjava.service; + +import org.junit.Before; +import org.springframework.beans.factory.annotation.Autowired; +import ru.javawebinar.topjava.repository.JpaUtil; + +/** + * GKislin + * 07.04.2015. + */ +abstract public class AbstractJpaUserServiceTest extends AbstractUserServiceTest { + @SuppressWarnings("SpringJavaAutowiringInspection") + @Autowired + private JpaUtil jpaUtil; + + @Before + public void setUp() throws Exception { + super.setUp(); + jpaUtil.clear2ndLevelHibernateCache(); + } +} diff --git a/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java index c930cec28d2f..0752fdbb225b 100644 --- a/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java @@ -7,7 +7,6 @@ import ru.javawebinar.topjava.UserTestData.*; import ru.javawebinar.topjava.model.Role; import ru.javawebinar.topjava.model.User; -import ru.javawebinar.topjava.repository.JpaUtil; import ru.javawebinar.topjava.util.exception.NotFoundException; import java.util.Arrays; @@ -21,13 +20,9 @@ abstract public class AbstractUserServiceTest extends AbstractServiceTest { @Autowired protected UserService service; - @Autowired - protected JpaUtil jpaUtil; - @Before public void setUp() throws Exception { service.evictCache(); - jpaUtil.clear2ndLevelHibernateCache(); } @Test diff --git a/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserServiceTest.java index 84ba35cf9032..5d67dce09e59 100644 --- a/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserServiceTest.java @@ -1,18 +1,17 @@ package ru.javawebinar.topjava.service.datajpa; import org.junit.Test; -import org.springframework.dao.DataAccessException; import org.springframework.test.context.ActiveProfiles; import ru.javawebinar.topjava.MealTestData; import ru.javawebinar.topjava.model.User; -import ru.javawebinar.topjava.service.AbstractUserServiceTest; +import ru.javawebinar.topjava.service.AbstractJpaUserServiceTest; import ru.javawebinar.topjava.util.exception.NotFoundException; import static ru.javawebinar.topjava.Profiles.DATAJPA; import static ru.javawebinar.topjava.UserTestData.*; @ActiveProfiles(DATAJPA) -public class DataJpaUserServiceTest extends AbstractUserServiceTest { +public class DataJpaUserServiceTest extends AbstractJpaUserServiceTest { @Test public void testGetWithMeals() throws Exception { User user = service.getWithMeals(USER_ID); diff --git a/src/test/java/ru/javawebinar/topjava/service/jpa/JpaUserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/jpa/JpaUserServiceTest.java index d1b3e4699785..ffb1fea03c22 100644 --- a/src/test/java/ru/javawebinar/topjava/service/jpa/JpaUserServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/jpa/JpaUserServiceTest.java @@ -1,10 +1,10 @@ package ru.javawebinar.topjava.service.jpa; import org.springframework.test.context.ActiveProfiles; -import ru.javawebinar.topjava.service.AbstractUserServiceTest; +import ru.javawebinar.topjava.service.AbstractJpaUserServiceTest; import static ru.javawebinar.topjava.Profiles.JPA; @ActiveProfiles(JPA) -public class JpaUserServiceTest extends AbstractUserServiceTest { +public class JpaUserServiceTest extends AbstractJpaUserServiceTest { } \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerSpringTest.java b/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerSpringTest.java index a9125c6e4d96..ca416455051c 100644 --- a/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerSpringTest.java +++ b/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerSpringTest.java @@ -22,7 +22,7 @@ * GKislin * 13.03.2015. */ -@ContextConfiguration({"classpath:spring/spring-app.xml", "classpath:spring/mock.xml"}) +@ContextConfiguration({"classpath:spring/spring-app.xml", "classpath:spring/spring-mvc.xml", "classpath:spring/mock.xml"}) @RunWith(SpringJUnit4ClassRunner.class) public class InMemoryAdminRestControllerSpringTest { diff --git a/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerTest.java b/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerTest.java index f7006200f781..69466f713308 100644 --- a/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerTest.java +++ b/src/test/java/ru/javawebinar/topjava/web/InMemoryAdminRestControllerTest.java @@ -21,14 +21,16 @@ public class InMemoryAdminRestControllerTest { @BeforeClass public static void beforeClass() { - appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml", "spring/mock.xml"); + appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml", "spring/spring-mvc.xml", "spring/mock.xml"); System.out.println("\n" + Arrays.toString(appCtx.getBeanDefinitionNames()) + "\n"); controller = appCtx.getBean(AdminRestController.class); } @AfterClass public static void afterClass() { - appCtx.close(); +// May cause during JUnit "Cache is not alive (STATUS_SHUTDOWN)" as JUnit share Spring context for speed +// http://stackoverflow.com/questions/16281802/ehcache-shutdown-causing-an-exception-while-running-test-suite +// appCtx.close(); } @Before From 2891e5570f00d21e719a9e65428d64e3ae4cec1b Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Sat, 16 Jul 2016 17:47:53 +0300 Subject: [PATCH 62/76] prepare to HW7 --- config/messages/app.properties | 11 +++++++++++ config/messages/app_ru.properties | 15 +++++++++++++-- .../javawebinar/topjava/web/RootController.java | 16 ++++++++++++++-- .../webapp/WEB-INF/jsp/fragments/bodyHeader.jsp | 3 ++- src/main/webapp/WEB-INF/jsp/index.jsp | 8 ++++---- src/main/webapp/WEB-INF/jsp/mealEdit.jsp | 12 +++++++----- src/main/webapp/WEB-INF/jsp/mealList.jsp | 14 ++++++-------- 7 files changed, 57 insertions(+), 22 deletions(-) diff --git a/config/messages/app.properties b/config/messages/app.properties index 58e0b7e45d6b..c4eb70fbcd45 100644 --- a/config/messages/app.properties +++ b/config/messages/app.properties @@ -1,4 +1,15 @@ app.title=Calories management +app.home=Home app.footer=Project Maven/ Spring/ Security/ JPA(Hibernate)/ Jackson/jQuery application +app.login=Login as users.title=User list +users.edit=Edit user +users.add=Add user + +meals.title=Meals list +meals.edit=Edit meal +meals.add=Add meal +meals.filter=Filter + +common.select=Select \ No newline at end of file diff --git a/config/messages/app_ru.properties b/config/messages/app_ru.properties index 95c1ca2d2b07..a145e013943e 100644 --- a/config/messages/app_ru.properties +++ b/config/messages/app_ru.properties @@ -1,4 +1,15 @@ app.title=Подсчет калорий -app.footer=Приложение по проекту Maven/ Spring/ Security/ JPA(Hibernate)/ Jackson/jQuery +app.home=Главная +app.footer=Приложение по вебинару Maven/ Spring/ Security/ JPA(Hibernate)/ Jackson/jQuery +app.login=Зайти как -users.title=Список пользователей \ No newline at end of file +users.title=Список пользователей +users.edit=Редактировать пользователя +users.add=Добавить пользователя + +meals.title=Список еды +meals.edit=Редактировать еду +meals.add=Добавить еду +meals.filter=Отфильтровать + +common.select=Выбрать \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/web/RootController.java b/src/main/java/ru/javawebinar/topjava/web/RootController.java index 95cff6f3eb4c..de114c4755ea 100644 --- a/src/main/java/ru/javawebinar/topjava/web/RootController.java +++ b/src/main/java/ru/javawebinar/topjava/web/RootController.java @@ -6,7 +6,9 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import ru.javawebinar.topjava.AuthorizedUser; +import ru.javawebinar.topjava.service.UserMealService; import ru.javawebinar.topjava.service.UserService; +import ru.javawebinar.topjava.util.UserMealsUtil; import javax.servlet.http.HttpServletRequest; @@ -17,7 +19,10 @@ @Controller public class RootController { @Autowired - private UserService service; + private UserService userService; + + @Autowired + private UserMealService mealService; @RequestMapping(value = "/", method = RequestMethod.GET) public String root() { @@ -26,10 +31,17 @@ public String root() { @RequestMapping(value = "/users", method = RequestMethod.GET) public String userList(Model model) { - model.addAttribute("userList", service.getAll()); + model.addAttribute("userList", userService.getAll()); return "userList"; } + @RequestMapping(value = "/meals", method = RequestMethod.GET) + public String mealList(Model model) { + model.addAttribute("mealList", + UserMealsUtil.getWithExceeded(mealService.getAll(AuthorizedUser.id()), AuthorizedUser.getCaloriesPerDay())); + return "mealList"; + } + @RequestMapping(value = "/users", method = RequestMethod.POST) public String setUser(HttpServletRequest request) { int userId = Integer.valueOf(request.getParameter("userId")); diff --git a/src/main/webapp/WEB-INF/jsp/fragments/bodyHeader.jsp b/src/main/webapp/WEB-INF/jsp/fragments/bodyHeader.jsp index 833a84d0b2a4..8c3a3bcb2496 100644 --- a/src/main/webapp/WEB-INF/jsp/fragments/bodyHeader.jsp +++ b/src/main/webapp/WEB-INF/jsp/fragments/bodyHeader.jsp @@ -1,4 +1,5 @@ <%@page contentType="text/html" pageEncoding="UTF-8" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> -
    +<%--http://stackoverflow.com/questions/10327390/how-should-i-get-root-folder-path-in-jsp-page--%> +
      
    \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/index.jsp b/src/main/webapp/WEB-INF/jsp/index.jsp index 83b0110f0b83..b6746cdb8853 100644 --- a/src/main/webapp/WEB-INF/jsp/index.jsp +++ b/src/main/webapp/WEB-INF/jsp/index.jsp @@ -8,15 +8,15 @@
    - Login as: - +
    diff --git a/src/main/webapp/WEB-INF/jsp/mealEdit.jsp b/src/main/webapp/WEB-INF/jsp/mealEdit.jsp index 993610e746a7..fa7bc1e57472 100644 --- a/src/main/webapp/WEB-INF/jsp/mealEdit.jsp +++ b/src/main/webapp/WEB-INF/jsp/mealEdit.jsp @@ -1,13 +1,14 @@ <%@ 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" %> - - Meal - - + +
    +

    Home

    +

    +

    Home

    ${param.action == 'create' ? 'Create meal' : 'Edit meal'}


    @@ -30,5 +31,6 @@
    + diff --git a/src/main/webapp/WEB-INF/jsp/mealList.jsp b/src/main/webapp/WEB-INF/jsp/mealList.jsp index 9a4929604c02..e3ca784ee721 100644 --- a/src/main/webapp/WEB-INF/jsp/mealList.jsp +++ b/src/main/webapp/WEB-INF/jsp/mealList.jsp @@ -3,14 +3,11 @@ <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="fn" uri="http://topjava.javawebinar.ru/functions" %> - - Meal list - - + +
    -

    Home

    -

    Meal list

    +

    From Date:
    @@ -28,10 +25,10 @@
    To Time:
    - +

    - Add Meal +
    @@ -59,5 +56,6 @@
    + From 7b69363d06fd04c10775346da76312fca0f025b3 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Sat, 16 Jul 2016 17:48:31 +0300 Subject: [PATCH 63/76] prepare to HW7 --- .../javawebinar/topjava/web/MealServlet.java | 97 ------------------- .../javawebinar/topjava/web/UserServlet.java | 46 --------- .../web/meal/AbstractUserMealController.java | 68 +++++++++++++ .../topjava/web/meal/UserMealController.java | 78 +++++++++++++++ .../web/meal/UserMealRestController.java | 63 ++---------- src/main/webapp/WEB-INF/jsp/mealEdit.jsp | 6 +- src/main/webapp/WEB-INF/jsp/mealList.jsp | 8 +- src/main/webapp/WEB-INF/web.xml | 22 ----- 8 files changed, 158 insertions(+), 230 deletions(-) delete mode 100644 src/main/java/ru/javawebinar/topjava/web/MealServlet.java delete mode 100644 src/main/java/ru/javawebinar/topjava/web/UserServlet.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/meal/AbstractUserMealController.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/meal/UserMealController.java diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java deleted file mode 100644 index a5e2ec2a0b98..000000000000 --- a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java +++ /dev/null @@ -1,97 +0,0 @@ -package ru.javawebinar.topjava.web; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.context.support.WebApplicationContextUtils; -import ru.javawebinar.topjava.model.UserMeal; -import ru.javawebinar.topjava.util.TimeUtil; -import ru.javawebinar.topjava.web.meal.UserMealRestController; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -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; - -/** - * User: gkislin - * Date: 19.08.2014 - */ -public class MealServlet extends HttpServlet { - private static final Logger LOG = LoggerFactory.getLogger(MealServlet.class); - - private UserMealRestController mealController; - - @Override - public void init(ServletConfig config) throws ServletException { - super.init(config); - WebApplicationContext springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); - mealController = springContext.getBean(UserMealRestController.class); - } - - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws 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"))); - - 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"); - - } 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); - } - } - - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String action = request.getParameter("action"); - - if (action == null) { - LOG.info("getAll"); - 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); - mealController.delete(id); - response.sendRedirect("meals"); - } else if (action.equals("create") || action.equals("update")) { - final UserMeal meal = action.equals("create") ? - new UserMeal(LocalDateTime.now().withNano(0).withSecond(0), "", 1000) : - mealController.get(getId(request)); // update - request.setAttribute("meal", meal); - request.getRequestDispatcher("mealEdit.jsp").forward(request, response); - } - } - - 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/UserServlet.java b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java deleted file mode 100644 index 186d60c4814c..000000000000 --- a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java +++ /dev/null @@ -1,46 +0,0 @@ -package ru.javawebinar.topjava.web; - -import org.slf4j.Logger; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.context.support.WebApplicationContextUtils; -import ru.javawebinar.topjava.AuthorizedUser; -import ru.javawebinar.topjava.web.user.AdminRestController; - -import javax.servlet.ServletConfig; -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); - - private AdminRestController adminController; - - @Override - public void init(ServletConfig config) throws ServletException { - super.init(config); - WebApplicationContext springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); - adminController = springContext.getBean(AdminRestController.class); - } - - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - int userId = Integer.valueOf(request.getParameter("userId")); - AuthorizedUser.setId(userId); - response.sendRedirect("meals"); - } - - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - LOG.debug("getAll"); - request.setAttribute("userList", adminController.getAll()); - request.getRequestDispatcher("/userList.jsp").forward(request, response); -// response.sendRedirect("userList.jsp"); - } -} diff --git a/src/main/java/ru/javawebinar/topjava/web/meal/AbstractUserMealController.java b/src/main/java/ru/javawebinar/topjava/web/meal/AbstractUserMealController.java new file mode 100644 index 000000000000..b8d75b362992 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/meal/AbstractUserMealController.java @@ -0,0 +1,68 @@ +package ru.javawebinar.topjava.web.meal; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import ru.javawebinar.topjava.AuthorizedUser; +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. + */ +public abstract class AbstractUserMealController { + private static final Logger LOG = LoggerFactory.getLogger(AbstractUserMealController.class); + + @Autowired + private UserMealService service; + + public UserMeal get(int id) { + int userId = AuthorizedUser.id(); + LOG.info("get meal {} for User {}", id, userId); + return service.get(id, userId); + } + + public void delete(int id) { + int userId = AuthorizedUser.id(); + LOG.info("delete meal {} for User {}", id, userId); + service.delete(id, userId); + } + + public List getAll() { + int userId = AuthorizedUser.id(); + LOG.info("getAll for User {}", userId); + return UserMealsUtil.getWithExceeded(service.getAll(userId), AuthorizedUser.getCaloriesPerDay()); + } + + public void update(UserMeal meal, int id) { + meal.setId(id); + int userId = AuthorizedUser.id(); + LOG.info("update {} for User {}", meal, userId); + service.update(meal, userId); + } + + public UserMeal create(UserMeal meal) { + meal.setId(null); + int userId = AuthorizedUser.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 = AuthorizedUser.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, AuthorizedUser.getCaloriesPerDay() + ); + } +} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/web/meal/UserMealController.java b/src/main/java/ru/javawebinar/topjava/web/meal/UserMealController.java new file mode 100644 index 000000000000..48b16fcb1f73 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/meal/UserMealController.java @@ -0,0 +1,78 @@ +package ru.javawebinar.topjava.web.meal; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import ru.javawebinar.topjava.model.UserMeal; +import ru.javawebinar.topjava.util.TimeUtil; + +import javax.servlet.http.HttpServletRequest; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Objects; + +/** + * GKislin + * 06.03.2015. + */ +@Controller +@RequestMapping(value = "/meals") +public class UserMealController extends AbstractUserMealController { + + @RequestMapping(value = "/delete", method = RequestMethod.GET) + public String delete(HttpServletRequest request) { + super.delete(getId(request)); + return "redirect:meals"; + } + + @RequestMapping(value = "/update", method = RequestMethod.GET) + public String editForUpdate(HttpServletRequest request, Model model) { + model.addAttribute("meal", super.get(getId(request))); + return "mealEdit"; + } + + @RequestMapping(value = "/create", method = RequestMethod.GET) + public String editForCreate(Model model) { + model.addAttribute("meal", new UserMeal(LocalDateTime.now().withNano(0).withSecond(0), "", 1000)); + return "mealEdit"; + } + + @RequestMapping(method = RequestMethod.POST) + public String updateOrCreate(HttpServletRequest request) { + String id = request.getParameter("id"); + UserMeal userMeal = new UserMeal(id.isEmpty() ? null : Integer.valueOf(id), + LocalDateTime.parse(request.getParameter("dateTime")), + request.getParameter("description"), + Integer.valueOf(request.getParameter("calories"))); + + if (userMeal.isNew()) { + super.create(userMeal); + } else { + super.update(userMeal, userMeal.getId()); + } + return "redirect:meals"; + } + + @RequestMapping(value = "/filter", method = RequestMethod.POST) + public String getBetween(HttpServletRequest request, Model model) { + 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)); + model.addAttribute("mealList", super.getBetween(startDate, startTime, endDate, endTime)); + return "mealList"; + } + + 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); + } +} \ No newline at end of file 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 919a7f92453d..f8a0b3175066 100644 --- a/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java @@ -1,71 +1,22 @@ 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.AuthorizedUser; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; 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 javax.servlet.http.HttpServletRequest; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.LocalTime; -import java.util.List; +import java.util.Objects; /** * 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 = AuthorizedUser.id(); - LOG.info("get meal {} for User {}", id, userId); - return service.get(id, userId); - } - - public void delete(int id) { - int userId = AuthorizedUser.id(); - LOG.info("delete meal {} for User {}", id, userId); - service.delete(id, userId); - } - - public List getAll() { - int userId = AuthorizedUser.id(); - LOG.info("getAll for User {}", userId); - return UserMealsUtil.getWithExceeded(service.getAll(userId), AuthorizedUser.getCaloriesPerDay()); - } - - public void update(UserMeal meal, int id) { - meal.setId(id); - int userId = AuthorizedUser.id(); - LOG.info("update {} for User {}", meal, userId); - service.update(meal, userId); - } - - public UserMeal create(UserMeal meal) { - meal.setId(null); - int userId = AuthorizedUser.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 = AuthorizedUser.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, AuthorizedUser.getCaloriesPerDay() - ); - } +public class UserMealRestController extends AbstractUserMealController { } \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/mealEdit.jsp b/src/main/webapp/WEB-INF/jsp/mealEdit.jsp index fa7bc1e57472..abc2638092fb 100644 --- a/src/main/webapp/WEB-INF/jsp/mealEdit.jsp +++ b/src/main/webapp/WEB-INF/jsp/mealEdit.jsp @@ -6,11 +6,7 @@
    -

    Home

    -

    - -

    Home

    -

    ${param.action == 'create' ? 'Create meal' : 'Edit meal'}

    +


    diff --git a/src/main/webapp/WEB-INF/jsp/mealList.jsp b/src/main/webapp/WEB-INF/jsp/mealList.jsp index e3ca784ee721..4e29121e902b 100644 --- a/src/main/webapp/WEB-INF/jsp/mealList.jsp +++ b/src/main/webapp/WEB-INF/jsp/mealList.jsp @@ -8,7 +8,7 @@

    - +
    From Date:
    @@ -28,7 +28,7 @@
    - +
    @@ -50,8 +50,8 @@ - - + +
    ${meal.description} ${meal.calories}UpdateDeleteUpdateDelete
    diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 330fb5bba850..accc39fc3d22 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -36,26 +36,4 @@ / - - From 97ae3cdb278c0f9b9dd0649c73fd4c480c53a783 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Sat, 16 Jul 2016 17:48:49 +0300 Subject: [PATCH 64/76] prepare to HW7 --- .../topjava/web/meal/UserMealController.java | 4 ++-- .../webapp/WEB-INF/jsp/fragments/headTag.jsp | 5 ++++- src/main/webapp/WEB-INF/web.xml | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/web/meal/UserMealController.java b/src/main/java/ru/javawebinar/topjava/web/meal/UserMealController.java index 48b16fcb1f73..bfe47c5243ac 100644 --- a/src/main/java/ru/javawebinar/topjava/web/meal/UserMealController.java +++ b/src/main/java/ru/javawebinar/topjava/web/meal/UserMealController.java @@ -24,7 +24,7 @@ public class UserMealController extends AbstractUserMealController { @RequestMapping(value = "/delete", method = RequestMethod.GET) public String delete(HttpServletRequest request) { super.delete(getId(request)); - return "redirect:meals"; + return "redirect:/meals"; } @RequestMapping(value = "/update", method = RequestMethod.GET) @@ -52,7 +52,7 @@ public String updateOrCreate(HttpServletRequest request) { } else { super.update(userMeal, userMeal.getId()); } - return "redirect:meals"; + return "redirect:/meals"; } @RequestMapping(value = "/filter", method = RequestMethod.POST) diff --git a/src/main/webapp/WEB-INF/jsp/fragments/headTag.jsp b/src/main/webapp/WEB-INF/jsp/fragments/headTag.jsp index 4f44c6dee4d5..90f86d23e672 100644 --- a/src/main/webapp/WEB-INF/jsp/fragments/headTag.jsp +++ b/src/main/webapp/WEB-INF/jsp/fragments/headTag.jsp @@ -1,9 +1,12 @@ <%@page contentType="text/html" pageEncoding="UTF-8" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <fmt:message key="app.title"/> + ${pageContext.request.requestURL} + - \ No newline at end of file + diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index accc39fc3d22..abc0d013bcfc 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -36,4 +36,21 @@ / + + encodingFilter + org.springframework.web.filter.CharacterEncodingFilter + + encoding + UTF-8 + + + forceEncoding + true + + + + encodingFilter + /* + + From f946c30f4fc86bfe7cee2dd2b45c9cdcddf9cd60 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Sat, 16 Jul 2016 17:49:18 +0300 Subject: [PATCH 65/76] prepare to HW7 --- .../ru/javawebinar/topjava/model/User.java | 27 +++++++++++++------ .../datajpa/DataJpaUserRepositoryImpl.java | 2 +- .../datajpa/ProxyUserMealRepository.java | 2 +- .../datajpa/ProxyUserRepository.java | 9 ++++--- .../repository/jpa/JpaUserRepositoryImpl.java | 4 ++- src/main/resources/db/populateDB.sql | 3 ++- .../ru/javawebinar/topjava/UserTestData.java | 5 ++-- .../service/AbstractUserServiceTest.java | 1 + 8 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index c6050d9f19d7..835068ad06fe 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -1,19 +1,15 @@ package ru.javawebinar.topjava.model; -import ru.javawebinar.topjava.util.UserMealsUtil; - import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.validator.constraints.Email; import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.NotEmpty; +import ru.javawebinar.topjava.util.UserMealsUtil; import javax.persistence.*; import javax.validation.constraints.Digits; -import java.util.Date; -import java.util.EnumSet; -import java.util.List; -import java.util.Set; +import java.util.*; /** * User: gkislin @@ -21,14 +17,25 @@ */ @NamedQueries({ @NamedQuery(name = User.DELETE, query = "DELETE FROM User u WHERE u.id=:id"), - @NamedQuery(name = User.BY_EMAIL, query = "SELECT u FROM User u LEFT JOIN FETCH u.roles WHERE u.email=?1"), - @NamedQuery(name = User.ALL_SORTED, query = "SELECT u FROM User u LEFT JOIN FETCH u.roles ORDER BY u.name, u.email"), + @NamedQuery(name = User.BY_EMAIL, query = "SELECT DISTINCT u FROM User u LEFT JOIN FETCH u.roles WHERE u.email=?1"), + @NamedQuery(name = User.ALL_SORTED, query = "SELECT DISTINCT u FROM User u LEFT JOIN FETCH u.roles ORDER BY u.name, u.email"), }) @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) @Entity +@NamedEntityGraphs({ + @NamedEntityGraph(name = User.GRAPH_WITH_ROLES, attributeNodes = @NamedAttributeNode("roles")), + @NamedEntityGraph(name = User.GRAPH_WITH_ROLES_AND_MEALS, attributeNodes = + { + @NamedAttributeNode("roles"), + @NamedAttributeNode("meals") + }) +}) @Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = "email", name = "users_unique_email_idx")}) public class User extends NamedEntity { + public static final String GRAPH_WITH_ROLES = "User.withRoles"; + public static final String GRAPH_WITH_ROLES_AND_MEALS = "User.withRolesAndMeals"; + public static final String DELETE = "User.delete"; public static final String ALL_SORTED = "User.getAllSorted"; public static final String BY_EMAIL = "User.getByEmail"; @@ -124,6 +131,10 @@ public Set getRoles() { return roles; } + public void setRoles(Collection roles) { + this.roles = EnumSet.copyOf(roles); + } + public String getPassword() { return password; } diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java index af7dfa663b0a..d0ca0a0fb9d6 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java @@ -45,6 +45,6 @@ public List getAll() { @Override public User getWithMeals(int id) { - return proxy.getWithMeals(id); + return proxy.findById(id); } } diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java index 3c857a4c4880..f30b6f5ee1c9 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java @@ -31,6 +31,6 @@ public interface ProxyUserMealRepository extends JpaRepository getBetween(@Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate, @Param("userId") int userId); - @Query("SELECT um FROM UserMeal um JOIN FETCH um.user WHERE um.id = ?1 and um.user.id = ?2") + @Query("SELECT um FROM UserMeal um JOIN FETCH um.user JOIN FETCH um.user.roles WHERE um.id = ?1 and um.user.id = ?2") UserMeal getWithUser(Integer id, Integer userId); } diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java index badae9d6e1a3..333aea256deb 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java @@ -1,5 +1,6 @@ package ru.javawebinar.topjava.repository.datajpa; +import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -26,14 +27,16 @@ public interface ProxyUserRepository extends JpaRepository { User save(User user); @Override + @EntityGraph(value = User.GRAPH_WITH_ROLES) User findOne(Integer id); @Override - @Query("SELECT u FROM User u LEFT JOIN FETCH u.roles ORDER BY u.name, u.email") + @Query("SELECT DISTINCT u FROM User u LEFT JOIN FETCH u.roles ORDER BY u.name, u.email") List findAll(); + @EntityGraph(value = User.GRAPH_WITH_ROLES) User getByEmail(String email); - @Query("SELECT u FROM User u LEFT JOIN FETCH u.meals WHERE u.id = ?1") - User getWithMeals(Integer id); + @EntityGraph(value = User.GRAPH_WITH_ROLES_AND_MEALS) + User findById(Integer id); } \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java index 2b4057f3a4b4..dd1e9043b8d9 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java @@ -7,6 +7,7 @@ import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; +import java.util.Collections; import java.util.List; /** @@ -42,7 +43,8 @@ public User save(User user) { @Override public User get(int id) { - return em.find(User.class, id); + return em.find(User.class, id, + Collections.singletonMap("javax.persistence.fetchgraph", em.getEntityGraph(User.GRAPH_WITH_ROLES))); } @Override diff --git a/src/main/resources/db/populateDB.sql b/src/main/resources/db/populateDB.sql index 0fbffd0dfb58..cc816500ce36 100644 --- a/src/main/resources/db/populateDB.sql +++ b/src/main/resources/db/populateDB.sql @@ -11,7 +11,8 @@ VALUES ('Admin', 'admin@gmail.com', 'admin'); INSERT INTO user_roles (role, user_id) VALUES ('ROLE_USER', 100000), - ('ROLE_ADMIN', 100001); + ('ROLE_ADMIN', 100001), + ('ROLE_USER', 100001); INSERT INTO meals (date_time, description, calories, user_id) VALUES ('2015-05-30 10:00:00', 'Завтрак', 500, 100000), diff --git a/src/test/java/ru/javawebinar/topjava/UserTestData.java b/src/test/java/ru/javawebinar/topjava/UserTestData.java index c6855207f44e..06823a8151d0 100644 --- a/src/test/java/ru/javawebinar/topjava/UserTestData.java +++ b/src/test/java/ru/javawebinar/topjava/UserTestData.java @@ -20,7 +20,7 @@ public class UserTestData { 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 User ADMIN = new User(ADMIN_ID, "Admin", "admin@gmail.com", "admin", Role.ROLE_ADMIN, Role.ROLE_USER); public static final ModelMatcher MATCHER = new ModelMatcher<>(u -> ((u instanceof TestUser) ? (TestUser) u : new TestUser(u))); @@ -69,7 +69,8 @@ public boolean equals(Object o) { && Objects.equals(this.name, that.name) && Objects.equals(this.email, that.email) && Objects.equals(this.caloriesPerDay, that.caloriesPerDay) - && Objects.equals(this.enabled, that.enabled); + && Objects.equals(this.enabled, that.enabled) + && Objects.equals(this.roles, that.roles); } } } diff --git a/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java index 0752fdbb225b..f81a79dbe6cc 100644 --- a/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java @@ -77,6 +77,7 @@ public void testUpdate() throws Exception { TestUser updated = new TestUser(USER); updated.setName("UpdatedName"); updated.setCaloriesPerDay(330); + updated.setRoles(Collections.singletonList(Role.ROLE_ADMIN)); service.update(updated.asUser()); MATCHER.assertEquals(updated, service.get(USER_ID)); } From 032b3e225edf563e4a061f2554d904df0976e827 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Sat, 16 Jul 2016 17:49:40 +0300 Subject: [PATCH 66/76] prepare to HW7 --- .../AbstractJdbcUserMealRepositoryImpl.java | 9 ++- .../jdbc/JdbcUserRepositoryImpl.java | 81 ++++++++++++++++++- src/main/resources/spring/spring-db.xml | 9 ++- 3 files changed, 92 insertions(+), 7 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/repository/jdbc/AbstractJdbcUserMealRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jdbc/AbstractJdbcUserMealRepositoryImpl.java index d60ffa64157a..d2d52fa7ce6b 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/jdbc/AbstractJdbcUserMealRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/jdbc/AbstractJdbcUserMealRepositoryImpl.java @@ -7,6 +7,8 @@ import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.transaction.annotation.Transactional; +import ru.javawebinar.topjava.model.Role; import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.repository.UserMealRepository; @@ -18,11 +20,12 @@ * User: gkislin * Date: 26.08.2014 */ - +@Transactional(readOnly = true) public abstract class AbstractJdbcUserMealRepositoryImpl implements UserMealRepository { - private SimpleJdbcInsert insertUserMeal; + private static final RowMapper ROLE_ROW_MAPPER = (rs, rowNum) -> Role.valueOf(rs.getString("role")); + private SimpleJdbcInsert insertUserMeal; private final RowMapper rowMapper; @Autowired @@ -41,6 +44,7 @@ public AbstractJdbcUserMealRepositoryImpl(RowMapper rowMapper, DataSou protected abstract T toDbValue(LocalDateTime ldt); @Override + @Transactional public UserMeal save(UserMeal userMeal, int userId) { MapSqlParameterSource map = new MapSqlParameterSource() .addValue("id", userMeal.getId()) @@ -65,6 +69,7 @@ public UserMeal save(UserMeal userMeal, int userId) { } @Override + @Transactional public boolean delete(int id, int userId) { return jdbcTemplate.update("DELETE FROM meals WHERE id=? AND user_id=?", id, userId) != 0; } diff --git a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepositoryImpl.java index 5646bad071ed..63ef6ad8dbbb 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepositoryImpl.java @@ -2,17 +2,27 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.support.DataAccessUtils; +import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; 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 org.springframework.transaction.annotation.Transactional; +import ru.javawebinar.topjava.model.Role; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.repository.UserRepository; import javax.sql.DataSource; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; /** * User: gkislin @@ -20,9 +30,11 @@ */ @Repository +@Transactional(readOnly = true) public class JdbcUserRepositoryImpl implements UserRepository { private static final BeanPropertyRowMapper ROW_MAPPER = BeanPropertyRowMapper.newInstance(User.class); + private static final RowMapper ROLE_ROW_MAPPER = (rs, rowNum) -> Role.valueOf(rs.getString("role")); @Autowired private JdbcTemplate jdbcTemplate; @@ -40,6 +52,7 @@ public JdbcUserRepositoryImpl(DataSource dataSource) { } @Override + @Transactional public User save(User user) { MapSqlParameterSource map = new MapSqlParameterSource() .addValue("id", user.getId()) @@ -53,7 +66,10 @@ public User save(User user) { if (user.isNew()) { Number newKey = insertUser.executeAndReturnKey(map); user.setId(newKey.intValue()); + insertRoles(user); } else { + deleteRoles(user); + insertRoles(user); namedParameterJdbcTemplate.update( "UPDATE users SET name=:name, email=:email, password=:password, " + "registered=:registered, enabled=:enabled, calories_per_day=:caloriesPerDay WHERE id=:id", map); @@ -62,6 +78,7 @@ public User save(User user) { } @Override + @Transactional public boolean delete(int id) { return jdbcTemplate.update("DELETE FROM users WHERE id=?", id) != 0; } @@ -69,16 +86,74 @@ public boolean delete(int id) { @Override public User get(int id) { List users = jdbcTemplate.query("SELECT * FROM users WHERE id=?", ROW_MAPPER, id); - return DataAccessUtils.singleResult(users); + return setRoles(DataAccessUtils.singleResult(users)); } @Override public User getByEmail(String email) { - return jdbcTemplate.queryForObject("SELECT * FROM users WHERE email=?", ROW_MAPPER, email); + return setRoles(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); + class UserRole { + final private Role role; + final private int userId; + + private UserRole(Role role, int userId) { + this.role = role; + this.userId = userId; + } + + public Role getRole() { + return role; + } + + public int getUserId() { + return userId; + } + } + + Map> userRolesMap = jdbcTemplate.query("SELECT role, user_id FROM user_roles", + (rs, rowNum) -> new UserRole(Role.valueOf(rs.getString("role")), rs.getInt("user_id"))).stream() + .collect( + Collectors.groupingBy(UserRole::getUserId, Collectors.mapping(UserRole::getRole, Collectors.toList())) + ); + + List users = jdbcTemplate.query("SELECT * FROM users ORDER BY name, email", ROW_MAPPER); + users.forEach(u -> u.setRoles(userRolesMap.get(u.getId()))); + return users; + } + + private void insertRoles(User u) { + Set roles = u.getRoles(); + Iterator iterator = roles.iterator(); + + jdbcTemplate.batchUpdate("INSERT INTO user_roles (user_id, role) VALUES (?, ?)", + new BatchPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + ps.setInt(1, u.getId()); + ps.setString(2, iterator.next().name()); + } + + @Override + public int getBatchSize() { + return roles.size(); + } + }); + } + + private void deleteRoles(User u) { + jdbcTemplate.update("DELETE FROM user_roles WHERE user_id=?", u.getId()); + } + + private User setRoles(User u) { + if (u != null) { + List roles = jdbcTemplate.query("SELECT role FROM user_roles WHERE user_id=?", + ROLE_ROW_MAPPER, u.getId()); + u.setRoles(roles); + } + return u; } } diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index 31542d8900cb..385b9b543a9c 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -20,6 +20,8 @@ + + @@ -57,6 +59,11 @@ + + + + @@ -87,8 +94,6 @@ - - From cc40dfb57b5f9eb1e2ac4175c25da0df0ac2465c Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Sun, 17 Jul 2016 23:52:46 +0300 Subject: [PATCH 67/76] prepare to HW7 --- src/main/resources/spring/spring-db.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index 385b9b543a9c..0d798f121a55 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -84,6 +84,9 @@ + + + From ff5d2509be60747fd986c16f97a08fc7aab9bfb7 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Sun, 17 Jul 2016 23:54:21 +0300 Subject: [PATCH 68/76] prepare to HW7 --- pom.xml | 19 +++++- src/main/resources/spring/spring-db.xml | 2 + .../topjava/web/AbstractControllerTest.java | 64 +++++++++++++++++++ .../topjava/web/user/RootControllerTest.java | 34 ++++++++++ 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/test/java/ru/javawebinar/topjava/web/AbstractControllerTest.java create mode 100644 src/test/java/ru/javawebinar/topjava/web/user/RootControllerTest.java diff --git a/pom.xml b/pom.xml index 5d84a2c8ac32..69a99df9dd57 100644 --- a/pom.xml +++ b/pom.xml @@ -26,8 +26,10 @@ 9.4.1208 + 4.12 + 1.3 5.1.0.Final @@ -174,13 +176,28 @@ junit ${junit.version} test + + + hamcrest-core + org.hamcrest + + + + + org.hamcrest + hamcrest-all + ${hamcrest.version} + test + + + javax.servlet jstl 1.2 - + org.apache.tomcat tomcat-servlet-api diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index 0d798f121a55..12c3ce8a2941 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -84,9 +84,11 @@ + diff --git a/src/test/java/ru/javawebinar/topjava/web/AbstractControllerTest.java b/src/test/java/ru/javawebinar/topjava/web/AbstractControllerTest.java new file mode 100644 index 000000000000..fd5691cfa9b4 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/web/AbstractControllerTest.java @@ -0,0 +1,64 @@ +package ru.javawebinar.topjava.web; + +import org.junit.Before; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.filter.CharacterEncodingFilter; +import ru.javawebinar.topjava.service.UserService; + +import javax.annotation.PostConstruct; + +import static ru.javawebinar.topjava.Profiles.ACTIVE_DB; +import static ru.javawebinar.topjava.Profiles.DB_IMPLEMENTATION; + +/** + * User: gkislin + * Date: 10.08.2014 + */ +@ContextConfiguration({ + "classpath:spring/spring-app.xml", + "classpath:spring/spring-mvc.xml", + "classpath:spring/spring-db.xml" +}) +@WebAppConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +@Transactional +@ActiveProfiles({ACTIVE_DB, DB_IMPLEMENTATION}) +abstract public class AbstractControllerTest { + + private static final CharacterEncodingFilter CHARACTER_ENCODING_FILTER = new CharacterEncodingFilter(); + + static { + CHARACTER_ENCODING_FILTER.setEncoding("UTF-8"); + CHARACTER_ENCODING_FILTER.setForceEncoding(true); + } + + protected MockMvc mockMvc; + + @Autowired + protected UserService userService; + + @Autowired + private WebApplicationContext webApplicationContext; + + @PostConstruct + void postConstruct() { + mockMvc = MockMvcBuilders + .webAppContextSetup(webApplicationContext) + .addFilter(CHARACTER_ENCODING_FILTER) + .build(); + } + + @Before + public void setUp() { + userService.evictCache(); + } +} diff --git a/src/test/java/ru/javawebinar/topjava/web/user/RootControllerTest.java b/src/test/java/ru/javawebinar/topjava/web/user/RootControllerTest.java new file mode 100644 index 000000000000..6cd1405613c2 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/web/user/RootControllerTest.java @@ -0,0 +1,34 @@ +package ru.javawebinar.topjava.web.user; + +import org.junit.Test; +import ru.javawebinar.topjava.web.AbstractControllerTest; + +import static org.hamcrest.Matchers.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static ru.javawebinar.topjava.UserTestData.USER; +import static ru.javawebinar.topjava.model.BaseEntity.START_SEQ; + +/** + * GKislin + * 10.04.2015. + */ +public class RootControllerTest extends AbstractControllerTest { + + @Test + public void testUserList() throws Exception { + mockMvc.perform(get("/users")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(view().name("userList")) + .andExpect(forwardedUrl("/WEB-INF/jsp/userList.jsp")) + .andExpect(model().attribute("userList", hasSize(2))) + .andExpect(model().attribute("userList", hasItem( + allOf( + hasProperty("id", is(START_SEQ)), + hasProperty("name", is(USER.getName())) + ) + ))); + } +} \ No newline at end of file From da5450c86af2697f8546fb0c367d90acc11fe97d Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Mon, 18 Jul 2016 00:20:50 +0300 Subject: [PATCH 69/76] prepare to HW7 --- .../topjava/web/user/AdminRestController.java | 37 +++++++++++++++---- .../web/user/ProfileRestController.java | 15 ++++++-- 2 files changed, 41 insertions(+), 11 deletions(-) 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 d6b8bb420803..c03c287b764f 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java @@ -1,38 +1,59 @@ package ru.javawebinar.topjava.web.user; -import org.springframework.stereotype.Controller; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import ru.javawebinar.topjava.model.User; +import java.net.URI; import java.util.List; /** * GKislin * 06.03.2015. */ -@Controller +@RestController +@RequestMapping(AdminRestController.REST_URL) public class AdminRestController extends AbstractUserController { + static final String REST_URL = "/rest/admin/users"; + @RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public List getAll() { return super.getAll(); } - public User get(int id) { + @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public User get(@PathVariable("id") int id) { return super.get(id); } - public User create(User user) { - return super.create(user); + @RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity createWithLocation(@RequestBody User user) { + User created = super.create(user); + + URI uriOfNewResource = ServletUriComponentsBuilder.fromCurrentContextPath() + .path(REST_URL + "/{id}") + .buildAndExpand(created.getId()).toUri(); + +// HttpHeaders httpHeaders = new HttpHeaders(); +// httpHeaders.setLocation(uriOfNewResource); + + return ResponseEntity.created(uriOfNewResource).body(created); } - public void delete(int id) { + @RequestMapping(value = "/{id}", method = RequestMethod.DELETE) + public void delete(@PathVariable("id") int id) { super.delete(id); } - public void update(User user, int id) { + @RequestMapping(value = "/{id}", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE) + public void update(@RequestBody User user, @PathVariable("id") int id) { super.update(user, id); } - public User getByMail(String email) { + @RequestMapping(value = "/by", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public User getByMail(@RequestParam("email") 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 index 443db9c53263..57f3d7f009ca 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java @@ -1,6 +1,10 @@ package ru.javawebinar.topjava.web.user; -import org.springframework.stereotype.Controller; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; import ru.javawebinar.topjava.AuthorizedUser; import ru.javawebinar.topjava.model.User; @@ -8,18 +12,23 @@ * GKislin * 06.03.2015. */ -@Controller +@RestController +@RequestMapping(ProfileRestController.REST_URL) public class ProfileRestController extends AbstractUserController { + static final String REST_URL = "/rest/profile"; + @RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public User get() { return super.get(AuthorizedUser.id()); } + @RequestMapping(method = RequestMethod.DELETE) public void delete() { super.delete(AuthorizedUser.id()); } - public void update(User user) { + @RequestMapping(method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE) + public void update(@RequestBody User user) { super.update(user, AuthorizedUser.id()); } } \ No newline at end of file From f0b001a5f54b4301b85eb7b3ec7b083a9a3f71b4 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 19 Jul 2016 23:33:38 +0300 Subject: [PATCH 70/76] prepare to HW7 --- pom.xml | 8 +++++++ .../javawebinar/topjava/model/BaseEntity.java | 5 ++++ .../ru/javawebinar/topjava/model/User.java | 2 ++ .../web/user/AdminRestControllerTest.java | 24 +++++++++++++++++++ 4 files changed, 39 insertions(+) create mode 100644 src/test/java/ru/javawebinar/topjava/web/user/AdminRestControllerTest.java diff --git a/pom.xml b/pom.xml index 69a99df9dd57..860d2f6c3d93 100644 --- a/pom.xml +++ b/pom.xml @@ -19,6 +19,7 @@ 1.10.2.RELEASE 8.0.33 4.2.6.RELEASE + 2.8.0 1.1.7 @@ -267,6 +268,13 @@ 2.2.5 provided + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson-json.version} + diff --git a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java index 007e260dcb68..11130a61a483 100644 --- a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java +++ b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java @@ -1,13 +1,18 @@ package ru.javawebinar.topjava.model; +import com.fasterxml.jackson.annotation.JsonAutoDetect; import javax.persistence.*; +import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY; +import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE; + /** * User: gkislin * Date: 22.08.2014 */ @MappedSuperclass @Access(AccessType.FIELD) +@JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, isGetterVisibility = NONE, setterVisibility = NONE) public class BaseEntity { public static final int START_SEQ = 100000; diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index 835068ad06fe..ed79411411ea 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -1,5 +1,6 @@ package ru.javawebinar.topjava.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.validator.constraints.Email; @@ -69,6 +70,7 @@ public class User extends NamedEntity { @OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY, mappedBy = "user") @OrderBy("dateTime DESC") + @JsonIgnore protected List meals; public User() { diff --git a/src/test/java/ru/javawebinar/topjava/web/user/AdminRestControllerTest.java b/src/test/java/ru/javawebinar/topjava/web/user/AdminRestControllerTest.java new file mode 100644 index 000000000000..686748b85646 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/web/user/AdminRestControllerTest.java @@ -0,0 +1,24 @@ +package ru.javawebinar.topjava.web.user; + +import org.junit.Test; +import org.springframework.http.MediaType; +import ru.javawebinar.topjava.web.AbstractControllerTest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static ru.javawebinar.topjava.UserTestData.ADMIN_ID; + +public class AdminRestControllerTest extends AbstractControllerTest { + + public static final String REST_URL = AdminRestController.REST_URL + '/'; + + @Test + public void testGet() throws Exception { + mockMvc.perform(get(REST_URL + ADMIN_ID)) + .andExpect(status().isOk()) + .andDo(print()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)); + } +} \ No newline at end of file From 5a19711f2c792b663464d652aaf3fc47f880e62f Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 19 Jul 2016 23:34:15 +0300 Subject: [PATCH 71/76] prepare to HW7 --- pom.xml | 6 +++ .../javawebinar/topjava/model/BaseEntity.java | 6 +-- .../ru/javawebinar/topjava/model/User.java | 3 +- .../ru/javawebinar/topjava/util/TimeUtil.java | 10 ++++- .../topjava/web/json/JacksonObjectMapper.java | 42 +++++++++++++++++++ .../web/json/JsonLocalDateTimeConverter.java | 42 +++++++++++++++++++ .../topjava/web/json/JsonUtil.java | 41 ++++++++++++++++++ src/main/resources/spring/spring-mvc.xml | 10 ++++- .../topjava/web/json/JsonUtilTest.java | 30 +++++++++++++ 9 files changed, 181 insertions(+), 9 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/web/json/JacksonObjectMapper.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/json/JsonLocalDateTimeConverter.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/json/JsonUtil.java create mode 100644 src/test/java/ru/javawebinar/topjava/web/json/JsonUtilTest.java diff --git a/pom.xml b/pom.xml index 860d2f6c3d93..ea68d992d2ce 100644 --- a/pom.xml +++ b/pom.xml @@ -275,6 +275,12 @@ jackson-databind ${jackson-json.version} + + com.fasterxml.jackson.datatype + jackson-datatype-hibernate5 + ${jackson-json.version} + + diff --git a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java index 11130a61a483..35e2a8c21cf4 100644 --- a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java +++ b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java @@ -1,18 +1,14 @@ package ru.javawebinar.topjava.model; -import com.fasterxml.jackson.annotation.JsonAutoDetect; import javax.persistence.*; -import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY; -import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE; - /** * User: gkislin * Date: 22.08.2014 */ @MappedSuperclass @Access(AccessType.FIELD) -@JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, isGetterVisibility = NONE, setterVisibility = NONE) +//@JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, isGetterVisibility = NONE, setterVisibility = NONE) public class BaseEntity { public static final int START_SEQ = 100000; diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index ed79411411ea..a40316873fc4 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -1,6 +1,5 @@ package ru.javawebinar.topjava.model; -import com.fasterxml.jackson.annotation.JsonIgnore; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.validator.constraints.Email; @@ -70,7 +69,7 @@ public class User extends NamedEntity { @OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY, mappedBy = "user") @OrderBy("dateTime DESC") - @JsonIgnore +// @JsonIgnore protected List meals; public User() { diff --git a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java index c6951ab73506..56348b3f9c24 100644 --- a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java @@ -35,4 +35,12 @@ public static LocalDate parseLocalDate(String str) { public static LocalTime parseLocalTime(String str) { return StringUtils.isEmpty(str) ? null : LocalTime.parse(str); } -} + + public static LocalDateTime parseLocalDateTime(String str) { + return parseLocalDateTime(str, DATE_TIME_FORMATTER); + } + + public static LocalDateTime parseLocalDateTime(String str, DateTimeFormatter formatter) { + return StringUtils.isEmpty(str) ? LocalDateTime.now() : LocalDateTime.parse(str, formatter); + } +} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/web/json/JacksonObjectMapper.java b/src/main/java/ru/javawebinar/topjava/web/json/JacksonObjectMapper.java new file mode 100644 index 000000000000..69b45078bbea --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/json/JacksonObjectMapper.java @@ -0,0 +1,42 @@ +package ru.javawebinar.topjava.web.json; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module; + +import java.time.LocalDateTime; + +/** + * User: gkislin + * Date: 26.05.2014 + *

    + * Handling Hibernate lazy-loading + * + * @link https://github.com/FasterXML/jackson + * @link https://github.com/FasterXML/jackson-datatype-hibernate + * @link http://wiki.fasterxml.com/JacksonHowToCustomSerializers + */ +public class JacksonObjectMapper extends ObjectMapper { + + private static final ObjectMapper MAPPER = new JacksonObjectMapper(); + + public static ObjectMapper getMapper() { + return MAPPER; + } + + private JacksonObjectMapper() { + registerModule(new Hibernate5Module()); + + SimpleModule customModule = new SimpleModule("customModule"); + customModule.addSerializer(new JsonLocalDateTimeConverter.UserSettingSerializer()); + customModule.addDeserializer(LocalDateTime.class, new JsonLocalDateTimeConverter.UserSettingDeserializer()); + registerModule(customModule); + + setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); + setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); + setSerializationInclusion(JsonInclude.Include.NON_NULL); + } +} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/web/json/JsonLocalDateTimeConverter.java b/src/main/java/ru/javawebinar/topjava/web/json/JsonLocalDateTimeConverter.java new file mode 100644 index 000000000000..6447099392a9 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/json/JsonLocalDateTimeConverter.java @@ -0,0 +1,42 @@ +package ru.javawebinar.topjava.web.json; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import ru.javawebinar.topjava.util.TimeUtil; + +import java.io.IOException; +import java.time.LocalDateTime; + +/** + * GKislin + * 06.01.2015. + */ +public class JsonLocalDateTimeConverter { + public static class UserSettingSerializer extends JsonSerializer { + @Override + public void serialize(LocalDateTime ldt, JsonGenerator jgen, SerializerProvider provider) throws IOException { + jgen.writeString(TimeUtil.toString(ldt)); + } + + @Override + public Class handledType() { + return LocalDateTime.class; + } + } + + public static class UserSettingDeserializer extends JsonDeserializer { + @Override + public LocalDateTime deserialize(JsonParser jp, DeserializationContext ctx) throws IOException { + return TimeUtil.parseLocalDateTime(jp.getText()); + } + + @Override + public Class handledType() { + return LocalDateTime.class; + } + } +} diff --git a/src/main/java/ru/javawebinar/topjava/web/json/JsonUtil.java b/src/main/java/ru/javawebinar/topjava/web/json/JsonUtil.java new file mode 100644 index 000000000000..c15e266c4dfe --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/json/JsonUtil.java @@ -0,0 +1,41 @@ +package ru.javawebinar.topjava.web.json; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectReader; + +import java.io.IOException; +import java.util.List; + +import static ru.javawebinar.topjava.web.json.JacksonObjectMapper.getMapper; + +/** + * User: gkislin + * Date: 30.04.2014 + */ +public class JsonUtil { + + public static List readValues(String json, Class clazz) { + ObjectReader reader = getMapper().readerFor(clazz); + try { + return reader.readValues(json).readAll(); + } catch (IOException e) { + throw new IllegalArgumentException("Invalid read array from JSON:\n'" + json + "'", e); + } + } + + public static T readValue(String json, Class clazz) { + try { + return getMapper().readValue(json, clazz); + } catch (IOException e) { + throw new IllegalArgumentException("Invalid read from JSON:\n'" + json + "'", e); + } + } + + public static String writeValue(T obj) { + try { + return getMapper().writeValueAsString(obj); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Invalid write to JSON:\n'" + obj + "'", e); + } + } +} diff --git a/src/main/resources/spring/spring-mvc.xml b/src/main/resources/spring/spring-mvc.xml index 12ac233daa15..86a60d059a02 100644 --- a/src/main/resources/spring/spring-mvc.xml +++ b/src/main/resources/spring/spring-mvc.xml @@ -5,7 +5,15 @@ 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 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> - + + + + + + + + + diff --git a/src/test/java/ru/javawebinar/topjava/web/json/JsonUtilTest.java b/src/test/java/ru/javawebinar/topjava/web/json/JsonUtilTest.java new file mode 100644 index 000000000000..d1a7589c42ea --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/web/json/JsonUtilTest.java @@ -0,0 +1,30 @@ +package ru.javawebinar.topjava.web.json; + +import org.junit.Test; +import ru.javawebinar.topjava.MealTestData; +import ru.javawebinar.topjava.model.UserMeal; + +import java.util.List; + +/** + * GKislin + * 22.07.2015. + */ +public class JsonUtilTest { + + @Test + public void testReadWriteValue() throws Exception { + String json = JsonUtil.writeValue(MealTestData.ADMIN_MEAL); + System.out.println(json); + UserMeal userMeal = JsonUtil.readValue(json, UserMeal.class); + MealTestData.MATCHER.assertEquals(MealTestData.ADMIN_MEAL, userMeal); + } + + @Test + public void testReadWriteValues() throws Exception { + String json = JsonUtil.writeValue(MealTestData.USER_MEALS); + System.out.println(json); + List userMeals = JsonUtil.readValues(json, UserMeal.class); + MealTestData.MATCHER.assertCollectionEquals(MealTestData.USER_MEALS, userMeals); + } +} \ No newline at end of file From b8b04f74225df66f28e81dfd8fc1cef5f360248a Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 19 Jul 2016 23:35:18 +0300 Subject: [PATCH 72/76] prepare to HW7 --- pom.xml | 5 +++ .../topjava/web/json/JacksonObjectMapper.java | 11 ++--- .../web/json/JsonLocalDateTimeConverter.java | 42 ------------------- 3 files changed, 9 insertions(+), 49 deletions(-) delete mode 100644 src/main/java/ru/javawebinar/topjava/web/json/JsonLocalDateTimeConverter.java diff --git a/pom.xml b/pom.xml index ea68d992d2ce..9a3cf51c1eff 100644 --- a/pom.xml +++ b/pom.xml @@ -280,6 +280,11 @@ jackson-datatype-hibernate5 ${jackson-json.version} + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson-json.version} + diff --git a/src/main/java/ru/javawebinar/topjava/web/json/JacksonObjectMapper.java b/src/main/java/ru/javawebinar/topjava/web/json/JacksonObjectMapper.java index 69b45078bbea..cdd7fcdd4d3b 100644 --- a/src/main/java/ru/javawebinar/topjava/web/json/JacksonObjectMapper.java +++ b/src/main/java/ru/javawebinar/topjava/web/json/JacksonObjectMapper.java @@ -4,10 +4,9 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module; - -import java.time.LocalDateTime; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; /** * User: gkislin @@ -30,10 +29,8 @@ public static ObjectMapper getMapper() { private JacksonObjectMapper() { registerModule(new Hibernate5Module()); - SimpleModule customModule = new SimpleModule("customModule"); - customModule.addSerializer(new JsonLocalDateTimeConverter.UserSettingSerializer()); - customModule.addDeserializer(LocalDateTime.class, new JsonLocalDateTimeConverter.UserSettingDeserializer()); - registerModule(customModule); + registerModule(new JavaTimeModule()); + configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); diff --git a/src/main/java/ru/javawebinar/topjava/web/json/JsonLocalDateTimeConverter.java b/src/main/java/ru/javawebinar/topjava/web/json/JsonLocalDateTimeConverter.java deleted file mode 100644 index 6447099392a9..000000000000 --- a/src/main/java/ru/javawebinar/topjava/web/json/JsonLocalDateTimeConverter.java +++ /dev/null @@ -1,42 +0,0 @@ -package ru.javawebinar.topjava.web.json; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import ru.javawebinar.topjava.util.TimeUtil; - -import java.io.IOException; -import java.time.LocalDateTime; - -/** - * GKislin - * 06.01.2015. - */ -public class JsonLocalDateTimeConverter { - public static class UserSettingSerializer extends JsonSerializer { - @Override - public void serialize(LocalDateTime ldt, JsonGenerator jgen, SerializerProvider provider) throws IOException { - jgen.writeString(TimeUtil.toString(ldt)); - } - - @Override - public Class handledType() { - return LocalDateTime.class; - } - } - - public static class UserSettingDeserializer extends JsonDeserializer { - @Override - public LocalDateTime deserialize(JsonParser jp, DeserializationContext ctx) throws IOException { - return TimeUtil.parseLocalDateTime(jp.getText()); - } - - @Override - public Class handledType() { - return LocalDateTime.class; - } - } -} From baa8468e52c641c928a4f66afc2b801bda6ab555 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 19 Jul 2016 23:36:04 +0300 Subject: [PATCH 73/76] prepare to HW7 --- .../ru/javawebinar/topjava/MealTestData.java | 3 +- .../java/ru/javawebinar/topjava/TestUtil.java | 31 +++++++++ .../ru/javawebinar/topjava/UserTestData.java | 2 +- .../topjava/matcher/ModelMatcher.java | 54 ++++++++++++++- .../topjava/matcher/TestMatcher.java | 29 ++++++++ .../web/user/AdminRestControllerTest.java | 68 +++++++++++++++++-- .../web/user/ProfileRestControllerTest.java | 47 +++++++++++++ 7 files changed, 226 insertions(+), 8 deletions(-) create mode 100644 src/test/java/ru/javawebinar/topjava/TestUtil.java create mode 100644 src/test/java/ru/javawebinar/topjava/matcher/TestMatcher.java create mode 100644 src/test/java/ru/javawebinar/topjava/web/user/ProfileRestControllerTest.java diff --git a/src/test/java/ru/javawebinar/topjava/MealTestData.java b/src/test/java/ru/javawebinar/topjava/MealTestData.java index 997184b17814..4e038c6a766f 100644 --- a/src/test/java/ru/javawebinar/topjava/MealTestData.java +++ b/src/test/java/ru/javawebinar/topjava/MealTestData.java @@ -1,5 +1,6 @@ package ru.javawebinar.topjava; +import ru.javawebinar.topjava.TestUtil.ToStringModelMatcher; import ru.javawebinar.topjava.matcher.ModelMatcher; import ru.javawebinar.topjava.model.UserMeal; @@ -16,7 +17,7 @@ */ public class MealTestData { - public static final ModelMatcher MATCHER = new ModelMatcher<>(UserMeal::toString); + public static final ModelMatcher MATCHER = new ToStringModelMatcher<>(UserMeal.class); public static final int MEAL1_ID = START_SEQ + 2; public static final int ADMIN_MEAL_ID = START_SEQ + 8; diff --git a/src/test/java/ru/javawebinar/topjava/TestUtil.java b/src/test/java/ru/javawebinar/topjava/TestUtil.java new file mode 100644 index 000000000000..bc9aa67c4897 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/TestUtil.java @@ -0,0 +1,31 @@ +package ru.javawebinar.topjava; + +import org.springframework.test.web.servlet.ResultActions; +import ru.javawebinar.topjava.matcher.ModelMatcher; + +import java.io.UnsupportedEncodingException; + +/** + * GKislin + * 05.01.2015. + */ +public class TestUtil { + + public static ResultActions print(ResultActions action) throws UnsupportedEncodingException { + System.out.println(getContent(action)); + return action; + } + + public static String getContent(ResultActions action) throws UnsupportedEncodingException { + return action.andReturn().getResponse().getContentAsString(); + } + + /** + * Compare entities using toString + */ + public static class ToStringModelMatcher extends ModelMatcher { + public ToStringModelMatcher(Class entityClass) { + super(Object::toString, entityClass); + } + } +} diff --git a/src/test/java/ru/javawebinar/topjava/UserTestData.java b/src/test/java/ru/javawebinar/topjava/UserTestData.java index 06823a8151d0..d6410ea3a13d 100644 --- a/src/test/java/ru/javawebinar/topjava/UserTestData.java +++ b/src/test/java/ru/javawebinar/topjava/UserTestData.java @@ -22,7 +22,7 @@ public class UserTestData { 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, Role.ROLE_USER); - public static final ModelMatcher MATCHER = new ModelMatcher<>(u -> ((u instanceof TestUser) ? (TestUser) u : new TestUser(u))); + public static final ModelMatcher MATCHER = new ModelMatcher<>(u -> ((u instanceof TestUser) ? (TestUser) u : new TestUser(u)), User.class); public static class TestUser extends User { diff --git a/src/test/java/ru/javawebinar/topjava/matcher/ModelMatcher.java b/src/test/java/ru/javawebinar/topjava/matcher/ModelMatcher.java index f2b18b2e34bd..b7078c203d2c 100644 --- a/src/test/java/ru/javawebinar/topjava/matcher/ModelMatcher.java +++ b/src/test/java/ru/javawebinar/topjava/matcher/ModelMatcher.java @@ -1,11 +1,20 @@ package ru.javawebinar.topjava.matcher; import org.junit.Assert; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.ResultMatcher; +import ru.javawebinar.topjava.TestUtil; +import ru.javawebinar.topjava.web.json.JsonUtil; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; import java.util.Collection; +import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; + /** * GKislin * 06.01.2015. @@ -15,9 +24,19 @@ */ public class ModelMatcher { protected Function entityConverter; + protected Class entityClass; - public ModelMatcher(Function entityConverter) { + public ModelMatcher(Function entityConverter, Class entityClass) { this.entityConverter = entityConverter; + this.entityClass = entityClass; + } + + private T fromJsonValue(String json) { + return JsonUtil.readValue(json, entityClass); + } + + private Collection fromJsonValues(String json) { + return JsonUtil.readValues(json, entityClass); } public void assertEquals(T expected, T actual) { @@ -28,7 +47,38 @@ public void assertCollectionEquals(Collection expected, Collection actual) Assert.assertEquals(map(expected, entityConverter), map(actual, entityConverter)); } - public static Collection map(Collection collection, Function converter) { + public static List map(Collection collection, Function converter) { return collection.stream().map(converter).collect(Collectors.toList()); } + + public ResultMatcher contentMatcher(T expect) { + return content().string( + new TestMatcher(expect) { + @Override + protected boolean compare(T expected, String body) { + R actualForCompare = entityConverter.apply(fromJsonValue(body)); + R expectedForCompare = entityConverter.apply(expected); + return expectedForCompare.equals(actualForCompare); + } + }); + } + + public final ResultMatcher contentListMatcher(T... expected) { + return contentListMatcher(Arrays.asList(expected)); + } + + public final ResultMatcher contentListMatcher(List expected) { + return content().string(new TestMatcher>(expected) { + @Override + protected boolean compare(List expected, String actual) { + List actualList = map(fromJsonValues(actual), entityConverter); + List expectedList = map(expected, entityConverter); + return expectedList.equals(actualList); + } + }); + } + + public T fromJsonAction(ResultActions action) throws UnsupportedEncodingException { + return fromJsonValue(TestUtil.getContent(action)); + } } diff --git a/src/test/java/ru/javawebinar/topjava/matcher/TestMatcher.java b/src/test/java/ru/javawebinar/topjava/matcher/TestMatcher.java new file mode 100644 index 000000000000..32d599020146 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/matcher/TestMatcher.java @@ -0,0 +1,29 @@ +package ru.javawebinar.topjava.matcher; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import ru.javawebinar.topjava.web.json.JsonUtil; + +/** + * GKislin + * 05.01.2015. + */ +abstract public class TestMatcher extends BaseMatcher { + protected T expected; + + public TestMatcher(T expected) { + this.expected = expected; + } + + @Override + public boolean matches(Object actual) { + return compare(expected, (String) actual); + } + + abstract protected boolean compare(T expected, String actual); + + @Override + public void describeTo(Description description) { + description.appendText(JsonUtil.writeValue(expected)); + } +} diff --git a/src/test/java/ru/javawebinar/topjava/web/user/AdminRestControllerTest.java b/src/test/java/ru/javawebinar/topjava/web/user/AdminRestControllerTest.java index 686748b85646..25020ef5b3d4 100644 --- a/src/test/java/ru/javawebinar/topjava/web/user/AdminRestControllerTest.java +++ b/src/test/java/ru/javawebinar/topjava/web/user/AdminRestControllerTest.java @@ -2,23 +2,83 @@ import org.junit.Test; import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.ResultActions; +import ru.javawebinar.topjava.TestUtil; +import ru.javawebinar.topjava.model.Role; +import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.web.AbstractControllerTest; +import ru.javawebinar.topjava.web.json.JsonUtil; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import java.util.Arrays; +import java.util.Collections; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static ru.javawebinar.topjava.UserTestData.ADMIN_ID; +import static ru.javawebinar.topjava.UserTestData.*; public class AdminRestControllerTest extends AbstractControllerTest { - public static final String REST_URL = AdminRestController.REST_URL + '/'; + private static final String REST_URL = AdminRestController.REST_URL + '/'; @Test public void testGet() throws Exception { mockMvc.perform(get(REST_URL + ADMIN_ID)) .andExpect(status().isOk()) .andDo(print()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)); + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MATCHER.contentMatcher(ADMIN)); + } + + @Test + public void testGetByEmail() throws Exception { + mockMvc.perform(get(REST_URL + "by?email=" + USER.getEmail())) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MATCHER.contentMatcher(USER)); + } + + @Test + public void testDelete() throws Exception { + mockMvc.perform(delete(REST_URL + USER_ID)) + .andDo(print()) + .andExpect(status().isOk()); + MATCHER.assertCollectionEquals(Collections.singletonList(ADMIN), userService.getAll()); + } + + @Test + public void testUpdate() throws Exception { + User updated = new User(USER); + updated.setName("UpdatedName"); + updated.setRoles(Collections.singletonList(Role.ROLE_ADMIN)); + mockMvc.perform(put(REST_URL + USER_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.writeValue(updated))) + .andExpect(status().isOk()); + + MATCHER.assertEquals(updated, userService.get(USER_ID)); + } + + @Test + public void testCreate() throws Exception { + TestUser expected = new TestUser("New", "new@gmail.com", "newPass", Role.ROLE_USER, Role.ROLE_ADMIN); + ResultActions action = mockMvc.perform(post(REST_URL) + .contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.writeValue(expected.asUser()))).andExpect(status().isCreated()); + + User returned = MATCHER.fromJsonAction(action); + expected.setId(returned.getId()); + + MATCHER.assertEquals(expected, returned); + MATCHER.assertCollectionEquals(Arrays.asList(ADMIN, expected, USER), userService.getAll()); + } + + @Test + public void testGetAll() throws Exception { + TestUtil.print(mockMvc.perform(get(REST_URL)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MATCHER.contentListMatcher(ADMIN, USER))); } } \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/web/user/ProfileRestControllerTest.java b/src/test/java/ru/javawebinar/topjava/web/user/ProfileRestControllerTest.java new file mode 100644 index 000000000000..3ca42cea3734 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/web/user/ProfileRestControllerTest.java @@ -0,0 +1,47 @@ +package ru.javawebinar.topjava.web.user; + +import org.junit.Test; +import org.springframework.http.MediaType; +import ru.javawebinar.topjava.TestUtil; +import ru.javawebinar.topjava.model.Role; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.web.AbstractControllerTest; +import ru.javawebinar.topjava.web.json.JsonUtil; + +import java.util.Collections; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static ru.javawebinar.topjava.UserTestData.*; +import static ru.javawebinar.topjava.web.user.ProfileRestController.REST_URL; + +public class ProfileRestControllerTest extends AbstractControllerTest { + + @Test + public void testGet() throws Exception { + TestUtil.print(mockMvc.perform(get(REST_URL)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MATCHER.contentMatcher(USER))); + } + + @Test + public void testDelete() throws Exception { + mockMvc.perform(delete(REST_URL)) + .andExpect(status().isOk()); + MATCHER.assertCollectionEquals(Collections.singletonList(ADMIN), userService.getAll()); + } + + @Test + public void testUpdate() throws Exception { + User updated = new User(USER_ID, "newName", "newemail@ya.ru", "newPassword", Role.ROLE_USER); + mockMvc.perform(put(REST_URL).contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.writeValue(updated))) + .andDo(print()) + .andExpect(status().isOk()); + + MATCHER.assertEquals(updated, new User(userService.getByEmail("newemail@ya.ru"))); + } +} \ No newline at end of file From dc059c5d3248f24eccddfe2cd21556a5947add30 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 19 Jul 2016 23:37:36 +0300 Subject: [PATCH 74/76] prepare to HW7 --- .../java/ru/javawebinar/topjava/matcher/ModelMatcher.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/java/ru/javawebinar/topjava/matcher/ModelMatcher.java b/src/test/java/ru/javawebinar/topjava/matcher/ModelMatcher.java index b7078c203d2c..0f902ef973b9 100644 --- a/src/test/java/ru/javawebinar/topjava/matcher/ModelMatcher.java +++ b/src/test/java/ru/javawebinar/topjava/matcher/ModelMatcher.java @@ -39,6 +39,14 @@ private Collection fromJsonValues(String json) { return JsonUtil.readValues(json, entityClass); } + private T fromJsonValue(String json) { + return JsonUtil.readValue(json, entityClass); + } + + private Collection fromJsonValues(String json) { + return JsonUtil.readValues(json, entityClass); + } + public void assertEquals(T expected, T actual) { Assert.assertEquals(entityConverter.apply(expected), entityConverter.apply(actual)); } From 4073dd6ad608985bf5bd23b5ec7f5513a121acd3 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 19 Jul 2016 23:38:13 +0300 Subject: [PATCH 75/76] prepare to HW7 --- src/main/java/ru/javawebinar/topjava/model/User.java | 5 +++-- .../topjava/service/AbstractJpaUserServiceTest.java | 8 ++++---- .../javawebinar/topjava/service/AbstractServiceTest.java | 2 +- .../topjava/service/AbstractUserServiceTest.java | 6 +++--- .../javawebinar/topjava/web/AbstractControllerTest.java | 5 +++++ 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index a40316873fc4..0bc496a799ca 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -5,6 +5,7 @@ import org.hibernate.validator.constraints.Email; import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.util.CollectionUtils; import ru.javawebinar.topjava.util.UserMealsUtil; import javax.persistence.*; @@ -89,7 +90,7 @@ public User(Integer id, String name, String email, String password, int calories this.password = password; this.caloriesPerDay = caloriesPerDay; this.enabled = enabled; - this.roles = roles; + setRoles(roles); } public String getEmail() { @@ -133,7 +134,7 @@ public Set getRoles() { } public void setRoles(Collection roles) { - this.roles = EnumSet.copyOf(roles); + this.roles = CollectionUtils.isEmpty(roles) ? Collections.emptySet() : EnumSet.copyOf(roles); } public String getPassword() { diff --git a/src/test/java/ru/javawebinar/topjava/service/AbstractJpaUserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractJpaUserServiceTest.java index eb8f8e9ea70e..a84a5d19ad20 100644 --- a/src/test/java/ru/javawebinar/topjava/service/AbstractJpaUserServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/AbstractJpaUserServiceTest.java @@ -1,6 +1,6 @@ package ru.javawebinar.topjava.service; -import org.junit.Before; +import org.junit.After; import org.springframework.beans.factory.annotation.Autowired; import ru.javawebinar.topjava.repository.JpaUtil; @@ -13,9 +13,9 @@ abstract public class AbstractJpaUserServiceTest extends AbstractUserServiceTest @Autowired private JpaUtil jpaUtil; - @Before - public void setUp() throws Exception { - super.setUp(); + @After + public void tearDown() throws Exception { + super.tearDown(); jpaUtil.clear2ndLevelHibernateCache(); } } diff --git a/src/test/java/ru/javawebinar/topjava/service/AbstractServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractServiceTest.java index 6548d1e8d644..a7895b7ea002 100644 --- a/src/test/java/ru/javawebinar/topjava/service/AbstractServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/AbstractServiceTest.java @@ -26,7 +26,7 @@ }) @RunWith(SpringJUnit4ClassRunner.class) @ActiveProfiles(ACTIVE_DB) -@Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8")) +@Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8"), executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) abstract public class AbstractServiceTest { protected final Logger log = LoggerFactory.getLogger(getClass()); diff --git a/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java index f81a79dbe6cc..316c2720a619 100644 --- a/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java @@ -1,6 +1,6 @@ package ru.javawebinar.topjava.service; -import org.junit.Before; +import org.junit.After; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; @@ -20,8 +20,8 @@ abstract public class AbstractUserServiceTest extends AbstractServiceTest { @Autowired protected UserService service; - @Before - public void setUp() throws Exception { + @After + public void tearDown() throws Exception { service.evictCache(); } diff --git a/src/test/java/ru/javawebinar/topjava/web/AbstractControllerTest.java b/src/test/java/ru/javawebinar/topjava/web/AbstractControllerTest.java index fd5691cfa9b4..a9615f4daaae 100644 --- a/src/test/java/ru/javawebinar/topjava/web/AbstractControllerTest.java +++ b/src/test/java/ru/javawebinar/topjava/web/AbstractControllerTest.java @@ -12,6 +12,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.filter.CharacterEncodingFilter; +import ru.javawebinar.topjava.repository.JpaUtil; import ru.javawebinar.topjava.service.UserService; import javax.annotation.PostConstruct; @@ -41,6 +42,9 @@ abstract public class AbstractControllerTest { CHARACTER_ENCODING_FILTER.setForceEncoding(true); } + @Autowired + private JpaUtil jpaUtil; + protected MockMvc mockMvc; @Autowired @@ -60,5 +64,6 @@ void postConstruct() { @Before public void setUp() { userService.evictCache(); + jpaUtil.clear2ndLevelHibernateCache(); } } From f00754ad49bef9e442cfdf67ea7e48ad28e33966 Mon Sep 17 00:00:00 2001 From: Orfaniel Date: Tue, 19 Jul 2016 23:52:36 +0300 Subject: [PATCH 76/76] prepare to HW7 --- config/Topjava-soapui-project.xml | 17 +++++++++++++++++ .../topjava/web/user/ProfileRestController.java | 5 +++++ src/main/resources/spring/spring-mvc.xml | 8 ++++++++ 3 files changed, 30 insertions(+) create mode 100644 config/Topjava-soapui-project.xml diff --git a/config/Topjava-soapui-project.xml b/config/Topjava-soapui-project.xml new file mode 100644 index 000000000000..44ad8436a5cc --- /dev/null +++ b/config/Topjava-soapui-project.xml @@ -0,0 +1,17 @@ + +http://localhost:8080text/html;charset=utf-8500 401htmlapplication/json200ns:Response<xml-fragment/>http://localhost:8080http://localhost/topjava/rest/admin/usersuser@yandex.rupasswordNo AuthorizationBasicNo Authorizationapplication/jsontext/html;charset=utf-8500htmlapplication/json201user:Response<xml-fragment/>http://localhost:8080{ + "name": "New2", + "email": "new2@yandex.ru", + "password": "passwordNew", + "roles": ["ROLE_USER"] +}http://localhost/topjava/rest/admin/usersNo AuthorizationBasicNo Authorizationtext/html;charset=utf-8500htmlapplication/json200ns:Response<xml-fragment/>http://localhost:8080http://localhost/topjava/rest/admin/users/100000No AuthorizationBasicNo Authorizationtext/html;charset=utf-8405 500htmlapplication/json200data200data200data<xml-fragment/>http://localhost:8080{ + "name": "UserUpdated", + "email": "user@yandex.ru", + "password": "passwordNew", + "roles": ["ROLE_USER"] +}http://localhost/topjava/rest/admin/users/100000BasicBasicGlobal HTTP Settingstext/html;charset=utf-8500htmlapplication/json200ns:Response<xml-fragment/>http://localhost:8080http://localhost/topjava/rest/profileBasicBasicGlobal HTTP Settingsapplication/jsontext/html;charset=utf-8500 405htmlapplication/json201user:Response200data200data200data200data200data<xml-fragment/>http://localhost:8080{ + "name": "New777", + "email": "new777@yandex.ru", + "password": "passwordNew", + "roles": ["ROLE_USER"] +}http://localhost/topjava/rest/profileNo AuthorizationBasicNo Authorization200datatext/html;charset=utf-8500htmlapplication/json200data<xml-fragment/>http://localhost:8080http://localhost/topjava/rest/profileNo AuthorizationBasicNo Authorization \ No newline at end of file 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 57f3d7f009ca..0b9f2b76f9af 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java @@ -31,4 +31,9 @@ public void delete() { public void update(@RequestBody User user) { super.update(user, AuthorizedUser.id()); } + + @RequestMapping(value = "/text", method = RequestMethod.GET) + public String testUTF() { + return "Русский текст"; + } } \ No newline at end of file diff --git a/src/main/resources/spring/spring-mvc.xml b/src/main/resources/spring/spring-mvc.xml index 86a60d059a02..a770bdfe84dd 100644 --- a/src/main/resources/spring/spring-mvc.xml +++ b/src/main/resources/spring/spring-mvc.xml @@ -12,6 +12,14 @@ + + + + text/plain;charset=UTF-8 + text/html;charset=UTF-8 + + +