diff --git a/2022-08/spring-13-data-jpa/.gitignore b/2022-08/spring-13-data-jpa/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2022-08/spring-13-data-jpa/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2022-08/spring-13-data-jpa/demo/.gitignore b/2022-08/spring-13-data-jpa/demo/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2022-08/spring-13-data-jpa/demo/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2022-08/spring-13-data-jpa/demo/pom.xml b/2022-08/spring-13-data-jpa/demo/pom.xml new file mode 100644 index 00000000..48523ba6 --- /dev/null +++ b/2022-08/spring-13-data-jpa/demo/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + ru.otus + demo + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.4.5 + + + + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + org.springframework.boot + spring-boot-starter-test + test + + + org.projectlombok + lombok + true + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/Main.java b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/Main.java new file mode 100644 index 00000000..bd056210 --- /dev/null +++ b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/Main.java @@ -0,0 +1,75 @@ +package ru.otus.springdata; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.ExampleMatcher; +import org.springframework.data.jpa.domain.Specification; +import ru.otus.springdata.domain.Email; +import ru.otus.springdata.domain.Person; +import ru.otus.springdata.repository.EmailRepository; +import ru.otus.springdata.repository.PersonRepository; + +import java.util.Objects; +import java.util.stream.Collectors; + +import static ru.otus.springdata.repository.PersonSpecification.emailAddressLike; +import static ru.otus.springdata.repository.PersonSpecification.nameLike; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + ConfigurableApplicationContext context = SpringApplication.run(Main.class); + + PersonRepository personRepository = context.getBean(PersonRepository.class); + EmailRepository emailRepository = context.getBean(EmailRepository.class); + + var pushkin = new Person("Александр Сергеевич Пушкин", new Email("alex.pushkin@mail.ru")); + var block = new Person("Александр Александрович Блок", new Email("alex.block@mail.ru")); + var lermontov = new Person("Михаил Юрьевич Лермонтов", new Email("michail.lermontov@bk.ru")); + var gorbachev = new Person("Михаил Сергеевич Горбачев", new Email("gorbachev@mail.ru")); + var bulgakov = new Person("Михаил Афанасьевич Булгаков", new Email("bulgakov@mail.ru")); + + emailRepository.save(pushkin.getEmail()); + emailRepository.save(block.getEmail()); + emailRepository.save(lermontov.getEmail()); + emailRepository.save(gorbachev.getEmail()); + emailRepository.save(bulgakov.getEmail()); + + personRepository.save(pushkin); + personRepository.save(block); + personRepository.save(lermontov); + personRepository.save(gorbachev); + personRepository.save(bulgakov); + + System.out.println("\n\nИщем почту Горбачева по его id"); + emailRepository.findByPersonId(gorbachev.getId()) + .ifPresent(System.out::println); + + + System.out.println("\n\nС помощью Example ищем всех пёрсонов с именем \"Михаил\" и почтой на \"mail.ru\""); + ExampleMatcher ignoringExampleMatcher = ExampleMatcher.matchingAll() + .withMatcher("email.address", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase()) + .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase()) + .withIgnorePaths("id", "email.id"); + + Example example = Example.of(new Person("Михаил", new Email(0, "mail.ru")), ignoringExampleMatcher); + + System.out.println(personRepository.findAll(example).stream().map(Objects::toString) + .collect(Collectors.joining("\n"))); + + + System.out.println("\n\nС помощью Specification ищем всех пёрсонов с именем \"Александр\" или с почтой на \"bk.ru\""); + + Specification specification = Specification.where(nameLike("Александр")) + .or(emailAddressLike("bk.ru")); + + System.out.println(personRepository.findAll(specification).stream().map(Objects::toString) + .collect(Collectors.joining("\n"))); + + System.out.println("\n\n"); + + } +} diff --git a/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/domain/Email.java b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/domain/Email.java new file mode 100644 index 00000000..e3b8d344 --- /dev/null +++ b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/domain/Email.java @@ -0,0 +1,27 @@ +package ru.otus.springdata.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +public class Email { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + private String address; + + public Email(String address) { + this.address = address; + } +} diff --git a/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/domain/Person.java b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/domain/Person.java new file mode 100644 index 00000000..e24e42aa --- /dev/null +++ b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/domain/Person.java @@ -0,0 +1,30 @@ +package ru.otus.springdata.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +public class Person { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + private String name; + + @OneToOne(orphanRemoval = true) + @JoinColumn(name = "email_id") + private Email email; + + public Person(String name, Email email) { + this.name = name; + this.email = email; + } + +} diff --git a/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/repository/EmailRepository.java b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/repository/EmailRepository.java new file mode 100644 index 00000000..a76a43ff --- /dev/null +++ b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/repository/EmailRepository.java @@ -0,0 +1,21 @@ +package ru.otus.springdata.repository; + +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.otus.springdata.domain.Email; + +import java.util.Optional; + +public interface EmailRepository extends JpaRepository, EmailRepositoryCustom { + + @Query("select e from Email e where e.address = :address") + Optional findByEmailAddress(@Param("address") String email); + + @Modifying + @Transactional + @Query("update Email e set e.address = :address where e.id = :id") + void updateEmailById(@Param("id") long id, @Param("address") String address); +} diff --git a/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/repository/EmailRepositoryCustom.java b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/repository/EmailRepositoryCustom.java new file mode 100644 index 00000000..db7112e1 --- /dev/null +++ b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/repository/EmailRepositoryCustom.java @@ -0,0 +1,9 @@ +package ru.otus.springdata.repository; + +import ru.otus.springdata.domain.Email; + +import java.util.Optional; + +public interface EmailRepositoryCustom { + Optional findByPersonId(long personId); +} diff --git a/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/repository/EmailRepositoryCustomImpl.java b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/repository/EmailRepositoryCustomImpl.java new file mode 100644 index 00000000..18f9ac33 --- /dev/null +++ b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/repository/EmailRepositoryCustomImpl.java @@ -0,0 +1,20 @@ +package ru.otus.springdata.repository; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; +import ru.otus.springdata.domain.Email; +import ru.otus.springdata.domain.Person; + +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class EmailRepositoryCustomImpl implements EmailRepositoryCustom { + + private final PersonRepository personRepository; + + @Override + public Optional findByPersonId(long personId) { + return personRepository.findById(personId).map(Person::getEmail); + } +} diff --git a/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/repository/PersonRepository.java b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/repository/PersonRepository.java new file mode 100644 index 00000000..7bb5c825 --- /dev/null +++ b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/repository/PersonRepository.java @@ -0,0 +1,20 @@ +package ru.otus.springdata.repository; + +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.repository.CrudRepository; +import ru.otus.springdata.domain.Person; + +import java.util.List; +import java.util.Optional; + +public interface PersonRepository extends JpaRepository, JpaSpecificationExecutor { + + @EntityGraph(attributePaths = "email") + List findAll(); + + Optional findByName(String s); + + Optional findByEmailAddress(String email); +} diff --git a/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/repository/PersonSpecification.java b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/repository/PersonSpecification.java new file mode 100644 index 00000000..3f8c67b3 --- /dev/null +++ b/2022-08/spring-13-data-jpa/demo/src/main/java/ru/otus/springdata/repository/PersonSpecification.java @@ -0,0 +1,21 @@ +package ru.otus.springdata.repository; + +import org.springframework.data.jpa.domain.Specification; +import ru.otus.springdata.domain.Person; + +public class PersonSpecification { + + public static Specification nameLike(String name) { + if (name == null) { + return null; + } + return (root, query, cb) -> cb.like(root.get("name"), "%" + name + "%"); + } + + public static Specification emailAddressLike(String address) { + if (address == null) { + return null; + } + return (root, query, cb) -> cb.like(root.join("email").get("address"), "%" + address + "%"); + } +} diff --git a/2022-08/spring-13-data-jpa/demo/src/main/resources/application.yml b/2022-08/spring-13-data-jpa/demo/src/main/resources/application.yml new file mode 100644 index 00000000..bd5b0f98 --- /dev/null +++ b/2022-08/spring-13-data-jpa/demo/src/main/resources/application.yml @@ -0,0 +1,20 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + initialization-mode: never + + jpa: + generate-ddl: true + hibernate: + ddl-auto: create + + properties: + hibernate: + format_sql: false + + show-sql: true + + +logging: + level: + ROOT: ERROR \ No newline at end of file diff --git a/2022-08/spring-13-data-jpa/exercise/.gitignore b/2022-08/spring-13-data-jpa/exercise/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2022-08/spring-13-data-jpa/exercise/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2022-08/spring-13-data-jpa/exercise/pom.xml b/2022-08/spring-13-data-jpa/exercise/pom.xml new file mode 100644 index 00000000..172b613d --- /dev/null +++ b/2022-08/spring-13-data-jpa/exercise/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + ru.otus + exercise + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.4.5 + + + + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + org.projectlombok + lombok + true + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-08/spring-13-data-jpa/exercise/src/main/java/ru/otus/springdata/Main.java b/2022-08/spring-13-data-jpa/exercise/src/main/java/ru/otus/springdata/Main.java new file mode 100644 index 00000000..dbbe3598 --- /dev/null +++ b/2022-08/spring-13-data-jpa/exercise/src/main/java/ru/otus/springdata/Main.java @@ -0,0 +1,23 @@ +package ru.otus.springdata; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; + + + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + ConfigurableApplicationContext context = SpringApplication.run(Main.class); + //PersonRepository personRepository = context.getBean(PersonRepository.class); + //EmailRepository emailRepository = context.getBean(EmailRepository.class); + + // personRepository.save(new Person("Александр Сергеевич Пушкин")); + // personRepository.save(new Person("Михаил Юрьевич Лермонтов")); + // personRepository.save(new Person("Михаил Сергеевич Горбачев")); + } + + +} diff --git a/2022-08/spring-13-data-jpa/exercise/src/main/java/ru/otus/springdata/domain/Email.java b/2022-08/spring-13-data-jpa/exercise/src/main/java/ru/otus/springdata/domain/Email.java new file mode 100644 index 00000000..5cb61fa0 --- /dev/null +++ b/2022-08/spring-13-data-jpa/exercise/src/main/java/ru/otus/springdata/domain/Email.java @@ -0,0 +1,21 @@ +package ru.otus.springdata.domain; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Email { + + private long id; + + private String address; + + public Email(String address) { + this.address = address; + } + +} diff --git a/2022-08/spring-13-data-jpa/exercise/src/main/java/ru/otus/springdata/domain/Person.java b/2022-08/spring-13-data-jpa/exercise/src/main/java/ru/otus/springdata/domain/Person.java new file mode 100644 index 00000000..cc8e6d0a --- /dev/null +++ b/2022-08/spring-13-data-jpa/exercise/src/main/java/ru/otus/springdata/domain/Person.java @@ -0,0 +1,26 @@ +package ru.otus.springdata.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +public class Person { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + private String name; + + public Person(String name) { + this.name = name; + } +} diff --git a/2022-08/spring-13-data-jpa/exercise/src/main/java/ru/otus/springdata/repository/EmailRepository.java b/2022-08/spring-13-data-jpa/exercise/src/main/java/ru/otus/springdata/repository/EmailRepository.java new file mode 100644 index 00000000..7a446b95 --- /dev/null +++ b/2022-08/spring-13-data-jpa/exercise/src/main/java/ru/otus/springdata/repository/EmailRepository.java @@ -0,0 +1,4 @@ +package ru.otus.springdata.repository; + +public interface EmailRepository { +} diff --git a/2022-08/spring-13-data-jpa/exercise/src/main/java/ru/otus/springdata/repository/PersonRepository.java b/2022-08/spring-13-data-jpa/exercise/src/main/java/ru/otus/springdata/repository/PersonRepository.java new file mode 100644 index 00000000..f8e5fc8a --- /dev/null +++ b/2022-08/spring-13-data-jpa/exercise/src/main/java/ru/otus/springdata/repository/PersonRepository.java @@ -0,0 +1,4 @@ +package ru.otus.springdata.repository; + +public interface PersonRepository { +} diff --git a/2022-08/spring-13-data-jpa/exercise/src/main/resources/application.yml b/2022-08/spring-13-data-jpa/exercise/src/main/resources/application.yml new file mode 100644 index 00000000..bd5b0f98 --- /dev/null +++ b/2022-08/spring-13-data-jpa/exercise/src/main/resources/application.yml @@ -0,0 +1,20 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + initialization-mode: never + + jpa: + generate-ddl: true + hibernate: + ddl-auto: create + + properties: + hibernate: + format_sql: false + + show-sql: true + + +logging: + level: + ROOT: ERROR \ No newline at end of file diff --git a/2022-08/spring-13-data-jpa/pom.xml b/2022-08/spring-13-data-jpa/pom.xml new file mode 100644 index 00000000..922fc48a --- /dev/null +++ b/2022-08/spring-13-data-jpa/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + ru.otus + spring-11-data-jpa + 1.0 + + pom + + + exercise + solution-01 + solution-02 + solution-03 + solution-04 + demo + + diff --git a/2022-08/spring-13-data-jpa/solution-01/.gitignore b/2022-08/spring-13-data-jpa/solution-01/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-01/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2022-08/spring-13-data-jpa/solution-01/pom.xml b/2022-08/spring-13-data-jpa/solution-01/pom.xml new file mode 100644 index 00000000..355f4335 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-01/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + ru.otus + solution-01 + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.4.5 + + + + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + org.springframework.boot + spring-boot-starter-test + test + + + org.projectlombok + lombok + true + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-08/spring-13-data-jpa/solution-01/src/main/java/ru/otus/springdata/Main.java b/2022-08/spring-13-data-jpa/solution-01/src/main/java/ru/otus/springdata/Main.java new file mode 100644 index 00000000..4961485f --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-01/src/main/java/ru/otus/springdata/Main.java @@ -0,0 +1,37 @@ +package ru.otus.springdata; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import ru.otus.springdata.domain.Person; +import ru.otus.springdata.repository.PersonRepository; + +import java.util.Objects; +import java.util.stream.Collectors; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + ConfigurableApplicationContext context = SpringApplication.run(Main.class); + + PersonRepository personRepository = context.getBean(PersonRepository.class); + + + personRepository.save(new Person("Александр Сергеевич Пушкин")); + personRepository.save(new Person("Михаил Юрьевич Лермонтов")); + personRepository.save(new Person("Михаил Сергеевич Горбачев")); + + System.out.println("\n\nИщем всех пёрсонов"); + System.out.println(personRepository.findAll().stream().map(Objects::toString) + .collect(Collectors.joining("\n"))); + + System.out.println("\n\nИщем Пушкина"); + personRepository.findByName("Александр Сергеевич Пушкин") + .ifPresent(System.out::println); + + + System.out.println("\n\n"); + + } +} diff --git a/2022-08/spring-13-data-jpa/solution-01/src/main/java/ru/otus/springdata/domain/Email.java b/2022-08/spring-13-data-jpa/solution-01/src/main/java/ru/otus/springdata/domain/Email.java new file mode 100644 index 00000000..3f0bd00c --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-01/src/main/java/ru/otus/springdata/domain/Email.java @@ -0,0 +1,24 @@ +package ru.otus.springdata.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Email { + + private long id; + + private String address; + + public Email(String address) { + this.address = address; + } +} diff --git a/2022-08/spring-13-data-jpa/solution-01/src/main/java/ru/otus/springdata/domain/Person.java b/2022-08/spring-13-data-jpa/solution-01/src/main/java/ru/otus/springdata/domain/Person.java new file mode 100644 index 00000000..96d92b91 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-01/src/main/java/ru/otus/springdata/domain/Person.java @@ -0,0 +1,25 @@ +package ru.otus.springdata.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +public class Person { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + private String name; + + public Person(String name) { + this.name = name; + } + +} diff --git a/2022-08/spring-13-data-jpa/solution-01/src/main/java/ru/otus/springdata/repository/EmailRepository.java b/2022-08/spring-13-data-jpa/solution-01/src/main/java/ru/otus/springdata/repository/EmailRepository.java new file mode 100644 index 00000000..788feda5 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-01/src/main/java/ru/otus/springdata/repository/EmailRepository.java @@ -0,0 +1,12 @@ +package ru.otus.springdata.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.otus.springdata.domain.Email; + +import java.util.List; + +public interface EmailRepository extends JpaRepository { + + @Override + List findAll(); +} diff --git a/2022-08/spring-13-data-jpa/solution-01/src/main/java/ru/otus/springdata/repository/PersonRepository.java b/2022-08/spring-13-data-jpa/solution-01/src/main/java/ru/otus/springdata/repository/PersonRepository.java new file mode 100644 index 00000000..012ded26 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-01/src/main/java/ru/otus/springdata/repository/PersonRepository.java @@ -0,0 +1,15 @@ +package ru.otus.springdata.repository; + +import org.springframework.data.repository.CrudRepository; +import ru.otus.springdata.domain.Person; + +import java.util.List; +import java.util.Optional; + +public interface PersonRepository extends CrudRepository { + + @Override + List findAll(); + + Optional findByName(String s); +} diff --git a/2022-08/spring-13-data-jpa/solution-01/src/main/resources/application.yml b/2022-08/spring-13-data-jpa/solution-01/src/main/resources/application.yml new file mode 100644 index 00000000..bd5b0f98 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-01/src/main/resources/application.yml @@ -0,0 +1,20 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + initialization-mode: never + + jpa: + generate-ddl: true + hibernate: + ddl-auto: create + + properties: + hibernate: + format_sql: false + + show-sql: true + + +logging: + level: + ROOT: ERROR \ No newline at end of file diff --git a/2022-08/spring-13-data-jpa/solution-02/.gitignore b/2022-08/spring-13-data-jpa/solution-02/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-02/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2022-08/spring-13-data-jpa/solution-02/pom.xml b/2022-08/spring-13-data-jpa/solution-02/pom.xml new file mode 100644 index 00000000..c6dd4ab8 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-02/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + ru.otus + solution-02 + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.4.5 + + + + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + org.springframework.boot + spring-boot-starter-test + test + + + org.projectlombok + lombok + true + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-08/spring-13-data-jpa/solution-02/src/main/java/ru/otus/springdata/Main.java b/2022-08/spring-13-data-jpa/solution-02/src/main/java/ru/otus/springdata/Main.java new file mode 100644 index 00000000..d25a29d2 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-02/src/main/java/ru/otus/springdata/Main.java @@ -0,0 +1,53 @@ +package ru.otus.springdata; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import ru.otus.springdata.domain.Email; +import ru.otus.springdata.domain.Person; +import ru.otus.springdata.repository.EmailRepository; +import ru.otus.springdata.repository.PersonRepository; + +import java.util.Objects; +import java.util.stream.Collectors; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + + ConfigurableApplicationContext context = SpringApplication.run(Main.class); + PersonRepository personRepository = context.getBean(PersonRepository.class); + EmailRepository emailRepository = context.getBean(EmailRepository.class); + + var pushkinEmail = new Email("alex.pushkin@mail.ru"); + var lermontovEmail = new Email("michail.lermontov@mail.ru"); + var gorbachevEmail = new Email("gorbachev@mail.ru"); + + var pushkin = new Person("Александр Сергеевич Пушкин"); + var lermontov = new Person("Михаил Юрьевич Лермонтов"); + var gorbachev = new Person("Михаил Сергеевич Горбачев"); + + emailRepository.save(pushkinEmail); + emailRepository.save(lermontovEmail); + emailRepository.save(gorbachevEmail); + + personRepository.save(pushkin); + personRepository.save(lermontov); + personRepository.save(gorbachev); + + System.out.println("\n\nИщем всех пёрсонов"); + System.out.println(personRepository.findAll().stream().map(Objects::toString) + .collect(Collectors.joining("\n"))); + + System.out.println("\n\nИщем Пушкина"); + personRepository.findByName("Александр Сергеевич Пушкин") + .ifPresent(System.out::println); + + System.out.println("\n\nИщем все почты"); + System.out.println(emailRepository.findAll().stream().map(Objects::toString) + .collect(Collectors.joining("\n"))); + + System.out.println("\n\n"); + } +} diff --git a/2022-08/spring-13-data-jpa/solution-02/src/main/java/ru/otus/springdata/domain/Email.java b/2022-08/spring-13-data-jpa/solution-02/src/main/java/ru/otus/springdata/domain/Email.java new file mode 100644 index 00000000..e3b8d344 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-02/src/main/java/ru/otus/springdata/domain/Email.java @@ -0,0 +1,27 @@ +package ru.otus.springdata.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +public class Email { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + private String address; + + public Email(String address) { + this.address = address; + } +} diff --git a/2022-08/spring-13-data-jpa/solution-02/src/main/java/ru/otus/springdata/domain/Person.java b/2022-08/spring-13-data-jpa/solution-02/src/main/java/ru/otus/springdata/domain/Person.java new file mode 100644 index 00000000..96d92b91 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-02/src/main/java/ru/otus/springdata/domain/Person.java @@ -0,0 +1,25 @@ +package ru.otus.springdata.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +public class Person { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + private String name; + + public Person(String name) { + this.name = name; + } + +} diff --git a/2022-08/spring-13-data-jpa/solution-02/src/main/java/ru/otus/springdata/repository/EmailRepository.java b/2022-08/spring-13-data-jpa/solution-02/src/main/java/ru/otus/springdata/repository/EmailRepository.java new file mode 100644 index 00000000..3d5c3152 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-02/src/main/java/ru/otus/springdata/repository/EmailRepository.java @@ -0,0 +1,13 @@ +package ru.otus.springdata.repository; + +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.otus.springdata.domain.Email; + +import java.util.Optional; + +public interface EmailRepository extends JpaRepository{ +} diff --git a/2022-08/spring-13-data-jpa/solution-02/src/main/java/ru/otus/springdata/repository/PersonRepository.java b/2022-08/spring-13-data-jpa/solution-02/src/main/java/ru/otus/springdata/repository/PersonRepository.java new file mode 100644 index 00000000..cd5bb3f0 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-02/src/main/java/ru/otus/springdata/repository/PersonRepository.java @@ -0,0 +1,14 @@ +package ru.otus.springdata.repository; + +import org.springframework.data.repository.CrudRepository; +import ru.otus.springdata.domain.Person; + +import java.util.List; +import java.util.Optional; + +public interface PersonRepository extends CrudRepository { + + List findAll(); + + Optional findByName(String s); +} diff --git a/2022-08/spring-13-data-jpa/solution-02/src/main/resources/application.yml b/2022-08/spring-13-data-jpa/solution-02/src/main/resources/application.yml new file mode 100644 index 00000000..bd5b0f98 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-02/src/main/resources/application.yml @@ -0,0 +1,20 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + initialization-mode: never + + jpa: + generate-ddl: true + hibernate: + ddl-auto: create + + properties: + hibernate: + format_sql: false + + show-sql: true + + +logging: + level: + ROOT: ERROR \ No newline at end of file diff --git a/2022-08/spring-13-data-jpa/solution-03/.gitignore b/2022-08/spring-13-data-jpa/solution-03/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-03/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2022-08/spring-13-data-jpa/solution-03/pom.xml b/2022-08/spring-13-data-jpa/solution-03/pom.xml new file mode 100644 index 00000000..4fff22c3 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-03/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + ru.otus + solution-03 + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.4.5 + + + + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + org.springframework.boot + spring-boot-starter-test + test + + + org.projectlombok + lombok + true + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-08/spring-13-data-jpa/solution-03/src/main/java/ru/otus/springdata/Main.java b/2022-08/spring-13-data-jpa/solution-03/src/main/java/ru/otus/springdata/Main.java new file mode 100644 index 00000000..a02e3e25 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-03/src/main/java/ru/otus/springdata/Main.java @@ -0,0 +1,55 @@ +package ru.otus.springdata; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.ExampleMatcher; +import ru.otus.springdata.domain.Email; +import ru.otus.springdata.domain.Person; +import ru.otus.springdata.repository.EmailRepository; +import ru.otus.springdata.repository.PersonRepository; + +import java.util.Objects; +import java.util.stream.Collectors; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + ConfigurableApplicationContext context = SpringApplication.run(Main.class); + + PersonRepository personRepository = context.getBean(PersonRepository.class); + EmailRepository emailRepository = context.getBean(EmailRepository.class); + + var pushkin = new Person("Александр Сергеевич Пушкин", new Email("alex.pushkin@mail.ru")); + var lermontov = new Person("Михаил Юрьевич Лермонтов", new Email("michail.lermontov@mail.ru")); + var gorbachev = new Person("Михаил Сергеевич Горбачев", new Email("gorbachev@mail.ru")); + + emailRepository.save(pushkin.getEmail()); + emailRepository.save(lermontov.getEmail()); + emailRepository.save(gorbachev.getEmail()); + + personRepository.save(pushkin); + personRepository.save(lermontov); + personRepository.save(gorbachev); + + System.out.println("\n\nИщем всех пёрсонов"); + System.out.println(personRepository.findAll().stream().map(Objects::toString) + .collect(Collectors.joining("\n"))); + + System.out.println("\n\nИщем Пушкина"); + personRepository.findByName("Александр Сергеевич Пушкин") + .ifPresent(System.out::println); + + System.out.println("\n\nИщем все почты"); + System.out.println(emailRepository.findAll().stream().map(Objects::toString) + .collect(Collectors.joining("\n"))); + + System.out.println("\n\nИщем Пушкина по его почте"); + personRepository.findByEmailAddress("alex.pushkin@mail.ru") + .ifPresent(System.out::println); + + System.out.println("\n\n"); + } +} diff --git a/2022-08/spring-13-data-jpa/solution-03/src/main/java/ru/otus/springdata/domain/Email.java b/2022-08/spring-13-data-jpa/solution-03/src/main/java/ru/otus/springdata/domain/Email.java new file mode 100644 index 00000000..e3b8d344 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-03/src/main/java/ru/otus/springdata/domain/Email.java @@ -0,0 +1,27 @@ +package ru.otus.springdata.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +public class Email { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + private String address; + + public Email(String address) { + this.address = address; + } +} diff --git a/2022-08/spring-13-data-jpa/solution-03/src/main/java/ru/otus/springdata/domain/Person.java b/2022-08/spring-13-data-jpa/solution-03/src/main/java/ru/otus/springdata/domain/Person.java new file mode 100644 index 00000000..e24e42aa --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-03/src/main/java/ru/otus/springdata/domain/Person.java @@ -0,0 +1,30 @@ +package ru.otus.springdata.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +public class Person { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + private String name; + + @OneToOne(orphanRemoval = true) + @JoinColumn(name = "email_id") + private Email email; + + public Person(String name, Email email) { + this.name = name; + this.email = email; + } + +} diff --git a/2022-08/spring-13-data-jpa/solution-03/src/main/java/ru/otus/springdata/repository/EmailRepository.java b/2022-08/spring-13-data-jpa/solution-03/src/main/java/ru/otus/springdata/repository/EmailRepository.java new file mode 100644 index 00000000..16f1d0c9 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-03/src/main/java/ru/otus/springdata/repository/EmailRepository.java @@ -0,0 +1,13 @@ +package ru.otus.springdata.repository; + +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.otus.springdata.domain.Email; + +import java.util.Optional; + +public interface EmailRepository extends JpaRepository { +} diff --git a/2022-08/spring-13-data-jpa/solution-03/src/main/java/ru/otus/springdata/repository/PersonRepository.java b/2022-08/spring-13-data-jpa/solution-03/src/main/java/ru/otus/springdata/repository/PersonRepository.java new file mode 100644 index 00000000..a6aa8dd3 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-03/src/main/java/ru/otus/springdata/repository/PersonRepository.java @@ -0,0 +1,18 @@ +package ru.otus.springdata.repository; + +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.repository.CrudRepository; +import ru.otus.springdata.domain.Person; + +import java.util.List; +import java.util.Optional; + +public interface PersonRepository extends CrudRepository { + + @EntityGraph(attributePaths = "email") + List findAll(); + + Optional findByName(String s); + + Optional findByEmailAddress(String email); +} diff --git a/2022-08/spring-13-data-jpa/solution-03/src/main/resources/application.yml b/2022-08/spring-13-data-jpa/solution-03/src/main/resources/application.yml new file mode 100644 index 00000000..bd5b0f98 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-03/src/main/resources/application.yml @@ -0,0 +1,20 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + initialization-mode: never + + jpa: + generate-ddl: true + hibernate: + ddl-auto: create + + properties: + hibernate: + format_sql: false + + show-sql: true + + +logging: + level: + ROOT: ERROR \ No newline at end of file diff --git a/2022-08/spring-13-data-jpa/solution-04/.gitignore b/2022-08/spring-13-data-jpa/solution-04/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-04/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2022-08/spring-13-data-jpa/solution-04/pom.xml b/2022-08/spring-13-data-jpa/solution-04/pom.xml new file mode 100644 index 00000000..6f0a221c --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-04/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + ru.otus + solution-04 + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.4.5 + + + + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + org.springframework.boot + spring-boot-starter-test + test + + + org.projectlombok + lombok + true + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-08/spring-13-data-jpa/solution-04/src/main/java/ru/otus/springdata/Main.java b/2022-08/spring-13-data-jpa/solution-04/src/main/java/ru/otus/springdata/Main.java new file mode 100644 index 00000000..4574b783 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-04/src/main/java/ru/otus/springdata/Main.java @@ -0,0 +1,64 @@ +package ru.otus.springdata; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.ExampleMatcher; +import ru.otus.springdata.domain.Email; +import ru.otus.springdata.domain.Person; +import ru.otus.springdata.repository.EmailRepository; +import ru.otus.springdata.repository.PersonRepository; + +import java.util.Objects; +import java.util.stream.Collectors; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + ConfigurableApplicationContext context = SpringApplication.run(Main.class); + + PersonRepository personRepository = context.getBean(PersonRepository.class); + EmailRepository emailRepository = context.getBean(EmailRepository.class); + + var pushkin = new Person("Александр Сергеевич Пушкин", new Email("alex.pushkin@mail.ru")); + var lermontov = new Person("Михаил Юрьевич Лермонтов", new Email("michail.lermontov@mail.ru")); + var gorbachev = new Person("Михаил Сергеевич Горбачев", new Email("gorbachev@mail.ru")); + + emailRepository.save(pushkin.getEmail()); + emailRepository.save(lermontov.getEmail()); + emailRepository.save(gorbachev.getEmail()); + + personRepository.save(pushkin); + personRepository.save(lermontov); + personRepository.save(gorbachev); + + System.out.println("\n\nИщем всех пёрсонов"); + System.out.println(personRepository.findAll().stream().map(Objects::toString) + .collect(Collectors.joining("\n"))); + + System.out.println("\n\nИщем Пушкина"); + personRepository.findByName("Александр Сергеевич Пушкин") + .ifPresent(System.out::println); + + System.out.println("\n\nИщем все почты"); + System.out.println(emailRepository.findAll().stream().map(Objects::toString) + .collect(Collectors.joining("\n"))); + + System.out.println("\n\nИщем Пушкина по его почте"); + personRepository.findByEmailAddress("alex.pushkin@mail.ru") + .ifPresent(System.out::println); + + System.out.println("\n\nОбновляем почту Лермонтову"); + System.out.println("До обновления: " + lermontov.getEmail()); + emailRepository.updateEmailById(lermontov.getId(), "michail1984@lermontov.ru"); + + System.out.println("\n\nИщем почту Лермонтова по новому адресу"); + emailRepository.findByEmailAddress("michail1984@lermontov.ru") + .ifPresent(e -> System.out.println("После обновления: " + e)); + + System.out.println("\n\n"); + + } +} diff --git a/2022-08/spring-13-data-jpa/solution-04/src/main/java/ru/otus/springdata/domain/Email.java b/2022-08/spring-13-data-jpa/solution-04/src/main/java/ru/otus/springdata/domain/Email.java new file mode 100644 index 00000000..e3b8d344 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-04/src/main/java/ru/otus/springdata/domain/Email.java @@ -0,0 +1,27 @@ +package ru.otus.springdata.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +public class Email { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + private String address; + + public Email(String address) { + this.address = address; + } +} diff --git a/2022-08/spring-13-data-jpa/solution-04/src/main/java/ru/otus/springdata/domain/Person.java b/2022-08/spring-13-data-jpa/solution-04/src/main/java/ru/otus/springdata/domain/Person.java new file mode 100644 index 00000000..e24e42aa --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-04/src/main/java/ru/otus/springdata/domain/Person.java @@ -0,0 +1,30 @@ +package ru.otus.springdata.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +public class Person { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + private String name; + + @OneToOne(orphanRemoval = true) + @JoinColumn(name = "email_id") + private Email email; + + public Person(String name, Email email) { + this.name = name; + this.email = email; + } + +} diff --git a/2022-08/spring-13-data-jpa/solution-04/src/main/java/ru/otus/springdata/repository/EmailRepository.java b/2022-08/spring-13-data-jpa/solution-04/src/main/java/ru/otus/springdata/repository/EmailRepository.java new file mode 100644 index 00000000..66b4da80 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-04/src/main/java/ru/otus/springdata/repository/EmailRepository.java @@ -0,0 +1,21 @@ +package ru.otus.springdata.repository; + +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.otus.springdata.domain.Email; + +import java.util.Optional; + +public interface EmailRepository extends JpaRepository { + + @Query("select e from Email e where e.address = :address") + Optional findByEmailAddress(@Param("address") String email); + + @Modifying + @Transactional + @Query("update Email e set e.address = :address where e.id = :id") + void updateEmailById(@Param("id") long id, @Param("address") String address); +} diff --git a/2022-08/spring-13-data-jpa/solution-04/src/main/java/ru/otus/springdata/repository/PersonRepository.java b/2022-08/spring-13-data-jpa/solution-04/src/main/java/ru/otus/springdata/repository/PersonRepository.java new file mode 100644 index 00000000..a6aa8dd3 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-04/src/main/java/ru/otus/springdata/repository/PersonRepository.java @@ -0,0 +1,18 @@ +package ru.otus.springdata.repository; + +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.repository.CrudRepository; +import ru.otus.springdata.domain.Person; + +import java.util.List; +import java.util.Optional; + +public interface PersonRepository extends CrudRepository { + + @EntityGraph(attributePaths = "email") + List findAll(); + + Optional findByName(String s); + + Optional findByEmailAddress(String email); +} diff --git a/2022-08/spring-13-data-jpa/solution-04/src/main/resources/application.yml b/2022-08/spring-13-data-jpa/solution-04/src/main/resources/application.yml new file mode 100644 index 00000000..bd5b0f98 --- /dev/null +++ b/2022-08/spring-13-data-jpa/solution-04/src/main/resources/application.yml @@ -0,0 +1,20 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + initialization-mode: never + + jpa: + generate-ddl: true + hibernate: + ddl-auto: create + + properties: + hibernate: + format_sql: false + + show-sql: true + + +logging: + level: + ROOT: ERROR \ No newline at end of file diff --git a/2022-08/spring-15/spring-data-keyvalue-class-work/pom.xml b/2022-08/spring-15/spring-data-keyvalue-class-work/pom.xml new file mode 100644 index 00000000..b2fbb1c3 --- /dev/null +++ b/2022-08/spring-15/spring-data-keyvalue-class-work/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + ru.otus + spring-data-keyvalue-class-work + 1.0 + + pom + + + spring-data-keyvalue-exercise + spring-data-keyvalue-solution + + diff --git a/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-exercise/pom.xml b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-exercise/pom.xml new file mode 100644 index 00000000..180b1a60 --- /dev/null +++ b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-exercise/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + ru.otus + spring-data-keyvalue-exercise + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.2.1.RELEASE + + + + + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-exercise/src/main/java/ru/otus/spring/Main.java b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-exercise/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..d0d34e97 --- /dev/null +++ b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-exercise/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,29 @@ +package ru.otus.spring; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.map.repository.config.EnableMapRepositories; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import javax.annotation.PostConstruct; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } + + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") + @Autowired + private PersonRepository repository; + + @PostConstruct + public void init() { + repository.save(new Person(1, "Pushkin")); + + repository.findAll(); + } +} diff --git a/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-exercise/src/main/java/ru/otus/spring/domain/Email.java b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-exercise/src/main/java/ru/otus/spring/domain/Email.java new file mode 100644 index 00000000..c1e24a7d --- /dev/null +++ b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-exercise/src/main/java/ru/otus/spring/domain/Email.java @@ -0,0 +1,25 @@ +package ru.otus.spring.domain; + +public class Email { + + private int id; + + private String email; + + public Email(String email) { + this.email = email; + } + + public Email(int id, String email) { + this.id = id; + this.email = email; + } + + public int getId() { + return id; + } + + public String getEmail() { + return email; + } +} diff --git a/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-exercise/src/main/java/ru/otus/spring/domain/Person.java b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-exercise/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..f707e14e --- /dev/null +++ b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-exercise/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,35 @@ +package ru.otus.spring.domain; + +import org.springframework.data.annotation.Id; +import org.springframework.data.keyvalue.annotation.KeySpace; + +public class Person { + + private int id; + private String name; + + public Person(String name) { + this.name = name; + } + + public Person(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..4b20e5b7 --- /dev/null +++ b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,11 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.CrudRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends CrudRepository { + + List findAll(); +} diff --git a/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/pom.xml b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/pom.xml new file mode 100644 index 00000000..7d0041e8 --- /dev/null +++ b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + ru.otus + spring-data-keyvalue-solution + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.2.1.RELEASE + + + + + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.data + spring-data-keyvalue + 2.2.1.RELEASE + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/Main.java b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..42d9078f --- /dev/null +++ b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,39 @@ +package ru.otus.spring; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.map.repository.config.EnableMapRepositories; +import ru.otus.spring.domain.Email; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.EmailRepository; +import ru.otus.spring.repostory.PersonRepository; + +import javax.annotation.PostConstruct; + +@SpringBootApplication +@EnableMapRepositories +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } + + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") + @Autowired + private PersonRepository repository; + + @Autowired + private EmailRepository emailRepository; + + @PostConstruct + public void init() { + repository.save(new Person(1, "Pushkin")); + repository.save(new Person(2, "Lermontov")); + System.out.println(repository.findAll()); + + emailRepository.save(new Email(1, "alex@pushkin.com")); + emailRepository.save(new Email(2, "micha@pushkin.com")); + System.out.println(emailRepository.findAll()); + } +} diff --git a/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/domain/Email.java b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/domain/Email.java new file mode 100644 index 00000000..86ddb0c1 --- /dev/null +++ b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/domain/Email.java @@ -0,0 +1,37 @@ +package ru.otus.spring.domain; + +import org.springframework.data.annotation.Id; +import org.springframework.data.keyvalue.annotation.KeySpace; + +@KeySpace("email") +public class Email { + @Id + private int id; + + private String email; + + public Email(int id, String email) { + this.id = id; + this.email = email; + } + + public Email(String email) { + this.email = email; + } + + public int getId() { + return id; + } + + public String getEmail() { + return email; + } + + @Override + public String toString() { + return "Email{" + + "id=" + id + + ", email='" + email + '\'' + + '}'; + } +} diff --git a/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/domain/Person.java b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..b0181bd1 --- /dev/null +++ b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,45 @@ +package ru.otus.spring.domain; + +import org.springframework.data.annotation.Id; +import org.springframework.data.keyvalue.annotation.KeySpace; + +@KeySpace("person") +public class Person { + + @Id + private int id; + private String name; + + public Person(int id, String name) { + this.id = id; + this.name = name; + } + + public Person(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", name='" + name + '\'' + + '}'; + } +} diff --git a/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/repostory/EmailRepository.java b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/repostory/EmailRepository.java new file mode 100644 index 00000000..6ce870a2 --- /dev/null +++ b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/repostory/EmailRepository.java @@ -0,0 +1,14 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.keyvalue.repository.KeyValueRepository; +import org.springframework.stereotype.Repository; +import ru.otus.spring.domain.Email; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface EmailRepository { + + List findAll(); + Email save(Email email); +} diff --git a/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/repostory/EmailRepositoryImpl.java b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/repostory/EmailRepositoryImpl.java new file mode 100644 index 00000000..e2aa75a1 --- /dev/null +++ b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/repostory/EmailRepositoryImpl.java @@ -0,0 +1,27 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.keyvalue.core.KeyValueOperations; +import org.springframework.stereotype.Repository; +import ru.otus.spring.domain.Email; + +import java.util.List; + +@Repository +public class EmailRepositoryImpl implements EmailRepository { + + final private KeyValueOperations keyValueTemplate; + + public EmailRepositoryImpl(KeyValueOperations keyValueTemplate) { + this.keyValueTemplate = keyValueTemplate; + } + + @Override + public List findAll() { + return (List) keyValueTemplate.findAll(Email.class); + } + + @Override + public Email save(Email email) { + return keyValueTemplate.insert(email); + } +} diff --git a/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..99a93c24 --- /dev/null +++ b/2022-08/spring-15/spring-data-keyvalue-class-work/spring-data-keyvalue-solution/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,12 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.keyvalue.repository.KeyValueRepository; +import org.springframework.data.repository.CrudRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends KeyValueRepository { + + List findAll(); +} diff --git a/2022-08/spring-15/spring-data-mongo-class-work/pom.xml b/2022-08/spring-15/spring-data-mongo-class-work/pom.xml new file mode 100644 index 00000000..a13c15b7 --- /dev/null +++ b/2022-08/spring-15/spring-data-mongo-class-work/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + ru.otus + spring-data-mongo-class-work + 1.0 + + pom + + + spring-data-mongo-exercise + spring-data-mongo-solution + + diff --git a/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-exercise/pom.xml b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-exercise/pom.xml new file mode 100644 index 00000000..5cb9d0e1 --- /dev/null +++ b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-exercise/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + ru.otus + spring-data-mongo-exercise + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.3.4.RELEASE + + + + + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-exercise/src/main/java/ru/otus/spring/Main.java b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-exercise/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..d67d7972 --- /dev/null +++ b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-exercise/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,31 @@ +package ru.otus.spring; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +@SpringBootApplication +public class Main { + + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") + @Autowired + private PersonRepository repository; + + public static void main(String[] args) throws InterruptedException { + ApplicationContext context = SpringApplication.run(Main.class); + + PersonRepository repository = context.getBean(PersonRepository.class); + + repository.save(new Person("Dostoevsky")); + + Thread.sleep(3000); + + System.out.println("\n\n\n----------------------------------------------\n\n"); + System.out.println("Авторы в БД:"); + repository.findAll().forEach(p -> System.out.println(p.getName())); + System.out.println("\n\n----------------------------------------------\n\n\n"); + } +} diff --git a/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-exercise/src/main/java/ru/otus/spring/domain/Person.java b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-exercise/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..2bdc3894 --- /dev/null +++ b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-exercise/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,27 @@ +package ru.otus.spring.domain; + +public class Person { + + private String id; + private String name; + + public Person(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..763a2288 --- /dev/null +++ b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,12 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.CrudRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + + +public interface PersonRepository extends CrudRepository { + + List findAll(); +} diff --git a/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-exercise/src/main/resources/application.yml b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-exercise/src/main/resources/application.yml new file mode 100644 index 00000000..9bffd5dc --- /dev/null +++ b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-exercise/src/main/resources/application.yml @@ -0,0 +1,4 @@ +spring: + data: + mongodb: + database: company diff --git a/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/pom.xml b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/pom.xml new file mode 100644 index 00000000..6045db5d --- /dev/null +++ b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + ru.otus + spring-data-mongo-solution + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.3.4.RELEASE + + + + + 11 + 11 + 4.1.17 + + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + + + + com.github.cloudyrock.mongock + mongock-spring-v5 + ${mongock.version} + + + + com.github.cloudyrock.mongock + mongodb-springdata-v3-driver + ${mongock.version} + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/src/main/java/ru/otus/spring/Main.java b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..fb0e8a60 --- /dev/null +++ b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,35 @@ +package ru.otus.spring; + +import com.github.cloudyrock.spring.v5.EnableMongock; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +@EnableMongock +@EnableMongoRepositories +@SpringBootApplication +public class Main { + + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") + @Autowired + private PersonRepository repository; + + public static void main(String[] args) throws InterruptedException { + ApplicationContext context = SpringApplication.run(Main.class); + + PersonRepository repository = context.getBean(PersonRepository.class); + + repository.save(new Person("Dostoevsky")); + + Thread.sleep(3000); + + System.out.println("\n\n\n----------------------------------------------\n\n"); + System.out.println("Авторы в БД:"); + repository.findAll().forEach(p -> System.out.println(p.getName())); + System.out.println("\n\n----------------------------------------------\n\n\n"); + } +} diff --git a/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/src/main/java/ru/otus/spring/domain/Person.java b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..12cf6355 --- /dev/null +++ b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,32 @@ +package ru.otus.spring.domain; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document(collection = "persons") +public class Person { + + @Id + private String id; + private String name; + + public Person(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/src/main/java/ru/otus/spring/mongock/changelog/DatabaseChangelog.java b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/src/main/java/ru/otus/spring/mongock/changelog/DatabaseChangelog.java new file mode 100644 index 00000000..f9226e50 --- /dev/null +++ b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/src/main/java/ru/otus/spring/mongock/changelog/DatabaseChangelog.java @@ -0,0 +1,30 @@ +package ru.otus.spring.mongock.changelog; + +import com.github.cloudyrock.mongock.ChangeLog; +import com.github.cloudyrock.mongock.ChangeSet; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import org.bson.Document; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +@ChangeLog +public class DatabaseChangelog { + + @ChangeSet(order = "001", id = "dropDb", author = "stvort", runAlways = true) + public void dropDb(MongoDatabase db) { + db.drop(); + } + + @ChangeSet(order = "002", id = "insertLermontov", author = "ydvorzhetskiy") + public void insertLermontov(MongoDatabase db) { + MongoCollection myCollection = db.getCollection("persons"); + var doc = new Document().append("name", "Lermontov"); + myCollection.insertOne(doc); + } + + @ChangeSet(order = "003", id = "insertPushkin", author = "stvort") + public void insertPushkin(PersonRepository repository) { + repository.save(new Person("Pushkin")); + } +} diff --git a/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..763a2288 --- /dev/null +++ b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,12 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.CrudRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + + +public interface PersonRepository extends CrudRepository { + + List findAll(); +} diff --git a/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/src/main/resources/application.yml b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/src/main/resources/application.yml new file mode 100644 index 00000000..dd00fa36 --- /dev/null +++ b/2022-08/spring-15/spring-data-mongo-class-work/spring-data-mongo-solution/src/main/resources/application.yml @@ -0,0 +1,10 @@ +spring: + data: + mongodb: + database: company + +mongock: + runner-type: "ApplicationRunner" # default + #runner-type: "InitializingBean" + change-logs-scan-package: + - ru.otus.spring.mongock.changelog diff --git a/2022-08/spring-17-mvc/pom.xml b/2022-08/spring-17-mvc/pom.xml new file mode 100644 index 00000000..c9bb3f66 --- /dev/null +++ b/2022-08/spring-17-mvc/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + ru.otus + spring-mvc-class-work + 1.0 + + pom + + + spring-mvc-exercise + spring-mvc-solution-1 + spring-mvc-solution-2 + spring-mvc-solution-3 + spring-mvc-demo + + diff --git a/2022-08/spring-17-mvc/spring-mvc-demo/pom.xml b/2022-08/spring-17-mvc/spring-mvc-demo/pom.xml new file mode 100644 index 00000000..77fbd138 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-demo/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + ru.otus + spring-mvc-demo + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.7.5 + + + + + 11 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/Main.java b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..e73a469d --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,26 @@ +package ru.otus.spring; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import javax.annotation.PostConstruct; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } + + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") + @Autowired + private PersonRepository repository; + + @PostConstruct + public void init() { + repository.save(new Person(1, "Pushkin")); + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/config/WebConfig.java b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/config/WebConfig.java new file mode 100644 index 00000000..e201fdcf --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/config/WebConfig.java @@ -0,0 +1,21 @@ +package ru.otus.spring.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import ru.otus.spring.rest.resolvers.SystemInfoMethodArgumentResolver; + +import java.util.List; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Autowired + private SystemInfoMethodArgumentResolver systemInfoMethodArgumentResolver; + + @Override + public void addArgumentResolvers(List resolvers) { + resolvers.add(systemInfoMethodArgumentResolver); + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/domain/Person.java b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..3a4c40b3 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,40 @@ +package ru.otus.spring.domain; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class Person { + + @Id + private long id; + private String name; + + public Person() { + } + + public Person(String name) { + this.name = name; + } + + public Person(long id, String name) { + this.id = id; + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/domain/SystemInfo.java b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/domain/SystemInfo.java new file mode 100644 index 00000000..c16a8a78 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/domain/SystemInfo.java @@ -0,0 +1,31 @@ +package ru.otus.spring.domain; + +public class SystemInfo { + private final String osName; + private final String timeZone; + private final String osArch; + private final int processorsCount; + + public SystemInfo(String osName, String timeZone, String osArch, int processorsCount) { + this.osName = osName; + this.timeZone = timeZone; + this.osArch = osArch; + this.processorsCount = processorsCount; + } + + public String getOsName() { + return osName; + } + + public String getTimeZone() { + return timeZone; + } + + public String getOsArch() { + return osArch; + } + + public int getProcessorsCount() { + return processorsCount; + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..99f11033 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,12 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.PagingAndSortingRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends PagingAndSortingRepository { + + List findAll(); + List findByName(String name); +} diff --git a/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/rest/PersonController.java b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/rest/PersonController.java new file mode 100644 index 00000000..b195143e --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/rest/PersonController.java @@ -0,0 +1,64 @@ +package ru.otus.spring.rest; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.rest.dto.PersonDto; +import ru.otus.spring.rest.exceptions.NotFoundException; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +public class PersonController { + + private final PersonRepository repository; + + public PersonController(PersonRepository repository) { + this.repository = repository; + } + + @RequestMapping(value = "/persons", method = RequestMethod.GET) + public List getAllPersons() { + return repository.findAll().stream() + .map(PersonDto::toDto) + .collect(Collectors.toList()); + } + + @RequestMapping(value = "/persons", method = RequestMethod.GET, params = "name") + public PersonDto getPersonByNameInRequest(@RequestParam("name") String name) { + Person person = repository.findByName(name).stream().findFirst().orElseThrow(NotFoundException::new); + return PersonDto.toDto(person); + } + + @GetMapping("/persons/{id}") + public PersonDto getPersonByIdInPath(@PathVariable("id") long id) { + Person person = repository.findById(id).orElseThrow(NotFoundException::new); + return PersonDto.toDto(person); + } + + @PostMapping("/persons") + public PersonDto createNewPerson(@RequestBody PersonDto dto) { + Person person = PersonDto.toDomainObject(dto); + Person savedPerson = repository.save(person); + return PersonDto.toDto(savedPerson); + } + + @PatchMapping("/persons/{id}/name") + public PersonDto updateNameById(@PathVariable("id") long id, @RequestParam("name") String name) { + Person person = repository.findById(id).orElseThrow(NotFoundException::new); + person.setName(name); + return PersonDto.toDto(repository.save(person)); + } + + @DeleteMapping("/persons/{id}") + public void deleteById(@PathVariable("id") long id) { + repository.deleteById(id); + } + + @ExceptionHandler(NotFoundException.class) + public ResponseEntity handleNotFound(NotFoundException ex) { + return ResponseEntity.badRequest().body("Таких тут нет!"); + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/rest/SystemInfoController.java b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/rest/SystemInfoController.java new file mode 100644 index 00000000..f188a94f --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/rest/SystemInfoController.java @@ -0,0 +1,14 @@ +package ru.otus.spring.rest; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import ru.otus.spring.domain.SystemInfo; + +@RestController +public class SystemInfoController { + + @GetMapping("/server/system/info") + public SystemInfo getServerSystemInfo(SystemInfo systemInfo) { + return systemInfo; + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/rest/dto/PersonDto.java b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/rest/dto/PersonDto.java new file mode 100644 index 00000000..a2aeae8f --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/rest/dto/PersonDto.java @@ -0,0 +1,54 @@ +/* + * Copyright 2016 Russian Post + * + * This source code is Russian Post Confidential Proprietary. + * This software is protected by copyright. All rights and titles are reserved. + * You shall not use, copy, distribute, modify, decompile, disassemble or reverse engineer the software. + * Otherwise this violation would be treated by law and would be subject to legal prosecution. + * Legal use of the software provides receipt of a license from the right name only. + */ +package ru.otus.spring.rest.dto; + +import ru.otus.spring.domain.Person; + +/** + * DTO that represents Person + */ +@SuppressWarnings("all") +public class PersonDto { + + private long id; + private String name; + + public PersonDto() { + } + + public PersonDto(long id, String name) { + this.id = id; + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public static Person toDomainObject(PersonDto dto) { + return new Person(dto.getId(), dto.getName()); + } + + public static PersonDto toDto(Person person) { + return new PersonDto(person.getId(), person.getName()); + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/rest/exceptions/NotFoundException.java b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/rest/exceptions/NotFoundException.java new file mode 100644 index 00000000..5dc475b8 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/rest/exceptions/NotFoundException.java @@ -0,0 +1,7 @@ +package ru.otus.spring.rest.exceptions; + +public class NotFoundException extends RuntimeException{ + + public NotFoundException() { + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/rest/resolvers/SystemInfoMethodArgumentResolver.java b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/rest/resolvers/SystemInfoMethodArgumentResolver.java new file mode 100644 index 00000000..51f517a7 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/rest/resolvers/SystemInfoMethodArgumentResolver.java @@ -0,0 +1,33 @@ +package ru.otus.spring.rest.resolvers; + +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; +import ru.otus.spring.domain.SystemInfo; +import ru.otus.spring.service.SystemInfoService; + +@Component +public class SystemInfoMethodArgumentResolver implements HandlerMethodArgumentResolver { + + private final SystemInfoService systemInfoService; + + public SystemInfoMethodArgumentResolver(SystemInfoService systemInfoService) { + this.systemInfoService = systemInfoService; + } + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.getParameterType().equals(SystemInfo.class); + } + + @Override + public Object resolveArgument(MethodParameter parameter, + ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, + WebDataBinderFactory binderFactory) throws Exception { + return systemInfoService.getSystemInfo(); + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/service/SystemInfoService.java b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/service/SystemInfoService.java new file mode 100644 index 00000000..26fb34d2 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-demo/src/main/java/ru/otus/spring/service/SystemInfoService.java @@ -0,0 +1,17 @@ +package ru.otus.spring.service; + +import org.springframework.stereotype.Service; +import ru.otus.spring.domain.SystemInfo; + +@Service +public class SystemInfoService { + + public SystemInfo getSystemInfo(){ + String osName = System.getProperty("os.name"); + String timeZone = System.getProperty("user.timezone"); + String osArch = System.getProperty("os.arch"); + int processorsCount = Runtime.getRuntime().availableProcessors(); + return new SystemInfo(osName, timeZone, osArch, processorsCount); + + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-demo/src/test/java/ru/otus/spring/rest/PersonControllerTest.java b/2022-08/spring-17-mvc/spring-mvc-demo/src/test/java/ru/otus/spring/rest/PersonControllerTest.java new file mode 100644 index 00000000..118a671a --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-demo/src/test/java/ru/otus/spring/rest/PersonControllerTest.java @@ -0,0 +1,127 @@ +package ru.otus.spring.rest; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.MockMvc; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.rest.dto.PersonDto; +import ru.otus.spring.service.SystemInfoService; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(PersonController.class) +class PersonControllerTest { + + public static final String ERROR_STRING = "Таких тут нет!"; + + @Autowired + private MockMvc mvc; + + @Autowired + private ObjectMapper mapper; + + @MockBean + private PersonRepository repository; + + @MockBean + private SystemInfoService systemInfoService; + + @Test + void shouldReturnCorrectPersonsList() throws Exception { + List persons = List.of(new Person(1, "Person1"), new Person(2, "Person2")); + given(repository.findAll()).willReturn(persons); + + List expectedResult = persons.stream() + .map(PersonDto::toDto).collect(Collectors.toList()); + + mvc.perform(get("/persons")) + .andExpect(status().isOk()) + .andExpect(content().json(mapper.writeValueAsString(expectedResult))); + } + + @Test + void shouldReturnCorrectPersonByNameInRequest() throws Exception { + Person person = new Person(1, "Person1"); + given(repository.findByName(person.getName())).willReturn(List.of(person)); + PersonDto expectedResult = PersonDto.toDto(person); + + mvc.perform(get("/persons").param("name", person.getName())) + .andExpect(status().isOk()) + .andExpect(content().json(mapper.writeValueAsString(expectedResult))); + } + + @Test + void shouldReturnCorrectPersonByIdInPath() throws Exception { + Person person = new Person(1, "Person1"); + given(repository.findById(1L)).willReturn(Optional.of(person)); + PersonDto expectedResult = PersonDto.toDto(person); + + mvc.perform(get("/persons/1")) + .andExpect(status().isOk()) + .andExpect(content().json(mapper.writeValueAsString(expectedResult))); + } + + @Test + void shouldReturnExpectedErrorWhenPersonNotFound() throws Exception { + given(repository.findById(1L)).willReturn(Optional.empty()); + + mvc.perform(get("/persons").param("name", "Person1")) + .andExpect(status().isBadRequest()) + .andExpect(content().string(ERROR_STRING)); + + mvc.perform(get("/persons/1")) + .andExpect(status().isBadRequest()) + .andExpect(content().string(ERROR_STRING)); + } + + @Test + void shouldCorrectSaveNewPerson() throws Exception { + Person person = new Person(1, "Person1"); + given(repository.save(any())).willReturn(person); + String expectedResult = mapper.writeValueAsString(PersonDto.toDto(person)); + + mvc.perform(post("/persons").contentType(APPLICATION_JSON) + .content(expectedResult)) + .andExpect(status().isOk()) + .andExpect(content().json(expectedResult)); + } + + @Test + void shouldCorrectUpdatePersonName() throws Exception { + Person person = new Person(1, "Person1"); + given(repository.findById(1L)).willReturn(Optional.of(person)); + given(repository.save(any())).willAnswer(invocation -> invocation.getArgument(0)); + + Person expectedPerson = new Person(1, "Person2"); + String expectedResult = mapper.writeValueAsString(PersonDto.toDto(expectedPerson)); + + mvc.perform(patch("/persons/{id}/name", 1).param("name", expectedPerson.getName()) + .content(expectedResult)) + .andExpect(status().isOk()) + .andExpect(content().json(expectedResult)); + } + + @Test + void shouldCorrectDeletePerson() throws Exception { + mvc.perform(delete("/persons/1")) + .andExpect(status().isOk()); + verify(repository, times(1)).deleteById(1L); + } + + +} \ No newline at end of file diff --git a/2022-08/spring-17-mvc/spring-mvc-demo/src/test/java/ru/otus/spring/rest/SystemInfoControllerTest.java b/2022-08/spring-17-mvc/spring-mvc-demo/src/test/java/ru/otus/spring/rest/SystemInfoControllerTest.java new file mode 100644 index 00000000..3c35c11b --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-demo/src/test/java/ru/otus/spring/rest/SystemInfoControllerTest.java @@ -0,0 +1,39 @@ +package ru.otus.spring.rest; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.test.web.servlet.MockMvc; +import ru.otus.spring.domain.SystemInfo; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.service.SystemInfoService; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; + +@WebMvcTest(SystemInfoController.class) +@Import(SystemInfoService.class) +class SystemInfoControllerTest { + + @Autowired + private MockMvc mvc; + + @Autowired + private ObjectMapper mapper; + + @MockBean + private PersonRepository repository; + + @Autowired + private SystemInfoService systemInfoService; + + @Test + void shouldReturnCorrectServerSystemInfo() throws Exception { + SystemInfo expectedSystemInfo = systemInfoService.getSystemInfo(); + mvc.perform(get("/server/system/info")) + .andExpect(content().json(mapper.writeValueAsString(expectedSystemInfo))); + } +} \ No newline at end of file diff --git a/2022-08/spring-17-mvc/spring-mvc-exercise/pom.xml b/2022-08/spring-17-mvc/spring-mvc-exercise/pom.xml new file mode 100644 index 00000000..c142c80e --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-exercise/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + ru.otus + spring-mvc-exercise + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.7.5 + + + + + 11 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/Main.java b/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..e73a469d --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,26 @@ +package ru.otus.spring; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import javax.annotation.PostConstruct; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } + + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") + @Autowired + private PersonRepository repository; + + @PostConstruct + public void init() { + repository.save(new Person(1, "Pushkin")); + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/domain/Person.java b/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..3a4c40b3 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,40 @@ +package ru.otus.spring.domain; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class Person { + + @Id + private long id; + private String name; + + public Person() { + } + + public Person(String name) { + this.name = name; + } + + public Person(long id, String name) { + this.id = id; + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..99f11033 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,12 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.PagingAndSortingRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends PagingAndSortingRepository { + + List findAll(); + List findByName(String name); +} diff --git a/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/rest/PersonController.java b/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/rest/PersonController.java new file mode 100644 index 00000000..344a34b7 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/rest/PersonController.java @@ -0,0 +1,13 @@ +package ru.otus.spring.rest; + +import ru.otus.spring.repostory.PersonRepository; + + +public class PersonController { + + private final PersonRepository repository; + + public PersonController(PersonRepository repository) { + this.repository = repository; + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/rest/dto/PersonDto.java b/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/rest/dto/PersonDto.java new file mode 100644 index 00000000..a2aeae8f --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/rest/dto/PersonDto.java @@ -0,0 +1,54 @@ +/* + * Copyright 2016 Russian Post + * + * This source code is Russian Post Confidential Proprietary. + * This software is protected by copyright. All rights and titles are reserved. + * You shall not use, copy, distribute, modify, decompile, disassemble or reverse engineer the software. + * Otherwise this violation would be treated by law and would be subject to legal prosecution. + * Legal use of the software provides receipt of a license from the right name only. + */ +package ru.otus.spring.rest.dto; + +import ru.otus.spring.domain.Person; + +/** + * DTO that represents Person + */ +@SuppressWarnings("all") +public class PersonDto { + + private long id; + private String name; + + public PersonDto() { + } + + public PersonDto(long id, String name) { + this.id = id; + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public static Person toDomainObject(PersonDto dto) { + return new Person(dto.getId(), dto.getName()); + } + + public static PersonDto toDto(Person person) { + return new PersonDto(person.getId(), person.getName()); + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/rest/exeptions/NotFoundException.java b/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/rest/exeptions/NotFoundException.java new file mode 100644 index 00000000..169b67b2 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-exercise/src/main/java/ru/otus/spring/rest/exeptions/NotFoundException.java @@ -0,0 +1,7 @@ +package ru.otus.spring.rest.exeptions; + +public class NotFoundException extends RuntimeException{ + + public NotFoundException() { + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-exercise/src/test/java/ru/otus/spring/rest/PersonControllerTest.java b/2022-08/spring-17-mvc/spring-mvc-exercise/src/test/java/ru/otus/spring/rest/PersonControllerTest.java new file mode 100644 index 00000000..2b7c8154 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-exercise/src/test/java/ru/otus/spring/rest/PersonControllerTest.java @@ -0,0 +1,83 @@ +package ru.otus.spring.rest; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.MockMvc; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.rest.dto.PersonDto; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(PersonController.class) +class PersonControllerTest { + + public static final String ERROR_STRING = "Таких тут нет!"; + + @Autowired + private MockMvc mvc; + + @Autowired + private ObjectMapper mapper; + + @MockBean + private PersonRepository repository; + + @Test + void shouldReturnCorrectPersonsList() throws Exception { + List persons = List.of(new Person(1, "Person1"), new Person(2, "Person2")); + given(repository.findAll()).willReturn(persons); + + List expectedResult = persons.stream() + .map(PersonDto::toDto).collect(Collectors.toList()); + + mvc.perform(get("/persons")) + .andExpect(status().isOk()) + .andExpect(content().json(mapper.writeValueAsString(expectedResult))); + } + + @Test + void shouldReturnCorrectPersonByNameInRequest() throws Exception { + Person person = new Person(1, "Person1"); + given(repository.findByName(person.getName())).willReturn(List.of(person)); + PersonDto expectedResult = PersonDto.toDto(person); + + mvc.perform(get("/persons").param("name", person.getName())) + .andExpect(status().isOk()) + .andExpect(content().json(mapper.writeValueAsString(expectedResult))); + } + + @Test + void shouldReturnCorrectPersonByIdInPath() throws Exception { + Person person = new Person(1, "Person1"); + given(repository.findById(1L)).willReturn(Optional.of(person)); + PersonDto expectedResult = PersonDto.toDto(person); + + mvc.perform(get("/persons/1")) + .andExpect(status().isOk()) + .andExpect(content().json(mapper.writeValueAsString(expectedResult))); + } + + @Test + void shouldReturnExpectedErrorWhenPersonNotFound() throws Exception { + given(repository.findById(1L)).willReturn(Optional.empty()); + + mvc.perform(get("/persons").param("name", "Person1")) + .andExpect(status().isBadRequest()) + .andExpect(content().string(ERROR_STRING)); + + mvc.perform(get("/persons/1")) + .andExpect(status().isBadRequest()) + .andExpect(content().string(ERROR_STRING)); + } +} \ No newline at end of file diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-1/pom.xml b/2022-08/spring-17-mvc/spring-mvc-solution-1/pom.xml new file mode 100644 index 00000000..38650710 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-1/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + ru.otus + spring-mvc-solution-1 + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.7.5 + + + + + 11 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/Main.java b/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..e73a469d --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,26 @@ +package ru.otus.spring; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import javax.annotation.PostConstruct; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } + + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") + @Autowired + private PersonRepository repository; + + @PostConstruct + public void init() { + repository.save(new Person(1, "Pushkin")); + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/domain/Person.java b/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..3a4c40b3 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,40 @@ +package ru.otus.spring.domain; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class Person { + + @Id + private long id; + private String name; + + public Person() { + } + + public Person(String name) { + this.name = name; + } + + public Person(long id, String name) { + this.id = id; + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..99f11033 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,12 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.PagingAndSortingRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends PagingAndSortingRepository { + + List findAll(); + List findByName(String name); +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/rest/PersonController.java b/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/rest/PersonController.java new file mode 100644 index 00000000..c8e47c24 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/rest/PersonController.java @@ -0,0 +1,27 @@ +package ru.otus.spring.rest; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.rest.dto.PersonDto; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +public class PersonController { + + private final PersonRepository repository; + + public PersonController(PersonRepository repository) { + this.repository = repository; + } + + @RequestMapping(value = "/persons", method = RequestMethod.GET) + public List getAllPersons() { + return repository.findAll().stream() + .map(PersonDto::toDto) + .collect(Collectors.toList()); + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/rest/dto/PersonDto.java b/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/rest/dto/PersonDto.java new file mode 100644 index 00000000..a2aeae8f --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/rest/dto/PersonDto.java @@ -0,0 +1,54 @@ +/* + * Copyright 2016 Russian Post + * + * This source code is Russian Post Confidential Proprietary. + * This software is protected by copyright. All rights and titles are reserved. + * You shall not use, copy, distribute, modify, decompile, disassemble or reverse engineer the software. + * Otherwise this violation would be treated by law and would be subject to legal prosecution. + * Legal use of the software provides receipt of a license from the right name only. + */ +package ru.otus.spring.rest.dto; + +import ru.otus.spring.domain.Person; + +/** + * DTO that represents Person + */ +@SuppressWarnings("all") +public class PersonDto { + + private long id; + private String name; + + public PersonDto() { + } + + public PersonDto(long id, String name) { + this.id = id; + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public static Person toDomainObject(PersonDto dto) { + return new Person(dto.getId(), dto.getName()); + } + + public static PersonDto toDto(Person person) { + return new PersonDto(person.getId(), person.getName()); + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/rest/exceptions/NotFoundException.java b/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/rest/exceptions/NotFoundException.java new file mode 100644 index 00000000..5dc475b8 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-1/src/main/java/ru/otus/spring/rest/exceptions/NotFoundException.java @@ -0,0 +1,7 @@ +package ru.otus.spring.rest.exceptions; + +public class NotFoundException extends RuntimeException{ + + public NotFoundException() { + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-1/src/test/java/ru/otus/spring/rest/PersonControllerTest.java b/2022-08/spring-17-mvc/spring-mvc-solution-1/src/test/java/ru/otus/spring/rest/PersonControllerTest.java new file mode 100644 index 00000000..2b7c8154 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-1/src/test/java/ru/otus/spring/rest/PersonControllerTest.java @@ -0,0 +1,83 @@ +package ru.otus.spring.rest; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.MockMvc; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.rest.dto.PersonDto; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(PersonController.class) +class PersonControllerTest { + + public static final String ERROR_STRING = "Таких тут нет!"; + + @Autowired + private MockMvc mvc; + + @Autowired + private ObjectMapper mapper; + + @MockBean + private PersonRepository repository; + + @Test + void shouldReturnCorrectPersonsList() throws Exception { + List persons = List.of(new Person(1, "Person1"), new Person(2, "Person2")); + given(repository.findAll()).willReturn(persons); + + List expectedResult = persons.stream() + .map(PersonDto::toDto).collect(Collectors.toList()); + + mvc.perform(get("/persons")) + .andExpect(status().isOk()) + .andExpect(content().json(mapper.writeValueAsString(expectedResult))); + } + + @Test + void shouldReturnCorrectPersonByNameInRequest() throws Exception { + Person person = new Person(1, "Person1"); + given(repository.findByName(person.getName())).willReturn(List.of(person)); + PersonDto expectedResult = PersonDto.toDto(person); + + mvc.perform(get("/persons").param("name", person.getName())) + .andExpect(status().isOk()) + .andExpect(content().json(mapper.writeValueAsString(expectedResult))); + } + + @Test + void shouldReturnCorrectPersonByIdInPath() throws Exception { + Person person = new Person(1, "Person1"); + given(repository.findById(1L)).willReturn(Optional.of(person)); + PersonDto expectedResult = PersonDto.toDto(person); + + mvc.perform(get("/persons/1")) + .andExpect(status().isOk()) + .andExpect(content().json(mapper.writeValueAsString(expectedResult))); + } + + @Test + void shouldReturnExpectedErrorWhenPersonNotFound() throws Exception { + given(repository.findById(1L)).willReturn(Optional.empty()); + + mvc.perform(get("/persons").param("name", "Person1")) + .andExpect(status().isBadRequest()) + .andExpect(content().string(ERROR_STRING)); + + mvc.perform(get("/persons/1")) + .andExpect(status().isBadRequest()) + .andExpect(content().string(ERROR_STRING)); + } +} \ No newline at end of file diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-2/pom.xml b/2022-08/spring-17-mvc/spring-mvc-solution-2/pom.xml new file mode 100644 index 00000000..29afc4b7 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-2/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + ru.otus + spring-mvc-solution-2 + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.7.5 + + + + + 11 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/Main.java b/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..e73a469d --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,26 @@ +package ru.otus.spring; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import javax.annotation.PostConstruct; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } + + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") + @Autowired + private PersonRepository repository; + + @PostConstruct + public void init() { + repository.save(new Person(1, "Pushkin")); + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/domain/Person.java b/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..3a4c40b3 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,40 @@ +package ru.otus.spring.domain; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class Person { + + @Id + private long id; + private String name; + + public Person() { + } + + public Person(String name) { + this.name = name; + } + + public Person(long id, String name) { + this.id = id; + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..99f11033 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,12 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.PagingAndSortingRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends PagingAndSortingRepository { + + List findAll(); + List findByName(String name); +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/rest/PersonController.java b/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/rest/PersonController.java new file mode 100644 index 00000000..2c1b02bc --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/rest/PersonController.java @@ -0,0 +1,40 @@ +package ru.otus.spring.rest; + +import org.springframework.web.bind.annotation.*; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.rest.dto.PersonDto; +import ru.otus.spring.rest.exceptions.NotFoundException; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +public class PersonController { + + private final PersonRepository repository; + + public PersonController(PersonRepository repository) { + this.repository = repository; + } + + @RequestMapping(value = "/persons", method = RequestMethod.GET) + public List getAllPersons() { + return repository.findAll().stream() + .map(PersonDto::toDto) + .collect(Collectors.toList()); + } + + @RequestMapping(value = "/persons", method = RequestMethod.GET, params = "name") + public PersonDto getPersonByNameInRequest(@RequestParam("name") String name) { + Person person = repository.findByName(name).stream().findFirst().orElseThrow(NotFoundException::new); + return PersonDto.toDto(person); + } + + @GetMapping("/persons/{id}") + public PersonDto getPersonByIdInPath(@PathVariable("id") long id) { + Person person = repository.findById(id).orElseThrow(NotFoundException::new); + return PersonDto.toDto(person); + } + +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/rest/dto/PersonDto.java b/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/rest/dto/PersonDto.java new file mode 100644 index 00000000..a2aeae8f --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/rest/dto/PersonDto.java @@ -0,0 +1,54 @@ +/* + * Copyright 2016 Russian Post + * + * This source code is Russian Post Confidential Proprietary. + * This software is protected by copyright. All rights and titles are reserved. + * You shall not use, copy, distribute, modify, decompile, disassemble or reverse engineer the software. + * Otherwise this violation would be treated by law and would be subject to legal prosecution. + * Legal use of the software provides receipt of a license from the right name only. + */ +package ru.otus.spring.rest.dto; + +import ru.otus.spring.domain.Person; + +/** + * DTO that represents Person + */ +@SuppressWarnings("all") +public class PersonDto { + + private long id; + private String name; + + public PersonDto() { + } + + public PersonDto(long id, String name) { + this.id = id; + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public static Person toDomainObject(PersonDto dto) { + return new Person(dto.getId(), dto.getName()); + } + + public static PersonDto toDto(Person person) { + return new PersonDto(person.getId(), person.getName()); + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/rest/exceptions/NotFoundException.java b/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/rest/exceptions/NotFoundException.java new file mode 100644 index 00000000..5dc475b8 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-2/src/main/java/ru/otus/spring/rest/exceptions/NotFoundException.java @@ -0,0 +1,7 @@ +package ru.otus.spring.rest.exceptions; + +public class NotFoundException extends RuntimeException{ + + public NotFoundException() { + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-2/src/test/java/ru/otus/spring/rest/PersonControllerTest.java b/2022-08/spring-17-mvc/spring-mvc-solution-2/src/test/java/ru/otus/spring/rest/PersonControllerTest.java new file mode 100644 index 00000000..6da9bef4 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-2/src/test/java/ru/otus/spring/rest/PersonControllerTest.java @@ -0,0 +1,83 @@ +package ru.otus.spring.rest; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.MockMvc; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.rest.dto.PersonDto; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(PersonController.class) +class PersonControllerTest { + + public static final String ERROR_STRING = "Таких тут нет!"; + + @Autowired + private MockMvc mvc; + + @Autowired + private ObjectMapper mapper; + + @MockBean + private PersonRepository repository; + + @Test + void shouldReturnCorrectPersonsList() throws Exception { + List persons = List.of(new Person(1, "Person1"), new Person(2, "Person2")); + given(repository.findAll()).willReturn(persons); + + List expectedResult = persons.stream() + .map(PersonDto::toDto).collect(Collectors.toList()); + + mvc.perform(get("/persons")) + .andExpect(status().isOk()) + .andExpect(content().json(mapper.writeValueAsString(expectedResult))); + } + + @Test + void shouldReturnCorrectPersonByNameInRequest() throws Exception { + Person person = new Person(1, "Person1"); + given(repository.findByName(person.getName())).willReturn(List.of(person)); + PersonDto expectedResult = PersonDto.toDto(person); + + mvc.perform(get("/persons").param("name", person.getName())) + .andExpect(status().isOk()) + .andExpect(content().json(mapper.writeValueAsString(expectedResult))); + } + + @Test + void shouldReturnCorrectPersonByIdInPath() throws Exception { + Person person = new Person(1, "Person1"); + given(repository.findById(1L)).willReturn(Optional.of(person)); + PersonDto expectedResult = PersonDto.toDto(person); + + mvc.perform(get("/persons/1")) + .andExpect(status().isOk()) + .andExpect(content().json(mapper.writeValueAsString(expectedResult))); + } + + @Test + void shouldReturnExpectedErrorWhenPersonNotFound() throws Exception { + given(repository.findById(1L)).willReturn(Optional.empty()); + + mvc.perform(get("/persons").param("name", "Person1")) + .andExpect(status().isBadRequest()) + .andExpect(content().string(ERROR_STRING)); + + mvc.perform(get("/persons/1")) + .andExpect(status().isBadRequest()) + .andExpect(content().string(ERROR_STRING)); + } +} \ No newline at end of file diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-3/pom.xml b/2022-08/spring-17-mvc/spring-mvc-solution-3/pom.xml new file mode 100644 index 00000000..7ba73a68 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-3/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + ru.otus + spring-mvc-solution-3 + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.6.7 + + + + + 11 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-3/requests.http b/2022-08/spring-17-mvc/spring-mvc-solution-3/requests.http new file mode 100644 index 00000000..958a57b2 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-3/requests.http @@ -0,0 +1,10 @@ +POST http://localhost:8080/person +Content-Type: application/json + +{ + "id": "2", + "name": "Pushkin" +} + +### +GET http://localhost:8080/persons/all \ No newline at end of file diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/Main.java b/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..e73a469d --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,26 @@ +package ru.otus.spring; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import javax.annotation.PostConstruct; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } + + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") + @Autowired + private PersonRepository repository; + + @PostConstruct + public void init() { + repository.save(new Person(1, "Pushkin")); + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/domain/Person.java b/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..3a4c40b3 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,40 @@ +package ru.otus.spring.domain; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class Person { + + @Id + private long id; + private String name; + + public Person() { + } + + public Person(String name) { + this.name = name; + } + + public Person(long id, String name) { + this.id = id; + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..99f11033 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,12 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.PagingAndSortingRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends PagingAndSortingRepository { + + List findAll(); + List findByName(String name); +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/rest/PersonController.java b/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/rest/PersonController.java new file mode 100644 index 00000000..f7ee302b --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/rest/PersonController.java @@ -0,0 +1,45 @@ +package ru.otus.spring.rest; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.rest.dto.PersonDto; +import ru.otus.spring.rest.exceptions.NotFoundException; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +public class PersonController { + + private final PersonRepository repository; + + public PersonController(PersonRepository repository) { + this.repository = repository; + } + + @RequestMapping(value = "/persons", method = RequestMethod.GET) + public List getAllPersons() { + return repository.findAll().stream() + .map(PersonDto::toDto) + .collect(Collectors.toList()); + } + + @RequestMapping(value = "/persons", method = RequestMethod.GET, params = "name") + public PersonDto getPersonByNameInRequest(@RequestParam("name") String name) { + Person person = repository.findByName(name).stream().findFirst().orElseThrow(NotFoundException::new); + return PersonDto.toDto(person); + } + + @GetMapping("/persons/{id}") + public PersonDto getPersonByIdInPath(@PathVariable("id") long id) { + Person person = repository.findById(id).orElseThrow(NotFoundException::new); + return PersonDto.toDto(person); + } + + @ExceptionHandler(NotFoundException.class) + public ResponseEntity handleNotFound(NotFoundException ex) { + return ResponseEntity.badRequest().body("Таких тут нет!"); + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/rest/dto/PersonDto.java b/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/rest/dto/PersonDto.java new file mode 100644 index 00000000..a2aeae8f --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/rest/dto/PersonDto.java @@ -0,0 +1,54 @@ +/* + * Copyright 2016 Russian Post + * + * This source code is Russian Post Confidential Proprietary. + * This software is protected by copyright. All rights and titles are reserved. + * You shall not use, copy, distribute, modify, decompile, disassemble or reverse engineer the software. + * Otherwise this violation would be treated by law and would be subject to legal prosecution. + * Legal use of the software provides receipt of a license from the right name only. + */ +package ru.otus.spring.rest.dto; + +import ru.otus.spring.domain.Person; + +/** + * DTO that represents Person + */ +@SuppressWarnings("all") +public class PersonDto { + + private long id; + private String name; + + public PersonDto() { + } + + public PersonDto(long id, String name) { + this.id = id; + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public static Person toDomainObject(PersonDto dto) { + return new Person(dto.getId(), dto.getName()); + } + + public static PersonDto toDto(Person person) { + return new PersonDto(person.getId(), person.getName()); + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/rest/exceptions/NotFoundException.java b/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/rest/exceptions/NotFoundException.java new file mode 100644 index 00000000..5dc475b8 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-3/src/main/java/ru/otus/spring/rest/exceptions/NotFoundException.java @@ -0,0 +1,7 @@ +package ru.otus.spring.rest.exceptions; + +public class NotFoundException extends RuntimeException{ + + public NotFoundException() { + } +} diff --git a/2022-08/spring-17-mvc/spring-mvc-solution-3/src/test/java/ru/otus/spring/rest/PersonControllerTest.java b/2022-08/spring-17-mvc/spring-mvc-solution-3/src/test/java/ru/otus/spring/rest/PersonControllerTest.java new file mode 100644 index 00000000..6da9bef4 --- /dev/null +++ b/2022-08/spring-17-mvc/spring-mvc-solution-3/src/test/java/ru/otus/spring/rest/PersonControllerTest.java @@ -0,0 +1,83 @@ +package ru.otus.spring.rest; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.MockMvc; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.rest.dto.PersonDto; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(PersonController.class) +class PersonControllerTest { + + public static final String ERROR_STRING = "Таких тут нет!"; + + @Autowired + private MockMvc mvc; + + @Autowired + private ObjectMapper mapper; + + @MockBean + private PersonRepository repository; + + @Test + void shouldReturnCorrectPersonsList() throws Exception { + List persons = List.of(new Person(1, "Person1"), new Person(2, "Person2")); + given(repository.findAll()).willReturn(persons); + + List expectedResult = persons.stream() + .map(PersonDto::toDto).collect(Collectors.toList()); + + mvc.perform(get("/persons")) + .andExpect(status().isOk()) + .andExpect(content().json(mapper.writeValueAsString(expectedResult))); + } + + @Test + void shouldReturnCorrectPersonByNameInRequest() throws Exception { + Person person = new Person(1, "Person1"); + given(repository.findByName(person.getName())).willReturn(List.of(person)); + PersonDto expectedResult = PersonDto.toDto(person); + + mvc.perform(get("/persons").param("name", person.getName())) + .andExpect(status().isOk()) + .andExpect(content().json(mapper.writeValueAsString(expectedResult))); + } + + @Test + void shouldReturnCorrectPersonByIdInPath() throws Exception { + Person person = new Person(1, "Person1"); + given(repository.findById(1L)).willReturn(Optional.of(person)); + PersonDto expectedResult = PersonDto.toDto(person); + + mvc.perform(get("/persons/1")) + .andExpect(status().isOk()) + .andExpect(content().json(mapper.writeValueAsString(expectedResult))); + } + + @Test + void shouldReturnExpectedErrorWhenPersonNotFound() throws Exception { + given(repository.findById(1L)).willReturn(Optional.empty()); + + mvc.perform(get("/persons").param("name", "Person1")) + .andExpect(status().isBadRequest()) + .andExpect(content().string(ERROR_STRING)); + + mvc.perform(get("/persons/1")) + .andExpect(status().isBadRequest()) + .andExpect(content().string(ERROR_STRING)); + } +} \ No newline at end of file