From 9ba51e0c6472fe8422abbd80ef479c7ee8d84150 Mon Sep 17 00:00:00 2001 From: Struchkov Mark Date: Sat, 22 Oct 2022 18:09:06 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BB=20=D0=BC=D0=BD=D0=BE=D0=B3=D0=BE=D0=BC=D0=BE?= =?UTF-8?q?=D0=B4=D1=83=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20crud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- filmorate-app/pom.xml | 93 ++++++++++ .../filmorate/FilmorateApplication.java | 0 .../src/main/resources/application-local.yml | 5 + .../src/main/resources/application.yml | 10 ++ .../db/changelog/changelog-master.xml | 9 + .../v.1.0.0/2022-10-22-create-main-tables.xml | 47 +++++ .../v.1.0.0/2022-10-22-insert-test-data.xml | 32 ++++ .../db/changelog/v.1.0.0/changelog.xml | 14 ++ filmorate-bom/pom.xml | 84 +++++++++ filmorate-context/pom.xml | 44 +++++ .../struchkov/filmorate/context/Message.java | 19 +++ .../context/exception/FilmorateException.java | 15 ++ .../context/exception/NotFoundException.java | 15 ++ .../context/repository/FilmRepository.java | 20 +++ .../context/repository/PersonRepository.java | 20 +++ .../context/service/FilmService.java | 24 +++ .../context/service/PersonService.java | 24 +++ filmorate-core/pom.xml | 53 ++++++ .../core/service/FilmServiceImpl.java | 69 ++++++++ .../core/service/PersonServiceImpl.java | 65 +++++++ filmorate-data-jpa/pom.xml | 57 +++++++ .../filmorate/data/entity/BaseEntity.java | 22 +++ .../filmorate/data/entity/FilmEntity.java | 38 +++++ .../filmorate/data/entity/PersonEntity.java | 29 ++++ .../filmorate/data/jpa/FilmJpaRepository.java | 7 + .../data/jpa/PersonJpaRepository.java | 7 + .../data/mapper/FilmEntityMapper.java | 14 ++ .../data/mapper/PersonEntityMapper.java | 14 ++ .../data/repository/FilmRepositoryImpl.java | 56 ++++++ .../data/repository/PersonRepositoryImpl.java | 58 +++++++ filmorate-data-local/pom.xml | 43 +++++ .../data/repository/FilmLocalRepository.java | 42 +++++ .../repository/PersonLocalRepository.java | 42 +++++ filmorate-domain/pom.xml | 37 ++++ .../dev/strichkov/filmorate/domain/Film.java | 29 ++++ .../strichkov/filmorate/domain/Person.java | 22 +++ .../filmorate/domain/page/Pagination.java | 13 ++ .../filmorate/domain/page/Sheet.java | 29 ++++ filmorate-web/pom.xml | 63 +++++++ .../web/controller/FilmController.java | 82 +++++++++ .../web/controller/PersonController.java | 82 +++++++++ .../web/converter/FilmToDtoConvert.java | 21 +++ .../web/converter/FilmToEntityConvert.java | 22 +++ .../struchkov/filmorate/web/dto/FilmDto.java | 39 +++++ .../filmorate/web/dto/PersonDto.java | 29 ++++ .../filmorate/web/mapper/PersonMapper.java | 14 ++ pom.xml | 161 ++++++++++++------ src/main/resources/application.properties | 1 - .../filmorate/FilmorateApplicationTests.java | 13 -- 49 files changed, 1678 insertions(+), 70 deletions(-) create mode 100644 filmorate-app/pom.xml rename {src => filmorate-app/src}/main/java/dev/struchkov/filmorate/FilmorateApplication.java (100%) create mode 100644 filmorate-app/src/main/resources/application-local.yml create mode 100644 filmorate-app/src/main/resources/application.yml create mode 100644 filmorate-app/src/main/resources/db/changelog/changelog-master.xml create mode 100644 filmorate-app/src/main/resources/db/changelog/v.1.0.0/2022-10-22-create-main-tables.xml create mode 100644 filmorate-app/src/main/resources/db/changelog/v.1.0.0/2022-10-22-insert-test-data.xml create mode 100644 filmorate-app/src/main/resources/db/changelog/v.1.0.0/changelog.xml create mode 100644 filmorate-bom/pom.xml create mode 100644 filmorate-context/pom.xml create mode 100644 filmorate-context/src/main/java/dev/struchkov/filmorate/context/Message.java create mode 100644 filmorate-context/src/main/java/dev/struchkov/filmorate/context/exception/FilmorateException.java create mode 100644 filmorate-context/src/main/java/dev/struchkov/filmorate/context/exception/NotFoundException.java create mode 100644 filmorate-context/src/main/java/dev/struchkov/filmorate/context/repository/FilmRepository.java create mode 100644 filmorate-context/src/main/java/dev/struchkov/filmorate/context/repository/PersonRepository.java create mode 100644 filmorate-context/src/main/java/dev/struchkov/filmorate/context/service/FilmService.java create mode 100644 filmorate-context/src/main/java/dev/struchkov/filmorate/context/service/PersonService.java create mode 100644 filmorate-core/pom.xml create mode 100644 filmorate-core/src/main/java/dev/struchkov/filmorate/core/service/FilmServiceImpl.java create mode 100644 filmorate-core/src/main/java/dev/struchkov/filmorate/core/service/PersonServiceImpl.java create mode 100644 filmorate-data-jpa/pom.xml create mode 100644 filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/entity/BaseEntity.java create mode 100644 filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/entity/FilmEntity.java create mode 100644 filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/entity/PersonEntity.java create mode 100644 filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/jpa/FilmJpaRepository.java create mode 100644 filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/jpa/PersonJpaRepository.java create mode 100644 filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/mapper/FilmEntityMapper.java create mode 100644 filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/mapper/PersonEntityMapper.java create mode 100644 filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/repository/FilmRepositoryImpl.java create mode 100644 filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/repository/PersonRepositoryImpl.java create mode 100644 filmorate-data-local/pom.xml create mode 100644 filmorate-data-local/src/main/java/dev/struchkov/filmorate/data/repository/FilmLocalRepository.java create mode 100644 filmorate-data-local/src/main/java/dev/struchkov/filmorate/data/repository/PersonLocalRepository.java create mode 100644 filmorate-domain/pom.xml create mode 100644 filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/Film.java create mode 100644 filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/Person.java create mode 100644 filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/page/Pagination.java create mode 100644 filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/page/Sheet.java create mode 100644 filmorate-web/pom.xml create mode 100644 filmorate-web/src/main/java/dev/struchkov/filmorate/web/controller/FilmController.java create mode 100644 filmorate-web/src/main/java/dev/struchkov/filmorate/web/controller/PersonController.java create mode 100644 filmorate-web/src/main/java/dev/struchkov/filmorate/web/converter/FilmToDtoConvert.java create mode 100644 filmorate-web/src/main/java/dev/struchkov/filmorate/web/converter/FilmToEntityConvert.java create mode 100644 filmorate-web/src/main/java/dev/struchkov/filmorate/web/dto/FilmDto.java create mode 100644 filmorate-web/src/main/java/dev/struchkov/filmorate/web/dto/PersonDto.java create mode 100644 filmorate-web/src/main/java/dev/struchkov/filmorate/web/mapper/PersonMapper.java delete mode 100644 src/main/resources/application.properties delete mode 100644 src/test/java/dev/struchkov/filmorate/FilmorateApplicationTests.java diff --git a/filmorate-app/pom.xml b/filmorate-app/pom.xml new file mode 100644 index 0000000..e2c5b38 --- /dev/null +++ b/filmorate-app/pom.xml @@ -0,0 +1,93 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.5 + + + + dev.struchkov.filmorate + filmorate-app + 0.0.1-SNAPSHOT + jar + + + + + dev.struchkov.filmorate + filmorate-bom + ${filmorate.version} + pom + import + + + + + + 17 + ${java.version} + ${java.version} + UTF-8 + UTF-8 + + 0.0.1-SNAPSHOT + + + + + dev.struchkov.filmorate + filmorate-core + + + dev.struchkov.filmorate + filmorate-data-jpa + + + + + + + dev.struchkov.filmorate + filmorate-web + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework.boot + spring-boot-actuator + + + + + filmorate + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + \ No newline at end of file diff --git a/src/main/java/dev/struchkov/filmorate/FilmorateApplication.java b/filmorate-app/src/main/java/dev/struchkov/filmorate/FilmorateApplication.java similarity index 100% rename from src/main/java/dev/struchkov/filmorate/FilmorateApplication.java rename to filmorate-app/src/main/java/dev/struchkov/filmorate/FilmorateApplication.java diff --git a/filmorate-app/src/main/resources/application-local.yml b/filmorate-app/src/main/resources/application-local.yml new file mode 100644 index 0000000..cc08e49 --- /dev/null +++ b/filmorate-app/src/main/resources/application-local.yml @@ -0,0 +1,5 @@ +spring: + application: + name: Filmorate Local + liquibase: + contexts: local \ No newline at end of file diff --git a/filmorate-app/src/main/resources/application.yml b/filmorate-app/src/main/resources/application.yml new file mode 100644 index 0000000..ae58d81 --- /dev/null +++ b/filmorate-app/src/main/resources/application.yml @@ -0,0 +1,10 @@ +spring: + application: + name: Filmorate + liquibase: + change-log: db/changelog/changelog-master.xml + datasource: + driver-class-name: org.postgresql.Driver + url: ${DB_URL} + username: ${DB_USERNAME} + password: ${DB_PASSWORD} diff --git a/filmorate-app/src/main/resources/db/changelog/changelog-master.xml b/filmorate-app/src/main/resources/db/changelog/changelog-master.xml new file mode 100644 index 0000000..5f7bae2 --- /dev/null +++ b/filmorate-app/src/main/resources/db/changelog/changelog-master.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/filmorate-app/src/main/resources/db/changelog/v.1.0.0/2022-10-22-create-main-tables.xml b/filmorate-app/src/main/resources/db/changelog/v.1.0.0/2022-10-22-create-main-tables.xml new file mode 100644 index 0000000..efb7b2d --- /dev/null +++ b/filmorate-app/src/main/resources/db/changelog/v.1.0.0/2022-10-22-create-main-tables.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/filmorate-app/src/main/resources/db/changelog/v.1.0.0/2022-10-22-insert-test-data.xml b/filmorate-app/src/main/resources/db/changelog/v.1.0.0/2022-10-22-insert-test-data.xml new file mode 100644 index 0000000..e361622 --- /dev/null +++ b/filmorate-app/src/main/resources/db/changelog/v.1.0.0/2022-10-22-insert-test-data.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/filmorate-app/src/main/resources/db/changelog/v.1.0.0/changelog.xml b/filmorate-app/src/main/resources/db/changelog/v.1.0.0/changelog.xml new file mode 100644 index 0000000..c76647e --- /dev/null +++ b/filmorate-app/src/main/resources/db/changelog/v.1.0.0/changelog.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/filmorate-bom/pom.xml b/filmorate-bom/pom.xml new file mode 100644 index 0000000..d33e951 --- /dev/null +++ b/filmorate-bom/pom.xml @@ -0,0 +1,84 @@ + + + 4.0.0 + + dev.struchkov.filmorate + filmorate-bom + 0.0.1-SNAPSHOT + pom + + + 17 + 17 + UTF-8 + + 0.0.1-SNAPSHOT + ${filmorate.version} + ${filmorate.version} + ${filmorate.version} + ${filmorate.version} + ${filmorate.version} + ${filmorate.version} + + 2.7.5 + + 1.5.2.Final + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.starter.parent.version} + pom + import + + + + dev.struchkov.filmorate + filmorate-domain + ${filmorate.domain.version} + + + dev.struchkov.filmorate + filmorate-context + ${filmorate.context.version} + + + dev.struchkov.filmorate + filmorate-core + ${filmorate.core.version} + + + dev.struchkov.filmorate + filmorate-data-local + ${filmorate.data.local.version} + + + dev.struchkov.filmorate + filmorate-data-jpa + ${filmorate.data.jpa.version} + + + dev.struchkov.filmorate + filmorate-web + ${filmorate.web.version} + + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + + \ No newline at end of file diff --git a/filmorate-context/pom.xml b/filmorate-context/pom.xml new file mode 100644 index 0000000..5f37749 --- /dev/null +++ b/filmorate-context/pom.xml @@ -0,0 +1,44 @@ + + + + dev.struchkov.filmorate + filmorate + 0.0.1-SNAPSHOT + + 4.0.0 + + filmorate-context + + + 17 + 17 + UTF-8 + + + + + dev.struchkov.filmorate + filmorate-domain + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + + \ No newline at end of file diff --git a/filmorate-context/src/main/java/dev/struchkov/filmorate/context/Message.java b/filmorate-context/src/main/java/dev/struchkov/filmorate/context/Message.java new file mode 100644 index 0000000..ca1d841 --- /dev/null +++ b/filmorate-context/src/main/java/dev/struchkov/filmorate/context/Message.java @@ -0,0 +1,19 @@ +package dev.struchkov.filmorate.context; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public final class Message { + + @UtilityClass + public static class NotFound { + public static final String FILM = "Фильм не найден. Идентификатор: {0}"; + public static final String PERSON = "Пользователь не найден. Идентификатор: {0}"; + } + + @UtilityClass + public static class Error { + + } + +} diff --git a/filmorate-context/src/main/java/dev/struchkov/filmorate/context/exception/FilmorateException.java b/filmorate-context/src/main/java/dev/struchkov/filmorate/context/exception/FilmorateException.java new file mode 100644 index 0000000..678a015 --- /dev/null +++ b/filmorate-context/src/main/java/dev/struchkov/filmorate/context/exception/FilmorateException.java @@ -0,0 +1,15 @@ +package dev.struchkov.filmorate.context.exception; + +import java.text.MessageFormat; + +public abstract class FilmorateException extends RuntimeException { + + protected FilmorateException(String message) { + super(message); + } + + protected FilmorateException(String message, Object... args) { + super(MessageFormat.format(message, args)); + } + +} diff --git a/filmorate-context/src/main/java/dev/struchkov/filmorate/context/exception/NotFoundException.java b/filmorate-context/src/main/java/dev/struchkov/filmorate/context/exception/NotFoundException.java new file mode 100644 index 0000000..acf9be3 --- /dev/null +++ b/filmorate-context/src/main/java/dev/struchkov/filmorate/context/exception/NotFoundException.java @@ -0,0 +1,15 @@ +package dev.struchkov.filmorate.context.exception; + +import java.util.function.Supplier; + +public class NotFoundException extends FilmorateException{ + + public NotFoundException(String message, Object... args) { + super(message, args); + } + + public static Supplier notFoundException(String message, Object... args) { + return () -> new NotFoundException(message, args); + } + +} diff --git a/filmorate-context/src/main/java/dev/struchkov/filmorate/context/repository/FilmRepository.java b/filmorate-context/src/main/java/dev/struchkov/filmorate/context/repository/FilmRepository.java new file mode 100644 index 0000000..c1800c6 --- /dev/null +++ b/filmorate-context/src/main/java/dev/struchkov/filmorate/context/repository/FilmRepository.java @@ -0,0 +1,20 @@ +package dev.struchkov.filmorate.context.repository; + +import dev.strichkov.filmorate.domain.Film; +import dev.strichkov.filmorate.domain.page.Pagination; +import dev.strichkov.filmorate.domain.page.Sheet; +import lombok.NonNull; + +import java.util.Optional; + +public interface FilmRepository { + + Film save(@NonNull Film film); + + Optional findById(@NonNull Long filmId); + + Sheet findAll(@NonNull Pagination pagination); + + void deleteById(@NonNull Long filmId); + +} diff --git a/filmorate-context/src/main/java/dev/struchkov/filmorate/context/repository/PersonRepository.java b/filmorate-context/src/main/java/dev/struchkov/filmorate/context/repository/PersonRepository.java new file mode 100644 index 0000000..3a54ba0 --- /dev/null +++ b/filmorate-context/src/main/java/dev/struchkov/filmorate/context/repository/PersonRepository.java @@ -0,0 +1,20 @@ +package dev.struchkov.filmorate.context.repository; + +import dev.strichkov.filmorate.domain.Person; +import dev.strichkov.filmorate.domain.page.Pagination; +import dev.strichkov.filmorate.domain.page.Sheet; +import lombok.NonNull; + +import java.util.Optional; + +public interface PersonRepository { + + Person save(@NonNull Person person); + + Optional findById(@NonNull Long personId); + + void deleteById(@NonNull Long personId); + + Sheet findByAll(@NonNull Pagination pagination); + +} diff --git a/filmorate-context/src/main/java/dev/struchkov/filmorate/context/service/FilmService.java b/filmorate-context/src/main/java/dev/struchkov/filmorate/context/service/FilmService.java new file mode 100644 index 0000000..33d2555 --- /dev/null +++ b/filmorate-context/src/main/java/dev/struchkov/filmorate/context/service/FilmService.java @@ -0,0 +1,24 @@ +package dev.struchkov.filmorate.context.service; + +import dev.strichkov.filmorate.domain.Film; +import dev.strichkov.filmorate.domain.page.Pagination; +import dev.strichkov.filmorate.domain.page.Sheet; +import lombok.NonNull; + +import java.util.Optional; + +public interface FilmService { + + Film create(@NonNull Film film); + + Film update(@NonNull Film film); + + void deleteById(@NonNull Long filmId); + + Optional getById(@NonNull Long filmId); + + Film getByIdOrThrow(@NonNull Long filmId); + + Sheet getAll(@NonNull Pagination pagination); + +} diff --git a/filmorate-context/src/main/java/dev/struchkov/filmorate/context/service/PersonService.java b/filmorate-context/src/main/java/dev/struchkov/filmorate/context/service/PersonService.java new file mode 100644 index 0000000..2090e47 --- /dev/null +++ b/filmorate-context/src/main/java/dev/struchkov/filmorate/context/service/PersonService.java @@ -0,0 +1,24 @@ +package dev.struchkov.filmorate.context.service; + +import dev.strichkov.filmorate.domain.Person; +import dev.strichkov.filmorate.domain.page.Pagination; +import dev.strichkov.filmorate.domain.page.Sheet; +import lombok.NonNull; + +import java.util.Optional; + +public interface PersonService { + + Person create(@NonNull Person person); + + Person update(@NonNull Person person); + + void deleteById(@NonNull Long personId); + + Optional getById(@NonNull Long personId); + + Person getByIdOrThrow(@NonNull Long personId); + + Sheet getAll(@NonNull Pagination pagination); + +} diff --git a/filmorate-core/pom.xml b/filmorate-core/pom.xml new file mode 100644 index 0000000..3a0ecaf --- /dev/null +++ b/filmorate-core/pom.xml @@ -0,0 +1,53 @@ + + + + dev.struchkov.filmorate + filmorate + 0.0.1-SNAPSHOT + + 4.0.0 + + filmorate-core + + + 17 + 17 + UTF-8 + + + + + dev.struchkov.filmorate + filmorate-context + + + + org.springframework + spring-context + + + org.springframework + spring-tx + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + + \ No newline at end of file diff --git a/filmorate-core/src/main/java/dev/struchkov/filmorate/core/service/FilmServiceImpl.java b/filmorate-core/src/main/java/dev/struchkov/filmorate/core/service/FilmServiceImpl.java new file mode 100644 index 0000000..0dbe14c --- /dev/null +++ b/filmorate-core/src/main/java/dev/struchkov/filmorate/core/service/FilmServiceImpl.java @@ -0,0 +1,69 @@ +package dev.struchkov.filmorate.core.service; + +import dev.strichkov.filmorate.domain.Film; +import dev.strichkov.filmorate.domain.page.Pagination; +import dev.strichkov.filmorate.domain.page.Sheet; +import dev.struchkov.filmorate.context.Message; +import dev.struchkov.filmorate.context.repository.FilmRepository; +import dev.struchkov.filmorate.context.service.FilmService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.Optional; + +import static dev.struchkov.filmorate.context.exception.NotFoundException.notFoundException; + +@Service +@RequiredArgsConstructor +public class FilmServiceImpl implements FilmService { + + private final FilmRepository repository; + + @Override + @Transactional + public Film create(@NonNull Film film) { + film.setDateCreated(film.getDateCreated()); + return repository.save(film); + } + + @Override + @Transactional + public Film update(@NonNull Film newFilm) { + final Film oldFilm = repository.findById(newFilm.getId()) + .orElseThrow(notFoundException(Message.NotFound.FILM, newFilm.getId())); + oldFilm.setName(newFilm.getName()); + oldFilm.setDurationInMinutes(newFilm.getDurationInMinutes()); + oldFilm.setDateRelease(newFilm.getDateRelease()); + oldFilm.setDescription(newFilm.getDescription()); + oldFilm.setDateUpdated(LocalDateTime.now()); + return oldFilm; + } + + @Override + public void deleteById(@NonNull Long filmId) { + repository.deleteById(filmId); + } + + @Override + @Transactional(readOnly = true) + public Optional getById(@NonNull Long filmId) { + return repository.findById(filmId); + } + + @Override + @Transactional(readOnly = true) + public Film getByIdOrThrow(@NonNull Long filmId) { + return repository.findById(filmId) + .orElseThrow(notFoundException(Message.NotFound.FILM, filmId)); + } + + @Override + @Transactional(readOnly = true) + public Sheet getAll(@NonNull Pagination pagination) { + return repository.findAll(pagination); + } + +} diff --git a/filmorate-core/src/main/java/dev/struchkov/filmorate/core/service/PersonServiceImpl.java b/filmorate-core/src/main/java/dev/struchkov/filmorate/core/service/PersonServiceImpl.java new file mode 100644 index 0000000..3e9e7fa --- /dev/null +++ b/filmorate-core/src/main/java/dev/struchkov/filmorate/core/service/PersonServiceImpl.java @@ -0,0 +1,65 @@ +package dev.struchkov.filmorate.core.service; + +import dev.strichkov.filmorate.domain.Person; +import dev.strichkov.filmorate.domain.page.Pagination; +import dev.strichkov.filmorate.domain.page.Sheet; +import dev.struchkov.filmorate.context.Message; +import dev.struchkov.filmorate.context.repository.PersonRepository; +import dev.struchkov.filmorate.context.service.PersonService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +import static dev.struchkov.filmorate.context.exception.NotFoundException.notFoundException; + +@Service +@RequiredArgsConstructor +public class PersonServiceImpl implements PersonService { + + private final PersonRepository repository; + + @Override + @Transactional + public Person create(@NonNull Person person) { + return repository.save(person); + } + + @Override + @Transactional + public Person update(@NonNull Person newPerson) { + final Person oldPerson = repository.findById(newPerson.getId()) + .orElseThrow(notFoundException(Message.NotFound.PERSON, newPerson.getId())); + oldPerson.setName(newPerson.getName()); + oldPerson.setEmail(newPerson.getEmail()); + oldPerson.setBirthday(newPerson.getBirthday()); + return oldPerson; + } + + @Override + @Transactional + public void deleteById(@NonNull Long personId) { + repository.deleteById(personId); + } + + @Override + @Transactional(readOnly = true) + public Optional getById(@NonNull Long personId) { + return repository.findById(personId); + } + + @Override + @Transactional(readOnly = true) + public Person getByIdOrThrow(@NonNull Long personId) { + return repository.findById(personId) + .orElseThrow(notFoundException(Message.NotFound.PERSON, personId)); + } + + @Override + @Transactional(readOnly = true) + public Sheet getAll(@NonNull Pagination pagination) { + return repository.findByAll(pagination); + } +} diff --git a/filmorate-data-jpa/pom.xml b/filmorate-data-jpa/pom.xml new file mode 100644 index 0000000..4a0c318 --- /dev/null +++ b/filmorate-data-jpa/pom.xml @@ -0,0 +1,57 @@ + + + + dev.struchkov.filmorate + filmorate + 0.0.1-SNAPSHOT + + 4.0.0 + + filmorate-data-jpa + + + + dev.struchkov.filmorate + filmorate-context + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.liquibase + liquibase-core + + + org.postgresql + postgresql + runtime + + + + org.mapstruct + mapstruct + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + + \ No newline at end of file diff --git a/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/entity/BaseEntity.java b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/entity/BaseEntity.java new file mode 100644 index 0000000..48f2343 --- /dev/null +++ b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/entity/BaseEntity.java @@ -0,0 +1,22 @@ +package dev.struchkov.filmorate.data.entity; + +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; + +@Getter +@Setter +@MappedSuperclass +public abstract class BaseEntity { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.SEQUENCE) + private Long id; + +} diff --git a/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/entity/FilmEntity.java b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/entity/FilmEntity.java new file mode 100644 index 0000000..1eeb916 --- /dev/null +++ b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/entity/FilmEntity.java @@ -0,0 +1,38 @@ +package dev.struchkov.filmorate.data.entity; + +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import java.time.LocalDateTime; + +@Entity +@Getter +@Setter +@Table(name = "film") +public class FilmEntity extends BaseEntity { + + @Column(name = "name") + private String name; + + @Column(name = "description") + private String description; + + @Column(name = "date_release") + private LocalDateTime dateRelease; + + @Column(name = "duration_in_minutes") + private Integer durationInMinutes; + + @Column(name = "date_created") + private LocalDateTime dateCreated; + + @Column(name = "date_updated") + private LocalDateTime dateUpdated; + + @Column(name = "person_owner_id") + private Long ownerId; + +} diff --git a/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/entity/PersonEntity.java b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/entity/PersonEntity.java new file mode 100644 index 0000000..73d448c --- /dev/null +++ b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/entity/PersonEntity.java @@ -0,0 +1,29 @@ +package dev.struchkov.filmorate.data.entity; + +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import java.time.LocalDateTime; + +@Entity +@Getter +@Setter +@Table(name = "person") +public class PersonEntity extends BaseEntity { + + @Column(name = "name") + private String name; + + @Column(name = "email") + private String email; + + @Column(name = "login") + private String login; + + @Column(name = "birthday") + private LocalDateTime birthday; + +} diff --git a/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/jpa/FilmJpaRepository.java b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/jpa/FilmJpaRepository.java new file mode 100644 index 0000000..dfdbdd6 --- /dev/null +++ b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/jpa/FilmJpaRepository.java @@ -0,0 +1,7 @@ +package dev.struchkov.filmorate.data.jpa; + +import dev.struchkov.filmorate.data.entity.FilmEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface FilmJpaRepository extends JpaRepository { +} diff --git a/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/jpa/PersonJpaRepository.java b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/jpa/PersonJpaRepository.java new file mode 100644 index 0000000..26a399a --- /dev/null +++ b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/jpa/PersonJpaRepository.java @@ -0,0 +1,7 @@ +package dev.struchkov.filmorate.data.jpa; + +import dev.struchkov.filmorate.data.entity.PersonEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface PersonJpaRepository extends JpaRepository { +} diff --git a/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/mapper/FilmEntityMapper.java b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/mapper/FilmEntityMapper.java new file mode 100644 index 0000000..e5c1a8c --- /dev/null +++ b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/mapper/FilmEntityMapper.java @@ -0,0 +1,14 @@ +package dev.struchkov.filmorate.data.mapper; + +import dev.strichkov.filmorate.domain.Film; +import dev.struchkov.filmorate.data.entity.FilmEntity; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface FilmEntityMapper { + + FilmEntity toEntity(Film film); + + Film toDomain(FilmEntity film); + +} diff --git a/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/mapper/PersonEntityMapper.java b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/mapper/PersonEntityMapper.java new file mode 100644 index 0000000..30663d1 --- /dev/null +++ b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/mapper/PersonEntityMapper.java @@ -0,0 +1,14 @@ +package dev.struchkov.filmorate.data.mapper; + +import dev.strichkov.filmorate.domain.Person; +import dev.struchkov.filmorate.data.entity.PersonEntity; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface PersonEntityMapper { + + PersonEntity toEntity(Person person); + + Person toDomain(PersonEntity entity); + +} diff --git a/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/repository/FilmRepositoryImpl.java b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/repository/FilmRepositoryImpl.java new file mode 100644 index 0000000..835e65b --- /dev/null +++ b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/repository/FilmRepositoryImpl.java @@ -0,0 +1,56 @@ +package dev.struchkov.filmorate.data.repository; + +import dev.strichkov.filmorate.domain.Film; +import dev.strichkov.filmorate.domain.page.Pagination; +import dev.strichkov.filmorate.domain.page.Sheet; +import dev.struchkov.filmorate.context.repository.FilmRepository; +import dev.struchkov.filmorate.data.jpa.FilmJpaRepository; +import dev.struchkov.filmorate.data.mapper.FilmEntityMapper; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class FilmRepositoryImpl implements FilmRepository { + + private final FilmJpaRepository jpaRepository; + private final FilmEntityMapper filmMapper; + + @Override + public Film save(@NonNull Film film) { + return filmMapper.toDomain( + jpaRepository.save(filmMapper.toEntity(film)) + ); + } + + @Override + public Optional findById(@NonNull Long filmId) { + return jpaRepository.findById(filmId) + .map(filmMapper::toDomain); + } + + @Override + public Sheet findAll(@NonNull Pagination pagination) { + final PageRequest pageable = PageRequest.of(pagination.getPageNumber(), pagination.getPageSize()); + final Page page = jpaRepository.findAll(pageable) + .map(filmMapper::toDomain); + return Sheet.builder() + .totalElements(page.getTotalElements()) + .totalPage(page.getTotalPages()) + .pageNumber(pagination.getPageNumber()) + .pageSize(pagination.getPageSize()) + .content(page.getContent()) + .build(); + } + + @Override + public void deleteById(@NonNull Long filmId) { + jpaRepository.deleteById(filmId); + } + +} diff --git a/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/repository/PersonRepositoryImpl.java b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/repository/PersonRepositoryImpl.java new file mode 100644 index 0000000..ce67dc3 --- /dev/null +++ b/filmorate-data-jpa/src/main/java/dev/struchkov/filmorate/data/repository/PersonRepositoryImpl.java @@ -0,0 +1,58 @@ +package dev.struchkov.filmorate.data.repository; + +import dev.strichkov.filmorate.domain.Person; +import dev.strichkov.filmorate.domain.page.Pagination; +import dev.strichkov.filmorate.domain.page.Sheet; +import dev.struchkov.filmorate.context.repository.PersonRepository; +import dev.struchkov.filmorate.data.jpa.PersonJpaRepository; +import dev.struchkov.filmorate.data.mapper.PersonEntityMapper; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class PersonRepositoryImpl implements PersonRepository { + + private final PersonJpaRepository jpaRepository; + private final PersonEntityMapper personMapper; + + @Override + public Person save(@NonNull Person person) { + return personMapper.toDomain( + jpaRepository.save( + personMapper.toEntity(person) + ) + ); + } + + @Override + public Optional findById(@NonNull Long personId) { + return jpaRepository.findById(personId) + .map(personMapper::toDomain); + } + + @Override + public void deleteById(@NonNull Long personId) { + jpaRepository.deleteById(personId); + } + + @Override + public Sheet findByAll(@NonNull Pagination pagination) { + final PageRequest pageable = PageRequest.of(pagination.getPageNumber(), pagination.getPageSize()); + final Page page = jpaRepository.findAll(pageable) + .map(personMapper::toDomain); + return Sheet.builder() + .totalPage(page.getTotalPages()) + .totalElements(page.getTotalElements()) + .pageSize(page.getSize()) + .pageNumber(page.getNumber()) + .content(page.getContent()) + .build(); + } + +} diff --git a/filmorate-data-local/pom.xml b/filmorate-data-local/pom.xml new file mode 100644 index 0000000..fdd00d0 --- /dev/null +++ b/filmorate-data-local/pom.xml @@ -0,0 +1,43 @@ + + + + dev.struchkov.filmorate + filmorate + 0.0.1-SNAPSHOT + + 4.0.0 + + filmorate-data-local + + + + org.springframework + spring-context + + + + dev.struchkov.filmorate + filmorate-context + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + + \ No newline at end of file diff --git a/filmorate-data-local/src/main/java/dev/struchkov/filmorate/data/repository/FilmLocalRepository.java b/filmorate-data-local/src/main/java/dev/struchkov/filmorate/data/repository/FilmLocalRepository.java new file mode 100644 index 0000000..cd602ce --- /dev/null +++ b/filmorate-data-local/src/main/java/dev/struchkov/filmorate/data/repository/FilmLocalRepository.java @@ -0,0 +1,42 @@ +package dev.struchkov.filmorate.data.repository; + +import dev.strichkov.filmorate.domain.Film; +import dev.strichkov.filmorate.domain.page.Pagination; +import dev.strichkov.filmorate.domain.page.Sheet; +import dev.struchkov.filmorate.context.repository.FilmRepository; +import lombok.NonNull; +import org.springframework.stereotype.Repository; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Repository +public class FilmLocalRepository implements FilmRepository { + + private final Map storage = new HashMap<>(); + private long gen = 0; + + @Override + public Film save(@NonNull Film film) { + film.setId(gen++); + storage.put(film.getId(), film); + return film; + } + + @Override + public Optional findById(@NonNull Long filmId) { + return Optional.ofNullable(storage.get(filmId)); + } + + @Override + public Sheet findAll(@NonNull Pagination pagination) { + throw new UnsupportedOperationException("Не работает :("); + } + + @Override + public void deleteById(@NonNull Long filmId) { + storage.remove(filmId); + } + +} diff --git a/filmorate-data-local/src/main/java/dev/struchkov/filmorate/data/repository/PersonLocalRepository.java b/filmorate-data-local/src/main/java/dev/struchkov/filmorate/data/repository/PersonLocalRepository.java new file mode 100644 index 0000000..fda0592 --- /dev/null +++ b/filmorate-data-local/src/main/java/dev/struchkov/filmorate/data/repository/PersonLocalRepository.java @@ -0,0 +1,42 @@ +package dev.struchkov.filmorate.data.repository; + +import dev.strichkov.filmorate.domain.Person; +import dev.strichkov.filmorate.domain.page.Pagination; +import dev.strichkov.filmorate.domain.page.Sheet; +import dev.struchkov.filmorate.context.repository.PersonRepository; +import lombok.NonNull; +import org.springframework.stereotype.Repository; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Repository +public class PersonLocalRepository implements PersonRepository { + + private final Map storage = new HashMap<>(); + private long gen = 0; + + @Override + public Person save(@NonNull Person person) { + person.setId(gen++); + storage.put(person.getId(), person); + return person; + } + + @Override + public Optional findById(@NonNull Long personId) { + return Optional.ofNullable(storage.get(personId)); + } + + @Override + public void deleteById(@NonNull Long personId) { + storage.remove(personId); + } + + @Override + public Sheet findByAll(@NonNull Pagination pagination) { + throw new UnsupportedOperationException("Не работает"); + } + +} diff --git a/filmorate-domain/pom.xml b/filmorate-domain/pom.xml new file mode 100644 index 0000000..d10c0e9 --- /dev/null +++ b/filmorate-domain/pom.xml @@ -0,0 +1,37 @@ + + + + dev.struchkov.filmorate + filmorate + 0.0.1-SNAPSHOT + + 4.0.0 + + filmorate-domain + + + 17 + 17 + UTF-8 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + + \ No newline at end of file diff --git a/filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/Film.java b/filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/Film.java new file mode 100644 index 0000000..c3de062 --- /dev/null +++ b/filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/Film.java @@ -0,0 +1,29 @@ +package dev.strichkov.filmorate.domain; + +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Getter +@Setter +public class Film { + + private Long id; + + private String name; + + private String description; + + private LocalDate dateRelease; + + private Integer durationInMinutes; + + private LocalDateTime dateCreated; + + private LocalDateTime dateUpdated; + + private Long ownerId; + +} diff --git a/filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/Person.java b/filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/Person.java new file mode 100644 index 0000000..f7fec23 --- /dev/null +++ b/filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/Person.java @@ -0,0 +1,22 @@ +package dev.strichkov.filmorate.domain; + +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Getter +@Setter +public class Person { + + private Long id; + + private String name; + + private String email; + + private String login; + + private LocalDateTime birthday; + +} diff --git a/filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/page/Pagination.java b/filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/page/Pagination.java new file mode 100644 index 0000000..10a4371 --- /dev/null +++ b/filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/page/Pagination.java @@ -0,0 +1,13 @@ +package dev.strichkov.filmorate.domain.page; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class Pagination { + + private Integer pageNumber; + private Integer pageSize; + +} diff --git a/filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/page/Sheet.java b/filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/page/Sheet.java new file mode 100644 index 0000000..20a21c7 --- /dev/null +++ b/filmorate-domain/src/main/java/dev/strichkov/filmorate/domain/page/Sheet.java @@ -0,0 +1,29 @@ +package dev.strichkov.filmorate.domain.page; + +import lombok.Builder; +import lombok.Getter; + +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Getter +@Builder +public class Sheet { + + private List content; + private Long totalElements; + private Integer totalPage; + private Integer pageSize; + private Integer pageNumber; + + public Sheet map(Function mapping) { + return Sheet.builder() + .totalElements(totalElements) + .totalPage(totalPage) + .pageNumber(pageNumber) + .pageSize(pageSize) + .content(content.stream().map(mapping).collect(Collectors.toList()) ) + .build(); + } +} diff --git a/filmorate-web/pom.xml b/filmorate-web/pom.xml new file mode 100644 index 0000000..aa51828 --- /dev/null +++ b/filmorate-web/pom.xml @@ -0,0 +1,63 @@ + + + + dev.struchkov.filmorate + filmorate + 0.0.1-SNAPSHOT + + 4.0.0 + + filmorate-web + + + 17 + 17 + UTF-8 + + + + + dev.struchkov.filmorate + filmorate-context + + + + org.springframework.boot + spring-boot-starter-web + + + org.mapstruct + mapstruct + + + io.swagger.core.v3 + swagger-annotations + 2.2.4 + + + org.springdoc + springdoc-openapi-ui + 1.6.12 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + + \ No newline at end of file diff --git a/filmorate-web/src/main/java/dev/struchkov/filmorate/web/controller/FilmController.java b/filmorate-web/src/main/java/dev/struchkov/filmorate/web/controller/FilmController.java new file mode 100644 index 0000000..9631294 --- /dev/null +++ b/filmorate-web/src/main/java/dev/struchkov/filmorate/web/controller/FilmController.java @@ -0,0 +1,82 @@ +package dev.struchkov.filmorate.web.controller; + +import dev.strichkov.filmorate.domain.Film; +import dev.strichkov.filmorate.domain.page.Pagination; +import dev.strichkov.filmorate.domain.page.Sheet; +import dev.struchkov.filmorate.context.service.FilmService; +import dev.struchkov.filmorate.web.dto.FilmDto; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.core.convert.ConversionService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +@RestController +@RequiredArgsConstructor +@RequestMapping("api/film") +@Tag(name = "Фильмы", description = "Эндпойнты для работы с фильмами") +public class FilmController { + + private final FilmService filmService; + private final ConversionService conversionService; + + @Operation(summary = "Добавление нового фильма") + @PostMapping(produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) + public ResponseEntity create(@RequestBody FilmDto filmDto) { + return ResponseEntity.ok( + conversionService.convert( + filmService.create(conversionService.convert(filmDto, Film.class)), + FilmDto.class + ) + ); + } + + @Operation(summary = "Обновление фильма") + @PutMapping(produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) + public ResponseEntity update(@RequestBody FilmDto filmDto) { + return ResponseEntity.ok( + conversionService.convert( + filmService.update(conversionService.convert(filmDto, Film.class)), + FilmDto.class + ) + ); + } + + @Operation(summary = "Получение фильма по идентификатору") + @PutMapping(value = "{filmId}", produces = APPLICATION_JSON_VALUE) + public ResponseEntity getById(@PathVariable Long filmId) { + return ResponseEntity.ok( + conversionService.convert( + filmService.getByIdOrThrow(filmId), + FilmDto.class + ) + ); + } + + @Operation(summary = "Получение всех фильмов с пагинацией") + @GetMapping(produces = APPLICATION_JSON_VALUE) + public ResponseEntity> getAllByFilter( + @Parameter(description = "Номер страницы", required = true) @Min(0) @RequestParam Integer pageNum, + @Parameter(description = "Количество элементов", required = true) @Min(1) @Max(100) @RequestParam Integer pageSize + ) { + return ResponseEntity.ok( + filmService.getAll(new Pagination(pageSize, pageSize)) + .map(film -> conversionService.convert(film, FilmDto.class)) + ); + } + +} diff --git a/filmorate-web/src/main/java/dev/struchkov/filmorate/web/controller/PersonController.java b/filmorate-web/src/main/java/dev/struchkov/filmorate/web/controller/PersonController.java new file mode 100644 index 0000000..5388cd8 --- /dev/null +++ b/filmorate-web/src/main/java/dev/struchkov/filmorate/web/controller/PersonController.java @@ -0,0 +1,82 @@ +package dev.struchkov.filmorate.web.controller; + +import dev.strichkov.filmorate.domain.page.Pagination; +import dev.strichkov.filmorate.domain.page.Sheet; +import dev.struchkov.filmorate.context.service.PersonService; +import dev.struchkov.filmorate.web.dto.PersonDto; +import dev.struchkov.filmorate.web.mapper.PersonMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +@RestController +@RequiredArgsConstructor +@RequestMapping("api/person") +@Tag(name = "Пользователи системы", description = "Эндпойнты для работы с пользователями системы") +public class PersonController { + + private final PersonService personService; + private final PersonMapper personMapper; + + @Operation(summary = "Регистрация нового пользователя") + @PostMapping(produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) + public ResponseEntity create(@RequestBody PersonDto personDto) { + return ResponseEntity.ok( + personMapper.toDto( + personService.create( + personMapper.toDomain(personDto) + ) + ) + ); + } + + @Operation(summary = "Обновление пользователя") + @PutMapping(produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE) + public ResponseEntity update(@RequestBody PersonDto personDto) { + return ResponseEntity.ok( + personMapper.toDto( + personService.update( + personMapper.toDomain(personDto) + ) + ) + ); + } + + @Operation(summary = "Получение пользователя по идентификатору") + @PutMapping(value = "{personId}", produces = APPLICATION_JSON_VALUE) + public ResponseEntity getById(@PathVariable Long personId) { + return ResponseEntity.ok( + personMapper.toDto( + personService.getByIdOrThrow(personId) + ) + ); + } + + @Operation(summary = "Получение всех пользователей с пагинацией") + @GetMapping(produces = APPLICATION_JSON_VALUE) + public ResponseEntity> getAllByFilter( + @Parameter(description = "Номер страницы", required = true) @Min(0) @RequestParam Integer pageNum, + @Parameter(description = "Количество элементов", required = true) @Min(1) @Max(100) @RequestParam Integer pageSize + ) { + return ResponseEntity.ok( + personService.getAll(new Pagination(pageNum, pageSize)) + .map(personMapper::toDto) + ); + } + +} diff --git a/filmorate-web/src/main/java/dev/struchkov/filmorate/web/converter/FilmToDtoConvert.java b/filmorate-web/src/main/java/dev/struchkov/filmorate/web/converter/FilmToDtoConvert.java new file mode 100644 index 0000000..63912ae --- /dev/null +++ b/filmorate-web/src/main/java/dev/struchkov/filmorate/web/converter/FilmToDtoConvert.java @@ -0,0 +1,21 @@ +package dev.struchkov.filmorate.web.converter; + +import dev.strichkov.filmorate.domain.Film; +import dev.struchkov.filmorate.web.dto.FilmDto; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; + +@Component +public class FilmToDtoConvert implements Converter { + + @Override + public FilmDto convert(Film source) { + final FilmDto filmDto = new FilmDto(); + filmDto.setId(source.getId()); + filmDto.setName(source.getName()); + filmDto.setDurationInMinutes(source.getDurationInMinutes()); + filmDto.setDateRelease(source.getDateRelease()); + filmDto.setDescription(source.getDescription()); + return filmDto; + } +} diff --git a/filmorate-web/src/main/java/dev/struchkov/filmorate/web/converter/FilmToEntityConvert.java b/filmorate-web/src/main/java/dev/struchkov/filmorate/web/converter/FilmToEntityConvert.java new file mode 100644 index 0000000..869c61b --- /dev/null +++ b/filmorate-web/src/main/java/dev/struchkov/filmorate/web/converter/FilmToEntityConvert.java @@ -0,0 +1,22 @@ +package dev.struchkov.filmorate.web.converter; + +import dev.strichkov.filmorate.domain.Film; +import dev.struchkov.filmorate.web.dto.FilmDto; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; + +@Component +public class FilmToEntityConvert implements Converter { + + @Override + public Film convert(FilmDto source) { + final Film film = new Film(); + film.setId(source.getId()); + film.setName(source.getName()); + film.setDescription(source.getDescription()); + film.setDateRelease(source.getDateRelease()); + film.setDurationInMinutes(source.getDurationInMinutes()); + return film; + } + +} diff --git a/filmorate-web/src/main/java/dev/struchkov/filmorate/web/dto/FilmDto.java b/filmorate-web/src/main/java/dev/struchkov/filmorate/web/dto/FilmDto.java new file mode 100644 index 0000000..023286d --- /dev/null +++ b/filmorate-web/src/main/java/dev/struchkov/filmorate/web/dto/FilmDto.java @@ -0,0 +1,39 @@ +package dev.struchkov.filmorate.web.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Getter +@Setter +@Schema(description = "Фильм") +public class FilmDto { + + @Schema(name = "Идентификатор") + private Long id; + + @Schema(name = "Название") + private String name; + + @Schema(name = "Описание") + private String description; + + @Schema(name = "Дата релиза") + private LocalDate dateRelease; + + @Schema(name = "Продолжительность") + private Integer durationInMinutes; + + @Schema(name = "Дата Создания") + private LocalDateTime dateCreated; + + @Schema(name = "Дата обновления") + private LocalDateTime dateUpdated; + + @Schema(name = "Владелец фильма") + private Long ownerId; + +} diff --git a/filmorate-web/src/main/java/dev/struchkov/filmorate/web/dto/PersonDto.java b/filmorate-web/src/main/java/dev/struchkov/filmorate/web/dto/PersonDto.java new file mode 100644 index 0000000..f9d09de --- /dev/null +++ b/filmorate-web/src/main/java/dev/struchkov/filmorate/web/dto/PersonDto.java @@ -0,0 +1,29 @@ +package dev.struchkov.filmorate.web.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Getter +@Setter +@Schema(description = "Пользователь системы") +public class PersonDto { + + @Schema(description = "Идентификатор") + private Long id; + + @Schema(description = "Имя") + private String name; + + @Schema(description = "Почта") + private String email; + + @Schema(description = "Логин") + private String login; + + @Schema(description = "День рождения") + private LocalDateTime birthday; + +} diff --git a/filmorate-web/src/main/java/dev/struchkov/filmorate/web/mapper/PersonMapper.java b/filmorate-web/src/main/java/dev/struchkov/filmorate/web/mapper/PersonMapper.java new file mode 100644 index 0000000..c4d9425 --- /dev/null +++ b/filmorate-web/src/main/java/dev/struchkov/filmorate/web/mapper/PersonMapper.java @@ -0,0 +1,14 @@ +package dev.struchkov.filmorate.web.mapper; + +import dev.strichkov.filmorate.domain.Person; +import dev.struchkov.filmorate.web.dto.PersonDto; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface PersonMapper { + + PersonDto toDto(Person person); + + Person toDomain(PersonDto personDto); + +} diff --git a/pom.xml b/pom.xml index 6944b36..599c60e 100644 --- a/pom.xml +++ b/pom.xml @@ -2,77 +2,126 @@ 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.7.5 - - - dev.struchkov.example + + dev.struchkov.filmorate filmorate 0.0.1-SNAPSHOT - filmorate - filmorate + pom + + + filmorate-domain + filmorate-context + filmorate-core + filmorate-data-jpa + filmorate-data-local + filmorate-web + + 17 - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.springframework.boot - spring-boot-starter-web - - - org.liquibase - liquibase-core - + ${java.version} + ${java.version} + UTF-8 + UTF-8 - - org.springframework.boot - spring-boot-devtools - runtime - true - - - org.postgresql - postgresql - runtime - - - org.springframework.boot - spring-boot-configuration-processor - true - + 3.10.1 + 3.2.1 + 3.4.1 + + + + + + dev.struchkov.filmorate + filmorate-bom + 0.0.1-SNAPSHOT + pom + import + + + + + org.projectlombok lombok true - org.springframework.boot - spring-boot-starter-test - test + org.mapstruct + mapstruct + + + org.mapstruct + mapstruct-processor - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${plugin.maven.compiler.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + org.projectlombok + lombok + 1.18.24 + + + org.mapstruct + mapstruct-processor + 1.5.2.Final + + + + + + + org.apache.maven.plugins + maven-source-plugin + ${plugin.maven.source.version} + + + attach-sources + + jar + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${plugin.maven.javadoc.version} + + + attach-javadocs + + jar + + + + + + + + + + uPagge + Struchkov Mark + mark@struchkov.dev + https://mark.struchkov.dev + + + diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index 8b13789..0000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/test/java/dev/struchkov/filmorate/FilmorateApplicationTests.java b/src/test/java/dev/struchkov/filmorate/FilmorateApplicationTests.java deleted file mode 100644 index 6f8b2b2..0000000 --- a/src/test/java/dev/struchkov/filmorate/FilmorateApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package dev.struchkov.filmorate; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class FilmorateApplicationTests { - - @Test - void contextLoads() { - } - -}