diff --git a/README.md b/README.md
index 10f29615..7fd61b43 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[](https://app.codacy.com/gh/JavaWebinar/topjava/dashboard)
+[](https://www.codacy.com/gh/JavaWebinar/topjava/dashboard)
Java Enterprise Online Project
===============================
@@ -11,13 +11,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)
+### 26.05: Старт проекта
+- Начало проверки [вступительного задания](https://github.com/JavaOPs/topjava#-Домашнее-задание-hw0)
-#### 02.02 Дедлайн на сдачу HW0
-### 05.02: 1-е занятие
+#### 31.05 Дедлайн на сдачу HW0
+### 02.06: 1-е занятие
+#### 03.06 Дедлайн подачи заявки на [дипломную программу](https://javaops.ru/view/register/diploma)
- Разбор домашнего задания вступительного занятия (вместе с Optional)
- Обзор используемых в проекте технологий. Интеграция ПО
- Maven
@@ -26,7 +27,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery +
- Уровни и зависимости логгирования. JMX
- Домашнее задание 1-го занятия (HW1 + Optional)
-### 12.02: 2-е занятие
+### 09.06: 2-е занятие
- Разбор домашнего задания HW1 + Optional
- Библиотека vs Фреймворк. Стандартные библиотеки Apache Commons, Guava
- Слои приложения. Создание каркаса приложения
@@ -34,7 +35,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery +
- Пояснения к HW2. Обработка Autowired
- Домашнее задание (HW2 + Optional)
-### 19.02: 3-е занятие
+### 16.06: 3-е занятие
- Разбор домашнего задания HW2 + Optional
- Жизненный цикл Spring контекста
- Тестирование через JUnit
@@ -47,7 +48,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery +
- Логирование тестов
- Домашнее задание (HW3 + Optional)
-### 26.02: 4-е занятие
+### 23.06: 4-е занятие
- Разбор домашнего задания HW3 + Optional
- Методы улучшения качества кода
- Spring: инициализация и популирование DB
@@ -57,7 +58,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-е занятие
+### 30.06: 5-е занятие
- Обзор JDK 9/17. Миграция Topjava с 1.8 на 17
- Разбор вопросов
- Разбор домашнего задания HW4 + Optional
@@ -68,7 +69,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery +
- Spring кэш
- Домашнее задание (HW5 + Optional)
-### 12.03: 6-е занятие
+### 07.07: 6-е занятие
- Разбор домашнего задания HW5 + Optional
- Кэш Hibernate
- Spring Web
@@ -81,7 +82,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery +
#### Большое ДЗ + выпускной проект + начинаем [курс BootJava](https://javaops.ru/view/bootjava) + подтягиваем "хвосты".
-### 26.03: 7-е занятие
+### 21.07: 7-е занятие
- Разбор домашнего задания HW6 + Optional
- Автогенерация DDL по модели
- Тестирование Spring MVC
@@ -92,7 +93,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery +
- Тестирование через SoapUi. UTF-8
- Домашнее задание (HW7 + Optional)
-### 02.04: 8-е занятие
+### 28.07: 8-е занятие
- Разбор домашнего задания HW7 + Optional
- WebJars. jQuery и JavaScript frameworks
- Bootstrap
@@ -101,7 +102,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery +
- Добавление Spring Security
- Домашнее задание (HW8 + Optional)
-### 09.04: 9-е занятие
+### 04.08: 9-е занятие
- Разбор домашнего задания HW8 + Optional
- Spring Binding
- Spring Validation
@@ -113,7 +114,7 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery +
- Cookie. Session
- Домашнее задание (HW9 + Optional)
-### 16.04: 10-е занятие
+### 11.08: 10-е занятие
- Разбор домашнего задания HW10 + Optional
- Кастомизация JSON (@JsonView) и валидации (groups)
- Рефакторинг: jQuery конверторы и группы валидации по умолчанию
@@ -126,22 +127,23 @@ Maven/ Spring/ Security/ JPA(Hibernate)/ REST(Jackson)/ Bootstrap(CSS)/ jQuery +
- Защита от межсайтовой подделки запросов (CSRF)
- Домашнее задание (HW10)
-### 23.04: 11-е занятие
+### 18.08: 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)
+- Собеседование. Разработка ПО
+- Возможные доработки приложения
+- Домашнее задание по проекту: составление резюме
+
+### 22.08: Миграция на 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)
+### 11.09.22: Дедлайн на сдачу [выпускного проекта](https://github.com/JavaOPs/topjava/blob/master/graduation.md)
+### 21.09.22: Получение дипломов для участников [Дипломной программы](https://javaops.ru/view/register/diploma)
diff --git a/pom.xml b/pom.xml
index b7f694fa..e03859c2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,48 +9,55 @@
1.0-SNAPSHOT
Calories Management
- https://javaops-demo.ru/topjava
+ http://topjava.herokuapp.com/
- 1.8
+ 17
UTF-8
UTF-8
- 5.3.39
-
- 5.6.15.Final
- 6.2.5.Final
- 3.0.1-b12
+ 5.3.20
+ 2.7.1
+ 9.0.64
- 1.2.13
+ 1.2.11
1.7.36
- 42.7.8
+ 42.4.0
+
+
+ 5.6.9.Final
+ 6.2.3.Final
+ 3.0.1-b12
+
+
+ 3.10.0
+
4.13.2
- 3.27.6
+ 3.23.1
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-war-plugin
+ 3.3.2
+
org.apache.maven.plugins
maven-surefire-plugin
@@ -68,13 +75,7 @@
org.slf4j
slf4j-api
${slf4j.version}
-
-
-
- org.slf4j
- jul-to-slf4j
- ${slf4j.version}
- runtime
+ compile
@@ -93,28 +94,14 @@
org.springframework
- spring-context
- ${spring.version}
+ spring-context-support
- org.springframework
- spring-orm
- ${spring.version}
+ org.springframework.data
+ spring-data-jpa
+ ${spring-data-jpa.version}
-
-
- org.postgresql
- postgresql
- ${postgresql.version}
-
-
- org.hsqldb
- hsqldb
- 2.3.4
-
-
-
org.hibernate
@@ -135,6 +122,32 @@
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
+
+
javax.servlet
@@ -159,7 +172,6 @@
org.springframework
spring-test
- ${spring.version}
test
@@ -171,8 +183,53 @@
+
+ hsqldb
+
+
+ org.hsqldb
+ hsqldb
+ 2.3.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
new file mode 100644
index 00000000..c7891e11
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/Profiles.java
@@ -0,0 +1,27 @@
+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");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/ru/javawebinar/topjava/model/AbstractBaseEntity.java b/src/main/java/ru/javawebinar/topjava/model/AbstractBaseEntity.java
index d9343a07..33a236b8 100644
--- a/src/main/java/ru/javawebinar/topjava/model/AbstractBaseEntity.java
+++ b/src/main/java/ru/javawebinar/topjava/model/AbstractBaseEntity.java
@@ -1,5 +1,6 @@
package ru.javawebinar.topjava.model;
+import org.springframework.data.domain.Persistable;
import org.springframework.util.Assert;
import javax.persistence.*;
@@ -7,7 +8,7 @@
@MappedSuperclass
// http://stackoverflow.com/questions/594597/hibernate-annotations-which-is-better-field-or-property-access
@Access(AccessType.FIELD)
-public abstract class AbstractBaseEntity {
+public abstract class AbstractBaseEntity implements Persistable {
public static final int START_SEQ = 100000;
@Id
@@ -26,6 +27,7 @@ public void setId(Integer id) {
this.id = id;
}
+ @Override
public Integer getId() {
return id;
}
@@ -35,6 +37,7 @@ public int id() {
return id;
}
+ @Override
public boolean isNew() {
return this.id == null;
}
diff --git a/src/main/java/ru/javawebinar/topjava/model/User.java b/src/main/java/ru/javawebinar/topjava/model/User.java
index b1892571..1b121fc0 100644
--- a/src/main/java/ru/javawebinar/topjava/model/User.java
+++ b/src/main/java/ru/javawebinar/topjava/model/User.java
@@ -44,8 +44,8 @@ public class User extends AbstractNamedEntity {
private Date registered = new Date();
@Enumerated(EnumType.STRING)
- @CollectionTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"),
- uniqueConstraints = {@UniqueConstraint(columnNames = {"user_id", "role"}, name = "uk_user_role")})
+ @CollectionTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id"),
+ uniqueConstraints = {@UniqueConstraint(columnNames = {"user_id", "role"}, name = "uk_user_roles")})
@Column(name = "role")
@ElementCollection(fetch = FetchType.EAGER)
private Set roles;
@@ -62,7 +62,7 @@ public User(User u) {
}
public User(Integer id, String name, String email, String password, Role... roles) {
- this(id, name, email, password, DEFAULT_CALORIES_PER_DAY, true, new Date(), Arrays.asList(roles));
+ this(id, name, email, password, DEFAULT_CALORIES_PER_DAY, true, new Date(), Arrays.asList((roles)));
}
public User(Integer id, String name, String email, String password, int caloriesPerDay, boolean enabled, Date registered, Collection roles) {
diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/CrudMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/CrudMealRepository.java
new file mode 100644
index 00000000..a3659675
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/CrudMealRepository.java
@@ -0,0 +1,7 @@
+package ru.javawebinar.topjava.repository.datajpa;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import ru.javawebinar.topjava.model.Meal;
+
+public interface CrudMealRepository extends JpaRepository {
+}
diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/CrudUserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/CrudUserRepository.java
new file mode 100644
index 00000000..24c42a81
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/CrudUserRepository.java
@@ -0,0 +1,19 @@
+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.User;
+
+@Transactional(readOnly = true)
+public interface CrudUserRepository extends JpaRepository {
+ @Transactional
+ @Modifying
+// @Query(name = User.DELETE)
+ @Query("DELETE FROM User u WHERE u.id=:id")
+ int delete(@Param("id") int id);
+
+ User getByEmail(String email);
+}
diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaMealRepository.java
new file mode 100644
index 00000000..d1b4c8ef
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaMealRepository.java
@@ -0,0 +1,43 @@
+package ru.javawebinar.topjava.repository.datajpa;
+
+import org.springframework.stereotype.Repository;
+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 crudRepository;
+
+ public DataJpaMealRepository(CrudMealRepository crudRepository) {
+ this.crudRepository = crudRepository;
+ }
+
+ @Override
+ public Meal save(Meal meal, int userId) {
+ return null;
+ }
+
+ @Override
+ public boolean delete(int id, int userId) {
+ return false;
+ }
+
+ @Override
+ public Meal get(int id, int userId) {
+ return null;
+ }
+
+ @Override
+ public List getAll(int userId) {
+ return null;
+ }
+
+ @Override
+ public List getBetweenHalfOpen(LocalDateTime startDateTime, LocalDateTime endDateTime, int userId) {
+ return null;
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepository.java b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepository.java
new file mode 100644
index 00000000..bc240d2d
--- /dev/null
+++ b/src/main/java/ru/javawebinar/topjava/repository/datajpa/DataJpaUserRepository.java
@@ -0,0 +1,44 @@
+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);
+ }
+}
diff --git a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcMealRepository.java b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcMealRepository.java
index 9c2a240b..fa26d566 100644
--- a/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcMealRepository.java
+++ b/src/main/java/ru/javawebinar/topjava/repository/jdbc/JdbcMealRepository.java
@@ -29,7 +29,7 @@ public class JdbcMealRepository implements MealRepository {
@Autowired
public JdbcMealRepository(JdbcTemplate jdbcTemplate, NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.insertMeal = new SimpleJdbcInsert(jdbcTemplate)
- .withTableName("meal")
+ .withTableName("meals")
.usingGeneratedKeyColumns("id");
this.jdbcTemplate = jdbcTemplate;
@@ -50,7 +50,7 @@ public Meal save(Meal meal, int userId) {
meal.setId(newId.intValue());
} else {
if (namedParameterJdbcTemplate.update("" +
- "UPDATE meal " +
+ "UPDATE meals " +
" SET description=:description, calories=:calories, date_time=:date_time " +
" WHERE id=:id AND user_id=:user_id", map) == 0) {
return null;
@@ -61,26 +61,26 @@ public Meal save(Meal meal, int userId) {
@Override
public boolean delete(int id, int userId) {
- return jdbcTemplate.update("DELETE FROM meal WHERE id=? AND user_id=?", id, userId) != 0;
+ return jdbcTemplate.update("DELETE FROM meals 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);
+ "SELECT * FROM meals 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);
+ "SELECT * FROM meals 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",
+ "SELECT * FROM meals 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/service/MealService.java b/src/main/java/ru/javawebinar/topjava/service/MealService.java
index 0e95f645..df874378 100644
--- a/src/main/java/ru/javawebinar/topjava/service/MealService.java
+++ b/src/main/java/ru/javawebinar/topjava/service/MealService.java
@@ -11,7 +11,7 @@
import static ru.javawebinar.topjava.util.DateTimeUtil.atStartOfDayOrMin;
import static ru.javawebinar.topjava.util.DateTimeUtil.atStartOfNextDayOrMax;
-import static ru.javawebinar.topjava.util.ValidationUtil.checkNotFound;
+import static ru.javawebinar.topjava.util.ValidationUtil.checkNotFoundWithId;
@Service
public class MealService {
@@ -23,11 +23,11 @@ public MealService(MealRepository repository) {
}
public Meal get(int id, int userId) {
- return checkNotFound(repository.get(id, userId), id);
+ return checkNotFoundWithId(repository.get(id, userId), id);
}
public void delete(int id, int userId) {
- checkNotFound(repository.delete(id, userId), id);
+ checkNotFoundWithId(repository.delete(id, userId), id);
}
public List getBetweenInclusive(@Nullable LocalDate startDate, @Nullable LocalDate endDate, int userId) {
@@ -40,7 +40,7 @@ public List getAll(int userId) {
public void update(Meal meal, int userId) {
Assert.notNull(meal, "meal must not be null");
- checkNotFound(repository.save(meal, userId), meal.id());
+ checkNotFoundWithId(repository.save(meal, userId), meal.id());
}
public Meal create(Meal meal, int userId) {
diff --git a/src/main/java/ru/javawebinar/topjava/service/UserService.java b/src/main/java/ru/javawebinar/topjava/service/UserService.java
index af4503db..e0979b7e 100644
--- a/src/main/java/ru/javawebinar/topjava/service/UserService.java
+++ b/src/main/java/ru/javawebinar/topjava/service/UserService.java
@@ -1,5 +1,7 @@
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;
@@ -8,6 +10,7 @@
import java.util.List;
import static ru.javawebinar.topjava.util.ValidationUtil.checkNotFound;
+import static ru.javawebinar.topjava.util.ValidationUtil.checkNotFoundWithId;
@Service
public class UserService {
@@ -18,17 +21,19 @@ 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) {
@@ -36,12 +41,14 @@ public User getByEmail(String email) {
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());
+ checkNotFoundWithId(repository.save(user), user.id());
}
}
\ 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 7c1ac9fe..a4665e2a 100644
--- a/src/main/java/ru/javawebinar/topjava/util/DateTimeUtil.java
+++ b/src/main/java/ru/javawebinar/topjava/util/DateTimeUtil.java
@@ -7,6 +7,7 @@
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
public class DateTimeUtil {
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
@@ -23,7 +24,7 @@ public static LocalDateTime atStartOfDayOrMin(LocalDate localDate) {
}
public static LocalDateTime atStartOfNextDayOrMax(LocalDate localDate) {
- return localDate != null ? localDate.plusDays(1).atStartOfDay() : MAX_DATE;
+ return localDate != null ? localDate.plus(1, ChronoUnit.DAYS).atStartOfDay() : MAX_DATE;
}
public static String toString(LocalDateTime ldt) {
diff --git a/src/main/java/ru/javawebinar/topjava/util/ValidationUtil.java b/src/main/java/ru/javawebinar/topjava/util/ValidationUtil.java
index fd4f10b4..5212eea7 100644
--- a/src/main/java/ru/javawebinar/topjava/util/ValidationUtil.java
+++ b/src/main/java/ru/javawebinar/topjava/util/ValidationUtil.java
@@ -9,12 +9,12 @@ public class ValidationUtil {
private ValidationUtil() {
}
- 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);
}
@@ -29,7 +29,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)");
}
diff --git a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java
index 544b9024..a8f60993 100644
--- a/src/main/java/ru/javawebinar/topjava/web/MealServlet.java
+++ b/src/main/java/ru/javawebinar/topjava/web/MealServlet.java
@@ -27,7 +27,7 @@ public class MealServlet extends HttpServlet {
@Override
public void init() {
- springContext = new ClassPathXmlApplicationContext("spring/spring-app.xml");
+ springContext = new ClassPathXmlApplicationContext("spring/spring-app.xml", "spring/spring-db.xml");
mealController = springContext.getBean(MealRestController.class);
}
@@ -38,7 +38,7 @@ public void destroy() {
}
@Override
- protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
Meal meal = new Meal(
LocalDateTime.parse(request.getParameter("dateTime")),
diff --git a/src/main/java/ru/javawebinar/topjava/web/SecurityUtil.java b/src/main/java/ru/javawebinar/topjava/web/SecurityUtil.java
index a48df32a..4bad5863 100644
--- a/src/main/java/ru/javawebinar/topjava/web/SecurityUtil.java
+++ b/src/main/java/ru/javawebinar/topjava/web/SecurityUtil.java
@@ -1,10 +1,12 @@
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 = 1;
+ private static int id = AbstractBaseEntity.START_SEQ;
private SecurityUtil() {
}
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 4c5c75d5..bbfe35e3 100644
--- a/src/main/java/ru/javawebinar/topjava/web/meal/MealRestController.java
+++ b/src/main/java/ru/javawebinar/topjava/web/meal/MealRestController.java
@@ -15,7 +15,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;
@Controller
public class MealRestController {
@@ -47,7 +47,7 @@ public List getAll() {
public Meal create(Meal meal) {
int userId = SecurityUtil.authUserId();
- checkIsNew(meal);
+ checkNew(meal);
log.info("create {} for user {}", meal, userId);
return service.create(meal, userId);
}
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 f9e6441b..0000f1c1 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/resources/cache/ehcache.xml b/src/main/resources/cache/ehcache.xml
new file mode 100644
index 00000000..05589f71
--- /dev/null
+++ b/src/main/resources/cache/ehcache.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+ 5
+
+ 5000
+
+
+
+
+
+
+ 1
+
+
+
+
diff --git a/src/main/resources/db/hsqldb.properties b/src/main/resources/db/hsqldb.properties
index c7944e25..3860149b 100644
--- a/src/main/resources/db/hsqldb.properties
+++ b/src/main/resources/db/hsqldb.properties
@@ -3,10 +3,9 @@
database.url=jdbc:hsqldb:mem:topjava
database.username=sa
database.password=
-database.driverClassName=org.hsqldb.jdbcDriver
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
+hibernate.use_sql_comments=truecomments=true
\ No newline at end of file
diff --git a/src/main/resources/db/initDB.sql b/src/main/resources/db/initDB.sql
index 4bf3d844..7644dc61 100644
--- a/src/main/resources/db/initDB.sql
+++ b/src/main/resources/db/initDB.sql
@@ -1,5 +1,5 @@
-DROP TABLE IF EXISTS user_role;
-DROP TABLE IF EXISTS meal;
+DROP TABLE IF EXISTS user_roles;
+DROP TABLE IF EXISTS meals;
DROP TABLE IF EXISTS users;
DROP SEQUENCE IF EXISTS global_seq;
@@ -17,7 +17,7 @@ CREATE TABLE users
);
CREATE UNIQUE INDEX users_unique_email_idx ON users (email);
-CREATE TABLE user_role
+CREATE TABLE user_roles
(
user_id INTEGER NOT NULL,
role VARCHAR NOT NULL,
@@ -25,7 +25,7 @@ CREATE TABLE user_role
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
);
-CREATE TABLE meal
+CREATE TABLE meals
(
id INTEGER PRIMARY KEY DEFAULT nextval('global_seq'),
user_id INTEGER NOT NULL,
@@ -34,4 +34,4 @@ CREATE TABLE meal
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
+CREATE UNIQUE INDEX meals_unique_user_datetime_idx ON meals (user_id, date_time);
\ No newline at end of file
diff --git a/src/main/resources/db/initDB_hsql.sql b/src/main/resources/db/initDB_hsql.sql
index 9e0e195e..37f2da1b 100644
--- a/src/main/resources/db/initDB_hsql.sql
+++ b/src/main/resources/db/initDB_hsql.sql
@@ -1,5 +1,5 @@
-DROP TABLE user_role IF EXISTS;
-DROP TABLE meal IF EXISTS;
+DROP TABLE user_roles IF EXISTS;
+DROP TABLE meals IF EXISTS;
DROP TABLE users IF EXISTS;
DROP SEQUENCE global_seq IF EXISTS;
@@ -18,15 +18,15 @@ CREATE TABLE users
CREATE UNIQUE INDEX users_unique_email_idx
ON USERS (email);
-CREATE TABLE user_role
+CREATE TABLE user_roles
(
user_id INTEGER NOT NULL,
- role VARCHAR(255) NOT NULL,
+ role VARCHAR(255),
CONSTRAINT user_roles_idx UNIQUE (user_id, role),
FOREIGN KEY (user_id) REFERENCES USERS (id) ON DELETE CASCADE
);
-CREATE TABLE meal
+CREATE TABLE meals
(
id INTEGER GENERATED BY DEFAULT AS SEQUENCE GLOBAL_SEQ PRIMARY KEY,
date_time TIMESTAMP NOT NULL,
@@ -35,5 +35,5 @@ CREATE TABLE meal
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
+CREATE UNIQUE INDEX meals_unique_user_datetime_idx
+ ON meals (user_id, date_time)
\ No newline at end of file
diff --git a/src/main/resources/db/populateDB.sql b/src/main/resources/db/populateDB.sql
index 5021dc6f..f29b325f 100644
--- a/src/main/resources/db/populateDB.sql
+++ b/src/main/resources/db/populateDB.sql
@@ -1,5 +1,5 @@
-DELETE FROM user_role;
-DELETE FROM meal;
+DELETE FROM user_roles;
+DELETE FROM meals;
DELETE FROM users;
ALTER SEQUENCE global_seq RESTART WITH 100000;
@@ -8,11 +8,11 @@ VALUES ('User', 'user@yandex.ru', 'password'),
('Admin', 'admin@gmail.com', 'admin'),
('Guest', 'guest@gmail.com', 'guest');
-INSERT INTO user_role (role, user_id)
+INSERT INTO user_roles (role, user_id)
VALUES ('USER', 100000),
('ADMIN', 100001);
-INSERT INTO meal (date_time, description, calories, user_id)
+INSERT INTO meals (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),
@@ -21,4 +21,4 @@ VALUES ('2020-01-30 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);
+ ('2020-01-31 21:00:00', 'Админ ужин', 1500, 100001);
\ No newline at end of file
diff --git a/src/main/resources/db/postgres.properties b/src/main/resources/db/postgres.properties
index fa02ee04..c45b1b6b 100644
--- a/src/main/resources/db/postgres.properties
+++ b/src/main/resources/db/postgres.properties
@@ -1,7 +1,10 @@
+#database.url=jdbc:postgresql://ec2-34-248-169-69.eu-west-1.compute.amazonaws.com:5432/d1ohm99dookbqn?ssl=true&sslmode=require&sslfactory=org.postgresql.ssl.NonValidatingFactory
+#database.username=qhazsiozndzrzc
+#database.password=749f7852a65b5ec57bde033af8fde7f8b782a3ef802921acd4613b133d62559e
+
database.url=jdbc:postgresql://localhost:5432/topjava
database.username=user
database.password=password
-database.driverClassName=org.postgresql.Driver
database.init=true
jdbc.initLocation=classpath:db/initDB.sql
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
index b73b1517..c7bffc3a 100644
--- a/src/main/resources/logback.xml
+++ b/src/main/resources/logback.xml
@@ -26,4 +26,4 @@
-
\ No newline at end of file
+
diff --git a/src/main/resources/spring/spring-app.xml b/src/main/resources/spring/spring-app.xml
index 4c17228b..d6c643e9 100644
--- a/src/main/resources/spring/spring-app.xml
+++ b/src/main/resources/spring/spring-app.xml
@@ -9,6 +9,7 @@
-->
+
diff --git a/src/main/resources/spring/spring-cache.xml b/src/main/resources/spring/spring-cache.xml
new file mode 100644
index 00000000..73325fee
--- /dev/null
+++ b/src/main/resources/spring/spring-cache.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/spring/spring-db.xml b/src/main/resources/spring/spring-db.xml
index 970261d0..46a9e1d3 100644
--- a/src/main/resources/spring/spring-db.xml
+++ b/src/main/resources/spring/spring-db.xml
@@ -4,41 +4,23 @@
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:tx="http://www.springframework.org/schema/tx"
+ xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
+ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
+ http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
-
+
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
@@ -48,6 +30,7 @@
@@ -70,9 +53,47 @@
-
-->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 0ac5a761..bd98d3bf 100644
--- a/src/main/webapp/WEB-INF/web.xml
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -4,7 +4,7 @@
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
- TopJava
+ Topjava
userServlet
@@ -25,4 +25,5 @@
mealServlet
/meals
+
diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html
index e887926b..57d710a8 100644
--- a/src/main/webapp/index.html
+++ b/src/main/webapp/index.html
@@ -9,8 +9,8 @@