From fbec6dbb6f354f18445a061f397a60fea8943854 Mon Sep 17 00:00:00 2001 From: Grigory Kislin Date: Sat, 5 Nov 2016 20:17:20 +0300 Subject: [PATCH 01/72] Add description --- README.md | 132 +++++++++++++++++++++++++++++++++++++++++++++++++ cv.md | 81 ++++++++++++++++++++++++++++++ description.md | 67 +++++++++++++++++++++++++ 3 files changed, 280 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..a915133ce7c3 --- /dev/null +++ b/README.md @@ -0,0 +1,132 @@ +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. +- **Wiki по ведению проекта в 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 + - Выставить кодировку UTF-8 в консоли + - Поставить кодировку UTF-8 + - Поменять фонт по умолчанию (DejaVu) +- По ходу видео сделать 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.getFilteredWithExceeded: +- должны возвращаться только записи между 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 +- Алексея Владыкин: Элементы функционального программирования в Java +- stream.map vs forEach + +``` +Сделать реализация через Java 8 Stream API. Заменяйте forEach оператором stream.map(..) +``` +### Полезные ресурсы +> ВНИМАНИЕ: основы JavaSсript необходимы для понимания проекта, начиная с 8-го занятия! + +Все остальное - опционально. + +#### HTML, JavaScript, CSS +- Введение в программирование на JavaScript +- Основы работы с HTML/CSS/JavaScript +- JavaScript - Основы +- Bootstrap 3 - Основы +- jQuery для начинающих + +#### Java (базовые вещи) +- Интуит. Программирование на Java +- Основы Java garbage collection +- Размер Java объектов +- Блог о памяти, сборщике мусора, многопоточности и производительности в JAVA +- Введение в Java Reflection API +- Структуры данных в картинках +- Обзор java.util.concurrent.* +- Синхронизация потоков +- String literal pool +- Маленькие хитрости Java +- A Guide to Java 8 + +#### Сервлеты +- Как создать Servlet? Полное руководство. +- Простое CRUD приложение на JSP и сервлетах + +#### JDBC, SQL +- Основы SQL на примере задачи +- Уроки по JDBC +- Learn SQL +- Интуит. Основы SQL +- Try SQL +- Курс "Введение в базы данных" + +#### Разное +- Эффективная работа с кодом в IntelliJ IDEA +- Quizful- тесты онлайн +- Введение в Linux + +#### Книги +- Джошуа Блох: 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..3e82f2e57718 --- /dev/null +++ b/cv.md @@ -0,0 +1,81 @@ +## Составление резюме, подготовка к интервью, поиск работы + +![cv](https://cloud.githubusercontent.com/assets/13649199/10877471/93ea86b8-8157-11e5-9bfa-95e3fba75c58.jpg) + +- Научиться программировать сложнее, чем кажется + +### Составление резюме: +- Выбрать шаблон для резюме +- Идеальное резюме Junior’а +- Как продать свое резюме в 2 раза дороже +- Как правильно составить резюме +- Резюме программистов. Часть 1 (плохие) +- Резюме программистов. Часть 2 (хорошие) +- Как составить резюме на английском +- ОФОРМЛЕНИЕ IT-РЕЗЮМЕ для USA + +### Наши истории (делимся опытом и успехом) + +### Тесты/задачи онлайн: +- Codility lesson tests +- Quizful- тесты онлайн +- Multiple-Choice Questions in Java +- LeetCode Online Judge +- Sphere online judge +- Codility programmers lessons +- Hackerrank practice coding + +### Интервью: +- Михаил Портнов. Собеседование на работу: как продать себя грамотно +- Михаил Портнов. Какие вопросы мы задаем на собеседовании? +- Канал: Резюме, поиск работы, интервью +- Яков Файн: Как стать профессиональным Java разработчиком +- Ответы на вопросы на собеседовании Junior Java Developer +- Список вопросов с ответами для собеседования по 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. + - отлично будет, если вы его еще как то сами доработаете + + +Делайте упор не на обучение, а на *участие в проекте*. Выполнение домашних заданий - это полноценное участие с написанием функционала по всем этим технологиям. На собеседовании меньше смотрят на то, что вы заканчивали, больше - на ваш опыт и то что вы знаете. + +- Ссылку на организацию можно поставить: http://javaops.ru (или в linkedin: https://www.linkedin.com/company/java-online-projects) + +### В течении проекта заполните форму соискателя "Разработчик Java" +Я ее рассылаю всем знакомым HR, уже есть пинги и трудоустройство. + +Ближе к концу курса я вышлю приглашение в нашу общую группу slack: общение на все темы 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 81a0a1a4defdf4ff29862d1f52286a191c2b9d60 Mon Sep 17 00:00:00 2001 From: Grigory Kislin Date: Thu, 10 Nov 2016 15:29:56 +0300 Subject: [PATCH 02/72] Add HW0 comments --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index a915133ce7c3..a21e81f9a3cc 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,14 @@ Optional ``` Сделать реализация через Java 8 Stream API. Заменяйте forEach оператором stream.map(..) ``` + +## ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Замечания к HW0 +- Код проекта менять можно! Одна из распространенных ошибок как в тестовых заданиях на собеседовании, так и при работе на проекте, что ничего нельзя менять. Конечно при правках в рабочем проекте обязятельно нужно проконсультироваться/проревьюится у авторов кода (находится по истории VCS) +- Наследовать `UserMealWithExceed` от `UserMeal` я не буду, т.к. это разные сущности: Transfer Object и Entity. Мы будет их проходить на 2м уроке. +- Правильная реализация должна быть простой и красивой, можно сделать 2-мя способами: через стримы и через циклы. Сложность должна быть O(N), т.е. без вложенных стримов и циклов. + +----- + ### Полезные ресурсы > ВНИМАНИЕ: основы JavaSсript необходимы для понимания проекта, начиная с 8-го занятия! From 4f29fe7f9c6f7280560ff0392fb34ad9c2535d8a Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 30 Nov 2016 16:08:58 +0300 Subject: [PATCH 03/72] Update README.md --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a21e81f9a3cc..ba1f3d88490a 100644 --- a/README.md +++ b/README.md @@ -96,11 +96,12 @@ Optional Все остальное - опционально. #### HTML, JavaScript, CSS +- HTML, CSS, JAVASCRIPT, SQL, JQUERY, BOOTSTRAP - Введение в программирование на JavaScript -- Основы работы с HTML/CSS/JavaScript -- JavaScript - Основы -- Bootstrap 3 - Основы -- jQuery для начинающих +- Основы работы с HTML/CSS/JavaScript +- JavaScript - Основы +- Bootstrap 3 - Основы +- jQuery для начинающих #### Java (базовые вещи) - Интуит. Программирование на Java From fab7022d92ff4e620c20f93424da29b3fb7aadba Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 1 Dec 2016 22:59:56 +0300 Subject: [PATCH 04/72] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ba1f3d88490a..d6f70812bab2 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,8 @@ Optional - Код проекта менять можно! Одна из распространенных ошибок как в тестовых заданиях на собеседовании, так и при работе на проекте, что ничего нельзя менять. Конечно при правках в рабочем проекте обязятельно нужно проконсультироваться/проревьюится у авторов кода (находится по истории VCS) - Наследовать `UserMealWithExceed` от `UserMeal` я не буду, т.к. это разные сущности: Transfer Object и Entity. Мы будет их проходить на 2м уроке. - Правильная реализация должна быть простой и красивой, можно сделать 2-мя способами: через стримы и через циклы. Сложность должна быть O(N), т.е. без вложенных стримов и циклов. +- При реализации через `Stream` заменяйте `forEach` оператором `stream.map(..)` +- Объявляйте переменные непосредственно перед использованием ----- From ce1cabaa433ba3db70443c0926b578f512331a30 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 1 Dec 2016 23:28:50 +0300 Subject: [PATCH 05/72] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d6f70812bab2..5ff5a6dc3c1f 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ Optional - Правильная реализация должна быть простой и красивой, можно сделать 2-мя способами: через стримы и через циклы. Сложность должна быть O(N), т.е. без вложенных стримов и циклов. - При реализации через `Stream` заменяйте `forEach` оператором `stream.map(..)` - Объявляйте переменные непосредственно перед использованием +- Пользуйтесь форматированием кода в IDEA: `Alt+Ctrl+L` ----- From 8615cef476595428b57b95b6d2f22922978e73fa Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 5 Dec 2016 22:26:25 +0300 Subject: [PATCH 06/72] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5ff5a6dc3c1f..8244862c6daa 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ Optional - При реализации через `Stream` заменяйте `forEach` оператором `stream.map(..)` - Объявляйте переменные непосредственно перед использованием - Пользуйтесь форматированием кода в IDEA: `Alt+Ctrl+L` +- Не оставляйте в коде ничего лишнего: закомментированный код, TODO и пр. ----- From b1b0174ce22eb80b80689169261482e59b751928 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 5 Dec 2016 23:07:03 +0300 Subject: [PATCH 07/72] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8244862c6daa..232902acabe5 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Optional - Наследовать `UserMealWithExceed` от `UserMeal` я не буду, т.к. это разные сущности: Transfer Object и Entity. Мы будет их проходить на 2м уроке. - Правильная реализация должна быть простой и красивой, можно сделать 2-мя способами: через стримы и через циклы. Сложность должна быть O(N), т.е. без вложенных стримов и циклов. - При реализации через `Stream` заменяйте `forEach` оператором `stream.map(..)` -- Объявляйте переменные непосредственно перед использованием +- Объявляйте переменные непосредственно перед использованием (если возможно - сразу с инициализацией) - Пользуйтесь форматированием кода в IDEA: `Alt+Ctrl+L` - Не оставляйте в коде ничего лишнего: закомментированный код, TODO и пр. From 212b86ad26edf06d278239febdfe6d56254bf3a8 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 5 Dec 2016 23:09:35 +0300 Subject: [PATCH 08/72] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 232902acabe5..ea9740632c06 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ Optional - Код проекта менять можно! Одна из распространенных ошибок как в тестовых заданиях на собеседовании, так и при работе на проекте, что ничего нельзя менять. Конечно при правках в рабочем проекте обязятельно нужно проконсультироваться/проревьюится у авторов кода (находится по истории VCS) - Наследовать `UserMealWithExceed` от `UserMeal` я не буду, т.к. это разные сущности: Transfer Object и Entity. Мы будет их проходить на 2м уроке. - Правильная реализация должна быть простой и красивой, можно сделать 2-мя способами: через стримы и через циклы. Сложность должна быть O(N), т.е. без вложенных стримов и циклов. +- При реализации через циклы посмотрите в `Map` на методы `getOrDefault` или `merge` - При реализации через `Stream` заменяйте `forEach` оператором `stream.map(..)` - Объявляйте переменные непосредственно перед использованием (если возможно - сразу с инициализацией) - Пользуйтесь форматированием кода в IDEA: `Alt+Ctrl+L` From 57437c95eb51546467d82d9e0c7b8de9a11d024c Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 5 Dec 2016 23:15:12 +0300 Subject: [PATCH 09/72] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ea9740632c06..6acf072c650b 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ Optional - При реализации через циклы посмотрите в `Map` на методы `getOrDefault` или `merge` - При реализации через `Stream` заменяйте `forEach` оператором `stream.map(..)` - Объявляйте переменные непосредственно перед использованием (если возможно - сразу с инициализацией) +- Если IDEA предлагает оптимизацию (желтым подчеркивает), нарпимер заменить лямбду на метод-референс, соглашайтесь (Alt+Enter) - Пользуйтесь форматированием кода в IDEA: `Alt+Ctrl+L` - Не оставляйте в коде ничего лишнего: закомментированный код, TODO и пр. From d7638c945b648da9ccebfe57c4868f0e66fa1042 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 5 Dec 2016 23:24:50 +0300 Subject: [PATCH 10/72] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6acf072c650b..2e830378d83f 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Optional - Объявляйте переменные непосредственно перед использованием (если возможно - сразу с инициализацией) - Если IDEA предлагает оптимизацию (желтым подчеркивает), нарпимер заменить лямбду на метод-референс, соглашайтесь (Alt+Enter) - Пользуйтесь форматированием кода в IDEA: `Alt+Ctrl+L` -- Не оставляйте в коде ничего лишнего: закомментированный код, TODO и пр. +- Перед check-in проверяйте чендж-лист (курсор на файл и Ctrl+D): не оставляйте в коде ничего лишнего (закомментированный код, TODO и пр.). Если файл не меняется (например только пробелы или переводы строк)- делайте ему revert. ----- From 0b35b47fcc8351ba2305cad88af7aca35dc58e03 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 5 Dec 2016 23:25:25 +0300 Subject: [PATCH 11/72] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2e830378d83f..728b6082bb48 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Optional - Объявляйте переменные непосредственно перед использованием (если возможно - сразу с инициализацией) - Если IDEA предлагает оптимизацию (желтым подчеркивает), нарпимер заменить лямбду на метод-референс, соглашайтесь (Alt+Enter) - Пользуйтесь форматированием кода в IDEA: `Alt+Ctrl+L` -- Перед check-in проверяйте чендж-лист (курсор на файл и Ctrl+D): не оставляйте в коде ничего лишнего (закомментированный код, TODO и пр.). Если файл не меняется (например только пробелы или переводы строк)- делайте ему revert. +- Перед check-in проверяйте чендж-лист (курсор на файл и Ctrl+D): не оставляйте в коде ничего лишнего (закомментированный код, TODO и пр.). Если файл не меняется (например только пробелы или переводы строк), делайте ему revert. ----- From be3ba116e232fa6ab946320fdca830b703ca28b2 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Mon, 5 Dec 2016 23:28:55 +0300 Subject: [PATCH 12/72] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 728b6082bb48..d7af8489d235 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Optional - Правильная реализация должна быть простой и красивой, можно сделать 2-мя способами: через стримы и через циклы. Сложность должна быть O(N), т.е. без вложенных стримов и циклов. - При реализации через циклы посмотрите в `Map` на методы `getOrDefault` или `merge` - При реализации через `Stream` заменяйте `forEach` оператором `stream.map(..)` -- Объявляйте переменные непосредственно перед использованием (если возможно - сразу с инициализацией) +- Объявляйте переменные непосредственно перед использованием (если возможно - сразу с инициализацией). При объявлении коллекций используйте тип переменной - интерфейс (Map, List, ..) - Если IDEA предлагает оптимизацию (желтым подчеркивает), нарпимер заменить лямбду на метод-референс, соглашайтесь (Alt+Enter) - Пользуйтесь форматированием кода в IDEA: `Alt+Ctrl+L` - Перед check-in проверяйте чендж-лист (курсор на файл и Ctrl+D): не оставляйте в коде ничего лишнего (закомментированный код, TODO и пр.). Если файл не меняется (например только пробелы или переводы строк), делайте ему revert. From 448cd3f00948b1b486d0a796501695f4dc6eb2bc Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Tue, 6 Dec 2016 00:35:32 +0300 Subject: [PATCH 13/72] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d7af8489d235..f10c6d256c4b 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ Optional - Если IDEA предлагает оптимизацию (желтым подчеркивает), нарпимер заменить лямбду на метод-референс, соглашайтесь (Alt+Enter) - Пользуйтесь форматированием кода в IDEA: `Alt+Ctrl+L` - Перед check-in проверяйте чендж-лист (курсор на файл и Ctrl+D): не оставляйте в коде ничего лишнего (закомментированный код, TODO и пр.). Если файл не меняется (например только пробелы или переводы строк), делайте ему revert. +- `System.out.println` нельзя делать нигде, кроме как в `main`. Позже введем логирование. ----- From ee05b33c21ad48b99238439de12b8b1e116e6287 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 8 Dec 2016 15:26:31 +0300 Subject: [PATCH 14/72] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f10c6d256c4b..2d76a8eae20e 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ Optional - A Guide to Java 8 - Шпаргалка Java Stream API - Алексея Владыкин: Элементы функционального программирования в Java +- Yakov Fain о новом в Java 8 - stream.map vs forEach ``` From 48bcba02b363ba75d8f879e10308b3c28448eb2f Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Sun, 11 Dec 2016 13:54:40 +0300 Subject: [PATCH 15/72] Update README.md --- README.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2d76a8eae20e..56674720ca77 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,20 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + Вводное занятие =============== -## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) Системы управления версиями. Git. +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) Осваиваем Java Enterprise. Трудоустройство. Ответы на вопросы. +- Слайды презентации +- Java Tools and Technologies Landscape for 2014 +- Java Tools and Technologies Landscape Report 2016 +- Из юниоров в разработчики: получаем первую работу + +#### Spring Pet-Clinic +- Spring PetClinic Sample Application +- Demo +- Presentation + +## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) Системы управления версиями. Git. - **Wiki по ведению проекта в Git** -- Система управления версиями. VCS/DVSC. +- Система управления версиями. VCS/DVSC. - Ресурсы: - Интерактивная Git обучалка - Еще одна интерактивная обучалка, по русски From dd2e20af77bcce899c84cdc468dc7fc810686dab Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 5 Jan 2017 14:53:11 +0300 Subject: [PATCH 16/72] Update cv.md --- cv.md | 1 + 1 file changed, 1 insertion(+) diff --git a/cv.md b/cv.md index 3e82f2e57718..76bb6058e59b 100644 --- a/cv.md +++ b/cv.md @@ -28,6 +28,7 @@ ### Интервью: - Михаил Портнов. Собеседование на работу: как продать себя грамотно - Михаил Портнов. Какие вопросы мы задаем на собеседовании? +- Михаил Портнов. Собеседование на работу: жизненный путь - Канал: Резюме, поиск работы, интервью - Яков Файн: Как стать профессиональным Java разработчиком - Ответы на вопросы на собеседовании Junior Java Developer From 25d2e25cde705b1a3b94a4d186cb64232af6a62e Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 11 Jan 2017 16:54:09 +0300 Subject: [PATCH 17/72] Update cv.md --- cv.md | 1 + 1 file changed, 1 insertion(+) diff --git a/cv.md b/cv.md index 76bb6058e59b..98f2508b8191 100644 --- a/cv.md +++ b/cv.md @@ -17,6 +17,7 @@ ### Наши истории (делимся опытом и успехом) ### Тесты/задачи онлайн: +- game: test Java skills - Codility lesson tests - Quizful- тесты онлайн - Multiple-Choice Questions in Java From b2c9917a34dc422421f7e2c60df070d2a2ad6cab Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sat, 14 Jan 2017 17:36:27 +0300 Subject: [PATCH 18/72] 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 a5396096632dc285ed272971adc01dae613d1604 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sat, 14 Jan 2017 17:55:30 +0300 Subject: [PATCH 19/72] Lambda samples --- .../java/ru/javawebinar/topjava/Main.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/javawebinar/topjava/Main.java b/src/main/java/ru/javawebinar/topjava/Main.java index b23a2f0961fc..9938c1371cb5 100644 --- a/src/main/java/ru/javawebinar/topjava/Main.java +++ b/src/main/java/ru/javawebinar/topjava/Main.java @@ -1,14 +1,32 @@ package ru.javawebinar.topjava; +import java.util.function.Consumer; + /** * User: gkislin * Date: 05.08.2015 * - * @link http://caloriesmng.herokuapp.com/ + * @link http://javawebinar.ru/topjava/ * @link https://github.com/JavaOPs/topjava */ public class Main { public static void main(String[] args) { + execute(() -> { + System.out.println("Hello Topjava!"); + }); + consume(System.out::println, "Hello Topjava!"); + } + + private static void execute(Runnable runnable) { + System.out.println("Start runner"); + runnable.run(); + System.out.println("End runner"); + } + + private static void consume(Consumer consumer, String out) { + System.out.println("Start consume"); + consumer.accept(out); + System.out.println("End consume"); System.out.format("Hello Topjava Enterprise!"); } } From 84d9a9bc8e29ee30fe1541af9edc7d76eef28d6f Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sat, 14 Jan 2017 17:57:19 +0300 Subject: [PATCH 20/72] HW0 done --- .../topjava/model/UserMealWithExceed.java | 10 ++++++++++ .../topjava/util/UserMealsUtil.java | 20 +++++++++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java index dab6c9468c5e..66c356922f6b 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java @@ -21,4 +21,14 @@ public UserMealWithExceed(LocalDateTime dateTime, String description, int calori this.calories = calories; this.exceed = exceed; } + + @Override + public String toString() { + return "UserMealWithExceed{" + + "dateTime=" + dateTime + + ", description='" + description + '\'' + + ", calories=" + calories + + ", exceed=" + exceed + + '}'; + } } diff --git a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java index 2cb426400fa5..79d1bd2ce6fc 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 @@ -23,13 +26,18 @@ public static void main(String[] args) { new UserMeal(LocalDateTime.of(2015, Month.MAY, 31,13,0), "Обед", 500), new UserMeal(LocalDateTime.of(2015, Month.MAY, 31,20,0), "Ужин", 510) ); - getFilteredMealsWithExceeded(mealList, LocalTime.of(7, 0), LocalTime.of(12,0), 2000); -// .toLocalDate(); -// .toLocalTime(); + List filteredMealsWithExceeded = getFilteredMealsWithExceeded(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); + filteredMealsWithExceeded.forEach(System.out::println); } - public static List getFilteredMealsWithExceeded(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { - // TODO return filtered list with correctly exceeded field - return null; + public static List getFilteredMealsWithExceeded(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + Map caloriesSumByDate = mealList.stream().collect(Collectors.groupingBy(um -> um.getDateTime().toLocalDate(), + Collectors.summingInt(UserMeal::getCalories))); + + return mealList.stream() + .filter(um->TimeUtil.isBetween(um.getDateTime().toLocalTime(), startTime, endTime)) + .map(um->new UserMealWithExceed(um.getDateTime(), um.getDescription(), um.getCalories(), + caloriesSumByDate.get(um.getDateTime().toLocalDate())> caloriesPerDay)) + .collect(Collectors.toList()); } } From 35e6922c232723e25ab838bc06a4c6978016f013 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sat, 14 Jan 2017 18:13:11 +0300 Subject: [PATCH 21/72] HW0 cyclic done --- .../topjava/util/UserMealsUtil.java | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java index 79d1bd2ce6fc..b691b02c8267 100644 --- a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java @@ -7,9 +7,7 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; -import java.util.Arrays; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; /** @@ -28,6 +26,8 @@ public static void main(String[] args) { ); List filteredMealsWithExceeded = getFilteredMealsWithExceeded(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); filteredMealsWithExceeded.forEach(System.out::println); + + System.out.println(getFilteredMealsWithExceededByCycle(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000)); } public static List getFilteredMealsWithExceeded(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { @@ -40,4 +40,24 @@ public static List getFilteredMealsWithExceeded(List caloriesPerDay)) .collect(Collectors.toList()); } + + public static List getFilteredMealsWithExceededByCycle(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + + Map caloriesSumPerDate = new HashMap<>(); + for (UserMeal meal : mealList) { + LocalDate mealDate = meal.getDateTime().toLocalDate(); + caloriesSumPerDate.put(mealDate, caloriesSumPerDate.getOrDefault(mealDate, 0) + meal.getCalories()); + } + + List mealExceeded = new ArrayList<>(); + for (UserMeal meal : mealList) { + LocalDateTime dateTime = meal.getDateTime(); + if (TimeUtil.isBetween(dateTime.toLocalTime(), startTime, endTime)) { + mealExceeded.add(new UserMealWithExceed(dateTime, meal.getDescription(), meal.getCalories(), + caloriesSumPerDate.get(dateTime.toLocalDate()) > caloriesPerDay)); + } + } + return mealExceeded; + } + } From f91ef847bf4681a4c42e0ed16763ad76c930aa83 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sat, 14 Jan 2017 20:35:51 +0300 Subject: [PATCH 22/72] switch to war packaging --- pom.xml | 3 ++- src/main/webapp/WEB-INF/web.xml | 18 ++++++++++++++++++ src/main/webapp/index.html | 10 ++++++++++ src/main/webapp/userList.jsp | 9 +++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/main/webapp/WEB-INF/web.xml create mode 100644 src/main/webapp/index.html create mode 100644 src/main/webapp/userList.jsp diff --git a/pom.xml b/pom.xml index c8a1c78f3b29..3f1e3780563a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ ru.javawebinar topjava - jar + war 1.0-SNAPSHOT @@ -13,6 +13,7 @@ 1.8 + UTF-8 UTF-8 diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000000..edca9575b44b --- /dev/null +++ b/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,18 @@ + + + Topjava + + + userServlet + ru.javawebinar.topjava.web.UserServlet + 0 + + + userServlet + /users + + + diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html new file mode 100644 index 000000000000..1937333f0dbe --- /dev/null +++ b/src/main/webapp/index.html @@ -0,0 +1,10 @@ + + + + + Top Java. + + +

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

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

User list

+ + From 09728a9cd9d36eb1551192f49dee022d2c26d872 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sat, 14 Jan 2017 20:39:15 +0300 Subject: [PATCH 23/72] add servlet jsp --- 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 3f1e3780563a..644419ce3d31 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,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 290acb76d5f6c38e7a531b430bd1872653ee0891 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sat, 14 Jan 2017 21:48:20 +0300 Subject: [PATCH 24/72] change forward to redirect --- 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 644419ce3d31..9a400f588605 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,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 efc5abb04bba96003eae6f905ebc0f540a49d8fb Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sat, 14 Jan 2017 21:59:02 +0300 Subject: [PATCH 25/72] add logging --- config/tomcat/setenv.bat | 4 + doc/lesson01.md | 84 +++++++++++++++++++ pom.xml | 33 ++++++++ .../ru/javawebinar/topjava/LoggerWrapper.java | 72 ++++++++++++++++ .../javawebinar/topjava/web/UserServlet.java | 5 ++ src/main/resources/logback.xml | 33 ++++++++ 6 files changed, 231 insertions(+) create mode 100644 config/tomcat/setenv.bat create mode 100644 doc/lesson01.md create mode 100644 src/main/java/ru/javawebinar/topjava/LoggerWrapper.java create mode 100644 src/main/resources/logback.xml diff --git a/config/tomcat/setenv.bat b/config/tomcat/setenv.bat new file mode 100644 index 000000000000..ebbd659386f6 --- /dev/null +++ b/config/tomcat/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/doc/lesson01.md b/doc/lesson01.md new file mode 100644 index 000000000000..e9999c2b68b6 --- /dev/null +++ b/doc/lesson01.md @@ -0,0 +1,84 @@ +# Занятие 1 онлайн проекта Topjava + +**Напоминаю, что патчи в материалах урока необходимо накатывать (Apply Patch) на ветку MASTER и БЕЗ ВАШИХ ИЗМЕНЕНИЙ, иначе с ними будут проблемы. Делать Apply можно как по ходу видео, так и немного заранее - тогда при просмотре видео вы сразу сможете отслеживать изменения кода проекта.** +## Материалы урока + +## Домашнее задание: реализация getFilteredMealsWithExceeded через Stream API +- Доступно о Java 8 Lambda +- **1_ Lambda_ samples.patch** +- **2_ HW0.patch** +- Перевод "Java 8 Stream Tutorial" +- Основное в Java 8 + +## Работа с git в IDEA. HW0: реализация через цикл. +- **3_ HW0_ cycles.patch** + +## Обзор используемых в проекте технологий. Интеграция ПО. +- Обзор популярности инструментов и технологий Java за 2014 г. +- Видео "Приложение Spring Pet Clinic" +- Приложение Spring Pet Clinic. +- Demo Spring Pet Clinic + +## Maven. +- Home Page +- Среда сборки проектов Maven. +- The Central Repository +- Maven archetype. Создание проекта на основе maven-archetype-webapp. Сборка проекта. +- Настройка пропертей Maven: кодировка, java version, зависимости, maven-compiler-plugin +- Build Lifecycle. +- Dependency Mechanism +- Зависимости, профили +- The Reactor. Snapshots +- Недостатки Maven. Другие инструменты сборки. +- Ресурсы: + - Maven: The Complete Reference + - Автоматизация сборки проекта + - Repository management Nexus + - Bintray: gateway to Maven Central + +## WAR. Веб-контейнер Tomcat. Сервлеты. +- **4_ Switch_ to_ war_ packaging.patch** +- **5_ Add_ servlet_ jsp_ html.patch** +- **6_ Forward_ to_ redirect.patch** + +- Перевод проекта на Web. +- Tomcat Home Page +- Сервлеты. +- Настройка и деплой в Tomcat. Tomcat manager. Remote debug. +- Запуск Tomcat через tomcat7-maven-plugin. Конфигурирование плагина. +- Запуск Tomcat из IDEA. Динамическое обновление без передеплоя. +- Redirect, Forward, Application context, Servlet context + - Томкат менеджер: http://localhost:8080/manager + - Наше приложение: http://localhost:8080/topjava + - Наш сервлет: http://localhost:8080/topjava/users + +- Ресурсы: + - Технологии Java для разработки веб-приложений + +## Логирование. +- **7_ Add_ logging.patch** + +- Видео с TopJava01 +- Java Logging: история кошмара +- Ведение лога приложения +- Добавление зависимостей логирования в проект. +- Log4j, Logback +- Конфигурирование логирования. Создание обертки логирования. Настройка Live Template. +- Интеграция IDEA с Tomcat, деплой. +- Тестирование логирования в сервлете. Переменная окружения TOPJAVA_ROOT. +- Управление логированием по JMX. +- Контекст приложения. Деплой в Tomcat без IDE. Remote debug. + +## Уровни и зависимости логгирования, JMX + +## Домашнее задание HW01 + + Попробовать разные деплои в Tomcat, remote и local debug + По аналогии с Users добавить MealServlet и mealList.jsp. + Добавить в JSP и index.html ссылки друг на друга + Задеплоить приложение (war) в Tomcat c applicationContext=topjava и проверить работу ссылок + +Optional + + Сделать реализацию CRUD (create/read/update/delete) для списка еды. + Цвет записи в таблице зависит от параметра isExceeded. \ No newline at end of file diff --git a/pom.xml b/pom.xml index 9a400f588605..ed8a30eb32c4 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,10 @@ UTF-8 UTF-8 + + + 1.1.2 + 1.7.7 @@ -35,6 +39,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 + @@ -43,6 +75,7 @@ 2.5 provided + diff --git a/src/main/java/ru/javawebinar/topjava/LoggerWrapper.java b/src/main/java/ru/javawebinar/topjava/LoggerWrapper.java new file mode 100644 index 000000000000..d2862a1856e1 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/LoggerWrapper.java @@ -0,0 +1,72 @@ +package ru.javawebinar.topjava; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * User: gkislin + * Date: 22.01.14 + */ +public class LoggerWrapper { + + private Logger logger; + + public LoggerWrapper(Logger logger) { + this.logger = logger; + } + + public static LoggerWrapper get(Class aClass) { + return new LoggerWrapper(LoggerFactory.getLogger(aClass)); + } + + public void debug(String msg) { + logger.debug(msg); + } + + public void info(String msg, Object... arguments) { + logger.info(msg, arguments); + } + + public void warn(String msg) { + logger.warn(msg); + } + + public void warn(String msg, Throwable t) { + logger.warn(msg, t); + } + + public void error(String msg) { + logger.error(msg); + } + + public void error(String msg, Throwable t) { + logger.error(msg, t); + } + + public boolean isDebug() { + return logger.isDebugEnabled(); + } + + public IllegalStateException getIllegalStateException(String msg) { + return getIllegalStateException(msg, null); + } + + public IllegalStateException getIllegalStateException(String msg, Throwable e) { + logger.error(msg, e); + return new IllegalStateException(msg, e); + } + + public IllegalArgumentException getIllegalArgumentException(String msg) { + return getIllegalArgumentException(msg, null); + } + + public IllegalArgumentException getIllegalArgumentException(String msg, Throwable e) { + logger.error(msg, e); + return new IllegalArgumentException(msg, e); + } + + public UnsupportedOperationException getUnsupportedOperationException(String msg) { + logger.error(msg); + return new UnsupportedOperationException(msg); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java index 70ce24c6c494..eb2188bc8435 100644 --- a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java @@ -1,5 +1,7 @@ package ru.javawebinar.topjava.web; +import ru.javawebinar.topjava.LoggerWrapper; + import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -11,8 +13,11 @@ * Date: 19.08.2014 */ public class UserServlet extends HttpServlet { + private static final LoggerWrapper LOG = LoggerWrapper.get(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..4ee2916e57d1 --- /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 2b1a8784942b8f93ec7ab436f191c1f010131667 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sat, 14 Jan 2017 23:32:35 +0300 Subject: [PATCH 26/72] HW1 done --- src/main/java/ru/javawebinar/topjava/util/TimeUtil.java | 8 ++++++++ 1 file changed, 8 insertions(+) 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); + } } From ba2449c9d450aaaa91a19756126968f90b3c67ef Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sat, 14 Jan 2017 23:34:01 +0300 Subject: [PATCH 27/72] HW1 done --- pom.xml | 6 +++ .../topjava/model/UserMealWithExceed.java | 16 +++++++ .../topjava/util/UserMealsUtil.java | 44 +++++++++++-------- .../javawebinar/topjava/web/MealServlet.java | 25 +++++++++++ src/main/webapp/WEB-INF/web.xml | 10 +++++ src/main/webapp/index.html | 9 +++- src/main/webapp/mealList.jsp | 41 +++++++++++++++++ src/main/webapp/userList.jsp | 3 +- 8 files changed, 132 insertions(+), 22 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/web/MealServlet.java create mode 100644 src/main/webapp/mealList.jsp diff --git a/pom.xml b/pom.xml index ed8a30eb32c4..44fe4e8dca85 100644 --- a/pom.xml +++ b/pom.xml @@ -76,6 +76,12 @@ provided + + javax.servlet + jstl + 1.2 + + diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java index 66c356922f6b..253c10383acf 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/UserMealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java index b691b02c8267..3527022247b1 100644 --- a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java @@ -15,46 +15,52 @@ * 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 void main(String[] args) { - List mealList = Arrays.asList( - new UserMeal(LocalDateTime.of(2015, Month.MAY, 30,10,0), "Завтрак", 500), - new UserMeal(LocalDateTime.of(2015, Month.MAY, 30,13,0), "Обед", 1000), - new UserMeal(LocalDateTime.of(2015, Month.MAY, 30,20,0), "Ужин", 500), - new UserMeal(LocalDateTime.of(2015, Month.MAY, 31,10,0), "Завтрак", 1000), - new UserMeal(LocalDateTime.of(2015, Month.MAY, 31,13,0), "Обед", 500), - new UserMeal(LocalDateTime.of(2015, Month.MAY, 31,20,0), "Ужин", 510) - ); - List filteredMealsWithExceeded = getFilteredMealsWithExceeded(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); + List filteredMealsWithExceeded = getFilteredWithExceeded(MEAL_LIST, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000); filteredMealsWithExceeded.forEach(System.out::println); - System.out.println(getFilteredMealsWithExceededByCycle(mealList, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000)); + System.out.println(getFilteredWithExceededByCycle(MEAL_LIST, LocalTime.of(7, 0), LocalTime.of(12, 0), 2000)); + } + + public static List getWithExceeded(Collection mealList, int caloriesPerDay) { + return getFilteredWithExceeded(mealList, LocalTime.MIN, LocalTime.MAX, caloriesPerDay); } - public static List getFilteredMealsWithExceeded(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + public static List getFilteredWithExceeded(Collection 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)) + .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 getFilteredMealsWithExceededByCycle(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { + public static UserMealWithExceed createWithExceed(UserMeal um, boolean exceeded) { + return new UserMealWithExceed(um.getDateTime(), um.getDescription(), um.getCalories(), exceeded); + } + + public static List getFilteredWithExceededByCycle(List mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) { Map caloriesSumPerDate = new HashMap<>(); for (UserMeal meal : mealList) { - LocalDate mealDate = meal.getDateTime().toLocalDate(); - caloriesSumPerDate.put(mealDate, caloriesSumPerDate.getOrDefault(mealDate, 0) + meal.getCalories()); + caloriesSumPerDate.merge(meal.getDateTime().toLocalDate(), meal.getCalories(), Integer::sum); } List mealExceeded = new ArrayList<>(); for (UserMeal meal : mealList) { LocalDateTime dateTime = meal.getDateTime(); if (TimeUtil.isBetween(dateTime.toLocalTime(), startTime, endTime)) { - mealExceeded.add(new UserMealWithExceed(dateTime, meal.getDescription(), meal.getCalories(), - caloriesSumPerDate.get(dateTime.toLocalDate()) > caloriesPerDay)); + mealExceeded.add(createWithExceed(meal, caloriesSumPerDate.get(dateTime.toLocalDate()) > caloriesPerDay)); } } return mealExceeded; 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..fbd7b0bfe274 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -0,0 +1,25 @@ +package ru.javawebinar.topjava.web; + +import ru.javawebinar.topjava.LoggerWrapper; +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 LoggerWrapper LOG = LoggerWrapper.get(MealServlet.class); + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + LOG.info("getAll"); + request.setAttribute("mealList", + UserMealsUtil.getWithExceeded(UserMealsUtil.MEAL_LIST, 2000)); + request.getRequestDispatcher("/mealList.jsp").forward(request, response); + } +} diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index edca9575b44b..6306688d0998 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -15,4 +15,14 @@ /users + + mealServlet + ru.javawebinar.topjava.web.MealServlet + 0 + + + mealServlet + /meals + + diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html index 1937333f0dbe..62ae01a26e9b 100644 --- a/src/main/webapp/index.html +++ b/src/main/webapp/index.html @@ -5,6 +5,11 @@ Top Java. -

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

+

Проект "Top Java."

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

Home

+

Meal list

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

User list

+

Home

+

User list

From 35733492dbeb868dfb7df1db2be1ca1268a35c2d Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sun, 15 Jan 2017 01:37:34 +0300 Subject: [PATCH 28/72] HW1 optional done --- src/main/webapp/mealList.jsp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/webapp/mealList.jsp b/src/main/webapp/mealList.jsp index 0707a7435082..dbf36345b502 100644 --- a/src/main/webapp/mealList.jsp +++ b/src/main/webapp/mealList.jsp @@ -14,6 +14,7 @@

Home

Meal list

+ Add Meal
@@ -21,6 +22,8 @@ + + @@ -33,6 +36,8 @@ + +
Date Description Calories
${meal.description} ${meal.calories}UpdateDelete
From 97759ef8d93506dd97bb3e4127824f7af1648b3b Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sun, 15 Jan 2017 01:38:05 +0300 Subject: [PATCH 29/72] HW1 optional done --- .../javawebinar/topjava/model/UserMeal.java | 29 ++++++++++ .../topjava/model/UserMealWithExceed.java | 14 ++++- .../InMemoryUserMealRepository.java | 52 ++++++++++++++++++ .../repository/UserMealRepository.java | 19 +++++++ .../topjava/util/UserMealsUtil.java | 2 +- .../javawebinar/topjava/web/MealServlet.java | 54 +++++++++++++++++-- src/main/webapp/mealEdit.jsp | 51 ++++++++++++++++++ 7 files changed, 215 insertions(+), 6 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/repository/InMemoryUserMealRepository.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..13662581d16e 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java @@ -7,6 +7,8 @@ * 11.01.2015. */ public class UserMeal { + protected Integer id; + protected final LocalDateTime dateTime; protected final String description; @@ -14,11 +16,20 @@ public class UserMeal { protected 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 253c10383acf..1f66bad92b56 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java @@ -7,6 +7,8 @@ * 11.01.2015. */ public class UserMealWithExceed { + protected Integer id; + protected final LocalDateTime dateTime; protected final String description; @@ -16,12 +18,21 @@ public class UserMealWithExceed { protected 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/InMemoryUserMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/InMemoryUserMealRepository.java new file mode 100644 index 000000000000..b318764fffdc --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/InMemoryUserMealRepository.java @@ -0,0 +1,52 @@ +package ru.javawebinar.topjava.repository; + +import ru.javawebinar.topjava.model.UserMeal; + +import java.time.LocalDateTime; +import java.time.Month; +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 InMemoryUserMealRepository implements UserMealRepository { + private Map repository = new ConcurrentHashMap<>(); + private AtomicInteger counter = new AtomicInteger(0); + + { + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 10, 0), "Завтрак", 500)); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 13, 0), "Обед", 1000)); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 20, 0), "Ужин", 500)); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 10, 0), "Завтрак", 1000)); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 13, 0), "Обед", 500)); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 20, 0), "Ужин", 510)); + } + + @Override + public UserMeal save(UserMeal userMeal) { + if (userMeal.isNew()) { + userMeal.setId(counter.incrementAndGet()); + } + return repository.put(userMeal.getId(), 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 3527022247b1..3dfa9fa9f655 100644 --- a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java @@ -46,7 +46,7 @@ public static List getFilteredWithExceeded(Collection getFilteredWithExceededByCycle(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 index fbd7b0bfe274..46053673b1ef 100644 --- a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -1,13 +1,19 @@ package ru.javawebinar.topjava.web; import ru.javawebinar.topjava.LoggerWrapper; +import ru.javawebinar.topjava.model.UserMeal; +import ru.javawebinar.topjava.repository.InMemoryUserMealRepository; +import ru.javawebinar.topjava.repository.UserMealRepository; import ru.javawebinar.topjava.util.UserMealsUtil; +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.LocalDateTime; +import java.util.Objects; /** * User: gkislin @@ -16,10 +22,50 @@ public class MealServlet extends HttpServlet { private static final LoggerWrapper LOG = LoggerWrapper.get(MealServlet.class); + private UserMealRepository repository; + + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + repository = new InMemoryUserMealRepository(); + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException { + request.setCharacterEncoding("UTF-8"); + String id = request.getParameter("id"); + UserMeal userMeal = new UserMeal(id.isEmpty() ? null : Integer.valueOf(id), + LocalDateTime.parse(request.getParameter("dateTime")), + request.getParameter("description"), + Integer.valueOf(request.getParameter("calories"))); + LOG.info(userMeal.isNew() ? "Create {}" : "Update {}", userMeal); + repository.save(userMeal); + response.sendRedirect("meals"); + } + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - LOG.info("getAll"); - request.setAttribute("mealList", - UserMealsUtil.getWithExceeded(UserMealsUtil.MEAL_LIST, 2000)); - request.getRequestDispatcher("/mealList.jsp").forward(request, response); + String action = request.getParameter("action"); + + if (action == null) { + LOG.info("getAll"); + request.setAttribute("mealList", + UserMealsUtil.getWithExceeded(repository.getAll(), 2000)); + request.getRequestDispatcher("/mealList.jsp").forward(request, response); + } else if (action.equals("delete")) { + int id = getId(request); + LOG.info("Delete {}", id); + repository.delete(id); + response.sendRedirect("meals"); + } else { + final UserMeal meal = action.equals("create") ? + new UserMeal(LocalDateTime.now(), "", 1000) : + repository.get(getId(request)); + request.setAttribute("meal", meal); + request.getRequestDispatcher("mealEdit.jsp").forward(request, response); + } + } + + private int getId(HttpServletRequest request) { + String paramId = Objects.requireNonNull(request.getParameter("id")); + return Integer.valueOf(paramId); } } diff --git a/src/main/webapp/mealEdit.jsp b/src/main/webapp/mealEdit.jsp new file mode 100644 index 000000000000..443933549130 --- /dev/null +++ b/src/main/webapp/mealEdit.jsp @@ -0,0 +1,51 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + Meal + + + +
+

Home

+

Edit meal

+
+ +
+ +
+
DateTime:
+
+
+
+
Description:
+
+
+
+
Calories:
+
+
+ + +
+
+ + From fd01d12cd428fb7887b2e03319d85d1569d27b30 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sun, 15 Jan 2017 15:32:37 +0300 Subject: [PATCH 30/72] distribution on layers --- .../ru/javawebinar/topjava/LoggedUser.java | 16 +++ .../ru/javawebinar/topjava/LoggerWrapper.java | 8 +- .../javawebinar/topjava/model/BaseEntity.java | 53 ++++++++++ .../topjava/model/NamedEntity.java | 31 ++++++ .../ru/javawebinar/topjava/model/Role.java | 10 ++ .../ru/javawebinar/topjava/model/User.java | 98 +++++++++++++++++++ .../topjava/repository/UserRepository.java | 24 +++++ .../topjava/service/UserMealService.java | 8 ++ .../topjava/service/UserMealServiceImpl.java | 13 +++ .../topjava/service/UserService.java | 26 +++++ .../topjava/service/UserServiceImpl.java | 41 ++++++++ .../topjava/util/exception/ExceptionUtil.java | 29 ++++++ .../util/exception/NotFoundException.java | 11 +++ .../web/meal/UserMealRestController.java | 12 +++ .../web/user/AbstractUserController.java | 48 +++++++++ .../topjava/web/user/AdminRestController.java | 36 +++++++ .../web/user/ProfileRestController.java | 23 +++++ 17 files changed, 486 insertions(+), 1 deletion(-) create mode 100644 src/main/java/ru/javawebinar/topjava/LoggedUser.java create mode 100644 src/main/java/ru/javawebinar/topjava/model/BaseEntity.java create mode 100644 src/main/java/ru/javawebinar/topjava/model/NamedEntity.java create mode 100644 src/main/java/ru/javawebinar/topjava/model/Role.java create mode 100644 src/main/java/ru/javawebinar/topjava/model/User.java create mode 100644 src/main/java/ru/javawebinar/topjava/repository/UserRepository.java create mode 100644 src/main/java/ru/javawebinar/topjava/service/UserMealService.java create mode 100644 src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java create mode 100644 src/main/java/ru/javawebinar/topjava/service/UserService.java create mode 100644 src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java create mode 100644 src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java create mode 100644 src/main/java/ru/javawebinar/topjava/util/exception/NotFoundException.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java diff --git a/src/main/java/ru/javawebinar/topjava/LoggedUser.java b/src/main/java/ru/javawebinar/topjava/LoggedUser.java new file mode 100644 index 000000000000..462aba786ee3 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/LoggedUser.java @@ -0,0 +1,16 @@ +package ru.javawebinar.topjava; + +/** + * GKislin + * 06.03.2015. + */ +public class LoggedUser { + + public static int id() { + return 1; + } + + public static int getCaloriesPerDay() { + return 2000; + } +} diff --git a/src/main/java/ru/javawebinar/topjava/LoggerWrapper.java b/src/main/java/ru/javawebinar/topjava/LoggerWrapper.java index d2862a1856e1..642bb6c4c7ea 100644 --- a/src/main/java/ru/javawebinar/topjava/LoggerWrapper.java +++ b/src/main/java/ru/javawebinar/topjava/LoggerWrapper.java @@ -2,6 +2,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ru.javawebinar.topjava.util.exception.NotFoundException; /** * User: gkislin @@ -69,4 +70,9 @@ public UnsupportedOperationException getUnsupportedOperationException(String msg logger.error(msg); return new UnsupportedOperationException(msg); } -} + + public NotFoundException getNotFoundException(String reason) { + logger.error("No data found"); + return new NotFoundException(reason); + } +} \ No newline at end of file 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..e8f1a2ce9223 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java @@ -0,0 +1,53 @@ +package ru.javawebinar.topjava.model; + +import ru.javawebinar.topjava.LoggerWrapper; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +public class BaseEntity { + protected static final LoggerWrapper LOG = LoggerWrapper.get(BaseEntity.class); + + 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); + } + + @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) { + throw LOG.getIllegalStateException("Equals '" + this + "' and '" + that + "' with null id"); + } + return id.equals(that.id); + } + + @Override + public int hashCode() { + return (id == null) ? 0 : id; + } + +} 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..c97b813cd42e --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -0,0 +1,98 @@ +package ru.javawebinar.topjava.model; + +import java.util.Date; +import java.util.EnumSet; +import java.util.Set; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +public class User extends NamedEntity { + + private static final int DEFAULT_CALORIES_PER_DAY = 2000; + + protected String email; + + protected String password; + + protected boolean enabled = true; + + protected Date registered = new Date(); + + protected Set roles; + + protected int caloriesPerDay = 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, DEFAULT_CALORIES_PER_DAY, true, EnumSet.of(role, roles)); + } + + public User(Integer id, String name, String email, String password, int caloriesPerDay, boolean enabled, Set roles) { + super(id, name); + this.email = email; + this.password = password; + this.caloriesPerDay = caloriesPerDay; + this.enabled = enabled; + this.roles = roles; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public void setPassword(String password) { + this.password = password; + } + + public Date getRegistered() { + return registered; + } + + public void setRegistered(Date registered) { + this.registered = registered; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public int getCaloriesPerDay() { + return caloriesPerDay; + } + + public void setCaloriesPerDay(int caloriesPerDay) { + this.caloriesPerDay = caloriesPerDay; + } + + public boolean isEnabled() { + return enabled; + } + + public Set getRoles() { + return roles; + } + + public String getPassword() { + return password; + } + + @Override + public String toString() { + return "User (" + + "id=" + id + + ", email=" + email + + ", name=" + name + + ", enabled=" + enabled + + ", roles=" + roles + + ", caloriesPerDay=" + caloriesPerDay + + ')'; + } +} diff --git a/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java new file mode 100644 index 000000000000..24c1c45beca6 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java @@ -0,0 +1,24 @@ +package ru.javawebinar.topjava.repository; + +import ru.javawebinar.topjava.model.User; + +import java.util.List; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +public interface UserRepository { + User save(User user); + + // false if not found + boolean delete(int id); + + // null if not found + User get(int id); + + // null if not found + User getByEmail(String email); + + List getAll(); +} diff --git a/src/main/java/ru/javawebinar/topjava/service/UserMealService.java b/src/main/java/ru/javawebinar/topjava/service/UserMealService.java new file mode 100644 index 000000000000..b17fec811065 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/service/UserMealService.java @@ -0,0 +1,8 @@ +package ru.javawebinar.topjava.service; + +/** + * GKislin + * 15.06.2015. + */ +public interface UserMealService { +} diff --git a/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java new file mode 100644 index 000000000000..5730b8bfb130 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java @@ -0,0 +1,13 @@ +package ru.javawebinar.topjava.service; + +import ru.javawebinar.topjava.repository.UserMealRepository; + +/** + * GKislin + * 06.03.2015. + */ +public class UserMealServiceImpl implements UserMealService { + + private UserMealRepository repository; + +} diff --git a/src/main/java/ru/javawebinar/topjava/service/UserService.java b/src/main/java/ru/javawebinar/topjava/service/UserService.java new file mode 100644 index 000000000000..85c15e48f951 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/service/UserService.java @@ -0,0 +1,26 @@ +package ru.javawebinar.topjava.service; + + +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.util.exception.NotFoundException; + +import java.util.List; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +public interface UserService { + + User save(User user); + + void delete(int id) throws NotFoundException; + + User get(int id) throws NotFoundException; + + User getByEmail(String email) throws NotFoundException; + + List getAll(); + + void update(User user); +} diff --git a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java new file mode 100644 index 000000000000..27a4b171c406 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java @@ -0,0 +1,41 @@ +package ru.javawebinar.topjava.service; + +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.repository.UserRepository; +import ru.javawebinar.topjava.util.exception.ExceptionUtil; +import ru.javawebinar.topjava.util.exception.NotFoundException; + +import java.util.List; + +/** + * GKislin + * 06.03.2015. + */ +public class UserServiceImpl implements UserService { + + private UserRepository repository; + + public User save(User user) { + return repository.save(user); + } + + public void delete(int id) { + ExceptionUtil.check(repository.delete(id), id); + } + + public User get(int id) throws NotFoundException { + return ExceptionUtil.check(repository.get(id), id); + } + + public User getByEmail(String email) throws NotFoundException { + return ExceptionUtil.check(repository.getByEmail(email), "email=" + email); + } + + public List getAll() { + return repository.getAll(); + } + + public void update(User user) { + repository.save(user); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java b/src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java new file mode 100644 index 000000000000..295aadab347f --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java @@ -0,0 +1,29 @@ +package ru.javawebinar.topjava.util.exception; + + +import ru.javawebinar.topjava.LoggerWrapper; + +/** + * User: gkislin + * Date: 14.05.2014 + */ +public class ExceptionUtil { + private static final LoggerWrapper LOG = LoggerWrapper.get(ExceptionUtil.class); + + public static void check(boolean found, int id) { + check(found, "id=" + id); + } + + public static T check(T object, int id) { + return check(object, "id=" + id); + } + + public static T check(T object, String msg) { + check(object != null, msg); + return object; + } + + public static void check(boolean found, String msg) { + if (!found) throw LOG.getNotFoundException("Not found entity with " + msg); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/util/exception/NotFoundException.java b/src/main/java/ru/javawebinar/topjava/util/exception/NotFoundException.java new file mode 100644 index 000000000000..7a770f0db834 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/util/exception/NotFoundException.java @@ -0,0 +1,11 @@ +package ru.javawebinar.topjava.util.exception; + +/** + * User: gkislin + * Date: 19.08.2014 + */ +public class NotFoundException extends RuntimeException { + public NotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java b/src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java new file mode 100644 index 000000000000..51e64a2712c8 --- /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.UserMealServiceImpl; + +/** + * GKislin + * 06.03.2015. + */ +public class UserMealRestController { + private UserMealServiceImpl 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..765c3ed7e113 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java @@ -0,0 +1,48 @@ +package ru.javawebinar.topjava.web.user; + +import ru.javawebinar.topjava.LoggerWrapper; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.service.UserService; + +import java.util.List; + +/** + * User: gkislin + */ +public abstract class AbstractUserController { + protected final LoggerWrapper LOG = LoggerWrapper.get(getClass()); + + private UserService service; + + public List getAll() { + LOG.info("getAll"); + return service.getAll(); + } + + public User get(int id) { + LOG.info("get " + id); + return service.get(id); + } + + public User create(User user) { + user.setId(null); + LOG.info("create " + user); + return service.save(user); + } + + public void delete(int id) { + LOG.info("delete " + id); + service.delete(id); + } + + public void update(User user, int id) { + user.setId(id); + LOG.info("update " + user); + service.update(user); + } + + public User getByMail(String email) { + LOG.info("getByEmail " + email); + return service.getByEmail(email); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java b/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java new file mode 100644 index 000000000000..cdd1e6bf11f8 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java @@ -0,0 +1,36 @@ +package ru.javawebinar.topjava.web.user; + +import ru.javawebinar.topjava.model.User; + +import java.util.List; + +/** + * GKislin + * 06.03.2015. + */ +public class AdminRestController extends AbstractUserController { + + public List getAll() { + return super.getAll(); + } + + public User get(int id) { + return super.get(id); + } + + public User create(User user) { + return super.create(user); + } + + public void delete(int id) { + super.delete(id); + } + + public void update(User user, int id) { + super.update(user, id); + } + + public User getByMail(String email) { + return super.getByMail(email); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java new file mode 100644 index 000000000000..6f0c970152af --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java @@ -0,0 +1,23 @@ +package ru.javawebinar.topjava.web.user; + +import ru.javawebinar.topjava.LoggedUser; +import ru.javawebinar.topjava.model.User; + +/** + * GKislin + * 06.03.2015. + */ +public class ProfileRestController extends AbstractUserController { + + public User get() { + return super.get(LoggedUser.id()); + } + + public void delete() { + super.delete(LoggedUser.id()); + } + + public void update(User user) { + super.update(user, LoggedUser.id()); + } +} \ No newline at end of file From e4ffb2b42eed513d4fe7f8f636ec7a8a4d13ac28 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sun, 15 Jan 2017 18:25:30 +0300 Subject: [PATCH 31/72] add spring context --- pom.xml | 14 ++++++ .../ru/javawebinar/topjava/SpringMain.java | 21 +++++++++ .../InMemoryUserMealRepository.java | 3 +- .../mock/MockUserRepositoryImpl.java | 46 +++++++++++++++++++ .../javawebinar/topjava/web/MealServlet.java | 2 +- src/main/resources/spring/spring-app.xml | 8 ++++ 6 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/SpringMain.java rename src/main/java/ru/javawebinar/topjava/repository/{ => mock}/InMemoryUserMealRepository.java (93%) create mode 100644 src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java create mode 100644 src/main/resources/spring/spring-app.xml diff --git a/pom.xml b/pom.xml index 44fe4e8dca85..7a394487dc53 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,8 @@ UTF-8 UTF-8 + 4.2.1.RELEASE + 1.1.2 1.7.7 @@ -82,6 +84,18 @@ 1.2 + + + org.springframework + spring-context + ${spring.version} + + + commons-logging + commons-logging + + + 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..720e8cc8b3d4 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/SpringMain.java @@ -0,0 +1,21 @@ +package ru.javawebinar.topjava; + +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import ru.javawebinar.topjava.repository.UserRepository; + +import java.util.Arrays; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +public class SpringMain { + public static void main(String[] args) { + ConfigurableApplicationContext appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml"); + System.out.println(Arrays.toString(appCtx.getBeanDefinitionNames())); + UserRepository userRepository = (UserRepository) appCtx.getBean("mockUserRepository"); + userRepository = appCtx.getBean(UserRepository.class); + appCtx.close(); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/repository/InMemoryUserMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepository.java similarity index 93% rename from src/main/java/ru/javawebinar/topjava/repository/InMemoryUserMealRepository.java rename to src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepository.java index b318764fffdc..6996132dd8c0 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/InMemoryUserMealRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepository.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 java.time.LocalDateTime; import java.time.Month; 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..6805a9fcd10e --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java @@ -0,0 +1,46 @@ +package ru.javawebinar.topjava.repository.mock; + +import ru.javawebinar.topjava.LoggerWrapper; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.repository.UserRepository; + +import java.util.Collections; +import java.util.List; + +/** + * GKislin + * 15.06.2015. + */ +public class MockUserRepositoryImpl implements UserRepository { + private static final LoggerWrapper LOG = LoggerWrapper.get(MockUserRepositoryImpl.class); + + @Override + public boolean delete(int id) { + LOG.info("delete " + id); + return true; + } + + @Override + public User save(User user) { + LOG.info("save " + user); + return user; + } + + @Override + public User get(int id) { + LOG.info("get " + id); + return null; + } + + @Override + public List getAll() { + LOG.info("getAll"); + return Collections.emptyList(); + } + + @Override + public User getByEmail(String email) { + LOG.info("getByEmail " + email); + return null; + } +} diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java index 46053673b1ef..905f50c71e71 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 ru.javawebinar.topjava.LoggerWrapper; import ru.javawebinar.topjava.model.UserMeal; -import ru.javawebinar.topjava.repository.InMemoryUserMealRepository; import ru.javawebinar.topjava.repository.UserMealRepository; +import ru.javawebinar.topjava.repository.mock.InMemoryUserMealRepository; import ru.javawebinar.topjava.util.UserMealsUtil; import javax.servlet.ServletConfig; diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml new file mode 100644 index 000000000000..19632d5645ac --- /dev/null +++ b/src/main/resources/spring/spring-app.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file From 788f91be32854a9a6835e67454a46366c8220495 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sun, 15 Jan 2017 18:56:23 +0300 Subject: [PATCH 32/72] add dependency injection --- src/main/resources/spring/spring-app.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml index 19632d5645ac..7b4fa1689425 100644 --- a/src/main/resources/spring/spring-app.xml +++ b/src/main/resources/spring/spring-app.xml @@ -1,8 +1,10 @@ + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> + + + \ No newline at end of file From 6560ee5ba96b436d42b6d3d6be25983b02ce2570 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sun, 15 Jan 2017 18:56:57 +0300 Subject: [PATCH 33/72] add dependency injection --- src/main/java/ru/javawebinar/topjava/SpringMain.java | 8 +++++--- .../ru/javawebinar/topjava/service/UserServiceImpl.java | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/SpringMain.java b/src/main/java/ru/javawebinar/topjava/SpringMain.java index 720e8cc8b3d4..063894391dcb 100644 --- a/src/main/java/ru/javawebinar/topjava/SpringMain.java +++ b/src/main/java/ru/javawebinar/topjava/SpringMain.java @@ -2,7 +2,9 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; -import ru.javawebinar.topjava.repository.UserRepository; +import ru.javawebinar.topjava.model.Role; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.service.UserService; import java.util.Arrays; @@ -14,8 +16,8 @@ public class SpringMain { public static void main(String[] args) { ConfigurableApplicationContext appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml"); System.out.println(Arrays.toString(appCtx.getBeanDefinitionNames())); - UserRepository userRepository = (UserRepository) appCtx.getBean("mockUserRepository"); - userRepository = appCtx.getBean(UserRepository.class); + UserService userService = appCtx.getBean(UserService.class); + System.out.println(userService.save(new User(1, "userName", "email", "password", Role.ROLE_ADMIN))); appCtx.close(); } } diff --git a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java index 27a4b171c406..066ae95037be 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java @@ -15,6 +15,10 @@ public class UserServiceImpl implements UserService { private UserRepository repository; + public void setRepository(UserRepository repository) { + this.repository = repository; + } + public User save(User user) { return repository.save(user); } From 97d43a87e2e4346061a39b2cef4a67fa814f222f Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sun, 15 Jan 2017 19:16:52 +0300 Subject: [PATCH 34/72] add annotation processing --- .../ru/javawebinar/topjava/web/user/ProfileRestController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java index 6f0c970152af..1114e57eeb1e 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java @@ -1,5 +1,6 @@ package ru.javawebinar.topjava.web.user; +import org.springframework.stereotype.Controller; import ru.javawebinar.topjava.LoggedUser; import ru.javawebinar.topjava.model.User; @@ -7,6 +8,7 @@ * GKislin * 06.03.2015. */ +@Controller public class ProfileRestController extends AbstractUserController { public User get() { From edb2cee6038e4d22cf3a4151f2e6a2da55bc139e Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sun, 15 Jan 2017 19:17:19 +0300 Subject: [PATCH 35/72] add annotation processing --- .../ru/javawebinar/topjava/SpringMain.java | 13 ++++++----- .../mock/MockUserRepositoryImpl.java | 2 ++ .../topjava/service/UserServiceImpl.java | 8 +++---- .../web/user/AbstractUserController.java | 2 ++ .../topjava/web/user/AdminRestController.java | 2 ++ src/main/resources/spring/spring-app.xml | 23 +++++++++++++++---- 6 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/SpringMain.java b/src/main/java/ru/javawebinar/topjava/SpringMain.java index 063894391dcb..9b14ec645a08 100644 --- a/src/main/java/ru/javawebinar/topjava/SpringMain.java +++ b/src/main/java/ru/javawebinar/topjava/SpringMain.java @@ -4,7 +4,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; import ru.javawebinar.topjava.model.Role; import ru.javawebinar.topjava.model.User; -import ru.javawebinar.topjava.service.UserService; +import ru.javawebinar.topjava.web.user.AdminRestController; import java.util.Arrays; @@ -14,10 +14,11 @@ */ public class SpringMain { public static void main(String[] args) { - ConfigurableApplicationContext appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml"); - System.out.println(Arrays.toString(appCtx.getBeanDefinitionNames())); - UserService userService = appCtx.getBean(UserService.class); - System.out.println(userService.save(new User(1, "userName", "email", "password", Role.ROLE_ADMIN))); - appCtx.close(); + // java 7 Automatic resource management + try (ConfigurableApplicationContext appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml")) { + System.out.println(Arrays.toString(appCtx.getBeanDefinitionNames())); + AdminRestController adminUserController = appCtx.getBean(AdminRestController.class); + System.out.println(adminUserController.create(new User(1, "userName", "email", "password", Role.ROLE_ADMIN))); + } } } diff --git a/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java index 6805a9fcd10e..cf2649b7bf46 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java @@ -1,5 +1,6 @@ package ru.javawebinar.topjava.repository.mock; +import org.springframework.stereotype.Repository; import ru.javawebinar.topjava.LoggerWrapper; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.repository.UserRepository; @@ -11,6 +12,7 @@ * GKislin * 15.06.2015. */ +@Repository public class MockUserRepositoryImpl implements UserRepository { private static final LoggerWrapper LOG = LoggerWrapper.get(MockUserRepositoryImpl.class); diff --git a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java index 066ae95037be..f83d039b7fbc 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java @@ -1,5 +1,7 @@ package ru.javawebinar.topjava.service; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.repository.UserRepository; import ru.javawebinar.topjava.util.exception.ExceptionUtil; @@ -11,14 +13,12 @@ * GKislin * 06.03.2015. */ +@Service public class UserServiceImpl implements UserService { + @Autowired private UserRepository repository; - public void setRepository(UserRepository repository) { - this.repository = repository; - } - public User save(User user) { return repository.save(user); } diff --git a/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java b/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java index 765c3ed7e113..98e0401f4523 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java @@ -1,5 +1,6 @@ package ru.javawebinar.topjava.web.user; +import org.springframework.beans.factory.annotation.Autowired; import ru.javawebinar.topjava.LoggerWrapper; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.service.UserService; @@ -12,6 +13,7 @@ public abstract class AbstractUserController { protected final LoggerWrapper LOG = LoggerWrapper.get(getClass()); + @Autowired private UserService service; public List getAll() { diff --git a/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java b/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java index cdd1e6bf11f8..d6b8bb420803 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java @@ -1,5 +1,6 @@ package ru.javawebinar.topjava.web.user; +import org.springframework.stereotype.Controller; import ru.javawebinar.topjava.model.User; import java.util.List; @@ -8,6 +9,7 @@ * GKislin * 06.03.2015. */ +@Controller public class AdminRestController extends AbstractUserController { public List getAll() { diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml index 7b4fa1689425..c285b264141d 100644 --- a/src/main/resources/spring/spring-app.xml +++ b/src/main/resources/spring/spring-app.xml @@ -1,10 +1,23 @@ + xmlns:context="http://www.springframework.org/schema/context" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> - + + + + + + + + + - - - \ No newline at end of file From 36aa805ee8e51ad5bc12f3d960cb5035fba08a1c Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sun, 15 Jan 2017 22:59:06 +0300 Subject: [PATCH 36/72] HW2 done --- .../ru/javawebinar/topjava/SpringMain.java | 14 +++++ .../javawebinar/topjava/model/UserMeal.java | 16 ++--- .../topjava/model/UserMealWithExceed.java | 2 +- .../repository/UserMealRepository.java | 15 +++-- ...va => InMemoryUserMealRepositoryImpl.java} | 35 +++++++---- .../topjava/service/UserMealService.java | 22 +++++++ .../topjava/service/UserMealServiceImpl.java | 38 ++++++++++++ .../topjava/service/UserService.java | 2 +- .../ru/javawebinar/topjava/util/TimeUtil.java | 4 ++ .../javawebinar/topjava/web/MealServlet.java | 13 +++-- .../web/meal/UserMealRestController.java | 58 ++++++++++++++++++- 11 files changed, 185 insertions(+), 34 deletions(-) rename src/main/java/ru/javawebinar/topjava/repository/mock/{InMemoryUserMealRepository.java => InMemoryUserMealRepositoryImpl.java} (55%) diff --git a/src/main/java/ru/javawebinar/topjava/SpringMain.java b/src/main/java/ru/javawebinar/topjava/SpringMain.java index 9b14ec645a08..11ae192771d1 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.model.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 13662581d16e..e1f99a737cf4 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java @@ -6,21 +6,23 @@ * GKislin * 11.01.2015. */ -public class UserMeal { - protected Integer id; +public class UserMeal extends BaseEntity { - protected final LocalDateTime dateTime; + protected LocalDateTime dateTime; - protected final String description; + protected String description; - protected final int calories; + protected int calories; + + public UserMeal() { + } 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; + super(id); this.dateTime = dateTime; this.description = description; this.calories = calories; @@ -59,4 +61,4 @@ public String toString() { ", calories=" + calories + '}'; } -} +} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java index 1f66bad92b56..9fd22fa22f71 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMealWithExceed.java @@ -7,7 +7,7 @@ * 11.01.2015. */ public class UserMealWithExceed { - protected Integer id; + protected final Integer id; protected final LocalDateTime dateTime; diff --git a/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java index ad656ea6cd19..01d301e19b9b 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,17 @@ * 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 DATE, TIME + Collection getAll(int userId); + + Collection getBetween(LocalDateTime startDate, LocalDateTime endDate, int userId); } diff --git a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java similarity index 55% rename from src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepository.java rename to src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java index 6996132dd8c0..73fefd5c3c72 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java @@ -1,7 +1,9 @@ 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 java.time.LocalDateTime; import java.time.Month; @@ -9,26 +11,28 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; /** * GKislin * 15.09.2015. */ -public class InMemoryUserMealRepository implements UserMealRepository { +@Repository +public class InMemoryUserMealRepositoryImpl implements UserMealRepository { private Map repository = new ConcurrentHashMap<>(); private AtomicInteger counter = new AtomicInteger(0); { - save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 10, 0), "Завтрак", 500)); - save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 13, 0), "Обед", 1000)); - save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 20, 0), "Ужин", 500)); - save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 10, 0), "Завтрак", 1000)); - save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 13, 0), "Обед", 500)); - save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 20, 0), "Ужин", 510)); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 10, 0), "Завтрак", 500), 1); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 13, 0), "Обед", 1000), 1); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 20, 0), "Ужин", 500), 1); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 10, 0), "Завтрак", 1000), 1); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 13, 0), "Обед", 500), 1); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 20, 0), "Ужин", 510), 1); } @Override - public UserMeal save(UserMeal userMeal) { + public UserMeal save(UserMeal userMeal, int userId) { if (userMeal.isNew()) { userMeal.setId(counter.incrementAndGet()); } @@ -36,18 +40,25 @@ public UserMeal save(UserMeal userMeal) { } @Override - public void delete(int id) { - repository.remove(id); + public boolean delete(int id, int userId) { + return repository.remove(id) != null; } @Override - public UserMeal get(int id) { + public UserMeal get(int id, int userId) { return repository.get(id); } @Override - public Collection getAll() { + public Collection getAll(int userId) { return repository.values(); } + + @Override + public Collection getBetween(LocalDateTime startDateTime, LocalDateTime endDateTime, int userId) { + return repository.values().stream() + .filter(um -> TimeUtil.isBetween(um.getDateTime(), startDateTime, endDateTime)) + .collect(Collectors.toList()); + } } diff --git a/src/main/java/ru/javawebinar/topjava/service/UserMealService.java b/src/main/java/ru/javawebinar/topjava/service/UserMealService.java index b17fec811065..50e9d4aaf7d1 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserMealService.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserMealService.java @@ -1,8 +1,30 @@ package ru.javawebinar.topjava.service; +import ru.javawebinar.topjava.model.UserMeal; + +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); + + void delete(int id, int userId); + + 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); + + UserMeal save(UserMeal meal, int userId); } diff --git a/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java index 5730b8bfb130..fe2aa873de5c 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java @@ -1,13 +1,51 @@ package ru.javawebinar.topjava.service; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.repository.UserMealRepository; +import ru.javawebinar.topjava.util.exception.ExceptionUtil; + +import java.time.LocalDateTime; +import java.util.Collection; /** * GKislin * 06.03.2015. */ +@Service public class UserMealServiceImpl implements UserMealService { + @Autowired private UserMealRepository repository; + @Override + public UserMeal get(int id, int userId) { + return ExceptionUtil.check(repository.get(id, userId), id); + } + + @Override + public void delete(int id, int userId) { + ExceptionUtil.check(repository.delete(id, userId), id); + } + + @Override + public Collection getBetweenDateTimes(LocalDateTime startDateTime, LocalDateTime endDateTime, int userId) { + return repository.getBetween(startDateTime, endDateTime, userId); + } + + @Override + public Collection getAll(int userId) { + return repository.getAll(userId); + } + + @Override + public UserMeal update(UserMeal meal, int userId) { + return ExceptionUtil.check(repository.save(meal, userId), meal.getId()); + } + + @Override + public UserMeal save(UserMeal meal, int userId) { + return repository.save(meal, userId); + } } diff --git a/src/main/java/ru/javawebinar/topjava/service/UserService.java b/src/main/java/ru/javawebinar/topjava/service/UserService.java index 85c15e48f951..1d8dab0fabda 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserService.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserService.java @@ -22,5 +22,5 @@ public interface UserService { List getAll(); - void update(User user); + void update(User user) throws NotFoundException; } diff --git a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java index 115311fad6b7..4546d5b3b010 100644 --- a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java @@ -15,6 +15,10 @@ public static boolean isBetween(LocalTime lt, LocalTime startTime, LocalTime end return lt.compareTo(startTime) >= 0 && lt.compareTo(endTime) <= 0; } + public static boolean isBetween(LocalDateTime ldt, LocalDateTime startDateTime, LocalDateTime endDateTime) { + return ldt.compareTo(startDateTime) >= 0 && ldt.compareTo(endDateTime) <= 0; + } + public static String toString(LocalDateTime ldt) { return ldt == null ? "" : ldt.format(DATE_TME_FORMATTER); } diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java index 905f50c71e71..6e00dfce0df6 100644 --- a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -1,9 +1,10 @@ package ru.javawebinar.topjava.web; +import ru.javawebinar.topjava.LoggedUser; import ru.javawebinar.topjava.LoggerWrapper; import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.repository.UserMealRepository; -import ru.javawebinar.topjava.repository.mock.InMemoryUserMealRepository; +import ru.javawebinar.topjava.repository.mock.InMemoryUserMealRepositoryImpl; import ru.javawebinar.topjava.util.UserMealsUtil; import javax.servlet.ServletConfig; @@ -27,7 +28,7 @@ public class MealServlet extends HttpServlet { @Override public void init(ServletConfig config) throws ServletException { super.init(config); - repository = new InMemoryUserMealRepository(); + repository = new InMemoryUserMealRepositoryImpl(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException { @@ -38,7 +39,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"); } @@ -48,17 +49,17 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t if (action == null) { LOG.info("getAll"); request.setAttribute("mealList", - UserMealsUtil.getWithExceeded(repository.getAll(), 2000)); + UserMealsUtil.getWithExceeded(repository.getAll(LoggedUser.id()), 2000)); request.getRequestDispatcher("/mealList.jsp").forward(request, response); } else if (action.equals("delete")) { int id = getId(request); LOG.info("Delete {}", id); - repository.delete(id); + repository.delete(id, LoggedUser.id()); response.sendRedirect("meals"); } else { final UserMeal meal = action.equals("create") ? new UserMeal(LocalDateTime.now(), "", 1000) : - repository.get(getId(request)); + repository.get(getId(request), LoggedUser.id()); request.setAttribute("meal", meal); request.getRequestDispatcher("mealEdit.jsp").forward(request, response); } 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 51e64a2712c8..bb3692af9f8b 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,64 @@ package ru.javawebinar.topjava.web.meal; -import ru.javawebinar.topjava.service.UserMealServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import ru.javawebinar.topjava.LoggedUser; +import ru.javawebinar.topjava.LoggerWrapper; +import ru.javawebinar.topjava.model.UserMeal; +import ru.javawebinar.topjava.model.UserMealWithExceed; +import ru.javawebinar.topjava.service.UserMealService; +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 UserMealServiceImpl service; + private static final LoggerWrapper LOG = LoggerWrapper.get(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 userId = LoggedUser.id(); + LOG.info("update {} for User {}", meal, userId); + service.update(meal, userId); + } + + public UserMeal create(UserMeal meal) { + 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, endDate, userId), startTime, endTime, LoggedUser.getCaloriesPerDay() + ); + } +} \ No newline at end of file From fb126fa870ec727f74c3c84e690b951b138dfd8d Mon Sep 17 00:00:00 2001 From: AndrePro Date: Sun, 15 Jan 2017 23:43:27 +0300 Subject: [PATCH 37/72] HW2 optional done --- .../ru/javawebinar/topjava/LoggedUser.java | 7 ++- .../repository/UserMealRepository.java | 1 + .../topjava/repository/UserRepository.java | 4 +- .../mock/InMemoryUserMealRepositoryImpl.java | 51 ++++++++++++----- .../mock/InMemoryUserRepositoryImpl.java | 57 +++++++++++++++++++ .../mock/MockUserRepositoryImpl.java | 48 ---------------- .../topjava/service/UserService.java | 4 +- .../topjava/service/UserServiceImpl.java | 4 +- .../ru/javawebinar/topjava/util/TimeUtil.java | 15 ++++- .../javawebinar/topjava/web/MealServlet.java | 55 ++++++++++++------ .../javawebinar/topjava/web/UserServlet.java | 7 +++ .../web/user/AbstractUserController.java | 4 +- .../topjava/web/user/AdminRestController.java | 4 +- src/main/webapp/css/style.css | 24 ++++++++ src/main/webapp/index.html | 11 +++- src/main/webapp/mealEdit.jsp | 19 +------ src/main/webapp/mealList.jsp | 25 ++++++-- 17 files changed, 223 insertions(+), 117 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 create mode 100644 src/main/webapp/css/style.css diff --git a/src/main/java/ru/javawebinar/topjava/LoggedUser.java b/src/main/java/ru/javawebinar/topjava/LoggedUser.java index 462aba786ee3..b3aefb7b5031 100644 --- a/src/main/java/ru/javawebinar/topjava/LoggedUser.java +++ b/src/main/java/ru/javawebinar/topjava/LoggedUser.java @@ -5,12 +5,17 @@ * 06.03.2015. */ public class LoggedUser { + public static int id = 1; public static int id() { - return 1; + return id; } public static int getCaloriesPerDay() { return 2000; } + + public static void setId(int id) { + LoggedUser.id = id; + } } diff --git a/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java index 01d301e19b9b..646b908602a4 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java @@ -22,5 +22,6 @@ public interface UserMealRepository { // ORDERED DATE, TIME Collection getAll(int userId); + // ORDERED DATE, TIME Collection getBetween(LocalDateTime startDate, LocalDateTime endDate, int userId); } diff --git a/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java index 24c1c45beca6..fe65d1abdd97 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java @@ -2,7 +2,7 @@ import ru.javawebinar.topjava.model.User; -import java.util.List; +import java.util.Collection; /** * User: gkislin @@ -20,5 +20,5 @@ public interface UserRepository { // null if not found User getByEmail(String email); - List getAll(); + Collection getAll(); } 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 73fefd5c3c72..3023155226d1 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java @@ -8,57 +8,78 @@ import java.time.LocalDateTime; import java.time.Month; import java.util.Collection; +import java.util.Comparator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; +import static ru.javawebinar.topjava.repository.mock.InMemoryUserRepositoryImpl.ADMIN_ID; +import static ru.javawebinar.topjava.repository.mock.InMemoryUserRepositoryImpl.USER_ID; + /** * GKislin * 15.09.2015. */ @Repository public class InMemoryUserMealRepositoryImpl implements UserMealRepository { - private Map repository = new ConcurrentHashMap<>(); + + public static final Comparator USER_MEAL_COMPARATOR = (um1, um2) -> um2.getDateTime().compareTo(um1.getDateTime()); + + // Map userId -> (mealId-> meal) + private Map> repository = new ConcurrentHashMap<>(); private AtomicInteger counter = new AtomicInteger(0); { - save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 10, 0), "Завтрак", 500), 1); - save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 13, 0), "Обед", 1000), 1); - save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 20, 0), "Ужин", 500), 1); - save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 10, 0), "Завтрак", 1000), 1); - save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 13, 0), "Обед", 500), 1); - save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 20, 0), "Ужин", 510), 1); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 10, 0), "Завтрак", 500), USER_ID); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 13, 0), "Обед", 1000), USER_ID); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 30, 20, 0), "Ужин", 500), USER_ID); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 10, 0), "Завтрак", 1000), USER_ID); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 13, 0), "Обед", 500), USER_ID); + save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 20, 0), "Ужин", 510), 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), "Админ ужин ", 510), ADMIN_ID); } @Override public UserMeal save(UserMeal userMeal, int userId) { + 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; } - return repository.put(userMeal.getId(), userMeal); + Map userMeals = repository.computeIfAbsent(userId, ConcurrentHashMap::new); + userMeals.put(mealId, userMeal); + return userMeal; + } @Override public boolean delete(int id, int userId) { - return repository.remove(id) != null; + Map userMeals = repository.get(userId); + return userMeals != null && userMeals.remove(id) != null; } @Override public UserMeal get(int id, int userId) { - return repository.get(id); + Map userMeals = repository.get(userId); + return userMeals == null ? null : userMeals.get(id); } @Override public Collection getAll(int userId) { - return repository.values(); + return repository.get(userId).values().stream().sorted(USER_MEAL_COMPARATOR).collect(Collectors.toList()); } @Override public Collection getBetween(LocalDateTime startDateTime, LocalDateTime endDateTime, int userId) { - return repository.values().stream() + return getAll(userId).stream() .filter(um -> TimeUtil.isBetween(um.getDateTime(), startDateTime, endDateTime)) + .sorted(USER_MEAL_COMPARATOR) .collect(Collectors.toList()); } -} - +} \ No newline at end of file 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..4c30ed5db086 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java @@ -0,0 +1,57 @@ +package ru.javawebinar.topjava.repository.mock; + +import org.springframework.stereotype.Repository; +import ru.javawebinar.topjava.model.Role; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.repository.UserRepository; + +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * GKislin + * 15.06.2015. + */ +@Repository +public class InMemoryUserRepositoryImpl implements UserRepository { + private Map repository = new ConcurrentHashMap<>(); + private AtomicInteger counter = new AtomicInteger(0); + + public static final int USER_ID = 1; + public static final int ADMIN_ID = 2; + + { + save(new User(1, "User", "user@yandex.ru", "password", Role.ROLE_USER)); + save(new User(2, "Admin", "admin@gmail.com", "admin", Role.ROLE_ADMIN)); + } + + @Override + public User save(User user) { + if (user.isNew()) { + user.setId(counter.incrementAndGet()); + } + return repository.put(user.getId(), user); + } + + @Override + public boolean delete(int id) { + return repository.remove(id) != null; + } + + @Override + public User get(int id) { + return repository.get(id); + } + + @Override + public Collection getAll() { + return repository.values(); + } + + @Override + public User getByEmail(String email) { + return getAll().stream().filter(u -> u.getEmail().equals(email)).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 cf2649b7bf46..000000000000 --- a/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -package ru.javawebinar.topjava.repository.mock; - -import org.springframework.stereotype.Repository; -import ru.javawebinar.topjava.LoggerWrapper; -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 LoggerWrapper LOG = LoggerWrapper.get(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/UserService.java b/src/main/java/ru/javawebinar/topjava/service/UserService.java index 1d8dab0fabda..8b0c6c7263fc 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserService.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserService.java @@ -4,7 +4,7 @@ import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.util.exception.NotFoundException; -import java.util.List; +import java.util.Collection; /** * User: gkislin @@ -20,7 +20,7 @@ public interface UserService { User getByEmail(String email) throws NotFoundException; - List getAll(); + Collection getAll(); void update(User user) throws NotFoundException; } diff --git a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java index f83d039b7fbc..50d2c55cf19d 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java @@ -7,7 +7,7 @@ import ru.javawebinar.topjava.util.exception.ExceptionUtil; import ru.javawebinar.topjava.util.exception.NotFoundException; -import java.util.List; +import java.util.Collection; /** * GKislin @@ -35,7 +35,7 @@ public User getByEmail(String email) throws NotFoundException { return ExceptionUtil.check(repository.getByEmail(email), "email=" + email); } - public List getAll() { + public Collection getAll() { return repository.getAll(); } diff --git a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java index 4546d5b3b010..d8342ec95a9e 100644 --- a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java @@ -1,5 +1,8 @@ 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; @@ -10,6 +13,8 @@ */ public class TimeUtil { public static final DateTimeFormatter DATE_TME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + public static final LocalDate MIN_DATE = LocalDate.of(0, 1, 1); + public static final LocalDate MAX_DATE = LocalDate.of(3000, 1, 1); public static boolean isBetween(LocalTime lt, LocalTime startTime, LocalTime endTime) { return lt.compareTo(startTime) >= 0 && lt.compareTo(endTime) <= 0; @@ -22,4 +27,12 @@ public static boolean isBetween(LocalDateTime ldt, LocalDateTime startDateTime, public static String toString(LocalDateTime ldt) { return ldt == null ? "" : ldt.format(DATE_TME_FORMATTER); } -} + + public static LocalDate parseLocalDate(String str, LocalDate def) { + return StringUtils.isEmpty(str) ? def : LocalDate.parse(str); + } + + public static LocalTime parseLocalTime(String str, LocalTime def) { + return StringUtils.isEmpty(str) ? def : LocalTime.parse(str); + } +} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java index 6e00dfce0df6..9e70adda130a 100644 --- a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -1,11 +1,11 @@ package ru.javawebinar.topjava.web; -import ru.javawebinar.topjava.LoggedUser; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; import ru.javawebinar.topjava.LoggerWrapper; 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.util.TimeUtil; +import ru.javawebinar.topjava.web.meal.UserMealRestController; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -13,7 +13,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; /** @@ -23,24 +25,42 @@ public class MealServlet extends HttpServlet { private static final LoggerWrapper LOG = LoggerWrapper.get(MealServlet.class); - private UserMealRepository repository; + private ConfigurableApplicationContext springContext; + private UserMealRestController mealController; @Override public void init(ServletConfig config) throws ServletException { super.init(config); - repository = new InMemoryUserMealRepositoryImpl(); + springContext = new ClassPathXmlApplicationContext("spring/spring-app.xml"); + mealController = springContext.getBean(UserMealRestController.class); + } + + @Override + public void destroy() { + springContext.close(); + super.destroy(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException { request.setCharacterEncoding("UTF-8"); - String id = request.getParameter("id"); - UserMeal userMeal = new UserMeal(id.isEmpty() ? null : Integer.valueOf(id), - 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()); - response.sendRedirect("meals"); + String action = request.getParameter("action"); + if (action == null) { + 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"))); + LOG.info(userMeal.isNew() ? "Create {}" : "Update {}", userMeal); + mealController.create(userMeal); + response.sendRedirect("meals"); + } else { + LocalDate startDate = TimeUtil.parseLocalDate(request.getParameter("startDate"), TimeUtil.MIN_DATE); + LocalDate endDate = TimeUtil.parseLocalDate(request.getParameter("endDate"), TimeUtil.MAX_DATE); + LocalTime startTime = TimeUtil.parseLocalTime(request.getParameter("startTime"), LocalTime.MIN); + LocalTime endTime = TimeUtil.parseLocalTime(request.getParameter("endTime"), LocalTime.MAX); + 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 { @@ -48,18 +68,17 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t if (action == null) { LOG.info("getAll"); - request.setAttribute("mealList", - UserMealsUtil.getWithExceeded(repository.getAll(LoggedUser.id()), 2000)); + request.setAttribute("mealList", mealController.getAll()); request.getRequestDispatcher("/mealList.jsp").forward(request, response); } else if (action.equals("delete")) { int id = getId(request); LOG.info("Delete {}", id); - repository.delete(id, LoggedUser.id()); + mealController.delete(id); response.sendRedirect("meals"); } else { final UserMeal meal = action.equals("create") ? new UserMeal(LocalDateTime.now(), "", 1000) : - repository.get(getId(request), LoggedUser.id()); + mealController.get(getId(request)); request.setAttribute("meal", meal); request.getRequestDispatcher("mealEdit.jsp").forward(request, response); } diff --git a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java index eb2188bc8435..40adae5b88cc 100644 --- a/src/main/java/ru/javawebinar/topjava/web/UserServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java @@ -1,5 +1,6 @@ package ru.javawebinar.topjava.web; +import ru.javawebinar.topjava.LoggedUser; import ru.javawebinar.topjava.LoggerWrapper; import javax.servlet.ServletException; @@ -15,6 +16,12 @@ public class UserServlet extends HttpServlet { private static final LoggerWrapper LOG = LoggerWrapper.get(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"); 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 98e0401f4523..afcd4db5a574 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java @@ -5,7 +5,7 @@ import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.service.UserService; -import java.util.List; +import java.util.Collection; /** * User: gkislin @@ -16,7 +16,7 @@ public abstract class AbstractUserController { @Autowired private UserService service; - public List getAll() { + public Collection getAll() { LOG.info("getAll"); return service.getAll(); } diff --git a/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java b/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java index d6b8bb420803..cd89f7bce290 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java @@ -3,7 +3,7 @@ import org.springframework.stereotype.Controller; import ru.javawebinar.topjava.model.User; -import java.util.List; +import java.util.Collection; /** * GKislin @@ -12,7 +12,7 @@ @Controller public class AdminRestController extends AbstractUserController { - public List getAll() { + public Collection getAll() { return super.getAll(); } 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/index.html b/src/main/webapp/index.html index 62ae01a26e9b..baacc9e9d84d 100644 --- a/src/main/webapp/index.html +++ b/src/main/webapp/index.html @@ -7,9 +7,16 @@

Проект "Top Java."


+
+ Login as: + +
diff --git a/src/main/webapp/mealEdit.jsp b/src/main/webapp/mealEdit.jsp index 443933549130..d71aeb3a6bbd 100644 --- a/src/main/webapp/mealEdit.jsp +++ b/src/main/webapp/mealEdit.jsp @@ -4,24 +4,7 @@ Meal - +
diff --git a/src/main/webapp/mealList.jsp b/src/main/webapp/mealList.jsp index dbf36345b502..2369a67ebd4f 100644 --- a/src/main/webapp/mealList.jsp +++ b/src/main/webapp/mealList.jsp @@ -5,15 +5,32 @@ Meal list - +

Home

Meal list

+
+
+
From Date:
+
+
+
+
To Date:
+
+
+
+
From Time:
+
+
+
+
To Time:
+
+
+ +
+
Add Meal
From f09b6f1a60ed953648952feb85dbb626b91e0611 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Mon, 16 Jan 2017 21:54:36 +0300 Subject: [PATCH 38/72] add postconstruct predestroy spring annotations --- .../mock/InMemoryUserRepositoryImpl.java | 15 +++++++++++++++ 1 file changed, 15 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 4c30ed5db086..8658e21e9122 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java @@ -1,10 +1,13 @@ package ru.javawebinar.topjava.repository.mock; import org.springframework.stereotype.Repository; +import ru.javawebinar.topjava.LoggerWrapper; import ru.javawebinar.topjava.model.Role; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.repository.UserRepository; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -16,6 +19,8 @@ */ @Repository public class InMemoryUserRepositoryImpl implements UserRepository { + private static final LoggerWrapper LOG = LoggerWrapper.get(InMemoryUserRepositoryImpl.class); + private Map repository = new ConcurrentHashMap<>(); private AtomicInteger counter = new AtomicInteger(0); @@ -27,6 +32,16 @@ public class InMemoryUserRepositoryImpl implements UserRepository { save(new User(2, "Admin", "admin@gmail.com", "admin", Role.ROLE_ADMIN)); } + @PostConstruct + public void postConstruct() { + LOG.info("+++ PostConstruct"); + } + + @PreDestroy + public void preDestroy() { + LOG.info("+++ PreDestroy"); + } + @Override public User save(User user) { if (user.isNew()) { From 42adde07a1969809f69ad62b97a81ae5c55645d9 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Mon, 16 Jan 2017 23:50:32 +0300 Subject: [PATCH 39/72] add junit --- pom.xml | 11 ++++ .../ru/javawebinar/topjava/LoggerWrapper.java | 2 +- .../ru/javawebinar/topjava/SpringMain.java | 0 .../ru/javawebinar/topjava/UserTestData.java | 16 ++++++ .../mock/InMemoryUserMealRepositoryImpl.java | 4 +- .../mock/InMemoryUserRepositoryImpl.java | 9 ---- .../topjava/web/AdminInMemoryTest.java | 53 +++++++++++++++++++ 7 files changed, 83 insertions(+), 12 deletions(-) rename src/{main => test}/java/ru/javawebinar/topjava/SpringMain.java (100%) 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 (84%) create mode 100644 src/test/java/ru/javawebinar/topjava/web/AdminInMemoryTest.java diff --git a/pom.xml b/pom.xml index 7a394487dc53..298f631cf466 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,9 @@ 1.1.2 1.7.7 + + + 4.12 @@ -96,6 +99,14 @@ + + + + junit + junit + ${junit.version} + test + diff --git a/src/main/java/ru/javawebinar/topjava/LoggerWrapper.java b/src/main/java/ru/javawebinar/topjava/LoggerWrapper.java index 642bb6c4c7ea..8ab6153791d8 100644 --- a/src/main/java/ru/javawebinar/topjava/LoggerWrapper.java +++ b/src/main/java/ru/javawebinar/topjava/LoggerWrapper.java @@ -72,7 +72,7 @@ public UnsupportedOperationException getUnsupportedOperationException(String msg } public NotFoundException getNotFoundException(String reason) { - logger.error("No data found"); + logger.error(reason); return new NotFoundException(reason); } } \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/SpringMain.java b/src/test/java/ru/javawebinar/topjava/SpringMain.java similarity index 100% rename from src/main/java/ru/javawebinar/topjava/SpringMain.java rename to src/test/java/ru/javawebinar/topjava/SpringMain.java 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..55a2c85f4770 --- /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(1, "User", "user@yandex.ru", "password", Role.ROLE_USER); + public static final User ADMIN = new User(2, "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 3023155226d1..ff71e1034b3c 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java +++ b/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java @@ -14,8 +14,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 84% 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 8658e21e9122..41cc257e9485 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java +++ b/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserRepositoryImpl.java @@ -2,7 +2,6 @@ import org.springframework.stereotype.Repository; import ru.javawebinar.topjava.LoggerWrapper; -import ru.javawebinar.topjava.model.Role; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.repository.UserRepository; @@ -24,14 +23,6 @@ public class InMemoryUserRepositoryImpl implements UserRepository { private Map repository = new ConcurrentHashMap<>(); private AtomicInteger counter = new AtomicInteger(0); - public static final int USER_ID = 1; - public static final int ADMIN_ID = 2; - - { - save(new User(1, "User", "user@yandex.ru", "password", Role.ROLE_USER)); - save(new User(2, "Admin", "admin@gmail.com", "admin", Role.ROLE_ADMIN)); - } - @PostConstruct public void postConstruct() { LOG.info("+++ PostConstruct"); diff --git a/src/test/java/ru/javawebinar/topjava/web/AdminInMemoryTest.java b/src/test/java/ru/javawebinar/topjava/web/AdminInMemoryTest.java new file mode 100644 index 000000000000..a0610df4ce92 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/web/AdminInMemoryTest.java @@ -0,0 +1,53 @@ +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 AdminInMemoryTest { + private static ConfigurableApplicationContext appCtx; + private static AdminRestController controller; + + @BeforeClass + public static void beforeClass() { + appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml"); + System.out.println("\n" + Arrays.toString(appCtx.getBeanDefinitionNames()) + "\n"); + controller = appCtx.getBean(AdminRestController.class); + } + + @Before + public void setUp() throws Exception { + UserRepository repository = appCtx.getBean(UserRepository.class); + repository.save(USER); + repository.save(ADMIN); + } + + @AfterClass + public static void afterClass() { + appCtx.close(); + } + + @Test + public void testDelete() throws Exception { + controller.delete(UserTestData.USER_ID); + Collection users = controller.getAll(); + Assert.assertEquals(users.size(), 1); + Assert.assertEquals(users.iterator().next(), ADMIN); + } + + @Test(expected = NotFoundException.class) + public void testDeleteNotFound() throws Exception { + controller.delete(10); + } +} \ No newline at end of file From 0e70c3f4871c900eddb3b6966a0c407ea449ae5f Mon Sep 17 00:00:00 2001 From: AndrePro Date: Tue, 17 Jan 2017 00:15:59 +0300 Subject: [PATCH 40/72] add spring tests --- .../topjava/web/SpringAdminInMemoryTest.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/test/java/ru/javawebinar/topjava/web/SpringAdminInMemoryTest.java diff --git a/src/test/java/ru/javawebinar/topjava/web/SpringAdminInMemoryTest.java b/src/test/java/ru/javawebinar/topjava/web/SpringAdminInMemoryTest.java new file mode 100644 index 000000000000..532a438557a9 --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/web/SpringAdminInMemoryTest.java @@ -0,0 +1,53 @@ +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 SpringAdminInMemoryTest { + + @Autowired + private AdminRestController controller; + + @Autowired + private UserRepository repository; + + @Before + public void setUp() throws Exception { + 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 d688c33ca0a426a0054e5cfd0d471c8b6568fa8c Mon Sep 17 00:00:00 2001 From: AndrePro Date: Tue, 17 Jan 2017 00:17:10 +0300 Subject: [PATCH 41/72] add spring tests --- pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pom.xml b/pom.xml index 298f631cf466..4d2ce7b4e22d 100644 --- a/pom.xml +++ b/pom.xml @@ -107,6 +107,13 @@ ${junit.version} test + + org.springframework + spring-test + ${spring.version} + test + + From 2c779a0cf1a5ec165f43df35f3f6d613872550ef Mon Sep 17 00:00:00 2001 From: AndrePro Date: Tue, 17 Jan 2017 00:48:53 +0300 Subject: [PATCH 42/72] add database --- pom.xml | 7 +++++++ src/main/resources/db/postgres.properties | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 src/main/resources/db/postgres.properties diff --git a/pom.xml b/pom.xml index 4d2ce7b4e22d..226f2a933449 100644 --- a/pom.xml +++ b/pom.xml @@ -100,6 +100,13 @@ + + + mysql + mysql-connector-java + 5.1.35 + + junit diff --git a/src/main/resources/db/postgres.properties b/src/main/resources/db/postgres.properties new file mode 100644 index 000000000000..e0d4ae2b15e1 --- /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:mysql://localhost:3306/topjava +database.username=root +database.password=venjdf From f98fad01d83de3e5b940ec938fd9c520c70f63e4 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Tue, 17 Jan 2017 22:35:57 +0300 Subject: [PATCH 43/72] populate DB --- src/main/resources/db/initDB.sql | 25 ++++++++++++++++++++++ src/main/resources/db/initDB_mysql.sql | 20 +++++++++++++++++ src/main/resources/db/populateDB.sql | 13 +++++++++++ src/main/resources/db/populateDB_mysql.sql | 9 ++++++++ 4 files changed, 67 insertions(+) create mode 100644 src/main/resources/db/initDB.sql create mode 100644 src/main/resources/db/initDB_mysql.sql create mode 100644 src/main/resources/db/populateDB.sql create mode 100644 src/main/resources/db/populateDB_mysql.sql diff --git a/src/main/resources/db/initDB.sql b/src/main/resources/db/initDB.sql new file mode 100644 index 000000000000..620c77f27b0e --- /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 unique_email 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/initDB_mysql.sql b/src/main/resources/db/initDB_mysql.sql new file mode 100644 index 000000000000..1245f553e2e1 --- /dev/null +++ b/src/main/resources/db/initDB_mysql.sql @@ -0,0 +1,20 @@ +CREATE TABLE users +( + id INT PRIMARY KEY AUTO_INCREMENT, + name VARCHAR(50) NOT NULL, + email VARCHAR(50) NOT NULL, + password VARCHAR(50) NOT NULL, + registered TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + calories_per_day INT DEFAULT '2000' +); +CREATE UNIQUE INDEX unique_email ON users (email); + +ALTER TABLE users AUTO_INCREMENT = 100000; + + +CREATE TABLE user_roles +( + user_id INTEGER NOT NULL, + role VARCHAR(50), + FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE +); \ No newline at end of file diff --git a/src/main/resources/db/populateDB.sql b/src/main/resources/db/populateDB.sql new file mode 100644 index 000000000000..d7439bba5994 --- /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; + +-- password +INSERT INTO users (name, email, password) +VALUES ('User', 'user@yandex.ru', 'password'); +-- admin +INSERT INTO users (name, email, password) +VALUES ('Admin', 'admin@gmail.com', 'admin'); + +INSERT INTO user_roles (role, user_id) VALUES ('ROLE_USER', 100000); +INSERT INTO user_roles (role, user_id) VALUES ('ROLE_ADMIN', 100001); diff --git a/src/main/resources/db/populateDB_mysql.sql b/src/main/resources/db/populateDB_mysql.sql new file mode 100644 index 000000000000..7f10e16cc2cb --- /dev/null +++ b/src/main/resources/db/populateDB_mysql.sql @@ -0,0 +1,9 @@ +-- password +INSERT INTO users (name, email, password) +VALUES ('User', 'user@yandex.ru', 'password'); +-- admin +INSERT INTO users (name, email, password) +VALUES ('Admin', 'admin@gmail.com', 'admin'); + +INSERT INTO user_roles (role, user_id) VALUES ('ROLE_USER', 100000); +INSERT INTO user_roles (role, user_id) VALUES ('ROLE_ADMIN', 100001); \ No newline at end of file From 9435cc865d07ed0380ac55a9f8307c0835c6ce8c Mon Sep 17 00:00:00 2001 From: AndrePro Date: Wed, 18 Jan 2017 00:27:14 +0300 Subject: [PATCH 44/72] implement JDBC_Template --- pom.xml | 5 ++ .../jdbc/JdbcUserRepositoryImpl.java | 82 +++++++++++++++++++ src/main/resources/db/postgres.properties | 1 + src/main/resources/spring/spring-db.xml | 25 ++++++ 4 files changed, 113 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 226f2a933449..04e729247cfd 100644 --- a/pom.xml +++ b/pom.xml @@ -106,6 +106,11 @@ mysql-connector-java 5.1.35 + + 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..221f966d08a9 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepositoryImpl.java @@ -0,0 +1,82 @@ +package ru.javawebinar.topjava.repository.jdbc; + +import org.springframework.beans.factory.annotation.Autowired; +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) { + return jdbcTemplate.queryForObject("SELECT * FROM users WHERE id=?", ROW_MAPPER, id); + } + + @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/db/postgres.properties b/src/main/resources/db/postgres.properties index e0d4ae2b15e1..a4669e9c8f96 100644 --- a/src/main/resources/db/postgres.properties +++ b/src/main/resources/db/postgres.properties @@ -2,6 +2,7 @@ #database.username=wegxlfzjjgxaxy #database.password=SSQyKKE_e93kiUCR-ehzMcKCxZ +database.driverClassName = com.mysql.jdbc.Driver database.url=jdbc:mysql://localhost:3306/topjava database.username=root database.password=venjdf diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml new file mode 100644 index 000000000000..d58f2b5459e2 --- /dev/null +++ b/src/main/resources/spring/spring-db.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 8dd5f65960b64a10fed155952798551bb86337ec Mon Sep 17 00:00:00 2001 From: AndrePro Date: Wed, 18 Jan 2017 01:52:30 +0300 Subject: [PATCH 45/72] test_userService --- .../javawebinar/topjava/model/BaseEntity.java | 2 + .../ru/javawebinar/topjava/model/User.java | 6 +- .../jdbc/JdbcUserMealRepositoryImpl.java | 42 ++++++++ .../jdbc/JdbcUserRepositoryImpl.java | 4 +- .../javawebinar/topjava/util/DbPopulator.java | 28 ++++++ src/main/resources/db/populateDB_mysql.sql | 3 + 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 | 66 ++++++++++++- .../topjava/matcher/ModelMatcher.java | 34 +++++++ .../topjava/service/UserServiceTest.java | 96 +++++++++++++++++++ 12 files changed, 294 insertions(+), 7 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 e8f1a2ce9223..40581879f82f 100644 --- a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java +++ b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java @@ -9,6 +9,8 @@ public class BaseEntity { protected static final LoggerWrapper LOG = LoggerWrapper.get(BaseEntity.class); + public static final int START_SEQ = 100000; + protected Integer id; public BaseEntity() { diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index c97b813cd42e..df24a0496f2b 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -10,7 +10,7 @@ */ public class User extends NamedEntity { - private static final int DEFAULT_CALORIES_PER_DAY = 2000; + protected static final int DEFAULT_CALORIES_PER_DAY = 2000; protected String email; @@ -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, 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/repository/jdbc/JdbcUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepositoryImpl.java index 221f966d08a9..5646bad071ed 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepositoryImpl.java @@ -1,6 +1,7 @@ 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; @@ -67,7 +68,8 @@ public boolean delete(int id) { @Override public User get(int id) { - return jdbcTemplate.queryForObject("SELECT * FROM users WHERE id=?", ROW_MAPPER, id); + List users = jdbcTemplate.query("SELECT * FROM users WHERE id=?", ROW_MAPPER, id); + return DataAccessUtils.singleResult(users); } @Override 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/db/populateDB_mysql.sql b/src/main/resources/db/populateDB_mysql.sql index 7f10e16cc2cb..79fbaccef692 100644 --- a/src/main/resources/db/populateDB_mysql.sql +++ b/src/main/resources/db/populateDB_mysql.sql @@ -1,3 +1,6 @@ +DELETE FROM user_roles; +DELETE FROM users; +ALTER TABLE users AUTO_INCREMENT = 100000; -- password INSERT INTO users (name, email, password) VALUES ('User', 'user@yandex.ru', 'password'); diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml index c285b264141d..756c97f42c35 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 d58f2b5459e2..93814d8157ed 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 55a2c85f4770..bdabcf52ac1a 100644 --- a/src/test/java/ru/javawebinar/topjava/UserTestData.java +++ b/src/test/java/ru/javawebinar/topjava/UserTestData.java @@ -1,16 +1,74 @@ package ru.javawebinar.topjava; +import ru.javawebinar.topjava.matcher.ModelMatcher; import ru.javawebinar.topjava.model.Role; import ru.javawebinar.topjava.model.User; +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, User.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; + } - public static final User USER = new User(1, "User", "user@yandex.ru", "password", Role.ROLE_USER); - public static final User ADMIN = new User(2, "Admin", "admin@gmail.com", "admin", Role.ROLE_ADMIN); + 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..45e43b2968aa --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java @@ -0,0 +1,96 @@ +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 ee4565a1feaf0c14b0c89662c30cf6c1b2b9644f Mon Sep 17 00:00:00 2001 From: AndrePro Date: Wed, 18 Jan 2017 23:12:33 +0300 Subject: [PATCH 46/72] fit to undergo test_userService --- src/main/java/ru/javawebinar/topjava/model/User.java | 5 ++++- src/main/resources/db/initDB_mysql.sql | 3 ++- src/test/java/ru/javawebinar/topjava/UserTestData.java | 1 - 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index df24a0496f2b..58bd1ccdfd42 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -84,6 +84,10 @@ public Set getRoles() { return roles; } + public void setRoles(Set roles) { + this.roles = roles; + } + public String getPassword() { return password; } @@ -95,7 +99,6 @@ public String toString() { ", email=" + email + ", name=" + name + ", enabled=" + enabled + - ", roles=" + roles + ", caloriesPerDay=" + caloriesPerDay + ')'; } diff --git a/src/main/resources/db/initDB_mysql.sql b/src/main/resources/db/initDB_mysql.sql index 1245f553e2e1..a436debeded8 100644 --- a/src/main/resources/db/initDB_mysql.sql +++ b/src/main/resources/db/initDB_mysql.sql @@ -5,7 +5,8 @@ CREATE TABLE users email VARCHAR(50) NOT NULL, password VARCHAR(50) NOT NULL, registered TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - calories_per_day INT DEFAULT '2000' + calories_per_day INT DEFAULT '2000', + enabled BOOL DEFAULT TRUE ); CREATE UNIQUE INDEX unique_email ON users (email); diff --git a/src/test/java/ru/javawebinar/topjava/UserTestData.java b/src/test/java/ru/javawebinar/topjava/UserTestData.java index bdabcf52ac1a..06c3df620c50 100644 --- a/src/test/java/ru/javawebinar/topjava/UserTestData.java +++ b/src/test/java/ru/javawebinar/topjava/UserTestData.java @@ -49,7 +49,6 @@ public String toString() { ", name=" + name + ", enabled=" + enabled + ", password=" + password + - ", authorities=" + roles + ')'; } From 9abdcef23d33e0f7e520c89a47ee3971da9eb14c Mon Sep 17 00:00:00 2001 From: AndrePro Date: Wed, 18 Jan 2017 23:36:10 +0300 Subject: [PATCH 47/72] add test-logging --- src/test/resources/logback-test.xml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/resources/logback-test.xml diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml new file mode 100644 index 000000000000..80c38026d409 --- /dev/null +++ b/src/test/resources/logback-test.xml @@ -0,0 +1,21 @@ + + + + true + + + + + UTF-8 + %-5level %logger{0} - %msg%n + + + + + + + + + + + \ No newline at end of file From 992f6be0cc09ffd127d6715a494b91c54619c132 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Wed, 18 Jan 2017 23:38:17 +0300 Subject: [PATCH 48/72] prepare to HW3 --- src/main/java/ru/javawebinar/topjava/web/MealServlet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java index 9e70adda130a..c146f9ad1757 100644 --- a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -31,7 +31,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); } From f53be4004e24032648928aa3ee48a40ca4823325 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Wed, 18 Jan 2017 23:57:09 +0300 Subject: [PATCH 49/72] prepare to HW3 --- src/main/java/ru/javawebinar/topjava/LoggedUser.java | 4 +++- src/main/webapp/index.html | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/LoggedUser.java b/src/main/java/ru/javawebinar/topjava/LoggedUser.java index b3aefb7b5031..b841a10772b7 100644 --- a/src/main/java/ru/javawebinar/topjava/LoggedUser.java +++ b/src/main/java/ru/javawebinar/topjava/LoggedUser.java @@ -1,11 +1,13 @@ package ru.javawebinar.topjava; +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/webapp/index.html b/src/main/webapp/index.html index baacc9e9d84d..3a36e8b392a9 100644 --- a/src/main/webapp/index.html +++ b/src/main/webapp/index.html @@ -9,8 +9,8 @@

Проект " Login as: From 5e07fc7a025964171c47af3a0c6517fa0ce472e2 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Thu, 19 Jan 2017 01:34:47 +0300 Subject: [PATCH 50/72] HW3 done --- .../javawebinar/topjava/model/UserMeal.java | 12 ++- .../jdbc/JdbcUserMealRepositoryImpl.java | 74 +++++++++++++-- src/main/resources/db/initDB.sql | 10 ++ src/main/resources/db/initDB_mysql.sql | 13 ++- src/main/resources/db/populateDB.sql | 16 +++- src/main/resources/db/populateDB_mysql.sql | 14 ++- .../ru/javawebinar/topjava/MealTestData.java | 29 ++++++ .../mock/InMemoryUserMealRepositoryImpl.java | 2 +- .../topjava/service/UserMealServiceTest.java | 92 +++++++++++++++++++ 9 files changed, 246 insertions(+), 16 deletions(-) create mode 100644 src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java index e1f99a737cf4..554dbfdac588 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java @@ -48,8 +48,16 @@ public Integer getId() { return id; } - public boolean isNew() { - return id == null; + 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 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..3125fd31f4b4 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.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.sql.Timestamp; import java.time.LocalDateTime; import java.util.List; @@ -15,28 +24,75 @@ @Repository public class JdbcUserMealRepositoryImpl implements UserMealRepository { + private static final RowMapper ROW_MAPPER = + (rs, rowNum) -> + new UserMeal(rs.getInt("id"), rs.getTimestamp("date_time").toLocalDateTime(), + rs.getString("description"), rs.getInt("calories")); + +/* private static RowMapper USER_ROW = new RowMapper(){ + @Override + public UserMeal mapRow(ResultSet rs, int rowNum) throws SQLException { + return null; + } + };*/ + + @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", Timestamp.valueOf(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, Timestamp.valueOf(startDate), Timestamp.valueOf(endDate)); } -} +} \ No newline at end of file diff --git a/src/main/resources/db/initDB.sql b/src/main/resources/db/initDB.sql index 620c77f27b0e..26f6ca2929d1 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,12 @@ 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, + description TEXT, + calories INT, + FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE +); diff --git a/src/main/resources/db/initDB_mysql.sql b/src/main/resources/db/initDB_mysql.sql index a436debeded8..b1013d9b14b5 100644 --- a/src/main/resources/db/initDB_mysql.sql +++ b/src/main/resources/db/initDB_mysql.sql @@ -18,4 +18,15 @@ CREATE TABLE user_roles user_id INTEGER NOT NULL, role VARCHAR(50), FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE -); \ No newline at end of file +); + +CREATE TABLE meals ( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + user_id INTEGER NOT NULL, + date_time TIMESTAMP, + description TEXT, + calories INT, + FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE +); + +ALTER TABLE meals AUTO_INCREMENT = 100000; \ No newline at end of file diff --git a/src/main/resources/db/populateDB.sql b/src/main/resources/db/populateDB.sql index d7439bba5994..a4db0daa2c84 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; @@ -9,5 +10,16 @@ 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); -INSERT INTO user_roles (role, user_id) VALUES ('ROLE_ADMIN', 100001); +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); diff --git a/src/main/resources/db/populateDB_mysql.sql b/src/main/resources/db/populateDB_mysql.sql index 79fbaccef692..38f623c60c01 100644 --- a/src/main/resources/db/populateDB_mysql.sql +++ b/src/main/resources/db/populateDB_mysql.sql @@ -1,6 +1,7 @@ DELETE FROM user_roles; DELETE FROM users; ALTER TABLE users AUTO_INCREMENT = 100000; +ALTER TABLE meals AUTO_INCREMENT = 100002; -- тк в исходном заполнении глобальный сиквенс SEQUENCE global_seq RESTART WITH 100000; -- password INSERT INTO users (name, email, password) VALUES ('User', 'user@yandex.ru', 'password'); @@ -9,4 +10,15 @@ INSERT INTO users (name, email, password) VALUES ('Admin', 'admin@gmail.com', 'admin'); INSERT INTO user_roles (role, user_id) VALUES ('ROLE_USER', 100000); -INSERT INTO user_roles (role, user_id) VALUES ('ROLE_ADMIN', 100001); \ No newline at end of file +INSERT INTO user_roles (role, user_id) VALUES ('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); \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/MealTestData.java b/src/test/java/ru/javawebinar/topjava/MealTestData.java index ac44047caa52..173673299f57 100644 --- a/src/test/java/ru/javawebinar/topjava/MealTestData.java +++ b/src/test/java/ru/javawebinar/topjava/MealTestData.java @@ -3,6 +3,14 @@ import ru.javawebinar.topjava.matcher.ModelMatcher; import ru.javawebinar.topjava.model.UserMeal; +import java.time.LocalDateTime; +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 +19,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, LocalDateTime.of(2015, Month.MAY, 30, 10, 0), "Завтрак", 500); + public static final UserMeal MEAL2 = new UserMeal(MEAL1_ID + 1, LocalDateTime.of(2015, Month.MAY, 30, 13, 0), "Обед", 1000); + public static final UserMeal MEAL3 = new UserMeal(MEAL1_ID + 2, LocalDateTime.of(2015, Month.MAY, 30, 20, 0), "Ужин", 500); + public static final UserMeal MEAL4 = new UserMeal(MEAL1_ID + 3, LocalDateTime.of(2015, Month.MAY, 31, 10, 0), "Завтрак", 500); + public static final UserMeal MEAL5 = new UserMeal(MEAL1_ID + 4, LocalDateTime.of(2015, Month.MAY, 31, 13, 0), "Обед", 1000); + public static final UserMeal MEAL6 = new UserMeal(MEAL1_ID + 5, LocalDateTime.of(2015, Month.MAY, 31, 20, 0), "Ужин", 510); + public static final UserMeal ADMIN_MEAL = new UserMeal(ADMIN_MEAL_ID, LocalDateTime.of(2015, Month.JUNE, 1, 14, 0), "Админ ланч", 510); + public static final UserMeal ADMIN_MEAL2 = new UserMeal(ADMIN_MEAL_ID + 1, LocalDateTime.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/repository/mock/InMemoryUserMealRepositoryImpl.java b/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java index ff71e1034b3c..73082554e58e 100644 --- a/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java +++ b/src/test/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepositoryImpl.java @@ -39,7 +39,7 @@ public class InMemoryUserMealRepositoryImpl implements UserMealRepository { save(new UserMeal(LocalDateTime.of(2015, Month.MAY, 31, 20, 0), "Ужин", 510), 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), "Админ ужин ", 510), ADMIN_ID); + save(new UserMeal(LocalDateTime.of(2015, Month.JUNE, 1, 21, 0), "Админ ужин", 1500), ADMIN_ID); } @Override 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 f2778785d2b983dce5b3b21bd035a01d6e4a9f52 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Thu, 19 Jan 2017 22:12:47 +0300 Subject: [PATCH 51/72] init db, applying sql-annotation --- .../javawebinar/topjava/util/DbPopulator.java | 28 ------------------- src/main/resources/db/postgres.properties | 1 + src/main/resources/spring/spring-db.xml | 12 ++++---- .../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 a4669e9c8f96..5adb874cba5f 100644 --- a/src/main/resources/db/postgres.properties +++ b/src/main/resources/db/postgres.properties @@ -6,3 +6,4 @@ database.driverClassName = com.mysql.jdbc.Driver database.url=jdbc:mysql://localhost:3306/topjava database.username=root database.password=venjdf +database.init=true diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index 93814d8157ed..0f0189f7d033 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -1,14 +1,16 @@ + 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: Thu, 19 Jan 2017 23:50:36 +0300 Subject: [PATCH 52/72] create mock test context(add mock.xml) --- src/test/java/ru/javawebinar/topjava/SpringMain.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/ru/javawebinar/topjava/SpringMain.java b/src/test/java/ru/javawebinar/topjava/SpringMain.java index 11ae192771d1..e1d2d2b6bd57 100644 --- a/src/test/java/ru/javawebinar/topjava/SpringMain.java +++ b/src/test/java/ru/javawebinar/topjava/SpringMain.java @@ -21,7 +21,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(new User(1, "userName", "email", "password", Role.ROLE_ADMIN))); From 21f90a43a091bc816a6fee79fb1dab177abf1f8b Mon Sep 17 00:00:00 2001 From: AndrePro Date: Thu, 19 Jan 2017 23:51:31 +0300 Subject: [PATCH 53/72] create mock test context(add mock.xml) --- .../jdbc/InMemoryUserRepositoryImpl.java | 63 +++++++++++++++++++ src/main/resources/spring/spring-app.xml | 2 - src/main/resources/spring/spring-db.xml | 2 + .../topjava/web/AdminInMemoryTest.java | 2 +- .../topjava/web/SpringAdminInMemoryTest.java | 2 +- src/test/resources/spring/mock.xml | 7 +++ 6 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/repository/jdbc/InMemoryUserRepositoryImpl.java create mode 100644 src/test/resources/spring/mock.xml diff --git a/src/main/java/ru/javawebinar/topjava/repository/jdbc/InMemoryUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/jdbc/InMemoryUserRepositoryImpl.java new file mode 100644 index 000000000000..9f257cefa9e3 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/jdbc/InMemoryUserRepositoryImpl.java @@ -0,0 +1,63 @@ +package ru.javawebinar.topjava.repository.jdbc; + +import org.springframework.stereotype.Repository; +import ru.javawebinar.topjava.LoggerWrapper; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.repository.UserRepository; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * GKislin + * 15.06.2015. + */ +@Repository +public class InMemoryUserRepositoryImpl implements UserRepository { + private static final LoggerWrapper LOG = LoggerWrapper.get(InMemoryUserRepositoryImpl.class); + + private Map repository = new ConcurrentHashMap<>(); + private AtomicInteger counter = new AtomicInteger(0); + + @PostConstruct + public void postConstruct() { + LOG.info("+++ PostConstruct"); + } + + @PreDestroy + public void preDestroy() { + LOG.info("+++ PreDestroy"); + } + + @Override + public User save(User user) { + if (user.isNew()) { + user.setId(counter.incrementAndGet()); + } + return repository.put(user.getId(), user); + } + + @Override + public boolean delete(int id) { + return repository.remove(id) != null; + } + + @Override + public User get(int id) { + return repository.get(id); + } + + @Override + public Collection getAll() { + return repository.values(); + } + + @Override + public User getByEmail(String email) { + return getAll().stream().filter(u -> u.getEmail().equals(email)).findFirst().orElse(null); + } +} diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml index 756c97f42c35..5ba07c0e0e8e 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 0f0189f7d033..2f95aa467225 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -6,6 +6,8 @@ + + 4.12 + + + 5.0.1.Final + 5.1.3.Final @@ -108,9 +112,19 @@ org.springframework - spring-jdbc + spring-orm ${spring.version} + + org.hibernate + hibernate-entitymanager + ${hibernate.version} + + + org.hibernate + hibernate-validator + ${hibernate-validator.version} + diff --git a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java index 40581879f82f..e5d8b6dd9971 100644 --- a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java +++ b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java @@ -2,15 +2,22 @@ import ru.javawebinar.topjava.LoggerWrapper; +import javax.persistence.*; + /** * User: gkislin * Date: 22.08.2014 */ +@MappedSuperclass +@Access(AccessType.FIELD) public class BaseEntity { protected static final LoggerWrapper LOG = LoggerWrapper.get(BaseEntity.class); 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 58bd1ccdfd42..a187a2ef0098 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -1,5 +1,11 @@ package ru.javawebinar.topjava.model; +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; @@ -8,20 +14,36 @@ * User: gkislin * Date: 22.08.2014 */ +@Entity +@Table(name = "users", uniqueConstraints = {@UniqueConstraint(columnNames = "email", name = "unique_email")}) public class User extends NamedEntity { protected static final int DEFAULT_CALORIES_PER_DAY = 2000; + @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 = "CURRENT_TIMESTAMP"/*"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 = 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 554dbfdac588..e4961b7251b2 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; /** @@ -14,6 +16,9 @@ public class UserMeal extends BaseEntity { protected int calories; + @ManyToOne(fetch = FetchType.LAZY) + 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 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 5adb874cba5f..091f59560568 100644 --- a/src/main/resources/db/postgres.properties +++ b/src/main/resources/db/postgres.properties @@ -7,3 +7,7 @@ database.url=jdbc:mysql://localhost:3306/topjava database.username=root database.password=venjdf 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 2f95aa467225..aea267a33299 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -1,14 +1,16 @@ - + - + - + + + + + + + + + + + + + + + + + + + \ No newline at end of file From c9485ce64807b07589629e11bfcf485a5f63c9ea Mon Sep 17 00:00:00 2001 From: AndrePro Date: Wed, 25 Jan 2017 22:49:03 +0300 Subject: [PATCH 56/72] jpa impl transaction --- .../javawebinar/topjava/model/BaseEntity.java | 2 +- .../ru/javawebinar/topjava/model/User.java | 9 +++++++ .../repository/jpa/JpaUserRepositoryImpl.java | 15 +++++++---- src/main/resources/spring/spring-db.xml | 27 ++++++++++++------- 4 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java index e5d8b6dd9971..b534e1e254ed 100644 --- a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java +++ b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java @@ -16,7 +16,7 @@ public class BaseEntity { public static final int START_SEQ = 100000; @Id - @SequenceGenerator(name = "global_seq", sequenceName = "global_seq", allocationSize = 1) + @SequenceGenerator(name = "global_seq", sequenceName = "sequence_data", allocationSize = 1) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "global_seq") protected Integer id; diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index a187a2ef0098..05d1af6d5e76 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -14,10 +14,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 = "unique_email")}) 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"; + protected static final int DEFAULT_CALORIES_PER_DAY = 2000; @Column(name = "email", nullable = false, unique = true) 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 aea267a33299..cbb3494cedd9 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -3,8 +3,9 @@ xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" + 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/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"> @@ -45,14 +46,20 @@ - + + + + \ No newline at end of file From df66a26a493029146a21d14daa8bc6b92ee92c3f Mon Sep 17 00:00:00 2001 From: AndrePro Date: Wed, 25 Jan 2017 23:50:59 +0300 Subject: [PATCH 57/72] hsqldb support --- pom.xml | 6 ++++ .../javawebinar/topjava/model/BaseEntity.java | 3 +- src/main/resources/db/hsqldb.properties | 13 +++++++ src/main/resources/db/initDB_hsql.sql | 36 +++++++++++++++++++ src/main/resources/db/postgres.properties | 1 + src/main/resources/spring/spring-db.xml | 12 ++++--- .../topjava/service/UserServiceTest.java | 3 +- 7 files changed, 67 insertions(+), 7 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 7024161802be..20325678922c 100644 --- a/pom.xml +++ b/pom.xml @@ -110,6 +110,12 @@ mysql-connector-java 5.1.35 + + org.hsqldb + hsqldb + 2.3.2 + + org.springframework spring-orm diff --git a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java index b534e1e254ed..3d9a785c2bb0 100644 --- a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java +++ b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java @@ -16,7 +16,8 @@ public class BaseEntity { public static final int START_SEQ = 100000; @Id - @SequenceGenerator(name = "global_seq", sequenceName = "sequence_data", allocationSize = 1) + @SequenceGenerator(name = "global_seq", sequenceName = "global_seq", allocationSize = 1) + /*@SequenceGenerator(name = "global_seq", sequenceName = "sequence_data", allocationSize = 1)*/ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "global_seq") protected Integer id; diff --git a/src/main/resources/db/hsqldb.properties b/src/main/resources/db/hsqldb.properties new file mode 100644 index 000000000000..33fc2abe454c --- /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 diff --git a/src/main/resources/db/initDB_hsql.sql b/src/main/resources/db/initDB_hsql.sql new file mode 100644 index 000000000000..274115ff7027 --- /dev/null +++ b/src/main/resources/db/initDB_hsql.sql @@ -0,0 +1,36 @@ +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 user_email_key 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 +); diff --git a/src/main/resources/db/postgres.properties b/src/main/resources/db/postgres.properties index 091f59560568..11ecbe7e8006 100644 --- a/src/main/resources/db/postgres.properties +++ b/src/main/resources/db/postgres.properties @@ -8,6 +8,7 @@ database.username=root database.password=venjdf database.init=true +jdbc.initLocation=initDB_mysql.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 cbb3494cedd9..72a5d6bda860 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -7,15 +7,17 @@ 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"> - + + + - + + + + Date: Thu, 26 Jan 2017 22:44:14 +0300 Subject: [PATCH 58/72] HW5 is done --- pom.xml | 7 +++- .../javawebinar/topjava/model/UserMeal.java | 37 +++++++++++++++- .../jpa/JpaUserMealRepositoryImpl.java | 42 ++++++++++++++++--- 3 files changed, 78 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 20325678922c..c7a779b67d52 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ 4.12 - 5.0.1.Final + 5.0.2.Final 5.1.3.Final @@ -126,6 +126,11 @@ hibernate-entitymanager ${hibernate.version} + + org.hibernate + hibernate-java8 + ${hibernate.version} + org.hibernate hibernate-validator diff --git a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java index e4961b7251b2..ed1208c73afb 100644 --- a/src/main/java/ru/javawebinar/topjava/model/UserMeal.java +++ b/src/main/java/ru/javawebinar/topjava/model/UserMeal.java @@ -1,22 +1,47 @@ package ru.javawebinar.topjava.model; -import javax.persistence.FetchType; -import javax.persistence.ManyToOne; +import org.hibernate.validator.constraints.NotEmpty; + +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") 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 protected LocalDateTime dateTime; + @Column(name = "description", nullable = false) + @NotEmpty protected String description; + @Column(name = "calories") protected int calories; @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id", nullable = false) private User user; public UserMeal() { @@ -65,6 +90,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 index 647a24eef180..b8411e48843b 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; + User ref = em.getReference(User.class, userId); + userMeal.setUser(ref); + + if (userMeal.isNew()) { + em.persist(userMeal); + return userMeal; + } else { + if (get(userMeal.getId(), userId) == null) return null; + 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 From 710e938a7ba9e3328d7af74f5d4689bf4d6858f5 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Thu, 26 Jan 2017 23:22:06 +0300 Subject: [PATCH 59/72] HW5 optional is done --- .../topjava/service/UserMealServiceTest.java | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java index 500485f12ee5..7e410033c1a8 100644 --- a/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java @@ -1,12 +1,17 @@ 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.springframework.beans.factory.annotation.Autowired; 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.LoggerWrapper; import ru.javawebinar.topjava.MealTestData; import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.util.exception.NotFoundException; @@ -14,6 +19,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; @@ -24,9 +30,28 @@ "classpath:spring/spring-db.xml" }) @RunWith(SpringJUnit4ClassRunner.class) -@Sql(scripts = "classpath:db/populateDB_mysql.sql", config = @SqlConfig(encoding = "UTF-8")) +@Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8")) /*classpath:db/populateDB_mysql.sql*/ public class UserMealServiceTest { + private static final LoggerWrapper LOG = LoggerWrapper.get(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 microseconds", + description.getMethodName(), TimeUnit.NANOSECONDS.toMicros(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 d80be7f13cccee4c46842b571e41feb606c3ffed Mon Sep 17 00:00:00 2001 From: AndrePro Date: Thu, 26 Jan 2017 23:39:29 +0300 Subject: [PATCH 60/72] add propogation(for trying it) --- .../topjava/repository/jpa/JpaUserMealRepositoryImpl.java | 3 ++- .../topjava/repository/jpa/JpaUserRepositoryImpl.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) 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 b8411e48843b..e6d033defd43 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserMealRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserMealRepositoryImpl.java @@ -2,6 +2,7 @@ import org.springframework.dao.support.DataAccessUtils; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.model.UserMeal; @@ -18,7 +19,7 @@ */ @Repository -@Transactional(readOnly = true) +@Transactional(readOnly = true, propagation = Propagation.SUPPORTS) public class JpaUserMealRepositoryImpl implements UserMealRepository { @PersistenceContext 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..9630539b0114 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepositoryImpl.java @@ -1,6 +1,7 @@ package ru.javawebinar.topjava.repository.jpa; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.repository.UserRepository; @@ -14,7 +15,7 @@ * Date: 29.08.2014 */ @Repository -@Transactional(readOnly = true) +@Transactional(readOnly = true, propagation = Propagation.SUPPORTS) public class JpaUserRepositoryImpl implements UserRepository { /* From a395057ca7a57f7f480c18a9b46dd1563e8b34f1 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Mon, 30 Jan 2017 00:38:31 +0300 Subject: [PATCH 61/72] profiles connection pool --- pom.xml | 41 +++++++++++++------ .../java/ru/javawebinar/topjava/Profiles.java | 13 ++++++ src/main/resources/db/initDB_mysql.sql | 4 ++ src/main/resources/db/populateDB_mysql.sql | 1 + src/main/resources/spring/spring-db.xml | 38 +++++++++++------ .../topjava/service/UserMealServiceTest.java | 7 ++-- .../topjava/service/UserServiceTest.java | 7 +++- 7 files changed, 82 insertions(+), 29 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/Profiles.java diff --git a/pom.xml b/pom.xml index c7a779b67d52..5db7bfc9691d 100644 --- a/pom.xml +++ b/pom.xml @@ -13,6 +13,7 @@ 1.8 + 7.0.57 UTF-8 UTF-8 @@ -104,18 +105,6 @@ - - - mysql - mysql-connector-java - 5.1.35 - - - org.hsqldb - hsqldb - 2.3.2 - - org.springframework spring-orm @@ -154,6 +143,34 @@ + + hsqldb + + + org.hsqldb + hsqldb + 2.3.2 + + + + + postgres + + + mysql + mysql-connector-java + 5.1.35 + + + 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..23e905ed9c20 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/Profiles.java @@ -0,0 +1,13 @@ +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"; +} diff --git a/src/main/resources/db/initDB_mysql.sql b/src/main/resources/db/initDB_mysql.sql index b1013d9b14b5..01d16cbe986d 100644 --- a/src/main/resources/db/initDB_mysql.sql +++ b/src/main/resources/db/initDB_mysql.sql @@ -1,3 +1,7 @@ +DROP TABLE IF EXISTS user_roles; +DROP TABLE IF EXISTS meals; +DROP TABLE IF EXISTS users; + CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, diff --git a/src/main/resources/db/populateDB_mysql.sql b/src/main/resources/db/populateDB_mysql.sql index 38f623c60c01..5b4484f22756 100644 --- a/src/main/resources/db/populateDB_mysql.sql +++ b/src/main/resources/db/populateDB_mysql.sql @@ -1,4 +1,5 @@ DELETE FROM user_roles; +DELETE FROM meals; DELETE FROM users; ALTER TABLE users AUTO_INCREMENT = 100000; ALTER TABLE meals AUTO_INCREMENT = 100002; -- тк в исходном заполнении глобальный сиквенс SEQUENCE global_seq RESTART WITH 100000; diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index 72a5d6bda860..5d30047669f3 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -7,8 +7,8 @@ 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"> - - + + @@ -16,18 +16,9 @@ - + - - - - - - - - @@ -64,4 +55,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 7e410033c1a8..9f4df4906622 100644 --- a/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java @@ -7,9 +7,8 @@ import org.junit.runner.Description; 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.jdbc.Sql; -import org.springframework.test.context.jdbc.SqlConfig; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import ru.javawebinar.topjava.LoggerWrapper; import ru.javawebinar.topjava.MealTestData; @@ -22,6 +21,7 @@ import java.util.concurrent.TimeUnit; import static ru.javawebinar.topjava.MealTestData.*; +import static ru.javawebinar.topjava.Profiles.POSTGRES; import static ru.javawebinar.topjava.UserTestData.ADMIN_ID; import static ru.javawebinar.topjava.UserTestData.USER_ID; @@ -30,7 +30,8 @@ "classpath:spring/spring-db.xml" }) @RunWith(SpringJUnit4ClassRunner.class) -@Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8")) /*classpath:db/populateDB_mysql.sql*/ +//@Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8")) /*classpath:db/populateDB_mysql.sql*/ +@ActiveProfiles(POSTGRES /*HSQLDB*/) public class UserMealServiceTest { private static final LoggerWrapper LOG = LoggerWrapper.get(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 f289049f80cb..ba5084470226 100644 --- a/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java @@ -4,6 +4,7 @@ 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; @@ -17,6 +18,7 @@ import java.util.Collection; import java.util.Collections; +import static ru.javawebinar.topjava.Profiles.POSTGRES; import static ru.javawebinar.topjava.UserTestData.*; @ContextConfiguration({ @@ -24,8 +26,9 @@ "classpath:spring/spring-db.xml" }) @RunWith(SpringJUnit4ClassRunner.class) -@Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8")) -/*@Sql(scripts = "classpath:db/populateDB_mysql.sql", config = @SqlConfig(encoding = "UTF-8"))*/ +//@Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8")) +@ActiveProfiles(POSTGRES/*HSQLDB*/) +@Sql(scripts = "classpath:db/populateDB_mysql.sql", config = @SqlConfig(encoding = "UTF-8")) public class UserServiceTest { @Autowired From 4be3ba4170e9266c35c19d3c501ccbf0bf1b3de7 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Mon, 30 Jan 2017 23:12:31 +0300 Subject: [PATCH 62/72] spring datajpa --- pom.xml | 16 +++++-- .../DataJpaUserMealRepositoryImpl.java | 40 ++++++++++++++++ .../datajpa/DataJpaUserRepositoryImpl.java | 47 +++++++++++++++++++ .../datajpa/ProxyUserRepository.java | 37 +++++++++++++++ src/main/resources/spring/spring-db.xml | 14 +++++- 5 files changed, 149 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 5db7bfc9691d..d30e7b14186f 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,7 @@ UTF-8 UTF-8 + 1.9.0.RELEASE 4.2.1.RELEASE @@ -106,9 +107,9 @@ - org.springframework - spring-orm - ${spring.version} + org.springframework.data + spring-data-jpa + ${spring-data-jpa.version} org.hibernate @@ -174,5 +175,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 5d30047669f3..bb8066207aa3 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -4,14 +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/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"> - + + + @@ -78,4 +81,11 @@ p:username="${database.username}" p:password="${database.password}"/> + + + + + + + \ No newline at end of file From 0b7a7192181f328379fe48fb8d422a488a3acf82 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Mon, 30 Jan 2017 23:32:23 +0300 Subject: [PATCH 63/72] spring cache --- pom.xml | 11 +- .../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, 503 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 d30e7b14186f..341b27813288 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,8 @@ 5.0.2.Final 5.1.3.Final + + 2.10.0 @@ -96,7 +98,7 @@ org.springframework - spring-context + spring-context-support ${spring.version} @@ -127,6 +129,13 @@ ${hibernate-validator.version} + + + net.sf.ehcache + ehcache + ${ehcache.version} + + junit diff --git a/src/main/java/ru/javawebinar/topjava/service/UserService.java b/src/main/java/ru/javawebinar/topjava/service/UserService.java index 8b0c6c7263fc..ba4e110d0007 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 { Collection getAll(); void update(User user) throws NotFoundException; + + 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 50d2c55cf19d..70db824e07d3 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.Collection; +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.check(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.check(repository.getByEmail(email), "email=" + email); } + @Cacheable("users") public Collection 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 5ba07c0e0e8e..995ebf9a02b5 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 ba5084470226..ba9491650da7 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; @@ -34,6 +35,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 8dbb8fd63e5cd58efb85c084714673ccd56c7136 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Tue, 31 Jan 2017 23:18:23 +0300 Subject: [PATCH 64/72] HW5 done --- .../java/ru/javawebinar/topjava/Profiles.java | 3 +- .../DataJpaUserMealRepositoryImpl.java | 25 ++++-- .../datajpa/ProxyUserMealRepository.java | 37 ++++++++ src/main/resources/spring/spring-db.xml | 86 +++++++++---------- .../topjava/service/AbstractServiceTest.java | 29 +++++++ ....java => AbstractUserMealServiceTest.java} | 17 +--- ...Test.java => AbstractUserServiceTest.java} | 19 +--- .../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 +++ src/test/resources/logback-test.xml | 3 + 14 files changed, 195 insertions(+), 84 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java create mode 100644 src/test/java/ru/javawebinar/topjava/service/AbstractServiceTest.java rename src/test/java/ru/javawebinar/topjava/service/{UserMealServiceTest.java => AbstractUserMealServiceTest.java} (82%) rename src/test/java/ru/javawebinar/topjava/service/{UserServiceTest.java => AbstractUserServiceTest.java} (76%) 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/main/java/ru/javawebinar/topjava/Profiles.java b/src/main/java/ru/javawebinar/topjava/Profiles.java index 23e905ed9c20..a3f5266a97ec 100644 --- a/src/main/java/ru/javawebinar/topjava/Profiles.java +++ b/src/main/java/ru/javawebinar/topjava/Profiles.java @@ -9,5 +9,6 @@ public class Profiles { POSTGRES = "postgres", HSQLDB = "hsqldb", JDBC = "jdbc", - JPA = "jpa"; + JPA = "jpa", + DATAJPA = "datajpa"; } 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..989522f560d6 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java @@ -0,0 +1,37 @@ +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); + + @Modifying + @Transactional + @Query("DELETE FROM UserMeal m WHERE m.user.id=:userId") + void deleteAll(@Param("userId") int userId); + + @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/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index bb8066207aa3..fab9f56fac37 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -8,57 +8,12 @@ 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"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -83,9 +38,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file 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..7c63ed46f28f --- /dev/null +++ b/src/test/java/ru/javawebinar/topjava/service/AbstractServiceTest.java @@ -0,0 +1,29 @@ +package ru.javawebinar.topjava.service; + +import org.junit.Rule; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +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 static ru.javawebinar.topjava.Profiles.POSTGRES; + +/** + * User: gkislin + * Date: 10.08.2014 + */ +@ContextConfiguration({ + "classpath:spring/spring-app.xml", + "classpath:spring/spring-db.xml" +}) +@RunWith(SpringJUnit4ClassRunner.class) +@ActiveProfiles({POSTGRES}) +@Sql(scripts = "classpath:db/populateDB_mysql.sql", config = @SqlConfig(encoding = "UTF-8")) +abstract public class AbstractServiceTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); +} diff --git a/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractUserMealServiceTest.java similarity index 82% rename from src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java rename to src/test/java/ru/javawebinar/topjava/service/AbstractUserMealServiceTest.java index 9f4df4906622..c52e5a51a5be 100644 --- a/src/test/java/ru/javawebinar/topjava/service/UserMealServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/AbstractUserMealServiceTest.java @@ -5,11 +5,7 @@ import org.junit.rules.ExpectedException; import org.junit.rules.Stopwatch; import org.junit.runner.Description; -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 ru.javawebinar.topjava.LoggerWrapper; import ru.javawebinar.topjava.MealTestData; import ru.javawebinar.topjava.model.UserMeal; @@ -21,20 +17,11 @@ import java.util.concurrent.TimeUnit; import static ru.javawebinar.topjava.MealTestData.*; -import static ru.javawebinar.topjava.Profiles.POSTGRES; 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")) /*classpath:db/populateDB_mysql.sql*/ -@ActiveProfiles(POSTGRES /*HSQLDB*/) -public class UserMealServiceTest { - - private static final LoggerWrapper LOG = LoggerWrapper.get(UserMealServiceTest.class); +abstract public class AbstractUserMealServiceTest extends AbstractServiceTest { + private static final LoggerWrapper LOG = LoggerWrapper.get(AbstractUserMealServiceTest.class); @Rule public ExpectedException thrown = ExpectedException.none(); diff --git a/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java similarity index 76% rename from src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java rename to src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java index ba9491650da7..74bccf3707b1 100644 --- a/src/test/java/ru/javawebinar/topjava/service/UserServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java @@ -2,14 +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.UserTestData.*; import ru.javawebinar.topjava.model.Role; import ru.javawebinar.topjava.model.User; @@ -19,18 +13,9 @@ import java.util.Collection; import java.util.Collections; -import static ru.javawebinar.topjava.Profiles.POSTGRES; 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(POSTGRES/*HSQLDB*/) -@Sql(scripts = "classpath:db/populateDB_mysql.sql", config = @SqlConfig(encoding = "UTF-8")) -public class UserServiceTest { +abstract public class AbstractUserServiceTest extends AbstractServiceTest { @Autowired protected UserService service; @@ -39,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..e72c2a7a4f0a --- /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..bbe1605b3aee --- /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..63227052ee17 --- /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..3088279e7736 --- /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..9175b47fed4b --- /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..8bcb8ffd0e6e --- /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 diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 80c38026d409..ac23a3f955ba 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -11,6 +11,9 @@ + + + From 1c6928e960b4477add914b299870f98408af31c8 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Tue, 31 Jan 2017 23:19:04 +0300 Subject: [PATCH 65/72] HW5 optional done --- .../java/ru/javawebinar/topjava/web/MealServlet.java | 9 ++++++--- src/test/java/ru/javawebinar/topjava/SpringMain.java | 9 ++++++--- src/test/resources/logback-test.xml | 3 +++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java index c146f9ad1757..9cbd11615abd 100644 --- a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -1,8 +1,8 @@ package ru.javawebinar.topjava.web; -import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import ru.javawebinar.topjava.LoggerWrapper; +import ru.javawebinar.topjava.Profiles; import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.util.TimeUtil; import ru.javawebinar.topjava.web.meal.UserMealRestController; @@ -25,13 +25,16 @@ public class MealServlet extends HttpServlet { private static final LoggerWrapper LOG = LoggerWrapper.get(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(); + springContext.getEnvironment().setActiveProfiles(Profiles.POSTGRES, Profiles.DATAJPA); + 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 f14692b18323..7f6917c78952 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.model.Role; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.to.UserMealWithExceed; @@ -21,7 +20,11 @@ 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.POSTGRES, Profiles.DATAJPA); + 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(new User(1, "userName", "email", "password", Role.ROLE_ADMIN))); diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index ac23a3f955ba..e9a3650502c1 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -14,6 +14,9 @@ + + + From 6cd734681ba4234ff71fe8678fd0f654924b9a96 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Wed, 1 Feb 2017 23:01:23 +0300 Subject: [PATCH 66/72] HW5 optional fetch --- src/main/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 +++++ .../repository/datajpa/ProxyUserMealRepository.java | 3 +++ .../repository/datajpa/ProxyUserRepository.java | 3 +++ .../javawebinar/topjava/service/UserMealService.java | 2 ++ .../topjava/service/UserMealServiceImpl.java | 12 ++++++++++++ .../ru/javawebinar/topjava/service/UserService.java | 4 +++- .../javawebinar/topjava/service/UserServiceImpl.java | 5 +++++ .../service/datajpa/DataJpaUserMealServiceTest.java | 11 +++++++++++ .../service/datajpa/DataJpaUserServiceTest.java | 10 ++++++++++ 13 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index 05d1af6d5e76..912b5b6b3139 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -8,6 +8,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 = DEFAULT_CALORIES_PER_DAY; + @OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY, mappedBy = "user") + @OrderBy("dateTime DESC") + protected List meals; + public User() { } @@ -123,6 +128,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 646b908602a4..afe485740dbe 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 DATE, TIME 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 fe65d1abdd97..cd331a2cea07 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); Collection 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 139946a33baa..422478684ec4 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepositoryImpl.java @@ -44,4 +44,9 @@ public User getByEmail(String email) { public List getAll() { return proxy.findAll(SORT_NAME_EMAIL); } + + @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 989522f560d6..2e13b933050c 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserMealRepository.java @@ -34,4 +34,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 ORDER BY um.dateTime DESC") + 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 092d847f2bb0..618f05eceaa7 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/ProxyUserRepository.java @@ -34,4 +34,7 @@ public interface ProxyUserRepository extends JpaRepository { List findAll(Sort sort); User getByEmail(String email); + + @Query("SELECT u FROM User u JOIN FETCH u.meals WHERE u.id = ?1") + User getWithMeals(Integer id); } diff --git a/src/main/java/ru/javawebinar/topjava/service/UserMealService.java b/src/main/java/ru/javawebinar/topjava/service/UserMealService.java index 50e9d4aaf7d1..2af9320798c3 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserMealService.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserMealService.java @@ -27,4 +27,6 @@ default Collection getBetweenDates(LocalDate startDate, LocalDate endD UserMeal update(UserMeal meal, int userId); 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 fe2aa873de5c..4f05d0b7eb5a 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java @@ -2,6 +2,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.repository.UserMealRepository; import ru.javawebinar.topjava.util.exception.ExceptionUtil; @@ -48,4 +49,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 repository.getWithUser(id, userId); + } } diff --git a/src/main/java/ru/javawebinar/topjava/service/UserService.java b/src/main/java/ru/javawebinar/topjava/service/UserService.java index ba4e110d0007..bed78aab5061 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 { Collection getAll(); void update(User user) throws NotFoundException; - + 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 70db824e07d3..e62c7f474146 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 repository.getWithMeals(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 e72c2a7a4f0a..c21c2ff095a9 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,21 @@ 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 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()); + } } \ 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 bbe1605b3aee..87927f8b2447 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,20 @@ package ru.javawebinar.topjava.service.datajpa; +import org.junit.Test; import org.springframework.test.context.ActiveProfiles; +import ru.javawebinar.topjava.MealTestData; +import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.service.AbstractUserServiceTest; import static ru.javawebinar.topjava.Profiles.DATAJPA; +import static ru.javawebinar.topjava.UserTestData.*; @ActiveProfiles({DATAJPA}) public class DataJpaUserServiceTest extends AbstractUserServiceTest { + @Test + public void testGetWithUser() throws Exception { + User user = service.getWithMeals(USER_ID); + MATCHER.assertEquals(USER, user); + MealTestData.MATCHER.assertCollectionEquals(MealTestData.USER_MEALS, user.getMeals()); + } } \ No newline at end of file From 0ebff58d8e6d4465f1aa9ded1608a450346b22fd Mon Sep 17 00:00:00 2001 From: AndrePro Date: Wed, 1 Feb 2017 23:31:49 +0300 Subject: [PATCH 67/72] hibernate cash(6_4) --- 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 341b27813288..7f7dc8ec8ec7 100644 --- a/pom.xml +++ b/pom.xml @@ -128,6 +128,11 @@ hibernate-validator ${hibernate-validator.version} + + org.hibernate + hibernate-ehcache + ${hibernate.version} + diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index 912b5b6b3139..0442a1dab76b 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -1,5 +1,7 @@ package ru.javawebinar.topjava.model; +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; @@ -20,6 +22,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 = "unique_email")}) 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.EAGER) + @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 fab9f56fac37..da21de34f1cb 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -59,6 +59,12 @@ + + + + + + @@ -74,6 +80,8 @@ + + diff --git a/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java index 74bccf3707b1..649f58c964f4 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 a069b5b7a1048ef0f860dd2810dda113d177ba80 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Thu, 2 Feb 2017 22:52:34 +0300 Subject: [PATCH 68/72] spring_web_6_5 --- pom.xml | 18 +++++++++++++++--- .../javawebinar/topjava/web/MealServlet.java | 16 +++------------- src/main/webapp/WEB-INF/web.xml | 16 ++++++++++++++++ 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/pom.xml b/pom.xml index 7f7dc8ec8ec7..32f7101160c2 100644 --- a/pom.xml +++ b/pom.xml @@ -83,12 +83,24 @@ - 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 + + + + javax.servlet jstl diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java index 9cbd11615abd..f16506d04393 100644 --- a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -1,8 +1,8 @@ package ru.javawebinar.topjava.web; -import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; import ru.javawebinar.topjava.LoggerWrapper; -import ru.javawebinar.topjava.Profiles; import ru.javawebinar.topjava.model.UserMeal; import ru.javawebinar.topjava.util.TimeUtil; import ru.javawebinar.topjava.web.meal.UserMealRestController; @@ -25,25 +25,15 @@ public class MealServlet extends HttpServlet { private static final LoggerWrapper LOG = LoggerWrapper.get(MealServlet.class); - private ClassPathXmlApplicationContext springContext; private UserMealRestController mealController; @Override public void init(ServletConfig config) throws ServletException { super.init(config); - springContext = new ClassPathXmlApplicationContext(); - springContext.getEnvironment().setActiveProfiles(Profiles.POSTGRES, Profiles.DATAJPA); - 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 javax.servlet.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..204a79700e0e 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,jpa + + + + contextConfigLocation + + classpath:spring/spring-app.xml + classpath:spring/spring-db.xml + + + + + org.springframework.web.context.ContextLoaderListener + userServlet ru.javawebinar.topjava.web.UserServlet From 78336bbc4829800fd9e38f606b3d9f0846dddcff Mon Sep 17 00:00:00 2001 From: AndrePro Date: Thu, 2 Feb 2017 23:58:57 +0300 Subject: [PATCH 69/72] jsp_jstl_i18_6_6 --- .../javawebinar/topjava/web/UserServlet.java | 21 ++++++++-- src/main/resources/messages/app.properties | 2 + src/main/resources/messages/app_ru.properties | 2 + src/main/resources/spring/spring-app.xml | 1 + src/main/resources/spring/spring-db.xml | 1 - src/main/webapp/css/style.css | 8 ++++ src/main/webapp/fragments/bodyHeader.jsp | 5 +++ src/main/webapp/fragments/footer.jsp | 4 ++ src/main/webapp/fragments/headTag.jsp | 10 +++++ src/main/webapp/index.html | 22 ----------- src/main/webapp/index.jsp | 28 +++++++++++++ src/main/webapp/mealList.jsp | 2 +- src/main/webapp/userList.jsp | 39 ++++++++++++++++--- .../topjava/service/AbstractServiceTest.java | 4 +- 14 files changed, 114 insertions(+), 35 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 40adae5b88cc..1e90d2c60d11 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.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; import ru.javawebinar.topjava.LoggedUser; import ru.javawebinar.topjava.LoggerWrapper; +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; @@ -16,6 +20,15 @@ public class UserServlet extends HttpServlet { private static final LoggerWrapper LOG = LoggerWrapper.get(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")); LoggedUser.setId(userId); @@ -23,9 +36,9 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) } 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"); + 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..d2c2c0fc7017 --- /dev/null +++ b/src/main/resources/messages/app.properties @@ -0,0 +1,2 @@ +app.title=Calories management +app.footer=Webinar Maven/ Spring/ Security/ JPA(Hibernate)/ Jackson/jQuery application diff --git a/src/main/resources/messages/app_ru.properties b/src/main/resources/messages/app_ru.properties new file mode 100644 index 000000000000..424c586d9067 --- /dev/null +++ b/src/main/resources/messages/app_ru.properties @@ -0,0 +1,2 @@ +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 \u0432\u0435\u0431\u0438\u043D\u0430\u0440\u0443 Maven/ Spring/ Security/ JPA(Hibernate)/ Jackson/jQuery diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml index 995ebf9a02b5..8eace62bb9c1 100644 --- a/src/main/resources/spring/spring-app.xml +++ b/src/main/resources/spring/spring-app.xml @@ -13,6 +13,7 @@ --> + diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index da21de34f1cb..7a43f4127372 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -80,7 +80,6 @@ - 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..ad383f16f619 --- /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" %> + + +
diff --git a/src/main/webapp/fragments/footer.jsp b/src/main/webapp/fragments/footer.jsp new file mode 100644 index 000000000000..a5c6ce4fcfb8 --- /dev/null +++ b/src/main/webapp/fragments/footer.jsp @@ -0,0 +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/fragments/headTag.jsp b/src/main/webapp/fragments/headTag.jsp new file mode 100644 index 000000000000..0238860698d7 --- /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"/> + + diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html deleted file mode 100644 index 3a36e8b392a9..000000000000 --- a/src/main/webapp/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - Top Java. - - -

Проект "Top Java."

-
-
- Login as: - - - - - diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp new file mode 100644 index 000000000000..dc764ba0cf03 --- /dev/null +++ b/src/main/webapp/index.jsp @@ -0,0 +1,28 @@ +<%@ 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: + + + +
+
+ + + diff --git a/src/main/webapp/mealList.jsp b/src/main/webapp/mealList.jsp index b16fa905434a..d1ecf39ca7c1 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 eae4726d4400..eaca9fed9caf 100644 --- a/src/main/webapp/userList.jsp +++ b/src/main/webapp/userList.jsp @@ -1,10 +1,39 @@ <%@ 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()%> +
+
+
+ diff --git a/src/test/java/ru/javawebinar/topjava/service/AbstractServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractServiceTest.java index 7c63ed46f28f..cac05ff91245 100644 --- a/src/test/java/ru/javawebinar/topjava/service/AbstractServiceTest.java +++ b/src/test/java/ru/javawebinar/topjava/service/AbstractServiceTest.java @@ -16,8 +16,8 @@ * Date: 10.08.2014 */ @ContextConfiguration({ - "classpath:spring/spring-app.xml", - "classpath:spring/spring-db.xml" + "classpath:spring/spring-db.xml", + "classpath:spring/spring-app.xml" }) @RunWith(SpringJUnit4ClassRunner.class) @ActiveProfiles({POSTGRES}) From d4d35bd288a511561b8e26c35e95c9303632d494 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Tue, 7 Feb 2017 23:03:14 +0300 Subject: [PATCH 70/72] tomcat_pool_jndi_6_7 --- pom.xml | 26 ++++++++++++- src/main/resources/db/hsqldb.properties | 1 - src/main/resources/db/tomcat.properties | 7 ++++ src/main/resources/spring/spring-db.xml | 19 +++++++--- src/main/resources/tomcat/context.xml | 49 +++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 7 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 32f7101160c2..ffd26612d3da 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,8 @@ 1.9.0.RELEASE 4.2.1.RELEASE + 5.1.35 + 1.1.2 1.7.7 @@ -48,6 +50,28 @@ ${java.version} + + + org.apache.tomcat.maven + tomcat7-maven-plugin + 2.2 + + src/main/resources/tomcat/context.xml + + UTF-8 + tomcat,jpa + + org.apache.coyote.http11.Http11NioProtocol + + + + mysql + mysql-connector-java + ${mysql.version} + + + + @@ -186,7 +210,7 @@ mysql mysql-connector-java - 5.1.35 + ${mysql.version} org.apache.tomcat diff --git a/src/main/resources/db/hsqldb.properties b/src/main/resources/db/hsqldb.properties index 33fc2abe454c..87e96e0986bd 100644 --- a/src/main/resources/db/hsqldb.properties +++ b/src/main/resources/db/hsqldb.properties @@ -3,7 +3,6 @@ database.url=jdbc:hsqldb:file:D:/temp/topjava database.username=sa database.password= -database.driverClassName=org.hsqldb.jdbcDriver 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..f84fd2bb0c9e --- /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 diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml index 7a43f4127372..2de6b560c51e 100644 --- a/src/main/resources/spring/spring-db.xml +++ b/src/main/resources/spring/spring-db.xml @@ -4,9 +4,13 @@ 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/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> + 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/jee http://www.springframework.org/schema/jee/spring-jee.xsd"> @@ -20,7 +24,7 @@ @@ -31,12 +35,17 @@ + + + + + diff --git a/src/main/resources/tomcat/context.xml b/src/main/resources/tomcat/context.xml new file mode 100644 index 000000000000..829b1189e5db --- /dev/null +++ b/src/main/resources/tomcat/context.xml @@ -0,0 +1,49 @@ + + + + + + + + WEB-INF/web.xml + ${catalina.base}/conf/web.xml + + + + + + + + + From 50737a80c3c09fd3c096b10465d1df65db018db1 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Wed, 8 Feb 2017 22:55:02 +0300 Subject: [PATCH 71/72] spring_webmvc_6_8 --- 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 | 0 .../{ => WEB-INF/jsp}/fragments/footer.jsp | 0 .../{ => WEB-INF/jsp}/fragments/headTag.jsp | 2 +- src/main/webapp/{ => WEB-INF/jsp}/index.jsp | 0 .../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, 78 insertions(+), 7 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 (100%) rename src/main/webapp/{ => WEB-INF/jsp}/fragments/footer.jsp (100%) rename src/main/webapp/{ => WEB-INF/jsp}/fragments/headTag.jsp (85%) rename src/main/webapp/{ => WEB-INF/jsp}/index.jsp (100%) 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 ffd26612d3da..d1db7b211fee 100644 --- a/pom.xml +++ b/pom.xml @@ -115,7 +115,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..2134910b0078 --- /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.LoggedUser; +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")); + LoggedUser.setId(userId); + return "redirect:meals"; + } +} diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml index 8eace62bb9c1..e7829802bb22 100644 --- a/src/main/resources/spring/spring-app.xml +++ b/src/main/resources/spring/spring-app.xml @@ -17,7 +17,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 100% rename from src/main/webapp/fragments/bodyHeader.jsp rename to src/main/webapp/WEB-INF/jsp/fragments/bodyHeader.jsp diff --git a/src/main/webapp/fragments/footer.jsp b/src/main/webapp/WEB-INF/jsp/fragments/footer.jsp similarity index 100% rename from src/main/webapp/fragments/footer.jsp rename to src/main/webapp/WEB-INF/jsp/fragments/footer.jsp 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 0238860698d7..4fb114c10428 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"/> - + diff --git a/src/main/webapp/index.jsp b/src/main/webapp/WEB-INF/jsp/index.jsp similarity index 100% rename from src/main/webapp/index.jsp rename to src/main/webapp/WEB-INF/jsp/index.jsp 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 d1ecf39ca7c1..76c9b3ee6403 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 204a79700e0e..ff0a2a2783ea 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 549b1f262de9df6a47715d3edea9c532b11e1ae5 Mon Sep 17 00:00:00 2001 From: AndrePro Date: Wed, 8 Feb 2017 23:21:10 +0300 Subject: [PATCH 72/72] spring_i18n_6_9 --- .../messages/app.properties | 0 .../messages/app_ru.properties | 0 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/userList.jsp | 2 -- 7 files changed, 18 insertions(+), 5 deletions(-) rename {src/main/resources => config}/messages/app.properties (100%) rename {src/main/resources => config}/messages/app_ru.properties (100%) diff --git a/src/main/resources/messages/app.properties b/config/messages/app.properties similarity index 100% rename from src/main/resources/messages/app.properties rename to config/messages/app.properties diff --git a/src/main/resources/messages/app_ru.properties b/config/messages/app_ru.properties similarity index 100% rename from src/main/resources/messages/app_ru.properties rename to config/messages/app_ru.properties 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 a5c6ce4fcfb8..dd38595e2431 100644 --- a/src/main/webapp/WEB-INF/jsp/fragments/footer.jsp +++ b/src/main/webapp/WEB-INF/jsp/fragments/footer.jsp @@ -1,4 +1,3 @@ <%@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 4fb114c10428..fc2b58f65786 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/userList.jsp b/src/main/webapp/WEB-INF/jsp/userList.jsp index eaca9fed9caf..1908c3557b7b 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" %> - -