diff --git a/.codacy.yml b/.codacy.yml deleted file mode 100644 index 311a8f4e0..000000000 --- a/.codacy.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -exclude_paths: - - 'src/main/webapp/**' - - '**.md' - - '**.sql' \ No newline at end of file diff --git a/README.md b/README.md index 10f296158..e32386164 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -[![Codacy Badge](https://app.codacy.com/project/badge/Grade/bee16f3145654047a0505c62aeefd8a2)](https://app.codacy.com/gh/JavaWebinar/topjava/dashboard) - Java Enterprise Online Project =============================== @@ -11,13 +9,14 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - [Wiki](https://github.com/JavaOPs/topjava/wiki) - [Wiki Git](https://github.com/JavaOPs/topjava/wiki/Git) - [Wiki IDEA](https://github.com/JavaOPs/topjava/wiki/IDEA) -- [Демо разрабатываемого приложения](http://javaops-demo.ru/topjava) +- [Демо разрабатываемого приложения](http://topjava.herokuapp.com/) -### 29.01: Старт проекта -- Начало проверки [вступительного задания HW0](https://github.com/JavaOPs/topjava#-Домашнее-задание-hw0) +### 29.09: Старт проекта +- Начало проверки [вступительного задания](https://github.com/JavaOPs/topjava#-Домашнее-задание-hw0) -#### 02.02 Дедлайн на сдачу HW0 -### 05.02: 1-е занятие +#### 04.10 Дедлайн на сдачу HW0 +### 06.10: 1-е занятие +#### 13.10 Дедлайн подачи заявки на [дипломную программу](https://javaops.ru/view/register/diploma) - Разбор домашнего задания вступительного занятия (вместе с Optional) - Обзор используемых в проекте технологий. Интеграция ПО - Maven @@ -26,7 +25,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - Уровни и зависимости логгирования. JMX - Домашнее задание 1-го занятия (HW1 + Optional) -### 12.02: 2-е занятие +### 13.10: 2-е занятие - Разбор домашнего задания HW1 + Optional - Библиотека vs Фреймворк. Стандартные библиотеки Apache Commons, Guava - Слои приложения. Создание каркаса приложения @@ -34,7 +33,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - Пояснения к HW2. Обработка Autowired - Домашнее задание (HW2 + Optional) -### 19.02: 3-е занятие +### 20.10: 3-е занятие - Разбор домашнего задания HW2 + Optional - Жизненный цикл Spring контекста - Тестирование через JUnit @@ -47,7 +46,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - Логирование тестов - Домашнее задание (HW3 + Optional) -### 26.02: 4-е занятие +### 27.10: 4-е занятие - Разбор домашнего задания HW3 + Optional - Методы улучшения качества кода - Spring: инициализация и популирование DB @@ -57,7 +56,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - Домашнее задание (HW4 + Optional) #### Начало выполнения [выпускного проекта](https://github.com/JavaOPs/topjava/blob/master/graduation.md) -### 05.03: 5-е занятие +### 01.11: 5-е занятие - Обзор JDK 9/17. Миграция Topjava с 1.8 на 17 - Разбор вопросов - Разбор домашнего задания HW4 + Optional @@ -68,7 +67,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - Spring кэш - Домашнее задание (HW5 + Optional) -### 12.03: 6-е занятие +### 10.11: 6-е занятие - Разбор домашнего задания HW5 + Optional - Кэш Hibernate - Spring Web @@ -81,7 +80,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + #### Большое ДЗ + выпускной проект + начинаем [курс BootJava](https://javaops.ru/view/bootjava) + подтягиваем "хвосты". -### 26.03: 7-е занятие +### 24.11: 7-е занятие - Разбор домашнего задания HW6 + Optional - Автогенерация DDL по модели - Тестирование Spring MVC @@ -92,7 +91,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - Тестирование через SoapUi. UTF-8 - Домашнее задание (HW7 + Optional) -### 02.04: 8-е занятие +### 01.12: 8-е занятие - Разбор домашнего задания HW7 + Optional - WebJars. jQuery и JavaScript frameworks - Bootstrap @@ -101,7 +100,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - Добавление Spring Security - Домашнее задание (HW8 + Optional) -### 09.04: 9-е занятие +### 08.12: 9-е занятие - Разбор домашнего задания HW8 + Optional - Spring Binding - Spring Validation @@ -113,7 +112,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - Cookie. Session - Домашнее задание (HW9 + Optional) -### 16.04: 10-е занятие +### 15.12: 10-е занятие - Разбор домашнего задания HW10 + Optional - Кастомизация JSON (@JsonView) и валидации (groups) - Рефакторинг: jQuery конверторы и группы валидации по умолчанию @@ -126,22 +125,23 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery + - Защита от межсайтовой подделки запросов (CSRF) - Домашнее задание (HW10) -### 23.04: 11-е занятие +### 22.12: 11-е занятие - Разбор домашнего задания HW10 + Optional - Локализация datatables, ошибок валидации - Защита от XSS (Cross Site Scripting) - Обработка ошибок 404 (NotFound) - Доступ к AuthorizedUser - Ограничение модификации пользователей -- Деплой приложения [на собственный выделенный сервер](https://github.com/JavaOPs/startup) -- Домашнее задание (HW11): сокрытия полей в Swagger -- Составление резюме. Собеседование. Разработка ПО. Возможные доработки приложения - -### 27.04: Миграция на Spring-Boot 3.5 -- Ревью вашего резюме +- Деплой [приложения в Heroku](http://topjava.herokuapp.com) +- Собеседование. Разработка ПО +- Возможные доработки приложения +- Домашнее задание по проекту: составление резюме + +### 26.12: Миграция на Spring-Boot - Основы Spring Boot. Spring Boot maven plugin - Lombok, база H2, ApplicationRunner - Spring Data REST + HATEOAS - Миграция приложения подсчета калорий на Spring Boot -### 11.05: Дедлайн на сдачу [выпускного проекта](https://github.com/JavaOPs/topjava/blob/master/graduation.md) +### 15.01.23: Дедлайн на сдачу [выпускного проекта](https://github.com/JavaOPs/topjava/blob/master/graduation.md) +### 25.01.23: Получение дипломов для участников [Дипломной программы](https://javaops.ru/view/register/diploma) diff --git a/config/Topjava-soapui-project.xml b/config/Topjava-soapui-project.xml deleted file mode 100644 index f9668d765..000000000 --- a/config/Topjava-soapui-project.xml +++ /dev/null @@ -1,395 +0,0 @@ - - - - - - - - http://localhost:8080 - - - - - - - - - text/html;charset=utf-8 - 500 401 - - html - - - application/json - 200 - - ns:Response - - - application/json;charset=UTF-8 - 200 - - Response - - - - <xml-fragment/> - - http://localhost:8080 - - http://localhost/topjava/rest/admin/users - - user@yandex.ru - password - No Authorization - Basic - No Authorization - - - - - - - - - - - application/json - - - - text/html;charset=utf-8 - 500 - - html - - - application/json - 201 - - user:Response - - - application/json;charset=UTF-8 - 201 - - user:Response - - - - <xml-fragment/> - - http://localhost:8080 - {"name": "New2", - "email": "new2@yandex.ru", - "password": "passwordNew", - "roles": ["USER"] - } - - http://localhost/topjava/rest/admin/users - - No Authorization - Basic - No Authorization - - - - - - - - - - - - - - - text/html;charset=utf-8 - 500 - - html - - - application/json - 200 - - ns:Response - - - application/json;charset=UTF-8 - 200 - - ns:Response - - - - <xml-fragment/> - - http://localhost:8080 - - http://localhost/topjava/rest/admin/users/100000 - - No Authorization - Basic - No Authorization - - - - - - - - - - - text/html;charset=utf-8 - 405 500 - - html - - - application/json - - - - - 200 - - data - - - - 200 - - data - - - - 200 - - data - - - - 200 - - data - - - - 200 - - data - - - - 200 - - data - - - - <xml-fragment/> - - http://localhost:8080 - {"name": "UserUpdated", - "email": "user@yandex.ru", - "password": "passwordNew", - "roles": ["USER"] - } - - http://localhost/topjava/rest/admin/users/100000 - - Basic - Basic - Global HTTP Settings - - - - - - - - - - - - - - - text/html;charset=utf-8 - 500 - - html - - - application/json - 200 - - ns:Response - - - application/json;charset=UTF-8 - 200 - - prof:Response - - - - <xml-fragment/> - - http://localhost:8080 - - http://localhost/topjava/rest/profile - - Basic - Basic - Global HTTP Settings - - - - - - - - - - - application/json - - - - text/html;charset=utf-8 - 500 405 - - html - - - application/json - 201 - - user:Response - - - - 200 - - data - - - - 200 - - data - - - - 200 - - data - - - - 200 - - data - - - - 200 - - data - - - - 200 - - data - - - - 200 - - data - - - - <xml-fragment/> - - http://localhost:8080 - {"name": "New777", - "email": "new777@yandex.ru", - "password": "passwordNew", - "roles": ["USER"] - } - - http://localhost/topjava/rest/profile - - No Authorization - Basic - No Authorization - - - - - - - - - - - - 200 - - data - - - text/html;charset=utf-8 - 500 - - html - - - application/json - - - - - 200 - - data - - - - 204 - - data - - - - <xml-fragment/> - - http://localhost:8080 - - http://localhost/topjava/rest/profile - - No Authorization - Basic - No Authorization - - - - - - - - - - - - - - \ No newline at end of file diff --git a/config/messages/app.properties b/config/messages/app.properties deleted file mode 100644 index 6b4d2d155..000000000 --- a/config/messages/app.properties +++ /dev/null @@ -1,29 +0,0 @@ -app.title=Calories management -app.home=Home -app.footer=Internship Spring 5/JPA Enterprise (Topjava) application -app.login=Login as - -user.title=Users -user.name=Name -user.email=Email -user.roles=Roles -user.active=Active -user.registered=Registered - -meal.title=Meals -meal.edit=Edit meal -meal.add=Add meal -meal.filter=Filter -meal.startDate=From date (inclusive) -meal.endDate=To date (inclusive) -meal.startTime=From time (inclusive) -meal.endTime=To time (exclusive) -meal.description=Description -meal.dateTime=Date/Time -meal.calories=Calories - -common.select=Select -common.delete=Delete -common.update=Update -common.save=Save -common.cancel=Cancel \ No newline at end of file diff --git a/config/messages/app_ru.properties b/config/messages/app_ru.properties deleted file mode 100644 index 97f3e9f05..000000000 --- a/config/messages/app_ru.properties +++ /dev/null @@ -1,29 +0,0 @@ -app.title=Подсчет калорий -app.home=Главная -app.footer=Приложение стажировки Spring 5/JPA Enterprise (Topjava) -app.login=Зайти как - -user.title=Пользователи -user.name=Имя -user.email=Почта -user.roles=Роли -user.active=Активный -user.registered=Зарегистрирован - -meal.title=Моя еда -meal.edit=Редактирование еды -meal.add=Добавление еды -meal.filter=Отфильтровать -meal.startDate=От даты (включая) -meal.endDate=До даты (включая) -meal.startTime=От времени (включая) -meal.endTime=До времени (исключая) -meal.description=Описание -meal.dateTime=Дата/Время -meal.calories=Калории - -common.select=Выбрать -common.delete=Удалить -common.update=Обновить -common.save=Сохранить -common.cancel=Отменить \ No newline at end of file diff --git a/lib/javax.annotation.jar b/lib/javax.annotation.jar new file mode 100644 index 000000000..52dca7f56 Binary files /dev/null and b/lib/javax.annotation.jar differ diff --git a/lib/javax.ejb.jar b/lib/javax.ejb.jar new file mode 100644 index 000000000..4ebf5ecd4 Binary files /dev/null and b/lib/javax.ejb.jar differ diff --git a/lib/javax.jms.jar b/lib/javax.jms.jar new file mode 100644 index 000000000..d31451ada Binary files /dev/null and b/lib/javax.jms.jar differ diff --git a/lib/javax.persistence.jar b/lib/javax.persistence.jar new file mode 100644 index 000000000..21d80e0ed Binary files /dev/null and b/lib/javax.persistence.jar differ diff --git a/lib/javax.resource.jar b/lib/javax.resource.jar new file mode 100644 index 000000000..696a23458 Binary files /dev/null and b/lib/javax.resource.jar differ diff --git a/lib/javax.servlet.jar b/lib/javax.servlet.jar new file mode 100644 index 000000000..0519e4a4e Binary files /dev/null and b/lib/javax.servlet.jar differ diff --git a/lib/javax.servlet.jsp.jar b/lib/javax.servlet.jsp.jar new file mode 100644 index 000000000..9c0631cea Binary files /dev/null and b/lib/javax.servlet.jsp.jar differ diff --git a/lib/javax.servlet.jsp.jstl.jar b/lib/javax.servlet.jsp.jstl.jar new file mode 100644 index 000000000..7be17cc74 Binary files /dev/null and b/lib/javax.servlet.jsp.jstl.jar differ diff --git a/lib/javax.transaction.jar b/lib/javax.transaction.jar new file mode 100644 index 000000000..729c69523 Binary files /dev/null and b/lib/javax.transaction.jar differ diff --git a/pom.xml b/pom.xml index e19fe64e8..6fe219d38 100644 --- a/pom.xml +++ b/pom.xml @@ -9,106 +9,33 @@ 1.0-SNAPSHOT Calories Management - https://javaops-demo.ru/topjava + http://topjava.herokuapp.com/ - 21 + 1.8 UTF-8 UTF-8 - 5.3.39 - 2.7.18 - 2.21.2 - 9.0.113 - - 5.6.15.Final - 6.2.5.Final - 3.0.1-b12 - - - 3.10.8 + 5.3.20 - 1.5.20 - 2.0.17 - - - 42.7.8 - - 5.14.1 - 3.27.6 - 3.0 + 1.3.4 + 2.0.3 topjava package - - org.apache.maven.plugins - maven-war-plugin - 3.4.0 - org.apache.maven.plugins maven-compiler-plugin - 3.14.1 + 3.8.1 ${java.version} ${java.version} - - - org.apache.maven.plugins - maven-surefire-plugin - 3.5.4 - - -Dfile.encoding=UTF-8 - - - - - - - org.codehaus.cargo - cargo-maven3-plugin - 1.10.26 - - - tomcat9x - - UTF-8 - tomcat,datajpa - - - - org.postgresql - postgresql - - - - - - - src/main/resources/tomcat/context.xml - conf/Catalina/localhost/ - ${project.build.finalName}.xml - - - - - - ru.javawebinar - topjava - war - - ${project.build.finalName} - - - - - @@ -118,6 +45,7 @@ org.slf4j slf4j-api ${slf4j.version} + compile @@ -127,87 +55,18 @@ runtime - - - com.google.code.findbugs - annotations - 3.0.1 - compile - - - - javax.annotation - javax.annotation-api - 1.3.2 - - org.springframework - spring-context-support - - - org.springframework.data - spring-data-jpa - ${spring-data-jpa.version} - - - - - org.hibernate - hibernate-core - ${hibernate.version} - - - org.hibernate.validator - hibernate-validator - ${hibernate-validator.version} - - - org.hibernate - hibernate-jcache - ${hibernate.version} - - - - - org.glassfish - javax.el - ${javax-el.version} - provided - - - - - javax.cache - cache-api - 1.1.0 - - - org.ehcache - ehcache - runtime - ${ehcache.version} - - - org.glassfish.jaxb - jaxb-runtime - - - - - - - org.glassfish.jaxb - jaxb-runtime - 2.4.0-b180830.0438 + spring-context + ${spring.version} - org.apache.tomcat - tomcat-servlet-api - ${tomcat.version} + javax.servlet + javax.servlet-api + 4.0.1 provided @@ -216,112 +75,11 @@ jstl 1.2 - - - org.springframework - spring-webmvc - - - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - com.fasterxml.jackson.datatype - jackson-datatype-hibernate5 - ${jackson.version} - - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - ${jackson.version} - - - - - org.junit.jupiter - junit-jupiter-engine - ${junit.version} - test - - - org.hamcrest - hamcrest-core - ${hamcrest.version} - test - - - - org.springframework - spring-test - test - - - org.assertj - assertj-core - ${assertj.version} - test - - - - - org.junit.platform - junit-platform-launcher - 1.14.3 - test - - - hsqldb - - - org.hsqldb - hsqldb - 2.7.4 - - - - - - postgres - - - org.postgresql - postgresql - ${postgresql.version} - - - org.apache.tomcat - tomcat-jdbc - ${tomcat.version} - provided - - - org.slf4j - jul-to-slf4j - ${slf4j.version} - runtime - - - - true - - - - - org.springframework - spring-framework-bom - ${spring.version} - pom - import - - - + \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/Profiles.java b/src/main/java/ru/javawebinar/topjava/Profiles.java deleted file mode 100644 index e4111a2af..000000000 --- a/src/main/java/ru/javawebinar/topjava/Profiles.java +++ /dev/null @@ -1,27 +0,0 @@ -package ru.javawebinar.topjava; - -import org.springframework.util.ClassUtils; - -public class Profiles { - public static final String - JDBC = "jdbc", - JPA = "jpa", - DATAJPA = "datajpa"; - - public static final String REPOSITORY_IMPLEMENTATION = DATAJPA; - - public static final String - POSTGRES_DB = "postgres", - HSQL_DB = "hsqldb"; - - // Get DB profile depending of DB driver in classpath - public static String getActiveDbProfile() { - if (ClassUtils.isPresent("org.postgresql.Driver", null)) { - return POSTGRES_DB; - } else if (ClassUtils.isPresent("org.hsqldb.jdbcDriver", null)) { - return HSQL_DB; - } else { - throw new IllegalStateException("Could not find DB driver"); - } - } -} diff --git a/src/test/java/ru/javawebinar/topjava/SpringMain.java b/src/main/java/ru/javawebinar/topjava/SpringMain.java similarity index 50% rename from src/test/java/ru/javawebinar/topjava/SpringMain.java rename to src/main/java/ru/javawebinar/topjava/SpringMain.java index 1dda999c5..85d0832e8 100644 --- a/src/test/java/ru/javawebinar/topjava/SpringMain.java +++ b/src/main/java/ru/javawebinar/topjava/SpringMain.java @@ -4,33 +4,17 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; import ru.javawebinar.topjava.model.Role; import ru.javawebinar.topjava.model.User; -import ru.javawebinar.topjava.to.MealTo; -import ru.javawebinar.topjava.web.meal.MealRestController; 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; public class SpringMain { public static void main(String[] args) { // java 7 automatic resource management (ARM) - try (ConfigurableApplicationContext appCtx = new ClassPathXmlApplicationContext("spring/inmemory.xml")) { + try (ConfigurableApplicationContext appCtx = new ClassPathXmlApplicationContext("spring/spring-app.xml")) { System.out.println("Bean definition names: " + Arrays.toString(appCtx.getBeanDefinitionNames())); AdminRestController adminUserController = appCtx.getBean(AdminRestController.class); adminUserController.create(new User(null, "userName", "email@mail.ru", "password", Role.ADMIN)); - System.out.println(); - - MealRestController mealController = appCtx.getBean(MealRestController.class); - List filteredMealsWithExcess = - mealController.getBetween( - LocalDate.of(2020, Month.JANUARY, 30), LocalTime.of(7, 0), - LocalDate.of(2020, Month.JANUARY, 31), LocalTime.of(11, 0)); - filteredMealsWithExcess.forEach(System.out::println); - System.out.println(); - System.out.println(mealController.getBetween(null, null, null, null)); } } } diff --git a/src/main/java/ru/javawebinar/topjava/model/AbstractBaseEntity.java b/src/main/java/ru/javawebinar/topjava/model/AbstractBaseEntity.java index e1200c3a5..8f27c902e 100644 --- a/src/main/java/ru/javawebinar/topjava/model/AbstractBaseEntity.java +++ b/src/main/java/ru/javawebinar/topjava/model/AbstractBaseEntity.java @@ -1,30 +1,8 @@ package ru.javawebinar.topjava.model; -import org.springframework.data.domain.Persistable; -import org.springframework.util.Assert; - -import javax.persistence.*; - -import static org.hibernate.proxy.HibernateProxyHelper.getClassWithoutInitializingProxy; - -@MappedSuperclass -// http://stackoverflow.com/questions/594597/hibernate-annotations-which-is-better-field-or-property-access -@Access(AccessType.FIELD) -//@JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, isGetterVisibility = NONE, setterVisibility = NONE) -public abstract class AbstractBaseEntity implements Persistable { - public static final int START_SEQ = 100000; - - @Id - @SequenceGenerator(name = "global_seq", sequenceName = "global_seq", allocationSize = 1, initialValue = START_SEQ) - // @Column(name = "id", unique = true, nullable = false, columnDefinition = "integer default nextval('global_seq')") - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "global_seq") -// See https://hibernate.atlassian.net/browse/HHH-3718 and https://hibernate.atlassian.net/browse/HHH-12034 -// Proxy initialization when accessing its identifier managed now by JPA_PROXY_COMPLIANCE setting +public abstract class AbstractBaseEntity { protected Integer id; - protected AbstractBaseEntity() { - } - protected AbstractBaseEntity(Integer id) { this.id = id; } @@ -33,37 +11,16 @@ public void setId(Integer id) { this.id = id; } - @Override public Integer getId() { return id; } - // doesn't work for hibernate lazy proxy - public int id() { - Assert.notNull(id, "Entity must have id"); - return id; - } - - @Override public boolean isNew() { - return getId() == null; + return this.id == null; } @Override public String toString() { - return getClass().getSimpleName() + ":" + getId(); - } - - // https://stackoverflow.com/a/78077907/548473 - @Override - public final boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClassWithoutInitializingProxy(this) != getClassWithoutInitializingProxy(o)) return false; - return getId() != null && getId().equals(((AbstractBaseEntity) o).getId()); - } - - @Override - public final int hashCode() { - return getClassWithoutInitializingProxy(this).hashCode(); + return getClass().getSimpleName() + ":" + id; } } \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/model/AbstractNamedEntity.java b/src/main/java/ru/javawebinar/topjava/model/AbstractNamedEntity.java index 0b32aac58..2054a3d3c 100644 --- a/src/main/java/ru/javawebinar/topjava/model/AbstractNamedEntity.java +++ b/src/main/java/ru/javawebinar/topjava/model/AbstractNamedEntity.java @@ -1,22 +1,9 @@ package ru.javawebinar.topjava.model; -import javax.persistence.Column; -import javax.persistence.MappedSuperclass; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Size; - - -@MappedSuperclass public abstract class AbstractNamedEntity extends AbstractBaseEntity { - @NotBlank - @Size(min = 2, max = 128) - @Column(name = "name", nullable = false) protected String name; - protected AbstractNamedEntity() { - } - protected AbstractNamedEntity(Integer id, String name) { super(id); this.name = name; diff --git a/src/main/java/ru/javawebinar/topjava/model/Meal.java b/src/main/java/ru/javawebinar/topjava/model/Meal.java index 22417097d..3abbee425 100644 --- a/src/main/java/ru/javawebinar/topjava/model/Meal.java +++ b/src/main/java/ru/javawebinar/topjava/model/Meal.java @@ -1,67 +1,37 @@ package ru.javawebinar.topjava.model; -import org.hibernate.annotations.OnDelete; -import org.hibernate.annotations.OnDeleteAction; -import org.hibernate.validator.constraints.Range; - -import javax.persistence.*; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -@NamedQueries({ - @NamedQuery(name = Meal.ALL_SORTED, query = "SELECT m FROM Meal m WHERE m.user.id=:userId ORDER BY m.dateTime DESC"), - @NamedQuery(name = Meal.DELETE, query = "DELETE FROM Meal m WHERE m.id=:id AND m.user.id=:userId"), - @NamedQuery(name = Meal.GET_BETWEEN, query = """ - SELECT m FROM Meal m - WHERE m.user.id=:userId AND m.dateTime >= :startDateTime AND m.dateTime < :endDateTime ORDER BY m.dateTime DESC - """), -// @NamedQuery(name = Meal.UPDATE, query = "UPDATE Meal m SET m.dateTime = :datetime, m.calories= :calories," + -// "m.description=:desc where m.id=:id and m.user.id=:userId") -}) -@Entity -@Table(name = "meal", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_id", "date_time"}, name = "meal_unique_user_datetime_idx")}) -public class Meal extends AbstractBaseEntity { - public static final String ALL_SORTED = "Meal.getAll"; - public static final String DELETE = "Meal.delete"; - public static final String GET_BETWEEN = "Meal.getBetween"; - - @Column(name = "date_time", nullable = false) - @NotNull - private LocalDateTime dateTime; - - @Column(name = "description", nullable = false) - @NotBlank - @Size(min = 2, max = 120) - private String description; - - @Column(name = "calories", nullable = false) - @Range(min = 10, max = 5000) - private int calories; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "user_id", nullable = false) - @OnDelete(action = OnDeleteAction.CASCADE) -// @NotNull - private User user; - - public Meal() { - } +public class Meal { + private Integer id; + + private final LocalDateTime dateTime; + + private final String description; + + private final int calories; public Meal(LocalDateTime dateTime, String description, int calories) { this(null, dateTime, description, calories); } public Meal(Integer id, LocalDateTime dateTime, String description, int calories) { - super(id); + this.id = id; this.dateTime = dateTime; this.description = description; this.calories = calories; } + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + public LocalDateTime getDateTime() { return dateTime; } @@ -82,24 +52,8 @@ public LocalTime getTime() { return dateTime.toLocalTime(); } - public void setDateTime(LocalDateTime dateTime) { - this.dateTime = dateTime; - } - - public void setDescription(String description) { - this.description = description; - } - - public void setCalories(int calories) { - this.calories = calories; - } - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; + public boolean isNew() { + return id == null; } @Override diff --git a/src/main/java/ru/javawebinar/topjava/to/MealTo.java b/src/main/java/ru/javawebinar/topjava/model/MealTo.java similarity index 96% rename from src/main/java/ru/javawebinar/topjava/to/MealTo.java rename to src/main/java/ru/javawebinar/topjava/model/MealTo.java index d14feae79..01b3a5fda 100644 --- a/src/main/java/ru/javawebinar/topjava/to/MealTo.java +++ b/src/main/java/ru/javawebinar/topjava/model/MealTo.java @@ -1,4 +1,4 @@ -package ru.javawebinar.topjava.to; +package ru.javawebinar.topjava.model; import java.time.LocalDateTime; diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java index 3b83fd506..b11abc469 100644 --- a/src/main/java/ru/javawebinar/topjava/model/User.java +++ b/src/main/java/ru/javawebinar/topjava/model/User.java @@ -1,96 +1,35 @@ package ru.javawebinar.topjava.model; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.*; -import org.hibernate.validator.constraints.Range; import org.springframework.util.CollectionUtils; -import javax.persistence.Entity; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OrderBy; -import javax.persistence.Table; -import javax.persistence.*; -import javax.validation.constraints.Email; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; import java.util.*; import static ru.javawebinar.topjava.util.MealsUtil.DEFAULT_CALORIES_PER_DAY; -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@NamedQueries({ - @NamedQuery(name = User.DELETE, query = "DELETE FROM User u WHERE u.id=:id"), - @NamedQuery(name = User.BY_EMAIL, query = "SELECT DISTINCT u FROM User u LEFT JOIN FETCH u.roles WHERE u.email=?1"), - @NamedQuery(name = User.ALL_SORTED, query = "SELECT u FROM User u ORDER BY u.name, u.email"), -}) -@Entity -@Table(name = "users") public class User extends AbstractNamedEntity { - public static final String DELETE = "User.delete"; - public static final String BY_EMAIL = "User.getByEmail"; - public static final String ALL_SORTED = "User.getAllSorted"; - - @Column(name = "email", nullable = false, unique = true) - @Email - @NotBlank - @Size(max = 128) private String email; - @Column(name = "password", nullable = false) - @NotBlank - @Size(min = 5, max = 128) private String password; - @Column(name = "enabled", nullable = false, columnDefinition = "bool default true") private boolean enabled = true; - @Column(name = "registered", nullable = false, columnDefinition = "timestamp default now()", updatable = false) - @NotNull private Date registered = new Date(); - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - @Enumerated(EnumType.STRING) - @CollectionTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), - uniqueConstraints = {@UniqueConstraint(columnNames = {"user_id", "role"}, name = "uk_user_role")}) - @Column(name = "role") - @ElementCollection(fetch = FetchType.EAGER) -// @Fetch(FetchMode.SUBSELECT) - @BatchSize(size = 200) - @JoinColumn - @OnDelete(action = OnDeleteAction.CASCADE) private Set roles; - @Column(name = "calories_per_day", nullable = false, columnDefinition = "int default 2000") - @Range(min = 10, max = 10000) private int caloriesPerDay = DEFAULT_CALORIES_PER_DAY; - @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")//, cascade = CascadeType.REMOVE, orphanRemoval = true) - @OrderBy("dateTime DESC") - @OnDelete(action = OnDeleteAction.CASCADE) //https://stackoverflow.com/a/44988100/548473 -// @JsonIgnore - private List meals; - - public User() { - } - - public User(User u) { - this(u.id, u.name, u.email, u.password, u.caloriesPerDay, u.enabled, u.registered, u.roles); - } - public User(Integer id, String name, String email, String password, Role... roles) { - this(id, name, email, password, DEFAULT_CALORIES_PER_DAY, true, new Date(), List.of(roles)); + this(id, name, email, password, DEFAULT_CALORIES_PER_DAY, true, Arrays.asList((roles))); } - public User(Integer id, String name, String email, String password, int caloriesPerDay, boolean enabled, Date registered, Collection roles) { + public User(Integer id, String name, String email, String password, int caloriesPerDay, boolean enabled, Collection roles) { super(id, name); this.email = email; this.password = password; this.caloriesPerDay = caloriesPerDay; this.enabled = enabled; - this.registered = registered; setRoles(roles); } @@ -142,10 +81,6 @@ 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/MealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/MealRepository.java index 1ad7f8d94..675cdbb1b 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/MealRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/MealRepository.java @@ -2,26 +2,19 @@ import ru.javawebinar.topjava.model.Meal; -import java.time.LocalDateTime; -import java.util.List; +import java.util.Collection; +// TODO add userId public interface MealRepository { // null if updated meal does not belong to userId - Meal save(Meal meal, int userId); + Meal save(Meal meal); // false if meal does not belong to userId - boolean delete(int id, int userId); + boolean delete(int id); // null if meal does not belong to userId - Meal get(int id, int userId); + Meal get(int id); // ORDERED dateTime desc - List getAll(int userId); - - // ORDERED dateTime desc - List getBetweenHalfOpen(LocalDateTime startDateTime, LocalDateTime endDateTime, int userId); - - default Meal getWithUser(int id, int userId) { - throw new UnsupportedOperationException(); - } + Collection getAll(); } diff --git a/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java index 9fecbddaa..138369789 100644 --- a/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java +++ b/src/main/java/ru/javawebinar/topjava/repository/UserRepository.java @@ -18,8 +18,4 @@ public interface UserRepository { User getByEmail(String email); List getAll(); - - default User getWithMeals(int id) { - throw new UnsupportedOperationException(); - } } \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/CrudMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/CrudMealRepository.java deleted file mode 100644 index 9aeef134f..000000000 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/CrudMealRepository.java +++ /dev/null @@ -1,29 +0,0 @@ -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.Meal; - -import java.time.LocalDateTime; -import java.util.List; - -@Transactional(readOnly = true) -public interface CrudMealRepository extends JpaRepository { - - @Modifying - @Transactional - @Query("DELETE FROM Meal m WHERE m.id=:id AND m.user.id=:userId") - int delete(@Param("id") int id, @Param("userId") int userId); - - @Query("SELECT m FROM Meal m WHERE m.user.id=:userId ORDER BY m.dateTime DESC") - List getAll(@Param("userId") int userId); - - @Query("SELECT m from Meal m WHERE m.user.id=:userId AND m.dateTime >= :startDate AND m.dateTime < :endDate ORDER BY m.dateTime DESC") - List getBetweenHalfOpen(@Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate, @Param("userId") int userId); - - @Query("SELECT m FROM Meal m JOIN FETCH m.user WHERE m.id = ?1 and m.user.id = ?2") - Meal getWithUser(int id, int userId); -} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/CrudUserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/CrudUserRepository.java deleted file mode 100644 index f3f362bdf..000000000 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/CrudUserRepository.java +++ /dev/null @@ -1,27 +0,0 @@ -package ru.javawebinar.topjava.repository.datajpa; - -import org.springframework.data.jpa.repository.*; -import org.springframework.data.repository.query.Param; -import org.springframework.transaction.annotation.Transactional; -import ru.javawebinar.topjava.model.User; - -import javax.persistence.QueryHint; - -@Transactional(readOnly = true) -public interface CrudUserRepository extends JpaRepository { - @Transactional - @Modifying - @Query("DELETE FROM User u WHERE u.id=:id") - int delete(@Param("id") int id); - - // https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#hql-distinct - @QueryHints({ - @QueryHint(name = org.hibernate.jpa.QueryHints.HINT_PASS_DISTINCT_THROUGH, value = "false") - }) - User getByEmail(String email); - - // https://stackoverflow.com/a/46013654/548473 - @EntityGraph(attributePaths = {"meals"}, type = EntityGraph.EntityGraphType.LOAD) - @Query("SELECT u FROM User u WHERE u.id=?1") - User getWithMeals(int id); -} diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaMealRepository.java deleted file mode 100644 index b5f4e3eeb..000000000 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaMealRepository.java +++ /dev/null @@ -1,58 +0,0 @@ -package ru.javawebinar.topjava.repository.datajpa; - -import org.springframework.stereotype.Repository; -import org.springframework.transaction.annotation.Transactional; -import ru.javawebinar.topjava.model.Meal; -import ru.javawebinar.topjava.repository.MealRepository; - -import java.time.LocalDateTime; -import java.util.List; - -@Repository -public class DataJpaMealRepository implements MealRepository { - - private final CrudMealRepository crudMealRepository; - private final CrudUserRepository crudUserRepository; - - public DataJpaMealRepository(CrudMealRepository crudMealRepository, CrudUserRepository crudUserRepository) { - this.crudMealRepository = crudMealRepository; - this.crudUserRepository = crudUserRepository; - } - - @Override - @Transactional - public Meal save(Meal meal, int userId) { - if (!meal.isNew() && get(meal.id(), userId) == null) { - return null; - } - meal.setUser(crudUserRepository.getReferenceById(userId)); - return crudMealRepository.save(meal); - } - - @Override - public boolean delete(int id, int userId) { - return crudMealRepository.delete(id, userId) != 0; - } - - @Override - public Meal get(int id, int userId) { - return crudMealRepository.findById(id) - .filter(meal -> meal.getUser().getId() == userId) - .orElse(null); - } - - @Override - public List getAll(int userId) { - return crudMealRepository.getAll(userId); - } - - @Override - public List getBetweenHalfOpen(LocalDateTime startDateTime, LocalDateTime endDateTime, int userId) { - return crudMealRepository.getBetweenHalfOpen(startDateTime, endDateTime, userId); - } - - @Override - public Meal getWithUser(int id, int userId) { - return crudMealRepository.getWithUser(id, userId); - } -} diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepository.java deleted file mode 100644 index 608c855e0..000000000 --- a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepository.java +++ /dev/null @@ -1,49 +0,0 @@ -package ru.javawebinar.topjava.repository.datajpa; - -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; - -@Repository -public class DataJpaUserRepository implements UserRepository { - private static final Sort SORT_NAME_EMAIL = Sort.by(Sort.Direction.ASC, "name", "email"); - - private final CrudUserRepository crudRepository; - - public DataJpaUserRepository(CrudUserRepository crudRepository) { - this.crudRepository = crudRepository; - } - - @Override - public User save(User user) { - return crudRepository.save(user); - } - - @Override - public boolean delete(int id) { - return crudRepository.delete(id) != 0; - } - - @Override - public User get(int id) { - return crudRepository.findById(id).orElse(null); - } - - @Override - public User getByEmail(String email) { - return crudRepository.getByEmail(email); - } - - @Override - public List getAll() { - return crudRepository.findAll(SORT_NAME_EMAIL); - } - - @Override - public User getWithMeals(int id) { - return crudRepository.getWithMeals(id); - } -} diff --git a/src/main/java/ru/javawebinar/topjava/repository/inmemory/InMemoryMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/inmemory/InMemoryMealRepository.java new file mode 100644 index 000000000..3c7c9ff94 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/inmemory/InMemoryMealRepository.java @@ -0,0 +1,46 @@ +package ru.javawebinar.topjava.repository.inmemory; + +import ru.javawebinar.topjava.model.Meal; +import ru.javawebinar.topjava.repository.MealRepository; +import ru.javawebinar.topjava.util.MealsUtil; + +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +public class InMemoryMealRepository implements MealRepository { + private final Map repository = new ConcurrentHashMap<>(); + private final AtomicInteger counter = new AtomicInteger(0); + + { + MealsUtil.meals.forEach(this::save); + } + + @Override + public Meal save(Meal meal) { + if (meal.isNew()) { + meal.setId(counter.incrementAndGet()); + repository.put(meal.getId(), meal); + return meal; + } + // handle case: update, but not present in storage + return repository.computeIfPresent(meal.getId(), (id, oldMeal) -> meal); + } + + @Override + public boolean delete(int id) { + return repository.remove(id) != null; + } + + @Override + public Meal get(int id) { + return repository.get(id); + } + + @Override + public Collection getAll() { + return repository.values(); + } +} + diff --git a/src/main/java/ru/javawebinar/topjava/repository/inmemory/InMemoryUserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/inmemory/InMemoryUserRepository.java new file mode 100644 index 000000000..e2f8a9b8b --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/repository/inmemory/InMemoryUserRepository.java @@ -0,0 +1,45 @@ +package ru.javawebinar.topjava.repository.inmemory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Repository; +import ru.javawebinar.topjava.model.User; +import ru.javawebinar.topjava.repository.UserRepository; + +import java.util.Collections; +import java.util.List; + +@Repository +public class InMemoryUserRepository implements UserRepository { + private static final Logger log = LoggerFactory.getLogger(InMemoryUserRepository.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/repository/jdbc/JdbcMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcMealRepository.java deleted file mode 100644 index 775d314ed..000000000 --- a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcMealRepository.java +++ /dev/null @@ -1,91 +0,0 @@ -package ru.javawebinar.topjava.repository.jdbc; - -import org.springframework.dao.support.DataAccessUtils; -import org.springframework.jdbc.core.BeanPropertyRowMapper; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; -import org.springframework.jdbc.core.simple.SimpleJdbcInsert; -import org.springframework.stereotype.Repository; -import org.springframework.transaction.annotation.Transactional; -import ru.javawebinar.topjava.model.Meal; -import ru.javawebinar.topjava.repository.MealRepository; -import ru.javawebinar.topjava.util.ValidationUtil; - -import java.time.LocalDateTime; -import java.util.List; - -@Repository -@Transactional(readOnly = true) -public class JdbcMealRepository implements MealRepository { - - private static final RowMapper ROW_MAPPER = BeanPropertyRowMapper.newInstance(Meal.class); - - private final JdbcTemplate jdbcTemplate; - - private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; - - private final SimpleJdbcInsert insertMeal; - - public JdbcMealRepository(JdbcTemplate jdbcTemplate, NamedParameterJdbcTemplate namedParameterJdbcTemplate) { - this.insertMeal = new SimpleJdbcInsert(jdbcTemplate) - .withTableName("meal") - .usingGeneratedKeyColumns("id"); - - this.jdbcTemplate = jdbcTemplate; - this.namedParameterJdbcTemplate = namedParameterJdbcTemplate; - } - - @Override - @Transactional - public Meal save(Meal meal, int userId) { - ValidationUtil.validate(meal); - - MapSqlParameterSource map = new MapSqlParameterSource() - .addValue("id", meal.getId()) - .addValue("description", meal.getDescription()) - .addValue("calories", meal.getCalories()) - .addValue("date_time", meal.getDateTime()) - .addValue("user_id", userId); - - if (meal.isNew()) { - Number newId = insertMeal.executeAndReturnKey(map); - meal.setId(newId.intValue()); - } else { - if (namedParameterJdbcTemplate.update("" + - "UPDATE meal " + - " SET description=:description, calories=:calories, date_time=:date_time " + - " WHERE id=:id AND user_id=:user_id", map) == 0) { - return null; - } - } - return meal; - } - - @Override - @Transactional - public boolean delete(int id, int userId) { - return jdbcTemplate.update("DELETE FROM meal WHERE id=? AND user_id=?", id, userId) != 0; - } - - @Override - public Meal get(int id, int userId) { - List meals = jdbcTemplate.query( - "SELECT * FROM meal WHERE id = ? AND user_id = ?", ROW_MAPPER, id, userId); - return DataAccessUtils.singleResult(meals); - } - - @Override - public List getAll(int userId) { - return jdbcTemplate.query( - "SELECT * FROM meal WHERE user_id=? ORDER BY date_time DESC", ROW_MAPPER, userId); - } - - @Override - public List getBetweenHalfOpen(LocalDateTime startDateTime, LocalDateTime endDateTime, int userId) { - return jdbcTemplate.query( - "SELECT * FROM meal WHERE user_id=? AND date_time >= ? AND date_time < ? ORDER BY date_time DESC", - ROW_MAPPER, userId, startDateTime, endDateTime); - } -} diff --git a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepository.java deleted file mode 100644 index ca5dcc185..000000000 --- a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcUserRepository.java +++ /dev/null @@ -1,123 +0,0 @@ -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.BeanPropertySqlParameterSource; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; -import org.springframework.jdbc.core.simple.SimpleJdbcInsert; -import org.springframework.stereotype.Repository; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; -import ru.javawebinar.topjava.model.Role; -import ru.javawebinar.topjava.model.User; -import ru.javawebinar.topjava.repository.UserRepository; -import ru.javawebinar.topjava.util.ValidationUtil; - -import java.util.*; - -@Repository -@Transactional(readOnly = true) -public class JdbcUserRepository implements UserRepository { - - private static final BeanPropertyRowMapper ROW_MAPPER = BeanPropertyRowMapper.newInstance(User.class); - - private final JdbcTemplate jdbcTemplate; - - private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; - - private final SimpleJdbcInsert insertUser; - - @Autowired - public JdbcUserRepository(JdbcTemplate jdbcTemplate, NamedParameterJdbcTemplate namedParameterJdbcTemplate) { - this.insertUser = new SimpleJdbcInsert(jdbcTemplate) - .withTableName("users") - .usingGeneratedKeyColumns("id"); - - this.jdbcTemplate = jdbcTemplate; - this.namedParameterJdbcTemplate = namedParameterJdbcTemplate; - } - - @Override - @Transactional - public User save(User user) { - ValidationUtil.validate(user); - - BeanPropertySqlParameterSource parameterSource = new BeanPropertySqlParameterSource(user); - - if (user.isNew()) { - Number newKey = insertUser.executeAndReturnKey(parameterSource); - user.setId(newKey.intValue()); - insertRoles(user); - } else { - if (namedParameterJdbcTemplate.update(""" - UPDATE users SET name=:name, email=:email, password=:password, - registered=:registered, enabled=:enabled, calories_per_day=:caloriesPerDay WHERE id=:id - """, parameterSource) == 0) { - return null; - } - // Simplest implementation. - // More complicated : get user roles from DB and compare them with user.roles (assume that roles are changed rarely). - // If roles are changed, calculate difference in java and delete/insert them. - deleteRoles(user); - insertRoles(user); - } - return user; - } - - @Override - @Transactional - public boolean delete(int id) { - return jdbcTemplate.update("DELETE FROM users WHERE id=?", id) != 0; - } - - @Override - public User get(int id) { - List users = jdbcTemplate.query("SELECT * FROM users WHERE id=?", ROW_MAPPER, id); - return setRoles(DataAccessUtils.singleResult(users)); - } - - @Override - public User getByEmail(String email) { -// return jdbcTemplate.queryForObject("SELECT * FROM users WHERE email=?", ROW_MAPPER, email); - List users = jdbcTemplate.query("SELECT * FROM users WHERE email=?", ROW_MAPPER, email); - return setRoles(DataAccessUtils.singleResult(users)); - } - - @Override - public List getAll() { - List users = jdbcTemplate.query("SELECT * FROM users ORDER BY name, email", ROW_MAPPER); - - Map> map = new HashMap<>(); - jdbcTemplate.query("SELECT * FROM user_role", rs -> { - map.computeIfAbsent(rs.getInt("user_id"), userId -> EnumSet.noneOf(Role.class)) - .add(Role.valueOf(rs.getString("role"))); - }); - users.forEach(u -> u.setRoles(map.get(u.getId()))); - return users; - } - - private void insertRoles(User u) { - Set roles = u.getRoles(); - if (!CollectionUtils.isEmpty(roles)) { - jdbcTemplate.batchUpdate("INSERT INTO user_role (user_id, role) VALUES (?, ?)", roles, roles.size(), - (ps, role) -> { - ps.setInt(1, u.id()); - ps.setString(2, role.name()); - }); - } - } - - private void deleteRoles(User u) { - jdbcTemplate.update("DELETE FROM user_role WHERE user_id=?", u.getId()); - } - - private User setRoles(User u) { - if (u != null) { - List roles = jdbcTemplate.queryForList("SELECT role FROM user_role WHERE user_id=?", Role.class, u.getId()); - u.setRoles(roles); - } - return u; - } -} diff --git a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaMealRepository.java deleted file mode 100644 index 6df9fd99f..000000000 --- a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaMealRepository.java +++ /dev/null @@ -1,62 +0,0 @@ -package ru.javawebinar.topjava.repository.jpa; - -import org.springframework.stereotype.Repository; -import org.springframework.transaction.annotation.Transactional; -import ru.javawebinar.topjava.model.Meal; -import ru.javawebinar.topjava.model.User; -import ru.javawebinar.topjava.repository.MealRepository; - -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import java.time.LocalDateTime; -import java.util.List; - -@Repository -@Transactional(readOnly = true) -public class JpaMealRepository implements MealRepository { - - @PersistenceContext - private EntityManager em; - - @Override - @Transactional - public Meal save(Meal meal, int userId) { - meal.setUser(em.getReference(User.class, userId)); - if (meal.isNew()) { - em.persist(meal); - return meal; - } - return get(meal.id(), userId) == null ? null : em.merge(meal); - } - - @Override - @Transactional - public boolean delete(int id, int userId) { - return em.createNamedQuery(Meal.DELETE) - .setParameter("id", id) - .setParameter("userId", userId) - .executeUpdate() != 0; - } - - @Override - public Meal get(int id, int userId) { - Meal meal = em.find(Meal.class, id); - return meal != null && meal.getUser().getId() == userId ? meal : null; - } - - @Override - public List getAll(int userId) { - return em.createNamedQuery(Meal.ALL_SORTED, Meal.class) - .setParameter("userId", userId) - .getResultList(); - } - - @Override - public List getBetweenHalfOpen(LocalDateTime startDateTime, LocalDateTime endDateTime, int userId) { - return em.createNamedQuery(Meal.GET_BETWEEN, Meal.class) - .setParameter("userId", userId) - .setParameter("startDateTime", startDateTime) - .setParameter("endDateTime", endDateTime) - .getResultList(); - } -} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepository.java deleted file mode 100644 index 22fa8f4e3..000000000 --- a/src/main/java/ru/javawebinar/topjava/repository/jpa/JpaUserRepository.java +++ /dev/null @@ -1,75 +0,0 @@ -package ru.javawebinar.topjava.repository.jpa; - -import org.hibernate.jpa.QueryHints; -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.repository.UserRepository; - -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import java.util.List; - -@Repository -@Transactional(readOnly = true) -public class JpaUserRepository implements UserRepository { - -/* - @Autowired - private SessionFactory sessionFactory; - - private Session openSession() { - return sessionFactory.getCurrentSession(); - } -*/ - - @PersistenceContext - private EntityManager em; - - @Override - @Transactional - 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 - @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"); - return query.setParameter("id", id).executeUpdate() != 0; -*/ - return em.createNamedQuery(User.DELETE) - .setParameter("id", id) - .executeUpdate() != 0; - } - - @Override - public User getByEmail(String email) { - List users = em.createNamedQuery(User.BY_EMAIL, User.class) - .setParameter(1, email) - .setHint(QueryHints.HINT_PASS_DISTINCT_THROUGH, false) - .getResultList(); - return DataAccessUtils.singleResult(users); - } - - @Override - public List getAll() { - return em.createNamedQuery(User.ALL_SORTED, User.class) - .getResultList(); - } -} diff --git a/src/main/java/ru/javawebinar/topjava/service/MealService.java b/src/main/java/ru/javawebinar/topjava/service/MealService.java index 5f759a11a..0dc4a43c3 100644 --- a/src/main/java/ru/javawebinar/topjava/service/MealService.java +++ b/src/main/java/ru/javawebinar/topjava/service/MealService.java @@ -1,54 +1,9 @@ package ru.javawebinar.topjava.service; -import org.springframework.lang.Nullable; -import org.springframework.stereotype.Service; -import org.springframework.util.Assert; -import ru.javawebinar.topjava.model.Meal; import ru.javawebinar.topjava.repository.MealRepository; -import java.time.LocalDate; -import java.util.List; - -import static ru.javawebinar.topjava.util.DateTimeUtil.atStartOfDayOrMin; -import static ru.javawebinar.topjava.util.DateTimeUtil.atStartOfNextDayOrMax; -import static ru.javawebinar.topjava.util.ValidationUtil.checkNotFound; - -@Service public class MealService { - private final MealRepository repository; - - public MealService(MealRepository repository) { - this.repository = repository; - } - - public Meal get(int id, int userId) { - return checkNotFound(repository.get(id, userId), id); - } - - public void delete(int id, int userId) { - checkNotFound(repository.delete(id, userId), id); - } - - public List getBetweenInclusive(@Nullable LocalDate startDate, @Nullable LocalDate endDate, int userId) { - return repository.getBetweenHalfOpen(atStartOfDayOrMin(startDate), atStartOfNextDayOrMax(endDate), userId); - } - - public List getAll(int userId) { - return repository.getAll(userId); - } - - public void update(Meal meal, int userId) { - Assert.notNull(meal, "meal must not be null"); - checkNotFound(repository.save(meal, userId), meal.id()); - } - - public Meal create(Meal meal, int userId) { - Assert.notNull(meal, "meal must not be null"); - return repository.save(meal, userId); - } + private MealRepository repository; - public Meal getWithUser(int id, int userId) { - return checkNotFound(repository.getWithUser(id, userId), id); - } } \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/service/UserService.java b/src/main/java/ru/javawebinar/topjava/service/UserService.java index 88b790359..8fbe8dc06 100644 --- a/src/main/java/ru/javawebinar/topjava/service/UserService.java +++ b/src/main/java/ru/javawebinar/topjava/service/UserService.java @@ -1,15 +1,13 @@ package ru.javawebinar.topjava.service; -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; -import org.springframework.util.Assert; import ru.javawebinar.topjava.model.User; import ru.javawebinar.topjava.repository.UserRepository; import java.util.List; import static ru.javawebinar.topjava.util.ValidationUtil.checkNotFound; +import static ru.javawebinar.topjava.util.ValidationUtil.checkNotFoundWithId; @Service public class UserService { @@ -20,38 +18,27 @@ public UserService(UserRepository repository) { this.repository = repository; } - @CacheEvict(value = "users", allEntries = true) public User create(User user) { - Assert.notNull(user, "user must not be null"); return repository.save(user); } - @CacheEvict(value = "users", allEntries = true) public void delete(int id) { - checkNotFound(repository.delete(id), id); + checkNotFoundWithId(repository.delete(id), id); } public User get(int id) { - return checkNotFound(repository.get(id), id); + return checkNotFoundWithId(repository.get(id), id); } public User getByEmail(String email) { - Assert.notNull(email, "email must not be null"); return checkNotFound(repository.getByEmail(email), "email=" + email); } - @Cacheable("users") public List getAll() { return repository.getAll(); } - @CacheEvict(value = "users", allEntries = true) public void update(User user) { - Assert.notNull(user, "user must not be null"); - checkNotFound(repository.save(user), user.id()); - } - - public User getWithMeals(int id) { - return checkNotFound(repository.getWithMeals(id), id); + checkNotFoundWithId(repository.save(user), user.getId()); } } \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/util/DateTimeUtil.java b/src/main/java/ru/javawebinar/topjava/util/DateTimeUtil.java index 7c1ac9fec..3f23f83fd 100644 --- a/src/main/java/ru/javawebinar/topjava/util/DateTimeUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/DateTimeUtil.java @@ -1,9 +1,5 @@ package ru.javawebinar.topjava.util; -import org.springframework.lang.Nullable; -import org.springframework.util.StringUtils; - -import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; @@ -11,32 +7,12 @@ public class DateTimeUtil { private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); - // DB doesn't support LocalDate.MIN/MAX - private static final LocalDateTime MIN_DATE = LocalDateTime.of(1, 1, 1, 0, 0); - private static final LocalDateTime MAX_DATE = LocalDateTime.of(3000, 1, 1, 0, 0); - - private DateTimeUtil() { - } - - public static LocalDateTime atStartOfDayOrMin(LocalDate localDate) { - return localDate != null ? localDate.atStartOfDay() : MIN_DATE; - } - - public static LocalDateTime atStartOfNextDayOrMax(LocalDate localDate) { - return localDate != null ? localDate.plusDays(1).atStartOfDay() : MAX_DATE; + public static boolean isBetweenHalfOpen(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_TIME_FORMATTER); } - - public static @Nullable - LocalDate parseLocalDate(@Nullable String str) { - return StringUtils.hasLength(str) ? LocalDate.parse(str) : null; - } - - public static @Nullable - LocalTime parseLocalTime(@Nullable String str) { - return StringUtils.hasLength(str) ? LocalTime.parse(str) : null; - } } + diff --git a/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java b/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java index 658671b9d..8d940a63e 100644 --- a/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/MealsUtil.java @@ -1,10 +1,13 @@ package ru.javawebinar.topjava.util; import ru.javawebinar.topjava.model.Meal; -import ru.javawebinar.topjava.to.MealTo; +import ru.javawebinar.topjava.model.MealTo; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.Month; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; @@ -14,15 +17,22 @@ public class MealsUtil { public static final int DEFAULT_CALORIES_PER_DAY = 2000; - private MealsUtil() { - } + public static final List meals = Arrays.asList( + new Meal(LocalDateTime.of(2020, Month.JANUARY, 30, 10, 0), "Завтрак", 500), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 30, 13, 0), "Обед", 1000), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 30, 20, 0), "Ужин", 500), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 0, 0), "Еда на граничное значение", 100), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 10, 0), "Завтрак", 1000), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 13, 0), "Обед", 500), + new Meal(LocalDateTime.of(2020, Month.JANUARY, 31, 20, 0), "Ужин", 410) + ); public static List getTos(Collection meals, int caloriesPerDay) { return filterByPredicate(meals, caloriesPerDay, meal -> true); } public static List getFilteredTos(Collection meals, int caloriesPerDay, LocalTime startTime, LocalTime endTime) { - return filterByPredicate(meals, caloriesPerDay, meal -> Util.isBetweenHalfOpen(meal.getTime(), startTime, endTime)); + return filterByPredicate(meals, caloriesPerDay, meal -> DateTimeUtil.isBetweenHalfOpen(meal.getTime(), startTime, endTime)); } private static List filterByPredicate(Collection meals, int caloriesPerDay, Predicate filter) { @@ -35,7 +45,7 @@ private static List filterByPredicate(Collection meals, int calori return meals.stream() .filter(filter) .map(meal -> createTo(meal, caloriesSumByDate.get(meal.getDate()) > caloriesPerDay)) - .toList(); + .collect(Collectors.toList()); } private static MealTo createTo(Meal meal, boolean excess) { diff --git a/src/main/java/ru/javawebinar/topjava/util/Util.java b/src/main/java/ru/javawebinar/topjava/util/Util.java deleted file mode 100644 index 9a083383d..000000000 --- a/src/main/java/ru/javawebinar/topjava/util/Util.java +++ /dev/null @@ -1,13 +0,0 @@ -package ru.javawebinar.topjava.util; - -import org.springframework.lang.Nullable; - -public class Util { - - private Util() { - } - - public static > boolean isBetweenHalfOpen(T value, @Nullable T start, @Nullable T end) { - return (start == null || value.compareTo(start) >= 0) && (end == null || value.compareTo(end) < 0); - } -} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/util/ValidationUtil.java b/src/main/java/ru/javawebinar/topjava/util/ValidationUtil.java index 52ba3b57e..971eb9c0c 100644 --- a/src/main/java/ru/javawebinar/topjava/util/ValidationUtil.java +++ b/src/main/java/ru/javawebinar/topjava/util/ValidationUtil.java @@ -1,39 +1,17 @@ package ru.javawebinar.topjava.util; + import ru.javawebinar.topjava.model.AbstractBaseEntity; import ru.javawebinar.topjava.util.exception.NotFoundException; -import javax.validation.*; -import java.util.Set; - public class ValidationUtil { - private static final Validator validator; - - static { - // From Javadoc: implementations are thread-safe and instances are typically cached and reused. - ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); - // From Javadoc: implementations of this interface must be thread-safe - validator = factory.getValidator(); - } - - private ValidationUtil() { - } - - public static void validate(T bean) { - // https://alexkosarev.name/2018/07/30/bean-validation-api/ - Set> violations = validator.validate(bean); - if (!violations.isEmpty()) { - throw new ConstraintViolationException(violations); - } - } - - public static T checkNotFound(T object, int id) { - checkNotFound(object != null, id); + public static T checkNotFoundWithId(T object, int id) { + checkNotFoundWithId(object != null, id); return object; } - public static void checkNotFound(boolean found, int id) { + public static void checkNotFoundWithId(boolean found, int id) { checkNotFound(found, "id=" + id); } @@ -48,7 +26,7 @@ public static void checkNotFound(boolean found, String msg) { } } - public static void checkIsNew(AbstractBaseEntity entity) { + public static void checkNew(AbstractBaseEntity entity) { if (!entity.isNew()) { throw new IllegalArgumentException(entity + " must be new (id=null)"); } @@ -58,7 +36,7 @@ public static void assureIdConsistent(AbstractBaseEntity entity, int id) { // conservative when you reply, but accept liberally (http://stackoverflow.com/a/32728226/548473) if (entity.isNew()) { entity.setId(id); - } else if (entity.id() != id) { + } else if (entity.getId() != id) { throw new IllegalArgumentException(entity + " must be with id=" + id); } } 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 000000000..5017a6287 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java @@ -0,0 +1,77 @@ +package ru.javawebinar.topjava.web; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.javawebinar.topjava.model.Meal; +import ru.javawebinar.topjava.repository.MealRepository; +import ru.javawebinar.topjava.repository.inmemory.InMemoryMealRepository; +import ru.javawebinar.topjava.util.MealsUtil; + +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.time.temporal.ChronoUnit; +import java.util.Objects; + +public class MealServlet extends HttpServlet { + private static final Logger log = LoggerFactory.getLogger(MealServlet.class); + + private MealRepository repository; + + @Override + public void init() { + repository = new InMemoryMealRepository(); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + request.setCharacterEncoding("UTF-8"); + String id = request.getParameter("id"); + + Meal meal = new Meal(id.isEmpty() ? null : Integer.valueOf(id), + LocalDateTime.parse(request.getParameter("dateTime")), + request.getParameter("description"), + Integer.parseInt(request.getParameter("calories"))); + + log.info(meal.isNew() ? "Create {}" : "Update {}", meal); + repository.save(meal); + response.sendRedirect("meals"); + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + String action = request.getParameter("action"); + + switch (action == null ? "all" : action) { + case "delete": + int id = getId(request); + log.info("Delete id={}", id); + repository.delete(id); + response.sendRedirect("meals"); + break; + case "create": + case "update": + final Meal meal = "create".equals(action) ? + new Meal(LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES), "", 1000) : + repository.get(getId(request)); + request.setAttribute("meal", meal); + request.getRequestDispatcher("/mealForm.jsp").forward(request, response); + break; + case "all": + default: + log.info("getAll"); + request.setAttribute("meals", + MealsUtil.getTos(repository.getAll(), MealsUtil.DEFAULT_CALORIES_PER_DAY)); + request.getRequestDispatcher("/meals.jsp").forward(request, response); + break; + } + } + + private int getId(HttpServletRequest request) { + String paramId = Objects.requireNonNull(request.getParameter("id")); + return Integer.parseInt(paramId); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/web/RootController.java b/src/main/java/ru/javawebinar/topjava/web/RootController.java deleted file mode 100644 index 921462ca9..000000000 --- a/src/main/java/ru/javawebinar/topjava/web/RootController.java +++ /dev/null @@ -1,54 +0,0 @@ -package ru.javawebinar.topjava.web; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import ru.javawebinar.topjava.service.MealService; -import ru.javawebinar.topjava.service.UserService; -import ru.javawebinar.topjava.util.MealsUtil; - -import javax.servlet.http.HttpServletRequest; - -@Controller -public class RootController { - private static final Logger log = LoggerFactory.getLogger(RootController.class); - - @Autowired - private UserService userService; - - @Autowired - private MealService mealService; - - @GetMapping("/") - public String root() { - log.info("root"); - return "index"; - } - - @GetMapping("/users") - public String getUsers(Model model) { - log.info("users"); - model.addAttribute("users", userService.getAll()); - return "users"; - } - - @PostMapping("/users") - public String setUser(HttpServletRequest request) { - int userId = Integer.parseInt(request.getParameter("userId")); - log.info("setUser {}", userId); - SecurityUtil.setAuthUserId(userId); - return "redirect:meals"; - } - - @GetMapping("/meals") - public String getMeals(Model model) { - log.info("meals"); - model.addAttribute("meals", - MealsUtil.getTos(mealService.getAll(SecurityUtil.authUserId()), SecurityUtil.authUserCaloriesPerDay())); - return "meals"; - } -} diff --git a/src/main/java/ru/javawebinar/topjava/web/SecurityUtil.java b/src/main/java/ru/javawebinar/topjava/web/SecurityUtil.java index 4bad5863e..e78a4b284 100644 --- a/src/main/java/ru/javawebinar/topjava/web/SecurityUtil.java +++ b/src/main/java/ru/javawebinar/topjava/web/SecurityUtil.java @@ -1,22 +1,11 @@ package ru.javawebinar.topjava.web; -import ru.javawebinar.topjava.model.AbstractBaseEntity; - import static ru.javawebinar.topjava.util.MealsUtil.DEFAULT_CALORIES_PER_DAY; public class SecurityUtil { - private static int id = AbstractBaseEntity.START_SEQ; - - private SecurityUtil() { - } - public static int authUserId() { - return id; - } - - public static void setAuthUserId(int id) { - SecurityUtil.id = id; + return 1; } public static int authUserCaloriesPerDay() { 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 000000000..f6cf12e69 --- /dev/null +++ b/src/main/java/ru/javawebinar/topjava/web/UserServlet.java @@ -0,0 +1,21 @@ +package ru.javawebinar.topjava.web; + +import org.slf4j.Logger; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +import static org.slf4j.LoggerFactory.getLogger; + +public class UserServlet extends HttpServlet { + private static final Logger log = getLogger(UserServlet.class); + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + log.debug("forward to users"); + request.getRequestDispatcher("/users.jsp").forward(request, response); + } +} diff --git a/src/main/java/ru/javawebinar/topjava/web/json/JacksonObjectMapper.java b/src/main/java/ru/javawebinar/topjava/web/json/JacksonObjectMapper.java deleted file mode 100644 index 8237df93b..000000000 --- a/src/main/java/ru/javawebinar/topjava/web/json/JacksonObjectMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package ru.javawebinar.topjava.web.json; - -import com.fasterxml.jackson.annotation.JsonAutoDetect; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.PropertyAccessor; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - -/** - *

- * Handling Hibernate lazy-loading - * - * @link https://github.com/FasterXML/jackson - * @link https://github.com/FasterXML/jackson-datatype-hibernate - * @link https://github.com/FasterXML/jackson-docs/wiki/JacksonHowToCustomSerializers - */ -public class JacksonObjectMapper extends ObjectMapper { - - private static final ObjectMapper MAPPER = new JacksonObjectMapper(); - - private JacksonObjectMapper() { - registerModule(new Hibernate5Module()); - - registerModule(new JavaTimeModule()); - configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); - - setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); - setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); - setSerializationInclusion(JsonInclude.Include.NON_NULL); - } - - public static ObjectMapper getMapper() { - return MAPPER; - } -} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/web/json/JsonUtil.java b/src/main/java/ru/javawebinar/topjava/web/json/JsonUtil.java deleted file mode 100644 index fda04590d..000000000 --- a/src/main/java/ru/javawebinar/topjava/web/json/JsonUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package ru.javawebinar.topjava.web.json; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectReader; - -import java.io.IOException; -import java.util.List; - -import static ru.javawebinar.topjava.web.json.JacksonObjectMapper.getMapper; - -public class JsonUtil { - - public static List readValues(String json, Class clazz) { - ObjectReader reader = getMapper().readerFor(clazz); - try { - return reader.readValues(json).readAll(); - } catch (IOException e) { - throw new IllegalArgumentException("Invalid read array from JSON:\n'" + json + "'", e); - } - } - - public static T readValue(String json, Class clazz) { - try { - return getMapper().readValue(json, clazz); - } catch (IOException e) { - throw new IllegalArgumentException("Invalid read from JSON:\n'" + json + "'", e); - } - } - - public static String writeValue(T obj) { - try { - return getMapper().writeValueAsString(obj); - } catch (JsonProcessingException e) { - throw new IllegalStateException("Invalid write to JSON:\n'" + obj + "'", e); - } - } -} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/web/meal/AbstractMealController.java b/src/main/java/ru/javawebinar/topjava/web/meal/AbstractMealController.java deleted file mode 100644 index 1931f998f..000000000 --- a/src/main/java/ru/javawebinar/topjava/web/meal/AbstractMealController.java +++ /dev/null @@ -1,72 +0,0 @@ -package ru.javawebinar.topjava.web.meal; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.lang.Nullable; -import ru.javawebinar.topjava.model.Meal; -import ru.javawebinar.topjava.service.MealService; -import ru.javawebinar.topjava.to.MealTo; -import ru.javawebinar.topjava.util.MealsUtil; -import ru.javawebinar.topjava.web.SecurityUtil; - -import java.time.LocalDate; -import java.time.LocalTime; -import java.util.List; - -import static ru.javawebinar.topjava.util.ValidationUtil.assureIdConsistent; -import static ru.javawebinar.topjava.util.ValidationUtil.checkIsNew; - -public abstract class AbstractMealController { - private final Logger log = LoggerFactory.getLogger(getClass()); - - @Autowired - private MealService service; - - public Meal get(int id) { - int userId = SecurityUtil.authUserId(); - log.info("get meal {} for user {}", id, userId); - return service.get(id, userId); - } - - public void delete(int id) { - int userId = SecurityUtil.authUserId(); - log.info("delete meal {} for user {}", id, userId); - service.delete(id, userId); - } - - public List getAll() { - int userId = SecurityUtil.authUserId(); - log.info("getAll for user {}", userId); - return MealsUtil.getTos(service.getAll(userId), SecurityUtil.authUserCaloriesPerDay()); - } - - public Meal create(Meal meal) { - int userId = SecurityUtil.authUserId(); - log.info("create {} for user {}", meal, userId); - checkIsNew(meal); - return service.create(meal, userId); - } - - public void update(Meal meal, int id) { - int userId = SecurityUtil.authUserId(); - log.info("update {} for user {}", meal, userId); - assureIdConsistent(meal, id); - service.update(meal, userId); - } - - /** - *

    Filter separately - *
  1. by date
  2. - *
  3. by time for every date
  4. - *
- */ - public List getBetween(@Nullable LocalDate startDate, @Nullable LocalTime startTime, - @Nullable LocalDate endDate, @Nullable LocalTime endTime) { - int userId = SecurityUtil.authUserId(); - log.info("getBetween dates({} - {}) time({} - {}) for user {}", startDate, endDate, startTime, endTime, userId); - - List mealsDateFiltered = service.getBetweenInclusive(startDate, endDate, userId); - return MealsUtil.getFilteredTos(mealsDateFiltered, SecurityUtil.authUserCaloriesPerDay(), startTime, endTime); - } -} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/web/meal/JspMealController.java b/src/main/java/ru/javawebinar/topjava/web/meal/JspMealController.java deleted file mode 100644 index 7e800f683..000000000 --- a/src/main/java/ru/javawebinar/topjava/web/meal/JspMealController.java +++ /dev/null @@ -1,70 +0,0 @@ -package ru.javawebinar.topjava.web.meal; - -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import ru.javawebinar.topjava.model.Meal; - -import javax.servlet.http.HttpServletRequest; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.temporal.ChronoUnit; -import java.util.Objects; - -import static ru.javawebinar.topjava.util.DateTimeUtil.parseLocalDate; -import static ru.javawebinar.topjava.util.DateTimeUtil.parseLocalTime; - -@Controller -@RequestMapping("/meals") -public class JspMealController extends AbstractMealController { - - @GetMapping("/delete") - public String delete(HttpServletRequest request) { - super.delete(getId(request)); - return "redirect:/meals"; - } - - @GetMapping("/update") - public String update(HttpServletRequest request, Model model) { - model.addAttribute("meal", super.get(getId(request))); - return "mealForm"; - } - - @GetMapping("/create") - public String create(Model model) { - model.addAttribute("meal", new Meal(LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES), "", 1000)); - return "mealForm"; - } - - @PostMapping - public String updateOrCreate(HttpServletRequest request) { - Meal meal = new Meal(LocalDateTime.parse(request.getParameter("dateTime")), - request.getParameter("description"), - Integer.parseInt(request.getParameter("calories"))); - - if (request.getParameter("id").isEmpty()) { - super.create(meal); - } else { - super.update(meal, getId(request)); - } - return "redirect:/meals"; - } - - @GetMapping("/filter") - public String getBetween(HttpServletRequest request, Model model) { - LocalDate startDate = parseLocalDate(request.getParameter("startDate")); - LocalDate endDate = parseLocalDate(request.getParameter("endDate")); - LocalTime startTime = parseLocalTime(request.getParameter("startTime")); - LocalTime endTime = parseLocalTime(request.getParameter("endTime")); - model.addAttribute("meals", super.getBetween(startDate, startTime, endDate, endTime)); - return "meals"; - } - - private int getId(HttpServletRequest request) { - String paramId = Objects.requireNonNull(request.getParameter("id")); - return Integer.parseInt(paramId); - } -} diff --git a/src/main/java/ru/javawebinar/topjava/web/meal/MealRestController.java b/src/main/java/ru/javawebinar/topjava/web/meal/MealRestController.java index 7f0a3d089..ab4e8ea8b 100644 --- a/src/main/java/ru/javawebinar/topjava/web/meal/MealRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/meal/MealRestController.java @@ -1,7 +1,8 @@ package ru.javawebinar.topjava.web.meal; -import org.springframework.stereotype.Controller; +import ru.javawebinar.topjava.service.MealService; -@Controller -public class MealRestController extends AbstractMealController { -} +public class MealRestController { + private MealService service; + +} \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java b/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java index f9e6441ba..0000f1c1e 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/AbstractUserController.java @@ -9,7 +9,7 @@ import java.util.List; import static ru.javawebinar.topjava.util.ValidationUtil.assureIdConsistent; -import static ru.javawebinar.topjava.util.ValidationUtil.checkIsNew; +import static ru.javawebinar.topjava.util.ValidationUtil.checkNew; public abstract class AbstractUserController { protected final Logger log = LoggerFactory.getLogger(getClass()); @@ -29,7 +29,7 @@ public User get(int id) { public User create(User user) { log.info("create {}", user); - checkIsNew(user); + checkNew(user); return service.create(user); } 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 095ced3b0..b37a8ed6c 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/AdminRestController.java @@ -1,59 +1,40 @@ package ru.javawebinar.topjava.web.user; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.support.ServletUriComponentsBuilder; +import org.springframework.stereotype.Controller; import ru.javawebinar.topjava.model.User; -import java.net.URI; import java.util.List; -@RestController -@RequestMapping(value = AdminRestController.REST_URL, produces = MediaType.APPLICATION_JSON_VALUE) +@Controller public class AdminRestController extends AbstractUserController { - static final String REST_URL = "/rest/admin/users"; - @Override - @GetMapping public List getAll() { return super.getAll(); } @Override - @GetMapping("/{id}") - public User get(@PathVariable int id) { + public User get(int id) { return super.get(id); } - @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity createWithLocation(@RequestBody User user) { - User created = super.create(user); - URI uriOfNewResource = ServletUriComponentsBuilder.fromCurrentContextPath() - .path(REST_URL + "/{id}") - .buildAndExpand(created.getId()).toUri(); - return ResponseEntity.created(uriOfNewResource).body(created); + @Override + public User create(User user) { + return super.create(user); } @Override - @DeleteMapping("/{id}") - @ResponseStatus(HttpStatus.NO_CONTENT) - public void delete(@PathVariable int id) { + public void delete(int id) { super.delete(id); } @Override - @PutMapping(value = "/{id}", consumes = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.NO_CONTENT) - public void update(@RequestBody User user, @PathVariable int id) { + public void update(User user, int id) { super.update(user, id); } @Override - @GetMapping("/by-email") - public User getByMail(@RequestParam String email) { + public User getByMail(String email) { return super.getByMail(email); } } \ No newline at end of file diff --git a/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java index 14559e4cf..7d3702c31 100644 --- a/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java +++ b/src/main/java/ru/javawebinar/topjava/web/user/ProfileRestController.java @@ -1,36 +1,22 @@ package ru.javawebinar.topjava.web.user; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.*; +import org.springframework.stereotype.Controller; import ru.javawebinar.topjava.model.User; import static ru.javawebinar.topjava.web.SecurityUtil.authUserId; -@RestController -@RequestMapping(value = ProfileRestController.REST_URL, produces = MediaType.APPLICATION_JSON_VALUE) +@Controller public class ProfileRestController extends AbstractUserController { - static final String REST_URL = "/rest/profile"; - @GetMapping public User get() { return super.get(authUserId()); } - @DeleteMapping - @ResponseStatus(HttpStatus.NO_CONTENT) public void delete() { super.delete(authUserId()); } - @PutMapping(consumes = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.NO_CONTENT) - public void update(@RequestBody User user) { + public void update(User user) { super.update(user, authUserId()); } - - @GetMapping("/text") - public String testUTF() { - return "Русский текст"; - } } \ No newline at end of file diff --git a/src/main/resources/cache/ehcache.xml b/src/main/resources/cache/ehcache.xml deleted file mode 100644 index 05589f71f..000000000 --- a/src/main/resources/cache/ehcache.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - 5 - - 5000 - - - - - - - 1 - - - - diff --git a/src/main/resources/db/hsqldb.properties b/src/main/resources/db/hsqldb.properties deleted file mode 100644 index 17c03ef4e..000000000 --- a/src/main/resources/db/hsqldb.properties +++ /dev/null @@ -1,11 +0,0 @@ -#database.url=jdbc:hsqldb:file:D:/temp/topjava - -database.url=jdbc:hsqldb:mem:topjava -database.username=sa -database.password= - -database.init=true -jdbc.initLocation=classpath:db/initDB_hsql.sql -jpa.showSql=true -hibernate.format_sql=true -hibernate.use_sql_comments=true \ No newline at end of file diff --git a/src/main/resources/db/initDB.sql b/src/main/resources/db/initDB.sql deleted file mode 100644 index 4bf3d8446..000000000 --- a/src/main/resources/db/initDB.sql +++ /dev/null @@ -1,37 +0,0 @@ -DROP TABLE IF EXISTS user_role; -DROP TABLE IF EXISTS meal; -DROP TABLE IF EXISTS users; -DROP SEQUENCE IF EXISTS global_seq; - -CREATE SEQUENCE global_seq START WITH 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() NOT NULL, - enabled BOOL DEFAULT TRUE NOT NULL, - calories_per_day INTEGER DEFAULT 2000 NOT NULL -); -CREATE UNIQUE INDEX users_unique_email_idx ON users (email); - -CREATE TABLE user_role -( - user_id INTEGER NOT NULL, - role VARCHAR NOT NULL, - CONSTRAINT user_roles_idx UNIQUE (user_id, role), - FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE -); - -CREATE TABLE meal -( - id INTEGER PRIMARY KEY DEFAULT nextval('global_seq'), - user_id INTEGER NOT NULL, - date_time TIMESTAMP NOT NULL, - description TEXT NOT NULL, - calories INT NOT NULL, - FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE -); -CREATE UNIQUE INDEX meal_unique_user_datetime_idx ON meal (user_id, date_time); \ No newline at end of file diff --git a/src/main/resources/db/initDB_hsql.sql b/src/main/resources/db/initDB_hsql.sql deleted file mode 100644 index 9e0e195e6..000000000 --- a/src/main/resources/db/initDB_hsql.sql +++ /dev/null @@ -1,39 +0,0 @@ -DROP TABLE user_role IF EXISTS; -DROP TABLE meal 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) NOT NULL, - email VARCHAR(255) NOT NULL, - password VARCHAR(255) NOT NULL, - registered TIMESTAMP DEFAULT now() NOT NULL, - enabled BOOLEAN DEFAULT TRUE NOT NULL, - calories_per_day INTEGER DEFAULT 2000 NOT NULL -); -CREATE UNIQUE INDEX users_unique_email_idx - ON USERS (email); - -CREATE TABLE user_role -( - user_id INTEGER NOT NULL, - role VARCHAR(255) NOT NULL, - CONSTRAINT user_roles_idx UNIQUE (user_id, role), - FOREIGN KEY (user_id) REFERENCES USERS (id) ON DELETE CASCADE -); - -CREATE TABLE meal -( - id INTEGER GENERATED BY DEFAULT AS SEQUENCE GLOBAL_SEQ PRIMARY KEY, - date_time TIMESTAMP NOT NULL, - description VARCHAR(255) NOT NULL, - calories INT NOT NULL, - user_id INTEGER NOT NULL, - FOREIGN KEY (user_id) REFERENCES USERS (id) ON DELETE CASCADE -); -CREATE UNIQUE INDEX meal_unique_user_datetime_idx - ON meal (user_id, date_time) \ No newline at end of file diff --git a/src/main/resources/db/populateDB.sql b/src/main/resources/db/populateDB.sql deleted file mode 100644 index 9e9bd828b..000000000 --- a/src/main/resources/db/populateDB.sql +++ /dev/null @@ -1,25 +0,0 @@ -DELETE FROM user_role; -DELETE FROM meal; -DELETE FROM users; -ALTER SEQUENCE global_seq RESTART WITH 100000; - -INSERT INTO users (name, email, password) -VALUES ('User', 'user@yandex.ru', 'password'), - ('Admin', 'admin@gmail.com', 'admin'), - ('Guest', 'guest@gmail.com', 'guest'); - -INSERT INTO user_role (role, user_id) -VALUES ('USER', 100000), - ('ADMIN', 100001), - ('USER', 100001); - -INSERT INTO meal (date_time, description, calories, user_id) -VALUES ('2020-01-30 10:00:00', 'Завтрак', 500, 100000), - ('2020-01-30 13:00:00', 'Обед', 1000, 100000), - ('2020-01-30 20:00:00', 'Ужин', 500, 100000), - ('2020-01-31 0:00:00', 'Еда на граничное значение', 100, 100000), - ('2020-01-31 10:00:00', 'Завтрак', 500, 100000), - ('2020-01-31 13:00:00', 'Обед', 1000, 100000), - ('2020-01-31 20:00:00', 'Ужин', 510, 100000), - ('2020-01-31 14:00:00', 'Админ ланч', 510, 100001), - ('2020-01-31 21:00:00', 'Админ ужин', 1500, 100001); diff --git a/src/main/resources/db/postgres.properties b/src/main/resources/db/postgres.properties deleted file mode 100644 index c56854a9b..000000000 --- a/src/main/resources/db/postgres.properties +++ /dev/null @@ -1,10 +0,0 @@ -database.url=jdbc:postgresql://localhost:5432/topjava -database.username=user -database.password=password - -database.init=true -jdbc.initLocation=classpath:db/initDB.sql -jpa.showSql=true -hibernate.format_sql=true -#https://hibernate.atlassian.net/browse/HHH-13280 -hibernate.use_sql_comments=false \ No newline at end of file diff --git a/src/main/resources/db/tomcat.properties b/src/main/resources/db/tomcat.properties deleted file mode 100644 index e11f0725f..000000000 --- a/src/main/resources/db/tomcat.properties +++ /dev/null @@ -1,5 +0,0 @@ -database.init=false -jdbc.initLocation=classpath:db/initDB.sql -jpa.showSql=true -hibernate.format_sql=true -hibernate.use_sql_comments=true \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 1d27e3f1e..bdf004d03 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -9,19 +9,18 @@ UTF-8 - %date %-5level %logger{50}.%M:%L - %msg%n + %date %-5level %logger{0} [%file:%line] %msg%n UTF-8 - %d{HH:mm:ss.SSS} %highlight(%-5level) %cyan(%class{50}.%M:%L) - %msg%n + %-5level %logger{0} [%file:%line] %msg%n - diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml index d57b656ae..cac42ba13 100644 --- a/src/main/resources/spring/spring-app.xml +++ b/src/main/resources/spring/spring-app.xml @@ -9,7 +9,10 @@ --> - + + + + \ No newline at end of file diff --git a/src/main/resources/spring/spring-cache.xml b/src/main/resources/spring/spring-cache.xml deleted file mode 100644 index 73325fee0..000000000 --- a/src/main/resources/spring/spring-cache.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml deleted file mode 100644 index 48afdb11a..000000000 --- a/src/main/resources/spring/spring-db.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/spring/spring-mvc.xml b/src/main/resources/spring/spring-mvc.xml deleted file mode 100644 index 68fe83a40..000000000 --- a/src/main/resources/spring/spring-mvc.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - text/plain;charset=UTF-8 - text/html;charset=UTF-8 - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/tomcat/context.xml b/src/main/resources/tomcat/context.xml deleted file mode 100644 index 9311d5904..000000000 --- a/src/main/resources/tomcat/context.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - WEB-INF/web.xml - ${catalina.base}/conf/web.xml - - - - - - - - - diff --git a/src/main/webapp/WEB-INF/jsp/fragments/bodyHeader.jsp b/src/main/webapp/WEB-INF/jsp/fragments/bodyHeader.jsp deleted file mode 100644 index 5b5efe57e..000000000 --- a/src/main/webapp/WEB-INF/jsp/fragments/bodyHeader.jsp +++ /dev/null @@ -1,6 +0,0 @@ -<%@page contentType="text/html" pageEncoding="UTF-8" %> -<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> - -
- | | -
\ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/fragments/footer.jsp b/src/main/webapp/WEB-INF/jsp/fragments/footer.jsp deleted file mode 100644 index 0935c441a..000000000 --- a/src/main/webapp/WEB-INF/jsp/fragments/footer.jsp +++ /dev/null @@ -1,4 +0,0 @@ -<%@page contentType="text/html" pageEncoding="UTF-8" %> -<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> -
-
\ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/fragments/headTag.jsp b/src/main/webapp/WEB-INF/jsp/fragments/headTag.jsp deleted file mode 100644 index 0c77f1085..000000000 --- a/src/main/webapp/WEB-INF/jsp/fragments/headTag.jsp +++ /dev/null @@ -1,10 +0,0 @@ -<%@page contentType="text/html" pageEncoding="UTF-8" %> -<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> -<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> - - - - <spring:message code="app.title"/> - - - \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/index.jsp b/src/main/webapp/WEB-INF/jsp/index.jsp deleted file mode 100644 index 847191965..000000000 --- a/src/main/webapp/WEB-INF/jsp/index.jsp +++ /dev/null @@ -1,21 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" %> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> - - - - - -
-
-
- : - - -
- - - \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/meals.jsp b/src/main/webapp/WEB-INF/jsp/meals.jsp deleted file mode 100644 index b42230b90..000000000 --- a/src/main/webapp/WEB-INF/jsp/meals.jsp +++ /dev/null @@ -1,64 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" %> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> -<%@ taglib prefix="fn" uri="http://topjava.javawebinar.ru/functions" %> - - - - - -
-

- -
-
-
:
-
-
-
-
:
-
-
-
-
:
-
-
-
-
:
-
-
- -
-
- -
- - - - - - - - - - - - - - - - - - - - -
- <%--${meal.dateTime.toLocalDate()} ${meal.dateTime.toLocalTime()}--%> - <%--<%=TimeUtil.toString(meal.getDateTime())%>--%> - <%--${fn:replace(meal.dateTime, 'T', ' ')}--%> - ${fn:formatDateTime(meal.dateTime)} - ${meal.description}${meal.calories}
-
- - - \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/users.jsp b/src/main/webapp/WEB-INF/jsp/users.jsp deleted file mode 100644 index 4d3d86789..000000000 --- a/src/main/webapp/WEB-INF/jsp/users.jsp +++ /dev/null @@ -1,38 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" %> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> -<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> - - - - - - -
-

- - - - - - - - - - - - - - - - - - - - - -
${user.email}${user.roles}${user.enabled}
-
- - - \ 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 65af7c831..bd98d3bf3 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -4,53 +4,26 @@ http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> - TopJava + Topjava - - spring.profiles.default - postgres,datajpa - - - - contextConfigLocation - - classpath:spring/spring-app.xml - classpath:spring/spring-db.xml - - + + userServlet + ru.javawebinar.topjava.web.UserServlet + 0 + + + userServlet + /users + - - - org.springframework.web.context.ContextLoaderListener - - mvc-dispatcher - org.springframework.web.servlet.DispatcherServlet - - contextConfigLocation - classpath:spring/spring-mvc.xml - - 1 + mealServlet + ru.javawebinar.topjava.web.MealServlet + 0 - mvc-dispatcher - / + mealServlet + /meals - - encodingFilter - org.springframework.web.filter.CharacterEncodingFilter - - encoding - UTF-8 - - - forceEncoding - true - - - - encodingFilter - /* - diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html new file mode 100644 index 000000000..714683bd3 --- /dev/null +++ b/src/main/webapp/index.html @@ -0,0 +1,14 @@ + + + + Java Enterprise (Topjava) + + +

Проект Java Enterprise (Topjava)

+
+ + + diff --git a/src/main/webapp/WEB-INF/jsp/mealForm.jsp b/src/main/webapp/mealForm.jsp similarity index 50% rename from src/main/webapp/WEB-INF/jsp/mealForm.jsp rename to src/main/webapp/mealForm.jsp index af6d7880e..28f140b65 100644 --- a/src/main/webapp/WEB-INF/jsp/mealForm.jsp +++ b/src/main/webapp/mealForm.jsp @@ -1,35 +1,51 @@ <%@ page contentType="text/html;charset=UTF-8" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> - - - + + Meal + + +
- -<%-- `meal.new` cause javax.el.ELException - bug tomcat --%> -

+

Home


+

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

+
-
:
+
DateTime:
-
:
+
Description:
-
:
+
Calories:
- - + +
- diff --git a/src/main/webapp/meals.jsp b/src/main/webapp/meals.jsp new file mode 100644 index 000000000..224d98761 --- /dev/null +++ b/src/main/webapp/meals.jsp @@ -0,0 +1,54 @@ +<%@ page contentType="text/html;charset=UTF-8" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> +<%@ taglib prefix="fn" uri="http://topjava.javawebinar.ru/functions" %> +<%--<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>--%> + + + Meal list + + + +
+

Home

+
+

Meals

+ Add Meal +

+ + + + + + + + + + + + + + + + + + + + +
DateDescriptionCalories
+ <%--${meal.dateTime.toLocalDate()} ${meal.dateTime.toLocalTime()}--%> + <%--<%=TimeUtil.toString(meal.getDateTime())%>--%> + <%--${fn:replace(meal.dateTime, 'T', ' ')}--%> + ${fn:formatDateTime(meal.dateTime)} + ${meal.description}${meal.calories}UpdateDelete
+
+ + \ No newline at end of file diff --git a/src/main/webapp/resources/css/style.css b/src/main/webapp/resources/css/style.css deleted file mode 100644 index a55147510..000000000 --- a/src/main/webapp/resources/css/style.css +++ /dev/null @@ -1,32 +0,0 @@ -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; -} - -tr[data-meal-excess="false"] { - color: green; -} - -tr[data-meal-excess="true"] { - color: red; -} - -header, footer { - background: none repeat scroll 0 0 #A6C9E2; - color: #2E6E9E; - font-size: 20px; - padding: 5px 20px; - margin: 6px 0; -} diff --git a/src/main/webapp/users.jsp b/src/main/webapp/users.jsp new file mode 100644 index 000000000..650c8dda4 --- /dev/null +++ b/src/main/webapp/users.jsp @@ -0,0 +1,11 @@ +<%@ page contentType="text/html;charset=UTF-8" %> + + + Users + + +

Home

+
+

Users

+ + \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/ActiveDbProfileResolver.java b/src/test/java/ru/javawebinar/topjava/ActiveDbProfileResolver.java deleted file mode 100644 index 43f143cc7..000000000 --- a/src/test/java/ru/javawebinar/topjava/ActiveDbProfileResolver.java +++ /dev/null @@ -1,19 +0,0 @@ -package ru.javawebinar.topjava; - -import org.springframework.lang.NonNull; -import org.springframework.test.context.support.DefaultActiveProfilesResolver; - -import java.util.Arrays; - -//http://stackoverflow.com/questions/23871255/spring-profiles-simple-example-of-activeprofilesresolver -public class ActiveDbProfileResolver extends DefaultActiveProfilesResolver { - @Override - public @NonNull - String[] resolve(@NonNull Class aClass) { - // https://stackoverflow.com/a/52438829/548473 - String[] activeProfiles = super.resolve(aClass); - String[] activeProfilesWithDb = Arrays.copyOf(activeProfiles, activeProfiles.length + 1); - activeProfilesWithDb[activeProfiles.length] = Profiles.getActiveDbProfile(); - return activeProfilesWithDb; - } -} diff --git a/src/test/java/ru/javawebinar/topjava/MatcherFactory.java b/src/test/java/ru/javawebinar/topjava/MatcherFactory.java deleted file mode 100644 index 40f3d8c22..000000000 --- a/src/test/java/ru/javawebinar/topjava/MatcherFactory.java +++ /dev/null @@ -1,67 +0,0 @@ -package ru.javawebinar.topjava; - -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.ResultActions; -import org.springframework.test.web.servlet.ResultMatcher; -import ru.javawebinar.topjava.web.json.JsonUtil; - -import java.io.UnsupportedEncodingException; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Factory for creating test matchers. - *

- * Comparing actual and expected objects via AssertJ - * Support converting json MvcResult to objects for comparation. - */ -public class MatcherFactory { - public static Matcher usingIgnoringFieldsComparator(Class clazz, String... fieldsToIgnore) { - return new Matcher<>(clazz, fieldsToIgnore); - } - - public static class Matcher { - private final Class clazz; - private final String[] fieldsToIgnore; - - private Matcher(Class clazz, String... fieldsToIgnore) { - this.clazz = clazz; - this.fieldsToIgnore = fieldsToIgnore; - } - - public void assertMatch(T actual, T expected) { - assertThat(actual).usingRecursiveComparison().ignoringFields(fieldsToIgnore).isEqualTo(expected); - } - - @SafeVarargs - public final void assertMatch(Iterable actual, T... expected) { - assertMatch(actual, List.of(expected)); - } - - public void assertMatch(Iterable actual, Iterable expected) { - assertThat(actual).usingRecursiveFieldByFieldElementComparatorIgnoringFields(fieldsToIgnore).isEqualTo(expected); - } - - public ResultMatcher contentJson(T expected) { - return result -> assertMatch(JsonUtil.readValue(getContent(result), clazz), expected); - } - - @SafeVarargs - public final ResultMatcher contentJson(T... expected) { - return contentJson(List.of(expected)); - } - - public ResultMatcher contentJson(Iterable expected) { - return result -> assertMatch(JsonUtil.readValues(getContent(result), clazz), expected); - } - - public T readFromJson(ResultActions action) throws UnsupportedEncodingException { - return JsonUtil.readValue(getContent(action.andReturn()), clazz); - } - - private static String getContent(MvcResult result) throws UnsupportedEncodingException { - return result.getResponse().getContentAsString(); - } - } -} diff --git a/src/test/java/ru/javawebinar/topjava/MealTestData.java b/src/test/java/ru/javawebinar/topjava/MealTestData.java deleted file mode 100644 index c2697db04..000000000 --- a/src/test/java/ru/javawebinar/topjava/MealTestData.java +++ /dev/null @@ -1,38 +0,0 @@ -package ru.javawebinar.topjava; - -import ru.javawebinar.topjava.model.Meal; - -import java.time.Month; -import java.time.temporal.ChronoUnit; -import java.util.List; - -import static java.time.LocalDateTime.of; -import static ru.javawebinar.topjava.model.AbstractBaseEntity.START_SEQ; - -public class MealTestData { - public static final MatcherFactory.Matcher MEAL_MATCHER = MatcherFactory.usingIgnoringFieldsComparator(Meal.class, "user"); - - public static final int NOT_FOUND = 10; - public static final int MEAL1_ID = START_SEQ + 3; - public static final int ADMIN_MEAL_ID = START_SEQ + 10; - - public static final Meal meal1 = new Meal(MEAL1_ID, of(2020, Month.JANUARY, 30, 10, 0), "Завтрак", 500); - public static final Meal meal2 = new Meal(MEAL1_ID + 1, of(2020, Month.JANUARY, 30, 13, 0), "Обед", 1000); - public static final Meal meal3 = new Meal(MEAL1_ID + 2, of(2020, Month.JANUARY, 30, 20, 0), "Ужин", 500); - public static final Meal meal4 = new Meal(MEAL1_ID + 3, of(2020, Month.JANUARY, 31, 0, 0), "Еда на граничное значение", 100); - public static final Meal meal5 = new Meal(MEAL1_ID + 4, of(2020, Month.JANUARY, 31, 10, 0), "Завтрак", 500); - public static final Meal meal6 = new Meal(MEAL1_ID + 5, of(2020, Month.JANUARY, 31, 13, 0), "Обед", 1000); - public static final Meal meal7 = new Meal(MEAL1_ID + 6, of(2020, Month.JANUARY, 31, 20, 0), "Ужин", 510); - public static final Meal adminMeal1 = new Meal(ADMIN_MEAL_ID, of(2020, Month.JANUARY, 31, 14, 0), "Админ ланч", 510); - public static final Meal adminMeal2 = new Meal(ADMIN_MEAL_ID + 1, of(2020, Month.JANUARY, 31, 21, 0), "Админ ужин", 1500); - - public static final List meals = List.of(meal7, meal6, meal5, meal4, meal3, meal2, meal1); - - public static Meal getNew() { - return new Meal(null, of(2020, Month.FEBRUARY, 1, 18, 0), "Созданный ужин", 300); - } - - public static Meal getUpdated() { - return new Meal(MEAL1_ID, meal1.getDateTime().plus(2, ChronoUnit.MINUTES), "Обновленный завтрак", 200); - } -} diff --git a/src/test/java/ru/javawebinar/topjava/TimingExtension.java b/src/test/java/ru/javawebinar/topjava/TimingExtension.java deleted file mode 100644 index cee6ae92c..000000000 --- a/src/test/java/ru/javawebinar/topjava/TimingExtension.java +++ /dev/null @@ -1,36 +0,0 @@ -package ru.javawebinar.topjava; - -import org.junit.jupiter.api.extension.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.StopWatch; - -public class TimingExtension implements - BeforeTestExecutionCallback, AfterTestExecutionCallback, BeforeAllCallback, AfterAllCallback { - - private static final Logger log = LoggerFactory.getLogger("result"); - - private StopWatch stopWatch; - - @Override - public void beforeAll(ExtensionContext extensionContext) { - stopWatch = new StopWatch("Execution time of " + extensionContext.getRequiredTestClass().getSimpleName()); - } - - @Override - public void beforeTestExecution(ExtensionContext extensionContext) { - String testName = extensionContext.getDisplayName(); - log.info("\nStart " + testName); - stopWatch.start(testName); - } - - @Override - public void afterTestExecution(ExtensionContext extensionContext) { - stopWatch.stop(); - } - - @Override - public void afterAll(ExtensionContext extensionContext) { - log.info('\n' + stopWatch.prettyPrint() + '\n'); - } -} diff --git a/src/test/java/ru/javawebinar/topjava/UserTestData.java b/src/test/java/ru/javawebinar/topjava/UserTestData.java deleted file mode 100644 index 285964552..000000000 --- a/src/test/java/ru/javawebinar/topjava/UserTestData.java +++ /dev/null @@ -1,37 +0,0 @@ -package ru.javawebinar.topjava; - -import ru.javawebinar.topjava.model.Role; -import ru.javawebinar.topjava.model.User; - -import java.util.Collections; -import java.util.Date; - -import static ru.javawebinar.topjava.model.AbstractBaseEntity.START_SEQ; - -public class UserTestData { - public static final MatcherFactory.Matcher USER_MATCHER = MatcherFactory.usingIgnoringFieldsComparator(User.class, "registered", "meals"); - - public static final int USER_ID = START_SEQ; - public static final int ADMIN_ID = START_SEQ + 1; - public static final int GUEST_ID = START_SEQ + 2; - public static final int NOT_FOUND = 10; - - public static final User user = new User(USER_ID, "User", "user@yandex.ru", "password", Role.USER); - public static final User admin = new User(ADMIN_ID, "Admin", "admin@gmail.com", "admin", Role.ADMIN, Role.USER); - public static final User guest = new User(GUEST_ID, "Guest", "guest@gmail.com", "guest"); - - public static User getNew() { - return new User(null, "New", "new@gmail.com", "newPass", 1555, false, new Date(), Collections.singleton(Role.USER)); - } - - public static User getUpdated() { - User updated = new User(user); - updated.setEmail("update@gmail.com"); - updated.setName("UpdatedName"); - updated.setCaloriesPerDay(330); - updated.setPassword("newPass"); - updated.setEnabled(false); - updated.setRoles(Collections.singletonList(Role.ADMIN)); - return updated; - } -} diff --git a/src/test/java/ru/javawebinar/topjava/repository/inmemory/InMemoryBaseRepository.java b/src/test/java/ru/javawebinar/topjava/repository/inmemory/InMemoryBaseRepository.java deleted file mode 100644 index 03770da21..000000000 --- a/src/test/java/ru/javawebinar/topjava/repository/inmemory/InMemoryBaseRepository.java +++ /dev/null @@ -1,45 +0,0 @@ -package ru.javawebinar.topjava.repository.inmemory; - -import ru.javawebinar.topjava.model.AbstractBaseEntity; - -import java.util.Collection; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; - -import static ru.javawebinar.topjava.model.AbstractBaseEntity.START_SEQ; - -public class InMemoryBaseRepository { - - static final AtomicInteger counter = new AtomicInteger(START_SEQ); - - final Map map = new ConcurrentHashMap<>(); - - public T save(T entity) { - Objects.requireNonNull(entity, "Entity must not be null"); - if (entity.isNew()) { - entity.setId(counter.incrementAndGet()); - map.put(entity.getId(), entity); - return entity; - } - return map.computeIfPresent(entity.getId(), (id, oldT) -> entity); - } - - public boolean delete(int id) { - return map.remove(id) != null; - } - - public T get(int id) { - return map.get(id); - } - - Collection getCollection() { - return map.values(); - } - - void put(T entity) { - Objects.requireNonNull(entity, "Entity must not be null"); - map.put(entity.id(), entity); - } -} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/repository/inmemory/InMemoryMealRepository.java b/src/test/java/ru/javawebinar/topjava/repository/inmemory/InMemoryMealRepository.java deleted file mode 100644 index 5c65ced86..000000000 --- a/src/test/java/ru/javawebinar/topjava/repository/inmemory/InMemoryMealRepository.java +++ /dev/null @@ -1,80 +0,0 @@ -package ru.javawebinar.topjava.repository.inmemory; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Repository; -import ru.javawebinar.topjava.MealTestData; -import ru.javawebinar.topjava.UserTestData; -import ru.javawebinar.topjava.model.Meal; -import ru.javawebinar.topjava.repository.MealRepository; -import ru.javawebinar.topjava.util.Util; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import java.time.LocalDateTime; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Predicate; - -@Repository -public class InMemoryMealRepository implements MealRepository { - private static final Logger log = LoggerFactory.getLogger(InMemoryMealRepository.class); - - // Map userId -> mealRepository - private final Map> usersMealsMap = new ConcurrentHashMap<>(); - - { - var userMeals = new InMemoryBaseRepository(); - MealTestData.meals.forEach(userMeals::put); - usersMealsMap.put(UserTestData.USER_ID, userMeals); - } - - - @Override - public Meal save(Meal meal, int userId) { - Objects.requireNonNull(meal, "meal must not be null"); - var meals = usersMealsMap.computeIfAbsent(userId, uId -> new InMemoryBaseRepository<>()); - return meals.save(meal); - } - - @PostConstruct - public void postConstruct() { - log.info("+++ PostConstruct"); - } - - @PreDestroy - public void preDestroy() { - log.info("+++ PreDestroy"); - } - - @Override - public boolean delete(int id, int userId) { - var meals = usersMealsMap.get(userId); - return meals != null && meals.delete(id); - } - - @Override - public Meal get(int id, int userId) { - var meals = usersMealsMap.get(userId); - return meals == null ? null : meals.get(id); - } - - @Override - public List getBetweenHalfOpen(LocalDateTime startDateTime, LocalDateTime endDateTime, int userId) { - return filterByPredicate(userId, meal -> Util.isBetweenHalfOpen(meal.getDateTime(), startDateTime, endDateTime)); - } - - @Override - public List getAll(int userId) { - return filterByPredicate(userId, meal -> true); - } - - private List filterByPredicate(int userId, Predicate filter) { - var meals = usersMealsMap.get(userId); - return meals == null ? Collections.emptyList() : - meals.getCollection().stream() - .filter(filter) - .sorted(Comparator.comparing(Meal::getDateTime).reversed()) - .toList(); - } -} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/repository/inmemory/InMemoryUserRepository.java b/src/test/java/ru/javawebinar/topjava/repository/inmemory/InMemoryUserRepository.java deleted file mode 100644 index f3585dfff..000000000 --- a/src/test/java/ru/javawebinar/topjava/repository/inmemory/InMemoryUserRepository.java +++ /dev/null @@ -1,40 +0,0 @@ -package ru.javawebinar.topjava.repository.inmemory; - -import org.springframework.stereotype.Repository; -import ru.javawebinar.topjava.model.User; -import ru.javawebinar.topjava.repository.UserRepository; - -import java.util.Comparator; -import java.util.List; -import java.util.Objects; - -import static ru.javawebinar.topjava.UserTestData.*; - - -@Repository -public class InMemoryUserRepository extends InMemoryBaseRepository implements UserRepository { - - public void init() { - map.clear(); - put(user); - put(admin); - put(guest); - counter.getAndSet(GUEST_ID + 1); - } - - @Override - public List getAll() { - return getCollection().stream() - .sorted(Comparator.comparing(User::getName).thenComparing(User::getEmail)) - .toList(); - } - - @Override - public User getByEmail(String email) { - Objects.requireNonNull(email, "email must not be null"); - return getCollection().stream() - .filter(u -> email.equals(u.getEmail())) - .findFirst() - .orElse(null); - } -} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/service/AbstractMealServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractMealServiceTest.java deleted file mode 100644 index 6b00e4481..000000000 --- a/src/test/java/ru/javawebinar/topjava/service/AbstractMealServiceTest.java +++ /dev/null @@ -1,112 +0,0 @@ -package ru.javawebinar.topjava.service; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataAccessException; -import ru.javawebinar.topjava.model.Meal; -import ru.javawebinar.topjava.util.exception.NotFoundException; - -import javax.validation.ConstraintViolationException; -import java.time.LocalDate; -import java.time.Month; - -import static java.time.LocalDateTime.of; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static ru.javawebinar.topjava.MealTestData.*; -import static ru.javawebinar.topjava.UserTestData.ADMIN_ID; -import static ru.javawebinar.topjava.UserTestData.USER_ID; - -public abstract class AbstractMealServiceTest extends AbstractServiceTest { - - @Autowired - protected MealService service; - - @Test - void delete() { - service.delete(MEAL1_ID, USER_ID); - assertThrows(NotFoundException.class, () -> service.get(MEAL1_ID, USER_ID)); - } - - @Test - void deleteNotFound() { - assertThrows(NotFoundException.class, () -> service.delete(NOT_FOUND, USER_ID)); - } - - @Test - void deleteNotOwn() { - assertThrows(NotFoundException.class, () -> service.delete(MEAL1_ID, ADMIN_ID)); - } - - @Test - void create() { - Meal created = service.create(getNew(), USER_ID); - int newId = created.id(); - Meal newMeal = getNew(); - newMeal.setId(newId); - MEAL_MATCHER.assertMatch(created, newMeal); - MEAL_MATCHER.assertMatch(service.get(newId, USER_ID), newMeal); - } - - @Test - void duplicateDateTimeCreate() { - assertThrows(DataAccessException.class, () -> - service.create(new Meal(null, meal1.getDateTime(), "duplicate", 100), USER_ID)); - } - - @Test - void get() { - Meal actual = service.get(ADMIN_MEAL_ID, ADMIN_ID); - MEAL_MATCHER.assertMatch(actual, adminMeal1); - } - - @Test - void getNotFound() { - assertThrows(NotFoundException.class, () -> service.get(NOT_FOUND, USER_ID)); - } - - @Test - void getNotOwn() { - assertThrows(NotFoundException.class, () -> service.get(MEAL1_ID, ADMIN_ID)); - } - - @Test - void update() { - Meal updated = getUpdated(); - service.update(updated, USER_ID); - MEAL_MATCHER.assertMatch(service.get(MEAL1_ID, USER_ID), getUpdated()); - } - - @Test - void updateNotOwn() { - NotFoundException exception = assertThrows(NotFoundException.class, () -> service.update(getUpdated(), ADMIN_ID)); - Assertions.assertEquals("Not found entity with id=" + MEAL1_ID, exception.getMessage()); - MEAL_MATCHER.assertMatch(service.get(MEAL1_ID, USER_ID), meal1); - } - - @Test - void getAll() { - MEAL_MATCHER.assertMatch(service.getAll(USER_ID), meals); - } - - @Test - void getBetweenInclusive() { - MEAL_MATCHER.assertMatch(service.getBetweenInclusive( - LocalDate.of(2020, Month.JANUARY, 30), - LocalDate.of(2020, Month.JANUARY, 30), USER_ID), - meal3, meal2, meal1); - } - - @Test - void getBetweenWithNullDates() { - MEAL_MATCHER.assertMatch(service.getBetweenInclusive(null, null, USER_ID), meals); - } - - @Test - void createWithException() throws Exception { - validateRootCause(ConstraintViolationException.class, () -> service.create(new Meal(null, of(2015, Month.JUNE, 1, 18, 0), " ", 300), USER_ID)); - validateRootCause(ConstraintViolationException.class, () -> service.create(new Meal(null, null, "Description", 300), USER_ID)); - validateRootCause(ConstraintViolationException.class, () -> service.create(new Meal(null, of(2015, Month.JUNE, 1, 18, 0), "Description", 9), USER_ID)); - validateRootCause(ConstraintViolationException.class, () -> service.create(new Meal(null, of(2015, Month.JUNE, 1, 18, 0), "Description", 5001), USER_ID)); - } -} \ 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 deleted file mode 100644 index 930548690..000000000 --- a/src/test/java/ru/javawebinar/topjava/service/AbstractServiceTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package ru.javawebinar.topjava.service; - -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.jdbc.SqlConfig; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; -import ru.javawebinar.topjava.ActiveDbProfileResolver; -import ru.javawebinar.topjava.TimingExtension; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; - -@SpringJUnitConfig(locations = { - "classpath:spring/spring-app.xml", - "classpath:spring/spring-db.xml" -}) -//@ExtendWith(SpringExtension.class) -@ActiveProfiles(resolver = ActiveDbProfileResolver.class) -@Sql(scripts = "classpath:db/populateDB.sql", config = @SqlConfig(encoding = "UTF-8")) -@ExtendWith(TimingExtension.class) -public abstract class AbstractServiceTest { - - // Check root cause with AssertJ: https://github.com/junit-team/junit-framework/issues/2129#issuecomment-565712630 - // Check root cause in JUnit: https://github.com/junit-team/junit4/pull/778 - protected void validateRootCause(Class rootExceptionClass, Runnable runnable) { - assertThatExceptionOfType(Throwable.class) - .isThrownBy(runnable::run) - .satisfiesAnyOf( - ex -> assertThat(ex).isInstanceOf(rootExceptionClass), - ex -> assertThat(ex).hasRootCauseInstanceOf(rootExceptionClass)); - } -} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java deleted file mode 100644 index fe6838b5f..000000000 --- a/src/test/java/ru/javawebinar/topjava/service/AbstractUserServiceTest.java +++ /dev/null @@ -1,88 +0,0 @@ -package ru.javawebinar.topjava.service; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataAccessException; -import ru.javawebinar.topjava.model.Role; -import ru.javawebinar.topjava.model.User; -import ru.javawebinar.topjava.util.exception.NotFoundException; - -import javax.validation.ConstraintViolationException; -import java.util.Date; -import java.util.List; -import java.util.Set; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static ru.javawebinar.topjava.UserTestData.*; - -public abstract class AbstractUserServiceTest extends AbstractServiceTest { - - @Autowired - protected UserService service; - - @Test - void create() { - User created = service.create(getNew()); - int newId = created.id(); - User newUser = getNew(); - newUser.setId(newId); - USER_MATCHER.assertMatch(created, newUser); - USER_MATCHER.assertMatch(service.get(newId), newUser); - } - - @Test - void duplicateMailCreate() { - assertThrows(DataAccessException.class, () -> - service.create(new User(null, "Duplicate", "user@yandex.ru", "newPass", Role.USER))); - } - - @Test - void delete() { - service.delete(USER_ID); - assertThrows(NotFoundException.class, () -> service.get(USER_ID)); - } - - @Test - void deletedNotFound() { - assertThrows(NotFoundException.class, () -> service.delete(NOT_FOUND)); - } - - @Test - void get() { - User user = service.get(ADMIN_ID); - USER_MATCHER.assertMatch(user, admin); - } - - @Test - void getNotFound() { - assertThrows(NotFoundException.class, () -> service.get(NOT_FOUND)); - } - - @Test - void getByEmail() { - User user = service.getByEmail("admin@gmail.com"); - USER_MATCHER.assertMatch(user, admin); - } - - @Test - void update() { - User updated = getUpdated(); - service.update(updated); - USER_MATCHER.assertMatch(service.get(USER_ID), getUpdated()); - } - - @Test - void getAll() { - List all = service.getAll(); - USER_MATCHER.assertMatch(all, admin, guest, user); - } - - @Test - void createWithException() throws Exception { - validateRootCause(ConstraintViolationException.class, () -> service.create(new User(null, " ", "mail@yandex.ru", "password", Role.USER))); - validateRootCause(ConstraintViolationException.class, () -> service.create(new User(null, "User", " ", "password", Role.USER))); - validateRootCause(ConstraintViolationException.class, () -> service.create(new User(null, "User", "mail@yandex.ru", " ", Role.USER))); - validateRootCause(ConstraintViolationException.class, () -> service.create(new User(null, "User", "mail@yandex.ru", "password", 9, true, new Date(), Set.of()))); - validateRootCause(ConstraintViolationException.class, () -> service.create(new User(null, "User", "mail@yandex.ru", "password", 10001, true, new Date(), Set.of()))); - } -} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaMealServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaMealServiceTest.java deleted file mode 100644 index 161c93fb5..000000000 --- a/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaMealServiceTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package ru.javawebinar.topjava.service.datajpa; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.springframework.test.context.ActiveProfiles; -import ru.javawebinar.topjava.MealTestData; -import ru.javawebinar.topjava.model.Meal; -import ru.javawebinar.topjava.service.AbstractMealServiceTest; -import ru.javawebinar.topjava.util.exception.NotFoundException; - -import static ru.javawebinar.topjava.MealTestData.*; -import static ru.javawebinar.topjava.Profiles.DATAJPA; -import static ru.javawebinar.topjava.UserTestData.*; - -@ActiveProfiles(DATAJPA) -class DataJpaMealServiceTest extends AbstractMealServiceTest { - @Test - void getWithUser() { - Meal adminMeal = service.getWithUser(ADMIN_MEAL_ID, ADMIN_ID); - MEAL_MATCHER.assertMatch(adminMeal, adminMeal1); - USER_MATCHER.assertMatch(adminMeal.getUser(), admin); - } - - @Test - void getWithUserNotFound() { - Assertions.assertThrows(NotFoundException.class, - () -> service.getWithUser(MealTestData.NOT_FOUND, ADMIN_ID)); - } -} diff --git a/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserServiceTest.java deleted file mode 100644 index d8a1f4106..000000000 --- a/src/test/java/ru/javawebinar/topjava/service/datajpa/DataJpaUserServiceTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package ru.javawebinar.topjava.service.datajpa; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.springframework.test.context.ActiveProfiles; -import ru.javawebinar.topjava.MealTestData; -import ru.javawebinar.topjava.UserTestData; -import ru.javawebinar.topjava.model.User; -import ru.javawebinar.topjava.service.AbstractUserServiceTest; -import ru.javawebinar.topjava.util.exception.NotFoundException; - -import static ru.javawebinar.topjava.MealTestData.MEAL_MATCHER; -import static ru.javawebinar.topjava.Profiles.DATAJPA; -import static ru.javawebinar.topjava.UserTestData.*; - -@ActiveProfiles(DATAJPA) -class DataJpaUserServiceTest extends AbstractUserServiceTest { - @Test - void getWithMeals() { - User admin = service.getWithMeals(ADMIN_ID); - USER_MATCHER.assertMatch(admin, UserTestData.admin); - MEAL_MATCHER.assertMatch(admin.getMeals(), MealTestData.adminMeal2, MealTestData.adminMeal1); - } - - @Test - void getWithMealsNotFound() { - Assertions.assertThrows(NotFoundException.class, - () -> service.getWithMeals(NOT_FOUND)); - } -} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/service/jdbc/JdbcMealServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/jdbc/JdbcMealServiceTest.java deleted file mode 100644 index aef588264..000000000 --- a/src/test/java/ru/javawebinar/topjava/service/jdbc/JdbcMealServiceTest.java +++ /dev/null @@ -1,10 +0,0 @@ -package ru.javawebinar.topjava.service.jdbc; - -import org.springframework.test.context.ActiveProfiles; -import ru.javawebinar.topjava.service.AbstractMealServiceTest; - -import static ru.javawebinar.topjava.Profiles.JDBC; - -@ActiveProfiles(JDBC) -class JdbcMealServiceTest extends AbstractMealServiceTest { -} \ 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 deleted file mode 100644 index 62ca7668c..000000000 --- a/src/test/java/ru/javawebinar/topjava/service/jdbc/JdbcUserServiceTest.java +++ /dev/null @@ -1,10 +0,0 @@ -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) -class JdbcUserServiceTest extends AbstractUserServiceTest { -} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/service/jpa/JpaMealServiceTest.java b/src/test/java/ru/javawebinar/topjava/service/jpa/JpaMealServiceTest.java deleted file mode 100644 index aaf5dcda9..000000000 --- a/src/test/java/ru/javawebinar/topjava/service/jpa/JpaMealServiceTest.java +++ /dev/null @@ -1,10 +0,0 @@ -package ru.javawebinar.topjava.service.jpa; - -import org.springframework.test.context.ActiveProfiles; -import ru.javawebinar.topjava.service.AbstractMealServiceTest; - -import static ru.javawebinar.topjava.Profiles.JPA; - -@ActiveProfiles(JPA) -class JpaMealServiceTest extends AbstractMealServiceTest { -} \ 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 deleted file mode 100644 index 6d1cd9154..000000000 --- a/src/test/java/ru/javawebinar/topjava/service/jpa/JpaUserServiceTest.java +++ /dev/null @@ -1,10 +0,0 @@ -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) -class JpaUserServiceTest extends AbstractUserServiceTest { -} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/web/AbstractControllerTest.java b/src/test/java/ru/javawebinar/topjava/web/AbstractControllerTest.java deleted file mode 100644 index 6fa9b1d4c..000000000 --- a/src/test/java/ru/javawebinar/topjava/web/AbstractControllerTest.java +++ /dev/null @@ -1,52 +0,0 @@ -package ru.javawebinar.topjava.web; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.ResultActions; -import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.filter.CharacterEncodingFilter; -import ru.javawebinar.topjava.ActiveDbProfileResolver; -import ru.javawebinar.topjava.Profiles; - -import javax.annotation.PostConstruct; - -@SpringJUnitWebConfig(locations = { - "classpath:spring/spring-app.xml", - "classpath:spring/spring-mvc.xml", - "classpath:spring/spring-db.xml" -}) -//@WebAppConfiguration -//@ExtendWith(SpringExtension.class) -@Transactional -@ActiveProfiles(resolver = ActiveDbProfileResolver.class, profiles = Profiles.REPOSITORY_IMPLEMENTATION) -public abstract class AbstractControllerTest { - - private static final CharacterEncodingFilter CHARACTER_ENCODING_FILTER = new CharacterEncodingFilter(); - - static { - CHARACTER_ENCODING_FILTER.setEncoding("UTF-8"); - CHARACTER_ENCODING_FILTER.setForceEncoding(true); - } - - private MockMvc mockMvc; - - @Autowired - private WebApplicationContext webApplicationContext; - - @PostConstruct - private void postConstruct() { - mockMvc = MockMvcBuilders - .webAppContextSetup(webApplicationContext) - .addFilter(CHARACTER_ENCODING_FILTER) - .build(); - } - - protected ResultActions perform(MockHttpServletRequestBuilder builder) throws Exception { - return mockMvc.perform(builder); - } -} diff --git a/src/test/java/ru/javawebinar/topjava/web/RootControllerTest.java b/src/test/java/ru/javawebinar/topjava/web/RootControllerTest.java deleted file mode 100644 index 2bec37dda..000000000 --- a/src/test/java/ru/javawebinar/topjava/web/RootControllerTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package ru.javawebinar.topjava.web; - -import org.assertj.core.matcher.AssertionMatcher; -import org.junit.jupiter.api.Test; -import ru.javawebinar.topjava.model.User; - -import java.util.List; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; -import static ru.javawebinar.topjava.UserTestData.*; - -class RootControllerTest extends AbstractControllerTest { - - @Test - void getUsers() throws Exception { - perform(get("/users")) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(view().name("users")) - .andExpect(forwardedUrl("/WEB-INF/jsp/users.jsp")) - .andExpect(model().attribute("users", - new AssertionMatcher>() { - @Override - public void assertion(List actual) throws AssertionError { - USER_MATCHER.assertMatch(actual, admin, guest, user); - } - } - )); - } -} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/web/json/JsonUtilTest.java b/src/test/java/ru/javawebinar/topjava/web/json/JsonUtilTest.java deleted file mode 100644 index 540586d11..000000000 --- a/src/test/java/ru/javawebinar/topjava/web/json/JsonUtilTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package ru.javawebinar.topjava.web.json; - -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import ru.javawebinar.topjava.model.Meal; - -import java.util.List; - -import static ru.javawebinar.topjava.MealTestData.*; - -class JsonUtilTest { - private static final Logger log = LoggerFactory.getLogger(JsonUtilTest.class); - - @Test - void readWriteValue() { - String json = JsonUtil.writeValue(adminMeal1); - log.info(json); - Meal meal = JsonUtil.readValue(json, Meal.class); - MEAL_MATCHER.assertMatch(meal, adminMeal1); - } - - @Test - void readWriteValues() { - String json = JsonUtil.writeValue(meals); - log.info(json); - List actual = JsonUtil.readValues(json, Meal.class); - MEAL_MATCHER.assertMatch(actual, meals); - } -} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/web/user/AdminRestControllerTest.java b/src/test/java/ru/javawebinar/topjava/web/user/AdminRestControllerTest.java deleted file mode 100644 index 6af80902c..000000000 --- a/src/test/java/ru/javawebinar/topjava/web/user/AdminRestControllerTest.java +++ /dev/null @@ -1,86 +0,0 @@ -package ru.javawebinar.topjava.web.user; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.ResultActions; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import ru.javawebinar.topjava.model.User; -import ru.javawebinar.topjava.service.UserService; -import ru.javawebinar.topjava.util.exception.NotFoundException; -import ru.javawebinar.topjava.web.AbstractControllerTest; -import ru.javawebinar.topjava.web.json.JsonUtil; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static ru.javawebinar.topjava.UserTestData.*; - -class AdminRestControllerTest extends AbstractControllerTest { - - private static final String REST_URL = AdminRestController.REST_URL + '/'; - - @Autowired - private UserService userService; - - @Test - void get() throws Exception { - perform(MockMvcRequestBuilders.get(REST_URL + ADMIN_ID)) - .andExpect(status().isOk()) - .andDo(print()) - // https://jira.spring.io/browse/SPR-14472 - .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) - .andExpect(USER_MATCHER.contentJson(admin)); - } - - @Test - void getByEmail() throws Exception { - perform(MockMvcRequestBuilders.get(REST_URL + "by-email?email=" + user.getEmail())) - .andExpect(status().isOk()) - .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) - .andExpect(USER_MATCHER.contentJson(user)); - } - - @Test - void delete() throws Exception { - perform(MockMvcRequestBuilders.delete(REST_URL + USER_ID)) - .andDo(print()) - .andExpect(status().isNoContent()); - assertThrows(NotFoundException.class, () -> userService.get(USER_ID)); - } - - @Test - void update() throws Exception { - User updated = getUpdated(); - perform(MockMvcRequestBuilders.put(REST_URL + USER_ID) - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.writeValue(updated))) - .andExpect(status().isNoContent()); - - USER_MATCHER.assertMatch(userService.get(USER_ID), updated); - } - - @Test - void createWithLocation() throws Exception { - User newUser = getNew(); - ResultActions action = perform(MockMvcRequestBuilders.post(REST_URL) - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.writeValue(newUser))) - .andExpect(status().isCreated()); - - User created = USER_MATCHER.readFromJson(action); - int newId = created.id(); - newUser.setId(newId); - USER_MATCHER.assertMatch(created, newUser); - USER_MATCHER.assertMatch(userService.get(newId), newUser); - } - - @Test - void getAll() throws Exception { - perform(MockMvcRequestBuilders.get(REST_URL)) - .andExpect(status().isOk()) - .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) - .andExpect(USER_MATCHER.contentJson(admin, guest, user)); - } -} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/web/user/InMemoryAdminRestControllerSpringTest.java b/src/test/java/ru/javawebinar/topjava/web/user/InMemoryAdminRestControllerSpringTest.java deleted file mode 100644 index 7568d0f52..000000000 --- a/src/test/java/ru/javawebinar/topjava/web/user/InMemoryAdminRestControllerSpringTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package ru.javawebinar.topjava.web.user; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; -import ru.javawebinar.topjava.repository.inmemory.InMemoryUserRepository; -import ru.javawebinar.topjava.util.exception.NotFoundException; - -import static ru.javawebinar.topjava.UserTestData.NOT_FOUND; -import static ru.javawebinar.topjava.UserTestData.USER_ID; - -@SpringJUnitConfig(locations = {"classpath:spring/inmemory.xml"}) -class InMemoryAdminRestControllerSpringTest { - - @Autowired - private AdminRestController controller; - - @Autowired - private InMemoryUserRepository repository; - - @BeforeEach - void setup() { - repository.init(); - } - - @Test - void delete() { - controller.delete(USER_ID); - Assertions.assertNull(repository.get(USER_ID)); - } - - @Test - void deleteNotFound() { - Assertions.assertThrows(NotFoundException.class, () -> controller.delete(NOT_FOUND)); - } -} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/web/user/InMemoryAdminRestControllerTest.java b/src/test/java/ru/javawebinar/topjava/web/user/InMemoryAdminRestControllerTest.java deleted file mode 100644 index c41fa0e6b..000000000 --- a/src/test/java/ru/javawebinar/topjava/web/user/InMemoryAdminRestControllerTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package ru.javawebinar.topjava.web.user; - -import org.junit.jupiter.api.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; -import ru.javawebinar.topjava.repository.inmemory.InMemoryUserRepository; -import ru.javawebinar.topjava.util.exception.NotFoundException; - -import java.util.Arrays; - -import static ru.javawebinar.topjava.UserTestData.NOT_FOUND; -import static ru.javawebinar.topjava.UserTestData.USER_ID; - -class InMemoryAdminRestControllerTest { - private static final Logger log = LoggerFactory.getLogger(InMemoryAdminRestControllerTest.class); - - private static ConfigurableApplicationContext appCtx; - private static AdminRestController controller; - private static InMemoryUserRepository repository; - - @BeforeAll - static void beforeClass() { - appCtx = new ClassPathXmlApplicationContext("spring/inmemory.xml"); - log.info("\n{}\n", Arrays.toString(appCtx.getBeanDefinitionNames())); - controller = appCtx.getBean(AdminRestController.class); - repository = appCtx.getBean(InMemoryUserRepository.class); - } - - @AfterAll - static void afterClass() { - // May cause during JUnit "Cache is not alive (STATUS_SHUTDOWN)" as JUnit share Spring context for speed - // http://stackoverflow.com/questions/16281802/ehcache-shutdown-causing-an-exception-while-running-test-suite - // appCtx.close(); - } - - @BeforeEach - void setup() { - // re-initialize - repository.init(); - } - - @Test - void delete() { - controller.delete(USER_ID); - Assertions.assertNull(repository.get(USER_ID)); - } - - @Test - void deleteNotFound() { - Assertions.assertThrows(NotFoundException.class, () -> controller.delete(NOT_FOUND)); - } -} \ No newline at end of file diff --git a/src/test/java/ru/javawebinar/topjava/web/user/ProfileRestControllerTest.java b/src/test/java/ru/javawebinar/topjava/web/user/ProfileRestControllerTest.java deleted file mode 100644 index e8882742d..000000000 --- a/src/test/java/ru/javawebinar/topjava/web/user/ProfileRestControllerTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package ru.javawebinar.topjava.web.user; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import ru.javawebinar.topjava.model.User; -import ru.javawebinar.topjava.service.UserService; -import ru.javawebinar.topjava.web.AbstractControllerTest; -import ru.javawebinar.topjava.web.json.JsonUtil; - -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static ru.javawebinar.topjava.UserTestData.*; -import static ru.javawebinar.topjava.web.user.ProfileRestController.REST_URL; - -class ProfileRestControllerTest extends AbstractControllerTest { - - @Autowired - private UserService userService; - - @Test - void get() throws Exception { - perform(MockMvcRequestBuilders.get(REST_URL)) - .andExpect(status().isOk()) - .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) - .andExpect(USER_MATCHER.contentJson(user)); - } - - @Test - void delete() throws Exception { - perform(MockMvcRequestBuilders.delete(REST_URL)) - .andExpect(status().isNoContent()); - USER_MATCHER.assertMatch(userService.getAll(), admin, guest); - } - - @Test - void update() throws Exception { - User updated = getUpdated(); - perform(MockMvcRequestBuilders.put(REST_URL).contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.writeValue(updated))) - .andDo(print()) - .andExpect(status().isNoContent()); - - USER_MATCHER.assertMatch(userService.get(USER_ID), updated); - } -} \ No newline at end of file diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml deleted file mode 100644 index 803655475..000000000 --- a/src/test/resources/logback-test.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - true - - - - - UTF-8 - %d{HH:mm:ss.SSS} %highlight(%-5level) %cyan(%class{50}.%M:%L) - %msg%n - - - - - - UTF-8 - %magenta(%msg%n) - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/spring/inmemory.xml b/src/test/resources/spring/inmemory.xml deleted file mode 100644 index 0c9d05028..000000000 --- a/src/test/resources/spring/inmemory.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/test/resources/spring/spring-cache.xml b/src/test/resources/spring/spring-cache.xml deleted file mode 100644 index 7c9dfda9a..000000000 --- a/src/test/resources/spring/spring-cache.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - false - - - - - - \ No newline at end of file