From 2c47cd7aca8063a80fbb1806f466e46b0918fa2f Mon Sep 17 00:00:00 2001 From: Grigory Kislin Date: Wed, 26 Aug 2015 02:13:54 +0300 Subject: [PATCH 01/24] Add readme and project description --- README.md | 53 +++++++++++++++++++++++++++++++++++++++++ description.md | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 README.md create mode 100644 description.md diff --git a/README.md b/README.md new file mode 100644 index 000000000000..b45455288acd --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +Java Enterprise Online Project +=============================== +Наиболее востребованные технологии /инструменты / фреймворки Java Enterprise: +Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + plugins. + +**Старт проекта 10.09.2015** + +Вводное занятие +=============== + +## Описание проекта + +#### Демо разрабатываемого приложения + +## Системы управления версиями. Git. + +- Система управления версиями. VCS/DVSC. +- Ресурсы: + - Интерактивная Git обучалка + - Основы Git + - Working with remote repositories + - Видео по обучению Git + - Как начать работать с GitHub: быстрый старт + - Справочник в графическом виде + - Git Overview + +## Работа с проектом (выполнять инструкции) +- **Prepare_ to_ HW0.patch (скачать и положить в каталог вашего проекта)** +- Доступно о Java 8 Lambda + +## Инструкция по шагам (из видео): +- Установить ПО (git, JDK8, IntelliJ IDEA, Maven) +- Создать аккаунт на GitHub +- Сделать Fork ЭТОГО проекта (https://github.com/JavaOPs/topjava) +- Сделать локальный репозиторий проекта: +
git clone https://github.com/[Ваш аккаунт]/topjava.git
+- Открыть и настроить проект в IDEA +- По ходу видео сделать Apply Patch... скаченного патча Prepare_ to_ HW0.patch +- Закоммитить и запушить изменения (commit + push) +- Сделать ветку домашнего задания +- Выполнить задание и залить на GitHub (commit + push) +- Отослать в skype мне ссылку вашей ветки GitHub (при оплате расширенного участия) +- Переключиться в основную ветку проекта master. + +### Вы готовы к участию в проекте! + +- Ресурсы + - Java 8: Lambda выражения + - Java 8 Date and Time API + - Java 8: Потоки + - Pуководство по Java 8 Stream + - Лямбда-выражения в Java 8 diff --git a/description.md b/description.md new file mode 100644 index 000000000000..c58f903605d4 --- /dev/null +++ b/description.md @@ -0,0 +1,64 @@ +#### Разработка полнофункционального Spring/JPA Enterprise приложения c авторизацией и правами доступа на основе ролей используя наиболее популярные инструменты и технологии Java: Maven, Spring, Security, JPA(Hibernate), REST(Jackson), Bootstrap, jQuery + plugins +- Основное внимание будет уделяться способам решения многочисленных проблем разработки в Spring/JPA, а также структурному (красивому и надежному) java кодированию и архитектуре приложения. +- Каждая итерация проекта в закрепляется домашним заданием по реализации схожей функциональности. Следующее занятие начинается с разбора домашних заданий. +- Большое внимание уделяется тестированию кода: в проекте ~ 85 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 +- Spring кэш +- Кэш Hibernate + +## Разработка WEB +- Spring Web +- JPS, JSTL, i18n +- Tomcat maven plugin. JNDI +- Spring Web MVC +- Spring Internationalization +- Тестирование Spring MVC +- REST контроллеры +- Тестирование REST контроллеров. Jackson. +- jackson-datatype-hibernate. Тестирование через матчеры. +- Тестирование через SoapUi. UTF-8 +- WebJars. Dandelion bundles +- 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 4d1659ebe7e8fe3b6b4630cf675c6a06667138ec Mon Sep 17 00:00:00 2001 From: Grigory Kislin Date: Wed, 26 Aug 2015 02:36:13 +0300 Subject: [PATCH 02/24] Add HW0 description --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index b45455288acd..7664343e5526 100644 --- a/README.md +++ b/README.md @@ -51,3 +51,13 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - Java 8: Потоки - Pуководство по Java 8 Stream - Лямбда-выражения в Java 8 + +## Домашнее задание HW0 + Реализовать UserMealsUtil.getFilteredMealsWithExceeded: + - должны возвращаться только записи между startTime и endTime + - поле UserMealWithExceed.exceed должно показывать, + превышает ли сумма калорий за весь день параметра метода caloriesPerDay + +Optional + + Сделать реализация через Java 8 Stream API From 07d9270bfe8de494fe0eb9623d32e3852c0ca7df Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 26 Aug 2015 22:50:44 +0300 Subject: [PATCH 03/24] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 7664343e5526..8df40dd1e70d 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,9 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - должны возвращаться только записи между startTime и endTime - поле UserMealWithExceed.exceed должно показывать, превышает ли сумма калорий за весь день параметра метода caloriesPerDay + Т.е UserMealWithExceed - это запись одной еды, но поле exceeded будет одинаково для всех записей за этот день. + поле LocalDateTime dateTime содержит в себе как дату, так и время. + Optional From dbaee9c3b1b434d4104becb3ded791d13c201764 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 26 Aug 2015 22:50:59 +0300 Subject: [PATCH 04/24] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8df40dd1e70d..441ad8c986f5 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - должны возвращаться только записи между startTime и endTime - поле UserMealWithExceed.exceed должно показывать, превышает ли сумма калорий за весь день параметра метода caloriesPerDay + Т.е UserMealWithExceed - это запись одной еды, но поле exceeded будет одинаково для всех записей за этот день. поле LocalDateTime dateTime содержит в себе как дату, так и время. From 3b8a1fddc03c1edb64411eeeaf8bfa40fc083223 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Wed, 26 Aug 2015 22:57:29 +0300 Subject: [PATCH 05/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 441ad8c986f5..8b6a15e01baf 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + превышает ли сумма калорий за весь день параметра метода caloriesPerDay Т.е UserMealWithExceed - это запись одной еды, но поле exceeded будет одинаково для всех записей за этот день. - поле LocalDateTime dateTime содержит в себе как дату, так и время. + Поле LocalDateTime dateTime содержит в себе как дату, так и время. Optional From 8f685ac3ea54b84f4d31d2102d8764be0508cbaf Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 27 Aug 2015 00:16:41 +0300 Subject: [PATCH 06/24] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8b6a15e01baf..d54fe95e64be 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - Как начать работать с GitHub: быстрый старт - Справочник в графическом виде - Git Overview + - Видеокурс по Git ## Работа с проектом (выполнять инструкции) - **Prepare_ to_ HW0.patch (скачать и положить в каталог вашего проекта)** From 2ab1fcf956d03d94410d7df1774fe97b80661df9 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 27 Aug 2015 01:08:49 +0300 Subject: [PATCH 07/24] Update README.md --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d54fe95e64be..9dafd9ca7ccb 100644 --- a/README.md +++ b/README.md @@ -59,10 +59,9 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - поле UserMealWithExceed.exceed должно показывать, превышает ли сумма калорий за весь день параметра метода caloriesPerDay - Т.е UserMealWithExceed - это запись одной еды, но поле exceeded будет одинаково для всех записей за этот день. - Поле LocalDateTime dateTime содержит в себе как дату, так и время. - - + Т.е UserMealWithExceed - это запись одной еды, но поле exceeded + будет одинаково для всех записей за этот день. + Optional Сделать реализация через Java 8 Stream API From 923ffb016cd86b2d762e2f29601eea56bc56be14 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 27 Aug 2015 21:42:49 +0300 Subject: [PATCH 08/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9dafd9ca7ccb..c24e80634907 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - Видеокурс по Git ## Работа с проектом (выполнять инструкции) -- **Prepare_ to_ HW0.patch (скачать и положить в каталог вашего проекта)** +- **Prepare_ to_ HW0.patch (скачать и положить в каталог вашего проекта)** - Доступно о Java 8 Lambda ## Инструкция по шагам (из видео): From c3e4cb8d6ae1db6a4191fd1a6cf30df71f62a435 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 27 Aug 2015 21:53:37 +0300 Subject: [PATCH 09/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c24e80634907..fb493e14d3e7 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - Видеокурс по Git ## Работа с проектом (выполнять инструкции) -- **Prepare_ to_ HW0.patch (скачать и положить в каталог вашего проекта)** +- **Prepare_ to_ HW0.patch (скачать и положить в каталог вашего проекта)** - Доступно о Java 8 Lambda ## Инструкция по шагам (из видео): From 06bf582383af1a19adaf9f133c0f1ce5dcdf163f Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 27 Aug 2015 21:56:07 +0300 Subject: [PATCH 10/24] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index fb493e14d3e7..673ddb527861 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,8 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + Т.е UserMealWithExceed - это запись одной еды, но поле exceeded будет одинаково для всех записей за этот день. + Проверте результат выполнения ДЗ! + Optional Сделать реализация через Java 8 Stream API From 0f1b7efc63a0ffebb073b4eb08879cc1ac0654c8 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 27 Aug 2015 22:56:27 +0300 Subject: [PATCH 11/24] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 673ddb527861..b1626e0f6c7a 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,8 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + Т.е UserMealWithExceed - это запись одной еды, но поле exceeded будет одинаково для всех записей за этот день. - Проверте результат выполнения ДЗ! - + - Проверте результат выполнения ДЗ! + - Оцените Time complexity вашего алгоритма. Optional Сделать реализация через Java 8 Stream API From 8a55d0308d867d0d2bdf06744c89107e9a59b521 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 27 Aug 2015 22:57:12 +0300 Subject: [PATCH 12/24] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b1626e0f6c7a..940b1930daab 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - Проверте результат выполнения ДЗ! - Оцените Time complexity вашего алгоритма. + Optional Сделать реализация через Java 8 Stream API From 61d268c859caed77710854baa93b0eb78c6a31bd Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 27 Aug 2015 22:57:37 +0300 Subject: [PATCH 13/24] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 940b1930daab..c46787df90ce 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,8 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + Т.е UserMealWithExceed - это запись одной еды, но поле exceeded будет одинаково для всех записей за этот день. - - Проверте результат выполнения ДЗ! - - Оцените Time complexity вашего алгоритма. + - Проверте результат выполнения ДЗ! + - Оцените Time complexity вашего алгоритма. Optional From cb1bdc90e898d57cad5c994374428c3ec43d6c5a Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 27 Aug 2015 22:58:28 +0300 Subject: [PATCH 14/24] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c46787df90ce..eba26abf06f5 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,8 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + Т.е UserMealWithExceed - это запись одной еды, но поле exceeded будет одинаково для всех записей за этот день. - - Проверте результат выполнения ДЗ! - - Оцените Time complexity вашего алгоритма. + - Проверте результат выполнения ДЗ! + - Оцените Time complexity вашего алгоритма. Optional From 4aab0cd914130fa77b75191aa2e45a6253b93c49 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 27 Aug 2015 22:59:24 +0300 Subject: [PATCH 15/24] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index eba26abf06f5..730f0db6d48c 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - Java 8: Потоки - Pуководство по Java 8 Stream - Лямбда-выражения в Java 8 + - Time complexity ## Домашнее задание HW0 Реализовать UserMealsUtil.getFilteredMealsWithExceeded: @@ -63,7 +64,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + будет одинаково для всех записей за этот день. - Проверте результат выполнения ДЗ! - - Оцените Time complexity вашего алгоритма. + - Оцените Time complexity вашего алгоритма. Optional From 5826ae4c9a8235f6386858ee3042793a429f6f87 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Thu, 27 Aug 2015 22:59:41 +0300 Subject: [PATCH 16/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 730f0db6d48c..b72739fa3954 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + будет одинаково для всех записей за этот день. - Проверте результат выполнения ДЗ! - - Оцените Time complexity вашего алгоритма. + - Оцените Time complexity вашего алгоритма. Optional From 0e12c984bbe6d15917c915f8b1f4578d319b1a6e Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Fri, 28 Aug 2015 02:35:44 +0300 Subject: [PATCH 17/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b72739fa3954..9c7c21e4e987 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Java Enterprise Online Project Наиболее востребованные технологии /инструменты / фреймворки Java Enterprise: Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + plugins. -**Старт проекта 10.09.2015** +### **Старт проекта 10.09.2015** Вводное занятие =============== From 15b19fdd4729ccfdf6a2f2251f51388a4b3fda4e Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Fri, 28 Aug 2015 02:37:14 +0300 Subject: [PATCH 18/24] Update description.md --- description.md | 1 + 1 file changed, 1 insertion(+) diff --git a/description.md b/description.md index c58f903605d4..dcef05a8d71c 100644 --- a/description.md +++ b/description.md @@ -1,3 +1,4 @@ +#### **Старт проекта 10.09.2015** #### Разработка полнофункционального Spring/JPA Enterprise приложения c авторизацией и правами доступа на основе ролей используя наиболее популярные инструменты и технологии Java: Maven, Spring, Security, JPA(Hibernate), REST(Jackson), Bootstrap, jQuery + plugins - Основное внимание будет уделяться способам решения многочисленных проблем разработки в Spring/JPA, а также структурному (красивому и надежному) java кодированию и архитектуре приложения. - Каждая итерация проекта в закрепляется домашним заданием по реализации схожей функциональности. Следующее занятие начинается с разбора домашних заданий. From f11517f0ca40dc73f4c0bf818de15a3c768bf4e3 Mon Sep 17 00:00:00 2001 From: Java Online Projects Date: Fri, 28 Aug 2015 02:37:53 +0300 Subject: [PATCH 19/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9c7c21e4e987..665b0580bb6e 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Java Enterprise Online Project Наиболее востребованные технологии /инструменты / фреймворки Java Enterprise: Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + plugins. -### **Старт проекта 10.09.2015** +#### **Старт проекта 10.09.2015** Вводное занятие =============== From 0b8d7821b60da5422d70ca9862e8b0f353e7af41 Mon Sep 17 00:00:00 2001 From: SeniorJava Date: Thu, 10 Sep 2015 12:29:22 +0300 Subject: [PATCH 20/24] Prepare_tu_HW0.patch --- .gitignore | 3 ++ .../javawebinar/topjava/model/UserMeal.java | 33 +++++++++++++++++ .../topjava/model/UserMealWithExceed.java | 24 +++++++++++++ .../ru/javawebinar/topjava/util/TimeUtil.java | 13 +++++++ .../topjava/util/UserMealsUtil.java | 35 +++++++++++++++++++ 5 files changed, 108 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/.gitignore b/.gitignore index 6ca05c4a5184..1c621b14b0e6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ log + +patches +.patch \ No newline at end of file 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 62e17e172652c655a364820cae425031989965dc Mon Sep 17 00:00:00 2001 From: SeniorJava Date: Tue, 15 Sep 2015 17:31:28 +0300 Subject: [PATCH 21/24] lesson_1 --- config/tomcat/setenv.bat | 4 + doc/lesson01.md | 84 +++++++++++++++++++ pom.xml | 46 +++++++++- .../ru/javawebinar/topjava/LoggerWrapper.java | 72 ++++++++++++++++ .../java/ru/javawebinar/topjava/Main.java | 20 ++++- .../topjava/model/UserMealWithExceed.java | 10 +++ .../topjava/util/UserMealsUtil.java | 44 ++++++++-- .../javawebinar/topjava/web/UserServlet.java | 24 ++++++ src/main/resources/logback.xml | 33 ++++++++ src/main/webapp/WEB-INF/web.xml | 18 ++++ src/main/webapp/index.html | 10 +++ src/main/webapp/userList.jsp | 9 ++ 12 files changed, 363 insertions(+), 11 deletions(-) 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/java/ru/javawebinar/topjava/web/UserServlet.java create mode 100644 src/main/resources/logback.xml create mode 100644 src/main/webapp/WEB-INF/web.xml create mode 100644 src/main/webapp/index.html create mode 100644 src/main/webapp/userList.jsp diff --git a/config/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 c8a1c78f3b29..ed8a30eb32c4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ ru.javawebinar topjava - jar + war 1.0-SNAPSHOT @@ -13,13 +13,18 @@ 1.8 + UTF-8 UTF-8 + + + 1.1.2 + 1.7.7 topjava - install + package org.apache.maven.plugins @@ -34,6 +39,43 @@ + + + org.slf4j + slf4j-api + ${slf4j.version} + compile + + + + org.slf4j + jcl-over-slf4j + ${slf4j.version} + runtime + + + + org.slf4j + jul-to-slf4j + ${slf4j.version} + runtime + + + + ch.qos.logback + logback-classic + ${logback.version} + runtime + + + + + javax.servlet + servlet-api + 2.5 + provided + + diff --git a/src/main/java/ru/javawebinar/topjava/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/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!"); } } 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..b691b02c8267 100644 --- a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java @@ -3,11 +3,12 @@ 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.*; +import java.util.stream.Collectors; /** * GKislin @@ -23,13 +24,40 @@ 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); + + 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) { - // 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()); } + + 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; + } + } 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..eb2188bc8435 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java @@ -0,0 +1,24 @@ +package ru.javawebinar.topjava.web; + +import ru.javawebinar.topjava.LoggerWrapper; + +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 { + 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 + + + + + + + + + + diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000000..edca9575b44b --- /dev/null +++ b/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,18 @@ + + + Topjava + + + userServlet + ru.javawebinar.topjava.web.UserServlet + 0 + + + userServlet + /users + + + diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html new file mode 100644 index 000000000000..1937333f0dbe --- /dev/null +++ b/src/main/webapp/index.html @@ -0,0 +1,10 @@ + + + + + Codestin Search App + + +

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

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

User list

+ + From e21de47eb756f2f54a0a34bed409b22ca95789e3 Mon Sep 17 00:00:00 2001 From: SeniorJava Date: Tue, 15 Sep 2015 21:30:54 +0300 Subject: [PATCH 22/24] fix .md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 665b0580bb6e..7d65f319d5fb 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + ## Системы управления версиями. Git. -- Система управления версиями. VCS/DVSC. +- Система управления версиями. +VCS/DVSC. - Ресурсы: - Интерактивная Git обучалка - Основы Git From f80fc0dbb6e52bd2f8d81db99afa041a34090d9d Mon Sep 17 00:00:00 2001 From: SeniorJava Date: Thu, 24 Sep 2015 16:36:30 +0300 Subject: [PATCH 23/24] fix .md --- doc/lesson01.md | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/doc/lesson01.md b/doc/lesson01.md index e9999c2b68b6..2ae5dafa1c9a 100644 --- a/doc/lesson01.md +++ b/doc/lesson01.md @@ -1,12 +1,12 @@ # Занятие 1 онлайн проекта Topjava -**Напоминаю, что патчи в материалах урока необходимо накатывать (Apply Patch) на ветку MASTER и БЕЗ ВАШИХ ИЗМЕНЕНИЙ, иначе с ними будут проблемы. Делать Apply можно как по ходу видео, так и немного заранее - тогда при просмотре видео вы сразу сможете отслеживать изменения кода проекта.** +**Напоминаю, что cвой код пишете только в ветках HW. Код в ветке MASTER трогать нельзя вообще! Модификация кода только через патчи в материалах урока (Apply Patch), иначе с ними будут проблемы. Делать Apply можно как по ходу видео, так и немного заранее - тогда при просмотре видео вы сразу сможете отслеживать изменения кода проекта.** ## Материалы урока ## Домашнее задание: реализация getFilteredMealsWithExceeded через Stream API - Доступно о Java 8 Lambda -- **1_ Lambda_ samples.patch** -- **2_ HW0.patch** +- **1_ Lambda_ samples.patch** +- **2_ HW0.patch** - Перевод "Java 8 Stream Tutorial" - Основное в Java 8 @@ -54,6 +54,7 @@ - Ресурсы: - Технологии Java для разработки веб-приложений + - Remotely debug on tomcat from IDEA ## Логирование. - **7_ Add_ logging.patch** @@ -69,16 +70,31 @@ - Управление логированием по JMX. - Контекст приложения. Деплой в Tomcat без IDE. Remote debug. -## Уровни и зависимости логгирования, JMX +## Уровни и зависимости логгирования. JMX ## Домашнее задание HW01 - - Попробовать разные деплои в Tomcat, remote и local debug + По аналогии с Users добавить MealServlet и mealList.jsp. - Добавить в JSP и index.html ссылки друг на друга - Задеплоить приложение (war) в Tomcat c applicationContext=topjava и проверить работу ссылок + Задеплоить приложение (war) в Tomcat c applicationContext=topjava + Попробовать разные деплои в Tomcat, remote и local debug + + Сделать отображения списка еды в jsp, цвет записи в таблице зависит от параметра isExceeded (красный/зеленый). + Вариант реализации: + - из сервлета обращаетесь к реализации хранения еды в памяти; + - преобразуете результат в List; + - кладете список в запрос (request.setAttribute); + - делаете forward на jsp для отрисовки таблицы (при redirect аттрибуты теряются). + В jsp для цикла можно использовать JSTL tag forEach. Optional Сделать реализацию CRUD (create/read/update/delete) для списка еды. - Цвет записи в таблице зависит от параметра isExceeded. \ No newline at end of file + AJAX/JavaScript использовать не надо, делаем через
Интернет-приложения на JAVA + - HTTP 1.0 vs 1.1 + - JSP + - JSTL для написания JSP страниц + - JSTL: Шаблоны для разработки веб-приложений в java + - MVC - Model View Controller \ No newline at end of file From 157ad5a1637e17fdc3fb70a8a682893ec959611a Mon Sep 17 00:00:00 2001 From: SeniorJava Date: Fri, 25 Sep 2015 15:35:17 +0300 Subject: [PATCH 24/24] Lesson_2 --- pom.xml | 20 ++++ .../ru/javawebinar/topjava/LoggedUser.java | 12 +++ .../ru/javawebinar/topjava/LoggerWrapper.java | 8 +- .../ru/javawebinar/topjava/SpringMain.java | 24 +++++ .../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 +++++++++++++++++++ .../javawebinar/topjava/model/UserMeal.java | 29 ++++++ .../topjava/model/UserMealWithExceed.java | 30 +++++- .../repository/UserMealRepository.java | 19 ++++ .../topjava/repository/UserRepository.java | 24 +++++ .../mock/InMemoryUserMealRepository.java | 53 ++++++++++ .../mock/MockUserRepositoryImpl.java | 48 +++++++++ .../topjava/service/UserMealService.java | 8 ++ .../topjava/service/UserMealServiceImpl.java | 13 +++ .../topjava/service/UserService.java | 26 +++++ .../topjava/service/UserServiceImpl.java | 45 +++++++++ .../ru/javawebinar/topjava/util/TimeUtil.java | 8 ++ .../topjava/util/UserMealsUtil.java | 44 +++++---- .../topjava/util/exception/ExceptionUtil.java | 29 ++++++ .../util/exception/NotFoundException.java | 11 +++ .../javawebinar/topjava/web/MealServlet.java | 71 ++++++++++++++ .../web/meal/UserMealRestController.java | 12 +++ .../web/user/AbstractUserController.java | 50 ++++++++++ .../topjava/web/user/AdminRestController.java | 38 +++++++ .../web/user/ProfileRestController.java | 25 +++++ src/main/resources/spring/spring-app.xml | 23 +++++ src/main/webapp/WEB-INF/web.xml | 10 ++ src/main/webapp/index.html | 9 +- src/main/webapp/mealEdit.jsp | 51 ++++++++++ src/main/webapp/mealList.jsp | 46 +++++++++ src/main/webapp/userList.jsp | 3 +- 33 files changed, 957 insertions(+), 24 deletions(-) create mode 100644 src/main/java/ru/javawebinar/topjava/LoggedUser.java create mode 100644 src/main/java/ru/javawebinar/topjava/SpringMain.java create mode 100644 src/main/java/ru/javawebinar/topjava/model/BaseEntity.java create mode 100644 src/main/java/ru/javawebinar/topjava/model/NamedEntity.java create mode 100644 src/main/java/ru/javawebinar/topjava/model/Role.java create mode 100644 src/main/java/ru/javawebinar/topjava/model/User.java create mode 100644 src/main/java/ru/javawebinar/topjava/repository/UserMealRepository.java create mode 100644 src/main/java/ru/javawebinar/topjava/repository/UserRepository.java create mode 100644 src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepository.java create mode 100644 src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java create mode 100644 src/main/java/ru/javawebinar/topjava/service/UserMealService.java create mode 100644 src/main/java/ru/javawebinar/topjava/service/UserMealServiceImpl.java create mode 100644 src/main/java/ru/javawebinar/topjava/service/UserService.java create mode 100644 src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java create mode 100644 src/main/java/ru/javawebinar/topjava/util/exception/ExceptionUtil.java create mode 100644 src/main/java/ru/javawebinar/topjava/util/exception/NotFoundException.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/MealServlet.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/meal/UserMealRestController.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java create mode 100644 src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java create mode 100644 src/main/resources/spring/spring-app.xml create mode 100644 src/main/webapp/mealEdit.jsp create mode 100644 src/main/webapp/mealList.jsp diff --git a/pom.xml b/pom.xml index ed8a30eb32c4..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 @@ -76,6 +78,24 @@ provided + + javax.servlet + jstl + 1.2 + + + + + org.springframework + spring-context + ${spring.version} + + + commons-logging + commons-logging + + + 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..6c7bac08b7a6 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/LoggedUser.java @@ -0,0 +1,12 @@ +package ru.javawebinar.topjava; + +/** + * GKislin + * 06.03.2015. + */ +public class LoggedUser { + + public static int id() { + return 1; + } +} 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/SpringMain.java b/src/main/java/ru/javawebinar/topjava/SpringMain.java new file mode 100644 index 000000000000..9b14ec645a08 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/SpringMain.java @@ -0,0 +1,24 @@ +package ru.javawebinar.topjava; + +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import ru.javawebinar.topjava.model.Role; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.web.user.AdminRestController; + +import java.util.Arrays; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +public class SpringMain { + public static void main(String[] args) { + // java 7 Automatic resource management + try (ConfigurableApplicationContext appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml")) { + System.out.println(Arrays.toString(appCtx.getBeanDefinitionNames())); + AdminRestController adminUserController = appCtx.getBean(AdminRestController.class); + System.out.println(adminUserController.create(new User(1, "userName", "email", "password", Role.ROLE_ADMIN))); + } + } +} diff --git a/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java b/src/main/java/ru/javawebinar/topjava/model/BaseEntity.java new file mode 100644 index 000000000000..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/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 66c356922f6b..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,16 +18,42 @@ 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; + } + + public String getDescription() { + return description; + } + + public int getCalories() { + return calories; + } + + public boolean isExceed() { + return exceed; + } + @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/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/repository/UserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java new file mode 100644 index 000000000000..24c1c45beca6 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java @@ -0,0 +1,24 @@ +package ru.javawebinar.topjava.repository; + +import ru.javawebinar.topjava.model.User; + +import java.util.List; + +/** + * User: gkislin + * Date: 22.08.2014 + */ +public interface UserRepository { + User save(User user); + + // false if not found + boolean delete(int id); + + // null if not found + User get(int id); + + // null if not found + User getByEmail(String email); + + List getAll(); +} diff --git a/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepository.java new file mode 100644 index 000000000000..6996132dd8c0 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/InMemoryUserMealRepository.java @@ -0,0 +1,53 @@ +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; +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/mock/MockUserRepositoryImpl.java b/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java new file mode 100644 index 000000000000..cf2649b7bf46 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/mock/MockUserRepositoryImpl.java @@ -0,0 +1,48 @@ +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/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..ecd332a5e9af --- /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 { + + public User save(User user); + + public void delete(int id) throws NotFoundException; + + public User get(int id) throws NotFoundException; + + public User getByEmail(String email) throws NotFoundException; + + public List getAll(); + + public 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..f83d039b7fbc --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/service/UserServiceImpl.java @@ -0,0 +1,45 @@ +package ru.javawebinar.topjava.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.repository.UserRepository; +import ru.javawebinar.topjava.util.exception.ExceptionUtil; +import ru.javawebinar.topjava.util.exception.NotFoundException; + +import java.util.List; + +/** + * GKislin + * 06.03.2015. + */ +@Service +public class UserServiceImpl implements UserService { + + @Autowired + private UserRepository repository; + + public User save(User user) { + return repository.save(user); + } + + public void delete(int id) { + ExceptionUtil.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/TimeUtil.java b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java index 02399b7288cf..115311fad6b7 100644 --- a/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/TimeUtil.java @@ -1,13 +1,21 @@ package ru.javawebinar.topjava.util; +import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.format.DateTimeFormatter; /** * GKislin * 07.01.2015. */ public class TimeUtil { + public static final DateTimeFormatter DATE_TME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + public static boolean isBetween(LocalTime lt, LocalTime startTime, LocalTime endTime) { return lt.compareTo(startTime) >= 0 && lt.compareTo(endTime) <= 0; } + + public static String toString(LocalDateTime ldt) { + return ldt == null ? "" : ldt.format(DATE_TME_FORMATTER); + } } diff --git a/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/UserMealsUtil.java index b691b02c8267..3dfa9fa9f655 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.getId(), 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/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/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java new file mode 100644 index 000000000000..905f50c71e71 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -0,0 +1,71 @@ +package ru.javawebinar.topjava.web; + +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.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 + * Date: 19.08.2014 + */ +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 { + 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/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..98e0401f4523 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java @@ -0,0 +1,50 @@ +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; + +import java.util.List; + +/** + * User: gkislin + */ +public abstract class AbstractUserController { + protected final LoggerWrapper LOG = LoggerWrapper.get(getClass()); + + @Autowired + private UserService service; + + public List getAll() { + LOG.info("getAll"); + return service.getAll(); + } + + public User get(int id) { + LOG.info("get " + id); + return service.get(id); + } + + public User create(User user) { + user.setId(null); + LOG.info("create " + user); + return service.save(user); + } + + public void delete(int id) { + LOG.info("delete " + id); + service.delete(id); + } + + public void update(User user, int id) { + user.setId(id); + LOG.info("update " + user); + service.update(user); + } + + public User getByMail(String email) { + LOG.info("getByEmail " + email); + return service.getByEmail(email); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java b/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java new file mode 100644 index 000000000000..d6b8bb420803 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java @@ -0,0 +1,38 @@ +package ru.javawebinar.topjava.web.user; + +import org.springframework.stereotype.Controller; +import ru.javawebinar.topjava.model.User; + +import java.util.List; + +/** + * GKislin + * 06.03.2015. + */ +@Controller +public class AdminRestController extends AbstractUserController { + + public List getAll() { + return super.getAll(); + } + + public User get(int id) { + return super.get(id); + } + + public User create(User user) { + return super.create(user); + } + + public void delete(int id) { + super.delete(id); + } + + public void update(User user, int id) { + super.update(user, id); + } + + public User getByMail(String email) { + return super.getByMail(email); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java new file mode 100644 index 000000000000..1114e57eeb1e --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java @@ -0,0 +1,25 @@ +package ru.javawebinar.topjava.web.user; + +import org.springframework.stereotype.Controller; +import ru.javawebinar.topjava.LoggedUser; +import ru.javawebinar.topjava.model.User; + +/** + * GKislin + * 06.03.2015. + */ +@Controller +public class ProfileRestController extends AbstractUserController { + + public User get() { + return super.get(LoggedUser.id()); + } + + public void delete() { + super.delete(LoggedUser.id()); + } + + public void update(User user) { + super.update(user, LoggedUser.id()); + } +} \ No newline at end of file diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml new file mode 100644 index 000000000000..c285b264141d --- /dev/null +++ b/src/main/resources/spring/spring-app.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 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 @@ Codestin Search App -

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

+

Проект "Top Java."

+
+ - \ No newline at end of file + 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" %> + + + + Codestin Search App + + + +
+

Home

+

Edit meal

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

Home

+

Meal list

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

User list

+

Home

+

User list