diff --git a/2019-11/spring-05/advanced-config-class-work/.gitignore b/2019-11/spring-05/advanced-config-class-work/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2019-11/spring-05/advanced-config-class-work/application-events-demo/.gitignore b/2019-11/spring-05/advanced-config-class-work/application-events-demo/.gitignore new file mode 100644 index 00000000..789ddc9e --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/application-events-demo/.gitignore @@ -0,0 +1,32 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +#other +*.bat +*/.idea +*.iml +*/target + +.idea +*.iml +target \ No newline at end of file diff --git a/2019-11/spring-05/advanced-config-class-work/application-events-demo/README.md b/2019-11/spring-05/advanced-config-class-work/application-events-demo/README.md new file mode 100644 index 00000000..63e68847 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/application-events-demo/README.md @@ -0,0 +1,2 @@ +# application-events-demo +Пример работы с событиями \ No newline at end of file diff --git a/2019-11/spring-05/advanced-config-class-work/application-events-demo/pom.xml b/2019-11/spring-05/advanced-config-class-work/application-events-demo/pom.xml new file mode 100644 index 00000000..b5e569e6 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/application-events-demo/pom.xml @@ -0,0 +1,85 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.7.RELEASE + + + + ru.otus.example + application-events-demo + 0.0.1-SNAPSHOT + application-events-demo + Application events demo + + + 11 + 11 + 11 + + + + + + org.springframework.boot + spring-boot-starter + + + + org.projectlombok + lombok + true + + + + org.springframework.shell + spring-shell-starter + 2.0.1.RELEASE + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + junit + junit + + + + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test + + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/ApplicationEventsDemoApplication.java b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/ApplicationEventsDemoApplication.java new file mode 100644 index 00000000..5b8d7ef3 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/ApplicationEventsDemoApplication.java @@ -0,0 +1,26 @@ +package ru.otus.example.applicationeventsdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.context.event.ApplicationEventMulticaster; +import org.springframework.context.event.SimpleApplicationEventMulticaster; +import org.springframework.core.task.SimpleAsyncTaskExecutor; + +@SpringBootApplication +public class ApplicationEventsDemoApplication { + + //@Bean @Primary + //@Bean(name = "applicationEventMulticaster") + public ApplicationEventMulticaster applicationEventMulticaster() { + SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster(); + eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor()); + return eventMulticaster; + } + + public static void main(String[] args) { + SpringApplication.run(ApplicationEventsDemoApplication.class, args); + } + +} diff --git a/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/EventsPublisher.java b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/EventsPublisher.java new file mode 100644 index 00000000..2274570a --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/EventsPublisher.java @@ -0,0 +1,5 @@ +package ru.otus.example.applicationeventsdemo.events; + +public interface EventsPublisher { + void publish(); +} diff --git a/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/HalfAGlassOfWaterEvent.java b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/HalfAGlassOfWaterEvent.java new file mode 100644 index 00000000..22bab552 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/HalfAGlassOfWaterEvent.java @@ -0,0 +1,15 @@ +package ru.otus.example.applicationeventsdemo.events; + +import lombok.Getter; +import org.springframework.context.ApplicationEvent; + +public class HalfAGlassOfWaterEvent extends ApplicationEvent { + + @Getter + private final String payload; + + public HalfAGlassOfWaterEvent(Object source) { + super(source); + payload = "Осталось половина стакана воды!!!"; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/HalfAGlassOfWaterEventPublisher.java b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/HalfAGlassOfWaterEventPublisher.java new file mode 100644 index 00000000..a1186fcc --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/HalfAGlassOfWaterEventPublisher.java @@ -0,0 +1,17 @@ +package ru.otus.example.applicationeventsdemo.events; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class HalfAGlassOfWaterEventPublisher implements EventsPublisher { + + private final ApplicationEventPublisher publisher; + + @Override + public void publish() { + publisher.publishEvent(new HalfAGlassOfWaterEvent(this)); + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/NegativeRespondent.java b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/NegativeRespondent.java new file mode 100644 index 00000000..ce6115c9 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/NegativeRespondent.java @@ -0,0 +1,18 @@ +package ru.otus.example.applicationeventsdemo.events; + +import lombok.SneakyThrows; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +@Component +public class NegativeRespondent implements ApplicationListener { + + @SneakyThrows + @Override + public void onApplicationEvent(HalfAGlassOfWaterEvent halfAGlassOfWaterEvent) { + Thread.sleep(100); + System.out.println("Негативно настроенный слушатель"); + System.out.println(String.format("- %s", halfAGlassOfWaterEvent.getPayload())); + System.out.println("- Какой ужас. Теперь он наполовину пуст!!!\n\n"); + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/PositiveRespondent.java b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/PositiveRespondent.java new file mode 100644 index 00000000..d9071026 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/PositiveRespondent.java @@ -0,0 +1,18 @@ +package ru.otus.example.applicationeventsdemo.events; + +import lombok.SneakyThrows; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +@Component +public class PositiveRespondent implements ApplicationListener { + + @SneakyThrows + @Override + public void onApplicationEvent(HalfAGlassOfWaterEvent halfAGlassOfWaterEvent) { + Thread.sleep(100); + System.out.println("Позитивно настроенный слушатель"); + System.out.println(String.format("- %s", halfAGlassOfWaterEvent.getPayload())); + System.out.println("- Ничего. Главное, что он наполовину полон!!!\n\n"); + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/shell/ApplicationEventsCommands.java b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/shell/ApplicationEventsCommands.java new file mode 100644 index 00000000..482e9855 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/shell/ApplicationEventsCommands.java @@ -0,0 +1,35 @@ +package ru.otus.example.applicationeventsdemo.shell; + +import lombok.RequiredArgsConstructor; +import org.springframework.shell.Availability; +import org.springframework.shell.standard.ShellComponent; +import org.springframework.shell.standard.ShellMethod; +import org.springframework.shell.standard.ShellMethodAvailability; +import org.springframework.shell.standard.ShellOption; +import ru.otus.example.applicationeventsdemo.events.EventsPublisher; + +@ShellComponent +@RequiredArgsConstructor +public class ApplicationEventsCommands { + + private final EventsPublisher eventsPublisher; + + private String userName; + + @ShellMethod(value = "Login command", key = {"l", "login"}) + public String login(@ShellOption(defaultValue = "stvort") String userName) { + this.userName = userName; + return String.format("Добро пожаловать: %s", userName); + } + + @ShellMethod(value = "Publish event command", key = {"p", "pub", "publish"}) + @ShellMethodAvailability(value = "isPublishEventCommandAvailable") + public String publishEvent() { + eventsPublisher.publish(); + return "Событие опубликовано"; + } + + private Availability isPublishEventCommandAvailable() { + return userName == null? Availability.unavailable("Сначала залогиньтесь"): Availability.available(); + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/resources/application.yml b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/resources/application.yml new file mode 100644 index 00000000..f78a9f36 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/main/resources/application.yml @@ -0,0 +1,3 @@ +logging: + level: + root: ERROR \ No newline at end of file diff --git a/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/test/java/ru/otus/example/applicationeventsdemo/shell/ApplicationEventsCommandsTest.java b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/test/java/ru/otus/example/applicationeventsdemo/shell/ApplicationEventsCommandsTest.java new file mode 100644 index 00000000..ee3c8d0f --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/test/java/ru/otus/example/applicationeventsdemo/shell/ApplicationEventsCommandsTest.java @@ -0,0 +1,67 @@ +package ru.otus.example.applicationeventsdemo.shell; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.shell.Availability; +import org.springframework.shell.CommandNotCurrentlyAvailable; +import org.springframework.shell.Shell; +import org.springframework.test.annotation.DirtiesContext; +import ru.otus.example.applicationeventsdemo.events.EventsPublisher; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@DisplayName("Тест команд shell ") +@SpringBootTest +class ApplicationEventsCommandsTest { + + @MockBean + private EventsPublisher eventsPublisher; + + @Autowired + private Shell shell; + + private static final String GREETING_PATTERN = "Добро пожаловать: %s"; + private static final String DEFAULT_LOGIN = "stvort"; + private static final String CUSTOM_LOGIN = "Вася"; + private static final String COMMAND_LOGIN = "login"; + private static final String COMMAND_LOGIN_SHORT = "l"; + private static final String COMMAND_PUBLISH = "publish"; + private static final String COMMAND_PUBLISH_EXPECTED_RESULT = "Событие опубликовано"; + private static final String COMMAND_LOGIN_PATTERN = "%s %s"; + + @DisplayName(" должен возвращать приветствие для всех форм команды логина") + @Test + void shouldReturnExpectedGreetingAfterLoginCommandEvaluated() { + String res = (String) shell.evaluate(() -> COMMAND_LOGIN); + assertThat(res).isEqualTo(String.format(GREETING_PATTERN, DEFAULT_LOGIN)); + + res = (String) shell.evaluate(() -> COMMAND_LOGIN_SHORT); + assertThat(res).isEqualTo(String.format(GREETING_PATTERN, DEFAULT_LOGIN)); + + res = (String) shell.evaluate(() -> String.format(COMMAND_LOGIN_PATTERN, COMMAND_LOGIN_SHORT, CUSTOM_LOGIN)); + assertThat(res).isEqualTo(String.format(GREETING_PATTERN, CUSTOM_LOGIN)); + } + + @DisplayName(" должен возвращать CommandNotCurrentlyAvailable если при попытке выполнения команды publish пользователь выполнил вход") + @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) + @Test + void shouldReturnCommandNotCurrentlyAvailableObjectWhenUserDoesNotLoginAfterPublishCommandEvaluated() { + Object res = shell.evaluate(() -> COMMAND_PUBLISH); + assertThat(res).isInstanceOf(CommandNotCurrentlyAvailable.class); + } + + @DisplayName(" должен возвращать статус выполнения команды publish и вызвать соответствующий метод сервиса есл икоманда выполнена после входа") + @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) + @Test + void shouldReturnExpectedMessageAndFirePublishMethodAfterPublishCommandEvaluated() { + shell.evaluate(() -> COMMAND_LOGIN); + String res = (String) shell.evaluate(() -> COMMAND_PUBLISH); + assertThat(res).isEqualTo(COMMAND_PUBLISH_EXPECTED_RESULT); + verify(eventsPublisher, times(1)).publish(); + } +} \ No newline at end of file diff --git a/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/test/resources/application.yml b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/test/resources/application.yml new file mode 100644 index 00000000..b4921681 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/application-events-demo/src/test/resources/application.yml @@ -0,0 +1,4 @@ +spring: + shell: + interactive: + enabled: false diff --git a/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/.gitignore b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/.gitignore new file mode 100644 index 00000000..789ddc9e --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/.gitignore @@ -0,0 +1,32 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +#other +*.bat +*/.idea +*.iml +*/target + +.idea +*.iml +target \ No newline at end of file diff --git a/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/README.md b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/README.md new file mode 100644 index 00000000..2c841b7e --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/README.md @@ -0,0 +1,2 @@ +# beans-lifecycle-demo +Пример жизненного цикла бинов \ No newline at end of file diff --git a/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/pom.xml b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/pom.xml new file mode 100644 index 00000000..a9c46a30 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.1.RELEASE + + + ru.otus.example + beans-lifecycle-demo + 0.0.1-SNAPSHOT + beans-lifecycle-demo + Beans lifecycle demo + + + 11 + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.shell + spring-shell-starter + 2.0.1.RELEASE + + + + org.projectlombok + lombok + true + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/BeansLifecycleDemoApplication.java b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/BeansLifecycleDemoApplication.java new file mode 100644 index 00000000..d3da1418 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/BeansLifecycleDemoApplication.java @@ -0,0 +1,13 @@ +package ru.otus.example.beanslifecycledemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class BeansLifecycleDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(BeansLifecycleDemoApplication.class, args); + } + +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/domain/FriendPhoneNumber.java b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/domain/FriendPhoneNumber.java new file mode 100644 index 00000000..913d7db0 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/domain/FriendPhoneNumber.java @@ -0,0 +1,8 @@ +package ru.otus.example.beanslifecycledemo.domain; + +public class FriendPhoneNumber extends PhoneNumber { + @Override + public String getOwnerName() { + return "Друг"; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/domain/GirlfiendPhoneNumber.java b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/domain/GirlfiendPhoneNumber.java new file mode 100644 index 00000000..54e4e173 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/domain/GirlfiendPhoneNumber.java @@ -0,0 +1,11 @@ +package ru.otus.example.beanslifecycledemo.domain; + +import org.springframework.stereotype.Component; + +@Component +public class GirlfiendPhoneNumber extends PhoneNumber { + @Override + public String getOwnerName() { + return "Подруга"; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/domain/Phone.java b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/domain/Phone.java new file mode 100644 index 00000000..b61d7fd7 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/domain/Phone.java @@ -0,0 +1,16 @@ +package ru.otus.example.beanslifecycledemo.domain; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class Phone { + private String greeting = "Погнали к родителям"; + + private final PhoneNumber favoriteNumber; + + public void callFavoriteNumber() { + System.out.println(favoriteNumber.getOwnerName() + " " + greeting); + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/domain/PhoneNumber.java b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/domain/PhoneNumber.java new file mode 100644 index 00000000..215bd09f --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/domain/PhoneNumber.java @@ -0,0 +1,7 @@ +package ru.otus.example.beanslifecycledemo.domain; + +public abstract class PhoneNumber { + public String getOwnerName() { + return "Спорт-лото"; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/lifecycle/CustomBeanFactoryPostProcessor.java b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/lifecycle/CustomBeanFactoryPostProcessor.java new file mode 100644 index 00000000..5f82e6e5 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/lifecycle/CustomBeanFactoryPostProcessor.java @@ -0,0 +1,32 @@ +package ru.otus.example.beanslifecycledemo.lifecycle; + +import org.springframework.beans.BeanMetadataAttribute; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.annotation.ScannedGenericBeanDefinition; +import ru.otus.example.beanslifecycledemo.domain.FriendPhoneNumber; +import ru.otus.example.beanslifecycledemo.domain.GirlfiendPhoneNumber; + +public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor { + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + + if (beanFactory.containsBean("customLifeCycleBean")) { + System.out.println("Шаг #1: BeanFactoryPostProcessor.postProcessBeanFactory\n"); + } + +/* + for (String beanName : beanFactory.getBeanDefinitionNames()) { + BeanDefinition d = beanFactory.getBeanDefinition(beanName); + + if (GirlfiendPhoneNumber.class.getName().equalsIgnoreCase(d.getBeanClassName())) { + d.setBeanClassName(FriendPhoneNumber.class.getName()); + ((ScannedGenericBeanDefinition) d).addMetadataAttribute(new BeanMetadataAttribute("className", FriendPhoneNumber.class.getName())); + d.setAutowireCandidate(true); + } + } +*/ + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/lifecycle/CustomBeanPostProcessor.java b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/lifecycle/CustomBeanPostProcessor.java new file mode 100644 index 00000000..9b9c5579 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/lifecycle/CustomBeanPostProcessor.java @@ -0,0 +1,40 @@ +package ru.otus.example.beanslifecycledemo.lifecycle; + +import lombok.SneakyThrows; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import ru.otus.example.beanslifecycledemo.domain.Phone; + +import java.lang.reflect.Field; + +public class CustomBeanPostProcessor implements BeanPostProcessor { + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (bean.getClass().equals(CustomLifeCycleBean.class)) { + System.out.println("Шаг #5: BeanPostProcessor.postProcessBeforeInitialization\n"); + } + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + if (bean.getClass().equals(CustomLifeCycleBean.class)) { + System.out.println("Шаг #9: BeanPostProcessor.postProcessAfterInitialization\n"); + } + + if (bean.getClass().isAssignableFrom(Phone.class)) { + //updateGreeting(bean); + } + return bean; + } + + @SneakyThrows + private void updateGreeting(Object bean) { + Class aClass = Phone.class; + Field greetingField = aClass.getDeclaredField("greeting"); + + greetingField.setAccessible(true); + greetingField.setAccessible(true); + greetingField.set(bean, "Ай-да в гараж. Стихи читать!"); + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/lifecycle/CustomLifeCycleBean.java b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/lifecycle/CustomLifeCycleBean.java new file mode 100644 index 00000000..b94d3e99 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/lifecycle/CustomLifeCycleBean.java @@ -0,0 +1,55 @@ +package ru.otus.example.beanslifecycledemo.lifecycle; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.*; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +public class CustomLifeCycleBean implements InitializingBean, DisposableBean, BeanNameAware, BeanFactoryAware, ApplicationContextAware { + + @Override + public void setBeanName(String s) { + System.out.println("Шаг #2: BeanNameAware\n"); + } + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + System.out.println("Шаг #3: BeanFactoryAware\n"); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + System.out.println("Шаг #4: ApplicationContextAware\n"); + } + + @PostConstruct + public void postConstruct() { + System.out.println("Шаг #6: @PostConstruct\n"); + } + + @Override + public void afterPropertiesSet() throws Exception { + System.out.println("Шаг #7: InitializingBean.afterPropertiesSet\n"); + } + + public void customInitMethod() { + System.out.println("Шаг #8: CustomLifeCycleBean.customInitMethod\n"); + } + + @PreDestroy + public void preDestroy() { + System.out.println("Шаг #10: @PreDestroy\n"); + } + + @Override + public void destroy() throws Exception { + System.out.println("Шаг #11: DisposableBean.destroy\n"); + } + + public void customDestroyMethod() { + System.out.println("Шаг #12: CustomLifeCycleBean.customDestroyMethod\n"); + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/lifecycle/LifeCycleConfig.java b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/lifecycle/LifeCycleConfig.java new file mode 100644 index 00000000..bd81fea0 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/lifecycle/LifeCycleConfig.java @@ -0,0 +1,27 @@ +package ru.otus.example.beanslifecycledemo.lifecycle; + +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LifeCycleConfig { + + @Bean + public BeanFactoryPostProcessor customBeanFactoryPostProcessor() { + return new CustomBeanFactoryPostProcessor(); + } + + @Bean + public BeanPostProcessor customBeanPostProcessor() { + return new CustomBeanPostProcessor(); + } + + @ConditionalOnProperty(name = "spring.shell.interactive.enabled", havingValue = "false") + @Bean(initMethod = "customInitMethod", destroyMethod = "customDestroyMethod") + public CustomLifeCycleBean customLifeCycleBean() { + return new CustomLifeCycleBean(); + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/shell/LifecycleDemoCommands.java b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/shell/LifecycleDemoCommands.java new file mode 100644 index 00000000..3987bc06 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/java/ru/otus/example/beanslifecycledemo/shell/LifecycleDemoCommands.java @@ -0,0 +1,18 @@ +package ru.otus.example.beanslifecycledemo.shell; + +import lombok.RequiredArgsConstructor; +import org.springframework.shell.standard.ShellComponent; +import org.springframework.shell.standard.ShellMethod; +import ru.otus.example.beanslifecycledemo.domain.Phone; + +@RequiredArgsConstructor +@ShellComponent +public class LifecycleDemoCommands { + + private final Phone phone; + + @ShellMethod(value = "Call favorite number", key = {"call-favorite-number", "cfn"}) + public void callFavoriteNumber() { + phone.callFavoriteNumber(); + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/resources/application.yml b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/resources/application.yml new file mode 100644 index 00000000..a50954b5 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-lifecycle-demo/src/main/resources/application.yml @@ -0,0 +1,8 @@ +logging: + level: + root: ERROR + +spring: + shell: + interactive: + enabled: false diff --git a/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/.gitignore b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/.gitignore new file mode 100644 index 00000000..789ddc9e --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/.gitignore @@ -0,0 +1,32 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +#other +*.bat +*/.idea +*.iml +*/target + +.idea +*.iml +target \ No newline at end of file diff --git a/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/README.md b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/README.md new file mode 100644 index 00000000..09665122 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/README.md @@ -0,0 +1,2 @@ +# beans-scopes-demo +Пример работы со областью действия (Scope) бинов \ No newline at end of file diff --git a/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/pom.xml b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/pom.xml new file mode 100644 index 00000000..ea2d2db1 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.2.1.RELEASE + + + + ru.otus.example + beans-scopes-demo + 0.0.1-SNAPSHOT + beans-scopes-demo + Beans scopes demo + + + 11 + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + + org.projectlombok + lombok + true + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/BeansScopesDemoApplication.java b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/BeansScopesDemoApplication.java new file mode 100644 index 00000000..a7ce4369 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/BeansScopesDemoApplication.java @@ -0,0 +1,13 @@ +package ru.otus.example.beansscopesdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class BeansScopesDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(BeansScopesDemoApplication.class, args); + } + +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/controllers/GreetingController.java b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/controllers/GreetingController.java new file mode 100644 index 00000000..1a309a90 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/controllers/GreetingController.java @@ -0,0 +1,40 @@ +package ru.otus.example.beansscopesdemo.controllers; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import ru.otus.example.beansscopesdemo.services.GreetingService; + +@Controller +public class GreetingController { + private final GreetingService singletonGreetingService; + private final GreetingService prototypeGreetingService1; + private final GreetingService prototypeGreetingService2; + private final GreetingService sessionGreetingService; + private final GreetingService requestGreetingService; + + public GreetingController(@Qualifier("SingletonGreetingService") GreetingService singletonGreetingService, + @Qualifier("PrototypeGreetingService")GreetingService prototypeGreetingService1, + @Qualifier("PrototypeGreetingService")GreetingService prototypeGreetingService2, + @Qualifier("SessionGreetingService")GreetingService sessionGreetingService, + @Qualifier("RequestGreetingService")GreetingService requestGreetingService + ) { + this.singletonGreetingService = singletonGreetingService; + this.prototypeGreetingService1 = prototypeGreetingService1; + this.prototypeGreetingService2 = prototypeGreetingService2; + this.sessionGreetingService = sessionGreetingService; + this.requestGreetingService = requestGreetingService; + } + + @GetMapping("/") + public String greetingPage(Model model) { + boolean isFirstGreetingSuccess = prototypeGreetingService1.isFirstGreetingSuccess(); + model.addAttribute("singletonGreeting", singletonGreetingService.greeting()); + model.addAttribute("sessionGreeting", sessionGreetingService.greeting()); + model.addAttribute("requestGreeting", requestGreetingService.greeting()); + model.addAttribute("prototype1Greeting", prototypeGreetingService1.greeting()); + model.addAttribute("prototype2Greeting", isFirstGreetingSuccess? prototypeGreetingService2.greeting(): "Пока жду"); + return "index"; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/AbstractGreetingServiceImpl.java b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/AbstractGreetingServiceImpl.java new file mode 100644 index 00000000..3fff2235 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/AbstractGreetingServiceImpl.java @@ -0,0 +1,35 @@ +package ru.otus.example.beansscopesdemo.services; + + +import org.springframework.beans.factory.annotation.Value; + +public abstract class AbstractGreetingServiceImpl implements GreetingService { + + @Value("${greetings.first-greeting}") + private String firstGreeting; + + @Value("${greetings.re-greeting}") + private String reGreeting; + + private boolean isFirstGreetingSuccess; + + public AbstractGreetingServiceImpl() { + this.isFirstGreetingSuccess = false; + } + + @Override + public boolean isFirstGreetingSuccess() { + return isFirstGreetingSuccess; + } + + @Override + public String greeting() { + return currentGreeting(); + } + + private synchronized String currentGreeting() { + String greeting = isFirstGreetingSuccess ? reGreeting : firstGreeting; + isFirstGreetingSuccess = true; + return greeting; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/GreetingService.java b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/GreetingService.java new file mode 100644 index 00000000..1347ff39 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/GreetingService.java @@ -0,0 +1,6 @@ +package ru.otus.example.beansscopesdemo.services; + +public interface GreetingService { + boolean isFirstGreetingSuccess(); + String greeting(); +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/PrototypeGreetingServiceImpl.java b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/PrototypeGreetingServiceImpl.java new file mode 100644 index 00000000..0932a66c --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/PrototypeGreetingServiceImpl.java @@ -0,0 +1,9 @@ +package ru.otus.example.beansscopesdemo.services; + +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Service; + +@Scope("prototype") +@Service("PrototypeGreetingService") +public class PrototypeGreetingServiceImpl extends AbstractGreetingServiceImpl { +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/RequestGreetingServiceImpl.java b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/RequestGreetingServiceImpl.java new file mode 100644 index 00000000..943c73db --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/RequestGreetingServiceImpl.java @@ -0,0 +1,11 @@ +package ru.otus.example.beansscopesdemo.services; + +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.stereotype.Service; +import org.springframework.web.context.WebApplicationContext; + +@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) +@Service("RequestGreetingService") +public class RequestGreetingServiceImpl extends AbstractGreetingServiceImpl { +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/SessionGreetingServiceImpl.java b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/SessionGreetingServiceImpl.java new file mode 100644 index 00000000..efff908a --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/SessionGreetingServiceImpl.java @@ -0,0 +1,11 @@ +package ru.otus.example.beansscopesdemo.services; + +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.stereotype.Service; +import org.springframework.web.context.WebApplicationContext; + +@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) +@Service("SessionGreetingService") +public class SessionGreetingServiceImpl extends AbstractGreetingServiceImpl { +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/SingletonGreetingServiceImpl.java b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/SingletonGreetingServiceImpl.java new file mode 100644 index 00000000..fb8406a5 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/java/ru/otus/example/beansscopesdemo/services/SingletonGreetingServiceImpl.java @@ -0,0 +1,9 @@ +package ru.otus.example.beansscopesdemo.services; + +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Service; + +@Scope("singleton") +@Service("SingletonGreetingService") +public class SingletonGreetingServiceImpl extends AbstractGreetingServiceImpl { +} diff --git a/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/resources/application.yml b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/resources/application.yml new file mode 100644 index 00000000..a18bec79 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/resources/application.yml @@ -0,0 +1,8 @@ +greetings: + first-greeting: Привет + re-greeting: Рад снова тебя видеть + + +logging: + level: + root: ERROR \ No newline at end of file diff --git a/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/resources/templates/index.html b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/resources/templates/index.html new file mode 100644 index 00000000..3719f228 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/beans-scopes-demo/src/main/resources/templates/index.html @@ -0,0 +1,45 @@ + + + + + Advanced configuration demo + + + +

+

Демонстрация @Scope

+ +

+ +
+ +

+

+

+

+

+ + \ No newline at end of file diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/.gitignore b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/.gitignore new file mode 100644 index 00000000..789ddc9e --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/.gitignore @@ -0,0 +1,32 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +#other +*.bat +*/.idea +*.iml +*/target + +.idea +*.iml +target \ No newline at end of file diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/README.md b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/README.md new file mode 100644 index 00000000..f596dfc9 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/README.md @@ -0,0 +1,2 @@ +# conditional-and-profiles-demo +Пример работы с профилями и автоконфигурациями \ No newline at end of file diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/pom.xml b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/pom.xml new file mode 100644 index 00000000..eac2b65a --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/pom.xml @@ -0,0 +1,83 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.1.RELEASE + + + + ru.otus.example + conditional-and-profiles-demo + 0.0.1-SNAPSHOT + conditional-and-profiles-demo + Conditional and profiles demo + + + 11 + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + junit + junit + + + + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test + + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + + + org.springframework.shell + spring-shell-starter + 2.0.1.RELEASE + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/ConditionalAndProfilesDemoApplication.java b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/ConditionalAndProfilesDemoApplication.java new file mode 100644 index 00000000..96f37fd9 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/ConditionalAndProfilesDemoApplication.java @@ -0,0 +1,13 @@ +package ru.otus.example.conditionalandprofilesdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ConditionalAndProfilesDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(ConditionalAndProfilesDemoApplication.class, args); + } + +} diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Alexey.java b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Alexey.java new file mode 100644 index 00000000..66091903 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Alexey.java @@ -0,0 +1,14 @@ +package ru.otus.example.conditionalandprofilesdemo.model; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; +import ru.otus.example.conditionalandprofilesdemo.model.base.Friend; + +@ConditionalOnProperty(name = "condition.alexey-exists", havingValue = "true") +@Component +public class Alexey extends Friend { + @Override + public String getName() { + return "Алексей"; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Anna.java b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Anna.java new file mode 100644 index 00000000..be26e16d --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Anna.java @@ -0,0 +1,14 @@ +package ru.otus.example.conditionalandprofilesdemo.model; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.stereotype.Component; +import ru.otus.example.conditionalandprofilesdemo.model.base.Friend; + +@ConditionalOnBean(Alexey.class) +@Component +public class Anna extends Friend { + @Override + public String getName() { + return "Аня"; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Oleg.java b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Oleg.java new file mode 100644 index 00000000..2a11f476 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Oleg.java @@ -0,0 +1,14 @@ +package ru.otus.example.conditionalandprofilesdemo.model; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; +import ru.otus.example.conditionalandprofilesdemo.model.base.Friend; + +@Profile("Oleg") +@Component +public class Oleg extends Friend { + @Override + public String getName() { + return "Олег"; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Peter.java b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Peter.java new file mode 100644 index 00000000..435891a8 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Peter.java @@ -0,0 +1,15 @@ +package ru.otus.example.conditionalandprofilesdemo.model; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; +import ru.otus.example.conditionalandprofilesdemo.model.base.Friend; + +@Profile("Peter") +@Component +public class Peter extends Friend { + + @Override + public String getName() { + return "Петр"; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Yana.java b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Yana.java new file mode 100644 index 00000000..76b0fca3 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Yana.java @@ -0,0 +1,16 @@ +package ru.otus.example.conditionalandprofilesdemo.model; + +import org.springframework.context.annotation.Conditional; +import org.springframework.stereotype.Component; +import ru.otus.example.conditionalandprofilesdemo.model.base.Friend; +import ru.otus.example.conditionalandprofilesdemo.model.conditions.YanaConditions; + + +@Conditional(YanaConditions.class) +@Component +public class Yana extends Friend { + @Override + public String getName() { + return "Яна"; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Yanis.java b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Yanis.java new file mode 100644 index 00000000..6dd2c14d --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/Yanis.java @@ -0,0 +1,14 @@ +package ru.otus.example.conditionalandprofilesdemo.model; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; +import ru.otus.example.conditionalandprofilesdemo.model.base.Friend; + +@ConditionalOnProperty(name = "condition.yanis-exists", havingValue = "true") +@Component +public class Yanis extends Friend { + @Override + public String getName() { + return "Янис"; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/base/Friend.java b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/base/Friend.java new file mode 100644 index 00000000..2d2eb67d --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/base/Friend.java @@ -0,0 +1,5 @@ +package ru.otus.example.conditionalandprofilesdemo.model.base; + +public abstract class Friend { + public abstract String getName(); +} diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/conditions/YanaConditions.java b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/conditions/YanaConditions.java new file mode 100644 index 00000000..cf130ebb --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/model/conditions/YanaConditions.java @@ -0,0 +1,20 @@ +package ru.otus.example.conditionalandprofilesdemo.model.conditions; + +import org.springframework.boot.autoconfigure.condition.AllNestedConditions; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + +public class YanaConditions extends AllNestedConditions { + + public YanaConditions() { + super(ConfigurationPhase.PARSE_CONFIGURATION); + } + + + @ConditionalOnProperty(name = "condition.alexey-exists", havingValue = "false") + static class AlexeyDoesNotExistsCondition { + } + + @ConditionalOnProperty(name = "condition.yanis-exists", havingValue = "true") + static class YanisExistsCondition { + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/shell/ConditionalAndProfilesDemoCommands.java b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/shell/ConditionalAndProfilesDemoCommands.java new file mode 100644 index 00000000..a0cf3f0b --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/java/ru/otus/example/conditionalandprofilesdemo/shell/ConditionalAndProfilesDemoCommands.java @@ -0,0 +1,21 @@ +package ru.otus.example.conditionalandprofilesdemo.shell; + +import lombok.RequiredArgsConstructor; +import org.springframework.shell.standard.ShellComponent; +import org.springframework.shell.standard.ShellMethod; +import ru.otus.example.conditionalandprofilesdemo.model.base.Friend; + +import java.util.List; +import java.util.stream.Collectors; + +@ShellComponent +@RequiredArgsConstructor +public class ConditionalAndProfilesDemoCommands { + + private final List partyMembers; + + @ShellMethod(value = "Print party members", key = {"print-party-members", "ppm"}) + public String printPartyMembers() { + return partyMembers.stream().map(Friend::getName).collect(Collectors.joining("\n")); + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/resources/application.yml b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/resources/application.yml new file mode 100644 index 00000000..5045336c --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/main/resources/application.yml @@ -0,0 +1,25 @@ +greetings: + first-greeting: Привет + re-greeting: Рад снова тебя видеть + + +condition: + alexey-exists: true + yanis-exists: false + +spring: + profiles: + #active: Oleg + #active: Peter + +logging: + level: + root: ERROR + + +--- +spring: + profiles: Peter + +condition: + yanis-exists: true diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/test/java/ru/otus/example/conditionalandprofilesdemo/test/ConditionalAndProfilesDemoApplicationTests.java b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/test/java/ru/otus/example/conditionalandprofilesdemo/test/ConditionalAndProfilesDemoApplicationTests.java new file mode 100644 index 00000000..ccb1307b --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/test/java/ru/otus/example/conditionalandprofilesdemo/test/ConditionalAndProfilesDemoApplicationTests.java @@ -0,0 +1,37 @@ +package ru.otus.example.conditionalandprofilesdemo.test; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import ru.otus.example.conditionalandprofilesdemo.model.base.Friend; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +//@ActiveProfiles({"Oleg"}) +//@ActiveProfiles({"Peter"}) +//@ActiveProfiles({"Oleg", "Peter"}) +@DisplayName("FriendsMap должна") +@SpringBootTest +class ConditionalAndProfilesDemoApplicationTests { + + @Autowired + private Map friendsMap; + + + @DisplayName(" содержать Олега") + @Test + void shouldContainOleg() { + assertThat(friendsMap).containsKey("oleg"); + } + + @DisplayName(" содержать Петра") + @Test + void shouldContainPetr() { + assertThat(friendsMap).containsKey("peter"); + } + +} diff --git a/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/test/resources/application.yml b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/test/resources/application.yml new file mode 100644 index 00000000..d1ae4f6e --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/conditional-and-profiles-demo/src/test/resources/application.yml @@ -0,0 +1,7 @@ +spring: + shell: + interactive: + enabled: false +logging: + level: + root: ERROR \ No newline at end of file diff --git a/2019-11/spring-05/advanced-config-class-work/pom.xml b/2019-11/spring-05/advanced-config-class-work/pom.xml new file mode 100644 index 00000000..0d03f5c7 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + ru.otus + advanced-config-class-work + 1.0 + + pom + + + beans-scopes-demo + beans-lifecycle-demo + application-events-demo + conditional-and-profiles-demo + test-configuration-demo + + diff --git a/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/.gitignore b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/.gitignore new file mode 100644 index 00000000..789ddc9e --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/.gitignore @@ -0,0 +1,32 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +#other +*.bat +*/.idea +*.iml +*/target + +.idea +*.iml +target \ No newline at end of file diff --git a/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/README.md b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/README.md new file mode 100644 index 00000000..00dadea2 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/README.md @@ -0,0 +1,2 @@ +# test-configuration-demo +Пример конфигурирования тестов \ No newline at end of file diff --git a/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/pom.xml b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/pom.xml new file mode 100644 index 00000000..d6677365 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/pom.xml @@ -0,0 +1,76 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.1.RELEASE + + + + ru.otus.example + test-configuration-demo + 0.0.1-SNAPSHOT + test-configuration-demo + Test configuration demo + + + 11 + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + junit + junit + + + + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test + + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/TestConfigurationDemoApplication.java b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/TestConfigurationDemoApplication.java new file mode 100644 index 00000000..e5dd8341 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/TestConfigurationDemoApplication.java @@ -0,0 +1,15 @@ +package ru.otus.example.testconfigurationdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@ComponentScan("ru.otus.example.testconfigurationdemo.family") +@SpringBootApplication +public class TestConfigurationDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(TestConfigurationDemoApplication.class, args); + } + +} diff --git a/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/family/FamilyMember.java b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/family/FamilyMember.java new file mode 100644 index 00000000..1685a4cc --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/family/FamilyMember.java @@ -0,0 +1,5 @@ +package ru.otus.example.testconfigurationdemo.family; + +public abstract class FamilyMember { + public abstract String getName(); +} diff --git a/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/family/childrens/Son.java b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/family/childrens/Son.java new file mode 100644 index 00000000..f3da3289 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/family/childrens/Son.java @@ -0,0 +1,12 @@ +package ru.otus.example.testconfigurationdemo.family.childrens; + +import org.springframework.stereotype.Component; +import ru.otus.example.testconfigurationdemo.family.FamilyMember; + +@Component +public class Son extends FamilyMember { + @Override + public String getName() { + return "Сын"; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/family/parents/Father.java b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/family/parents/Father.java new file mode 100644 index 00000000..d531bda5 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/family/parents/Father.java @@ -0,0 +1,10 @@ +package ru.otus.example.testconfigurationdemo.family.parents; + +import ru.otus.example.testconfigurationdemo.family.FamilyMember; + +public class Father extends FamilyMember { + @Override + public String getName() { + return "Папа"; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/family/parents/Mother.java b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/family/parents/Mother.java new file mode 100644 index 00000000..d9b97b75 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/family/parents/Mother.java @@ -0,0 +1,12 @@ +package ru.otus.example.testconfigurationdemo.family.parents; + +import org.springframework.stereotype.Component; +import ru.otus.example.testconfigurationdemo.family.FamilyMember; + +@Component +public class Mother extends FamilyMember { + @Override + public String getName() { + return "Мама"; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/family/pets/Dog.java b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/family/pets/Dog.java new file mode 100644 index 00000000..3e436c12 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/main/java/ru/otus/example/testconfigurationdemo/family/pets/Dog.java @@ -0,0 +1,13 @@ +package ru.otus.example.testconfigurationdemo.family.pets; + +import org.springframework.stereotype.Component; +import ru.otus.example.testconfigurationdemo.family.FamilyMember; + +@Component +public class Dog extends FamilyMember { + + @Override + public String getName() { + return "Собака"; + } +} diff --git a/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/test/java/ru/otus/example/testconfigurationdemo/demo1/NestedConfigurationDemoTest.java b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/test/java/ru/otus/example/testconfigurationdemo/demo1/NestedConfigurationDemoTest.java new file mode 100644 index 00000000..ec5baa93 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/test/java/ru/otus/example/testconfigurationdemo/demo1/NestedConfigurationDemoTest.java @@ -0,0 +1,37 @@ +package ru.otus.example.testconfigurationdemo.demo1; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import ru.otus.example.testconfigurationdemo.family.FamilyMember; +import ru.otus.example.testconfigurationdemo.family.pets.Dog; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +@DisplayName("В NestedConfigurationDemoTest семья должна ") +@SpringBootTest +public class NestedConfigurationDemoTest { + + @Configuration + static class NestedConfiguration { + @Bean + FamilyMember dog() { + return new Dog(); + } + } + + @Autowired + private Map family; + + @DisplayName(" содержать только собаку ") + @Test + void shouldContainOnlyDog() { + assertThat(family).containsOnlyKeys("dog"); + } + +} diff --git a/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/test/java/ru/otus/example/testconfigurationdemo/demo1/NestedTestConfigurationDemoTest.java b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/test/java/ru/otus/example/testconfigurationdemo/demo1/NestedTestConfigurationDemoTest.java new file mode 100644 index 00000000..df8ee16f --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/test/java/ru/otus/example/testconfigurationdemo/demo1/NestedTestConfigurationDemoTest.java @@ -0,0 +1,37 @@ +package ru.otus.example.testconfigurationdemo.demo1; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import ru.otus.example.testconfigurationdemo.family.FamilyMember; +import ru.otus.example.testconfigurationdemo.family.parents.Father; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +@DisplayName("В NestedTestConfigurationDemoTest семья должна ") +@SpringBootTest +public class NestedTestConfigurationDemoTest { + + @TestConfiguration + static class NestedTestConfiguration { + @Bean + FamilyMember father() { + return new Father(); + } + } + + @Autowired + private Map family; + + @DisplayName(" содержать маму, папу, сына и собаку ") + @Test + void shouldContainAllFamilyWithFather() { + assertThat(family).containsOnlyKeys("mother", "father", "son", "dog"); + } + +} diff --git a/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/test/java/ru/otus/example/testconfigurationdemo/demo1/PlainSpringBootTestDemoTest.java b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/test/java/ru/otus/example/testconfigurationdemo/demo1/PlainSpringBootTestDemoTest.java new file mode 100644 index 00000000..07c32f59 --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/test/java/ru/otus/example/testconfigurationdemo/demo1/PlainSpringBootTestDemoTest.java @@ -0,0 +1,26 @@ +package ru.otus.example.testconfigurationdemo.demo1; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import ru.otus.example.testconfigurationdemo.family.FamilyMember; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +@DisplayName("В PlainSpringBootTestDemoTest семья должна ") +@SpringBootTest +public class PlainSpringBootTestDemoTest { + + @Autowired + private Map family; + + @DisplayName(" содержать маму, сына и собаку ") + @Test + void shouldContainAllFamilyExceptFather() { + assertThat(family).containsOnlyKeys("mother", "son", "dog"); + } + +} diff --git a/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/test/java/ru/otus/example/testconfigurationdemo/demo2/SpringBootTestWithExternalLimitationDemoTest.java b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/test/java/ru/otus/example/testconfigurationdemo/demo2/SpringBootTestWithExternalLimitationDemoTest.java new file mode 100644 index 00000000..98241b1b --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/test/java/ru/otus/example/testconfigurationdemo/demo2/SpringBootTestWithExternalLimitationDemoTest.java @@ -0,0 +1,26 @@ +package ru.otus.example.testconfigurationdemo.demo2; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import ru.otus.example.testconfigurationdemo.family.FamilyMember; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +@DisplayName("В SpringBootTestWithExternalLimitationDemoTest семья должна ") +@SpringBootTest +public class SpringBootTestWithExternalLimitationDemoTest { + + @Autowired + private Map family; + + @DisplayName(" содержать маму, папу и сына") + @Test + void shouldContainAllFamilyExceptFather() { + assertThat(family).containsOnlyKeys("mother", "father", "son"); + } + +} diff --git a/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/test/java/ru/otus/example/testconfigurationdemo/demo2/TestSpringBootConfiguration.java b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/test/java/ru/otus/example/testconfigurationdemo/demo2/TestSpringBootConfiguration.java new file mode 100644 index 00000000..b4106d4b --- /dev/null +++ b/2019-11/spring-05/advanced-config-class-work/test-configuration-demo/src/test/java/ru/otus/example/testconfigurationdemo/demo2/TestSpringBootConfiguration.java @@ -0,0 +1,17 @@ +package ru.otus.example.testconfigurationdemo.demo2; + +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import ru.otus.example.testconfigurationdemo.family.FamilyMember; +import ru.otus.example.testconfigurationdemo.family.parents.Father; + +@ComponentScan({"ru.otus.example.testconfigurationdemo.family.parents", + "ru.otus.example.testconfigurationdemo.family.childrens"}) +@SpringBootConfiguration +public class TestSpringBootConfiguration { + @Bean + FamilyMember father() { + return new Father(); + } +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/.gitignore b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/pom.xml b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/pom.xml new file mode 100644 index 00000000..1538c35c --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + ru.otus + jdbc-demo-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-starter-jdbc + + + com.h2database + h2 + 1.4.200 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/java/ru/otus/spring/Main.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..8916eb04 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,20 @@ +package ru.otus.spring; + +import org.h2.tools.Console; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import ru.otus.spring.dao.PersonDao; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) throws Exception { + + ApplicationContext context = SpringApplication.run(Main.class); + + PersonDao dao = context.getBean(PersonDao.class); + + Console.main(args); + } +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/java/ru/otus/spring/dao/PersonDao.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/java/ru/otus/spring/dao/PersonDao.java new file mode 100644 index 00000000..4ee1a3b3 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/java/ru/otus/spring/dao/PersonDao.java @@ -0,0 +1,4 @@ +package ru.otus.spring.dao; + +public interface PersonDao { +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java new file mode 100644 index 00000000..b38dd2a5 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java @@ -0,0 +1,8 @@ +package ru.otus.spring.dao; + +import org.springframework.stereotype.Repository; + +@SuppressWarnings({"SqlNoDataSourceInspection", "ConstantConditions", "SqlDialectInspection"}) +@Repository +public class PersonDaoJdbc implements PersonDao { +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/java/ru/otus/spring/domain/Person.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..e34ae29c --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,20 @@ +package ru.otus.spring.domain; + +public class Person { + + private final int id; + private final String name; + + public Person(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/resources/data.sql b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/resources/data.sql new file mode 100644 index 00000000..240a5b4e --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/resources/data.sql @@ -0,0 +1 @@ +insert into persons (id, `name`) values (1, 'masha'); diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/resources/schema.sql b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/resources/schema.sql new file mode 100644 index 00000000..b38e5bc8 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-exercise/src/main/resources/schema.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS PERSONS; +CREATE TABLE PERSONS(ID INT PRIMARY KEY, NAME VARCHAR(255)); diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/.gitignore b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/pom.xml b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/pom.xml new file mode 100644 index 00000000..dad2e34c --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + ru.otus + jdbc-demo-solution-step-1 + 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-starter-jdbc + + + com.h2database + h2 + 1.4.200 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/java/ru/otus/spring/Main.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..8916eb04 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,20 @@ +package ru.otus.spring; + +import org.h2.tools.Console; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import ru.otus.spring.dao.PersonDao; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) throws Exception { + + ApplicationContext context = SpringApplication.run(Main.class); + + PersonDao dao = context.getBean(PersonDao.class); + + Console.main(args); + } +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/java/ru/otus/spring/dao/PersonDao.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/java/ru/otus/spring/dao/PersonDao.java new file mode 100644 index 00000000..4ee1a3b3 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/java/ru/otus/spring/dao/PersonDao.java @@ -0,0 +1,4 @@ +package ru.otus.spring.dao; + +public interface PersonDao { +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java new file mode 100644 index 00000000..dc1933f1 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java @@ -0,0 +1,17 @@ +package ru.otus.spring.dao; + +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.stereotype.Repository; + +@SuppressWarnings({"SqlNoDataSourceInspection", "ConstantConditions", "SqlDialectInspection"}) +@Repository +public class PersonDaoJdbc implements PersonDao { + + private final JdbcOperations jdbc; + + public PersonDaoJdbc(JdbcOperations jdbcOperations) + { + this.jdbc = jdbcOperations; + } + +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/java/ru/otus/spring/domain/Person.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..e34ae29c --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,20 @@ +package ru.otus.spring.domain; + +public class Person { + + private final int id; + private final String name; + + public Person(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/resources/data.sql b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/resources/data.sql new file mode 100644 index 00000000..240a5b4e --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/resources/data.sql @@ -0,0 +1 @@ +insert into persons (id, `name`) values (1, 'masha'); diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/resources/schema.sql b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/resources/schema.sql new file mode 100644 index 00000000..b38e5bc8 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-1/src/main/resources/schema.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS PERSONS; +CREATE TABLE PERSONS(ID INT PRIMARY KEY, NAME VARCHAR(255)); diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/.gitignore b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/pom.xml b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/pom.xml new file mode 100644 index 00000000..d5004851 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + ru.otus + jdbc-demo-solution-step-2 + 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-starter-jdbc + + + com.h2database + h2 + 1.4.200 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/java/ru/otus/spring/Main.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..6c08834b --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,23 @@ +package ru.otus.spring; + +import org.h2.tools.Console; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import ru.otus.spring.dao.PersonDao; +import ru.otus.spring.domain.Person; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) throws Exception { + + ApplicationContext context = SpringApplication.run(Main.class); + + PersonDao dao = context.getBean(PersonDao.class); + + System.out.println("All count " + dao.count()); + + Console.main(args); + } +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/java/ru/otus/spring/dao/PersonDao.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/java/ru/otus/spring/dao/PersonDao.java new file mode 100644 index 00000000..9f5581fd --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/java/ru/otus/spring/dao/PersonDao.java @@ -0,0 +1,6 @@ +package ru.otus.spring.dao; + +public interface PersonDao { + + int count(); +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java new file mode 100644 index 00000000..f069a7a2 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java @@ -0,0 +1,23 @@ +package ru.otus.spring.dao; + +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.stereotype.Repository; +import ru.otus.spring.domain.Person; + +@SuppressWarnings({"SqlNoDataSourceInspection", "ConstantConditions", "SqlDialectInspection"}) +@Repository +public class PersonDaoJdbc implements PersonDao { + + private final JdbcOperations jdbc; + + public PersonDaoJdbc(JdbcOperations jdbcOperations) + { + this.jdbc = jdbcOperations; + } + + @Override + public int count() { + return jdbc.queryForObject("select count(*) from persons", Integer.class); + } + +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/java/ru/otus/spring/domain/Person.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..e34ae29c --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,20 @@ +package ru.otus.spring.domain; + +public class Person { + + private final int id; + private final String name; + + public Person(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/resources/data.sql b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/resources/data.sql new file mode 100644 index 00000000..240a5b4e --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/resources/data.sql @@ -0,0 +1 @@ +insert into persons (id, `name`) values (1, 'masha'); diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/resources/schema.sql b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/resources/schema.sql new file mode 100644 index 00000000..b38e5bc8 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-2/src/main/resources/schema.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS PERSONS; +CREATE TABLE PERSONS(ID INT PRIMARY KEY, NAME VARCHAR(255)); diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/.gitignore b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/pom.xml b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/pom.xml new file mode 100644 index 00000000..83d1a443 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + ru.otus + jdbc-demo-solution-step-3 + 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-starter-jdbc + + + com.h2database + h2 + 1.4.200 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/java/ru/otus/spring/Main.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..2bc8e898 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,27 @@ +package ru.otus.spring; + +import org.h2.tools.Console; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import ru.otus.spring.dao.PersonDao; +import ru.otus.spring.domain.Person; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) throws Exception { + + ApplicationContext context = SpringApplication.run(Main.class); + + PersonDao dao = context.getBean(PersonDao.class); + + System.out.println("All count " + dao.count()); + + dao.insert(new Person(2, "ivan")); + + System.out.println("All count " + dao.count()); + + Console.main(args); + } +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/java/ru/otus/spring/dao/PersonDao.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/java/ru/otus/spring/dao/PersonDao.java new file mode 100644 index 00000000..73109a4a --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/java/ru/otus/spring/dao/PersonDao.java @@ -0,0 +1,12 @@ +package ru.otus.spring.dao; + +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonDao { + + int count(); + + void insert(Person person); +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java new file mode 100644 index 00000000..35b648f2 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java @@ -0,0 +1,33 @@ +package ru.otus.spring.dao; + +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Repository; +import ru.otus.spring.domain.Person; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +@SuppressWarnings({"SqlNoDataSourceInspection", "ConstantConditions", "SqlDialectInspection"}) +@Repository +public class PersonDaoJdbc implements PersonDao { + + private final JdbcOperations jdbc; + + public PersonDaoJdbc(JdbcOperations jdbcOperations) + { + this.jdbc = jdbcOperations; + } + + @Override + public int count() { + return jdbc.queryForObject("select count(*) from persons", Integer.class); + } + + @Override + public void insert(Person person) { + jdbc.update("insert into persons (id, `name`) values (?, ?)", person.getId(), person.getName()); + } + +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/java/ru/otus/spring/domain/Person.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..e34ae29c --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,20 @@ +package ru.otus.spring.domain; + +public class Person { + + private final int id; + private final String name; + + public Person(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/resources/data.sql b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/resources/data.sql new file mode 100644 index 00000000..240a5b4e --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/resources/data.sql @@ -0,0 +1 @@ +insert into persons (id, `name`) values (1, 'masha'); diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/resources/schema.sql b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/resources/schema.sql new file mode 100644 index 00000000..b38e5bc8 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-3/src/main/resources/schema.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS PERSONS; +CREATE TABLE PERSONS(ID INT PRIMARY KEY, NAME VARCHAR(255)); diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/.gitignore b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/pom.xml b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/pom.xml new file mode 100644 index 00000000..624d36b1 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + ru.otus + jdbc-demo-solution-step-4 + 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-starter-jdbc + + + com.h2database + h2 + 1.4.200 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/java/ru/otus/spring/Main.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..4bc2aca8 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,31 @@ +package ru.otus.spring; + +import org.h2.tools.Console; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import ru.otus.spring.dao.PersonDao; +import ru.otus.spring.domain.Person; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) throws Exception { + + ApplicationContext context = SpringApplication.run(Main.class); + + PersonDao dao = context.getBean(PersonDao.class); + + System.out.println("All count " + dao.count()); + + dao.insert(new Person(2, "ivan")); + + System.out.println("All count " + dao.count()); + + Person ivan = dao.getById(2); + + System.out.println("Ivan id: " + ivan.getId() + " name: " + ivan.getName()); + + Console.main(args); + } +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/java/ru/otus/spring/dao/PersonDao.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/java/ru/otus/spring/dao/PersonDao.java new file mode 100644 index 00000000..a2b1379a --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/java/ru/otus/spring/dao/PersonDao.java @@ -0,0 +1,16 @@ +package ru.otus.spring.dao; + +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonDao { + + int count(); + + void insert(Person person); + + Person getById(int id); + + List getAll(); +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java new file mode 100644 index 00000000..a89d7c0b --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java @@ -0,0 +1,56 @@ +package ru.otus.spring.dao; + +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; +import org.springframework.stereotype.Repository; +import ru.otus.spring.domain.Person; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@SuppressWarnings({"SqlNoDataSourceInspection", "ConstantConditions", "SqlDialectInspection"}) +@Repository +public class PersonDaoJdbc implements PersonDao { + + private final JdbcOperations jdbc; + + public PersonDaoJdbc(JdbcOperations jdbcOperations) + { + this.jdbc = jdbcOperations; + } + + @Override + public int count() { + return jdbc.queryForObject("select count(*) from persons", Integer.class); + } + + @Override + public void insert(Person person) { + jdbc.update("insert into persons (id, `name`) values (?, ?)", person.getId(), person.getName()); + } + + @Override + public Person getById(int id) { + return jdbc.queryForObject("select * from persons where id = ?", new Object[] {id}, new PersonMapper()); + } + + @Override + public List getAll() { + return jdbc.query("select * from persons", new PersonMapper()); + } + + + private static class PersonMapper implements RowMapper { + + @Override + public Person mapRow(ResultSet resultSet, int i) throws SQLException { + int id = resultSet.getInt("id"); + String name = resultSet.getString("name"); + return new Person(id, name); + } + } +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/java/ru/otus/spring/domain/Person.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..e34ae29c --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,20 @@ +package ru.otus.spring.domain; + +public class Person { + + private final int id; + private final String name; + + public Person(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/resources/data.sql b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/resources/data.sql new file mode 100644 index 00000000..240a5b4e --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/resources/data.sql @@ -0,0 +1 @@ +insert into persons (id, `name`) values (1, 'masha'); diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/resources/schema.sql b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/resources/schema.sql new file mode 100644 index 00000000..b38e5bc8 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-4/src/main/resources/schema.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS PERSONS; +CREATE TABLE PERSONS(ID INT PRIMARY KEY, NAME VARCHAR(255)); diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/.gitignore b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/pom.xml b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/pom.xml new file mode 100644 index 00000000..6987d731 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + ru.otus + jdbc-demo-solution-step-final + 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-starter-jdbc + + + com.h2database + h2 + 1.4.200 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/java/ru/otus/spring/Main.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..05636811 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,33 @@ +package ru.otus.spring; + +import org.h2.tools.Console; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import ru.otus.spring.dao.PersonDao; +import ru.otus.spring.domain.Person; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) throws Exception { + + ApplicationContext context = SpringApplication.run(Main.class); + + PersonDao dao = context.getBean(PersonDao.class); + + System.out.println("All count " + dao.count()); + + dao.insert(new Person(2, "ivan")); + + System.out.println("All count " + dao.count()); + + Person ivan = dao.getById(2); + + System.out.println("Ivan id: " + ivan.getId() + " name: " + ivan.getName()); + + System.out.println(dao.getAll()); + + Console.main(args); + } +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/java/ru/otus/spring/dao/PersonDao.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/java/ru/otus/spring/dao/PersonDao.java new file mode 100644 index 00000000..9843d440 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/java/ru/otus/spring/dao/PersonDao.java @@ -0,0 +1,18 @@ +package ru.otus.spring.dao; + +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonDao { + + int count(); + + void insert(Person person); + + Person getById(int id); + + List getAll(); + + void deleteById(int id); +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java new file mode 100644 index 00000000..348e4df5 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java @@ -0,0 +1,70 @@ +package ru.otus.spring.dao; + +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; +import org.springframework.stereotype.Repository; +import ru.otus.spring.domain.Person; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@SuppressWarnings({"SqlNoDataSourceInspection", "ConstantConditions", "SqlDialectInspection"}) +@Repository +public class PersonDaoJdbc implements PersonDao { + + private final JdbcOperations jdbc; + private final NamedParameterJdbcOperations namedParameterJdbcOperations; + + public PersonDaoJdbc(NamedParameterJdbcOperations namedParameterJdbcOperations) + { + // Это просто отсавили, чтобы не переписывать код + // В идеале всё должно быть на NamedParameterJdbcOperations + this.jdbc = namedParameterJdbcOperations.getJdbcOperations(); + this.namedParameterJdbcOperations = namedParameterJdbcOperations; + } + + @Override + public int count() { + return jdbc.queryForObject("select count(*) from persons", Integer.class); + } + + @Override + public void insert(Person person) { + jdbc.update("insert into persons (id, `name`) values (?, ?)", person.getId(), person.getName()); + } + + @Override + public Person getById(int id) { + Map params = Collections.singletonMap("id", id); + return namedParameterJdbcOperations.queryForObject( + "select * from persons where id = :id", params, new PersonMapper() + ); + } + + @Override + public List getAll() { + return jdbc.query("select * from persons", new PersonMapper()); + } + + @Override + public void deleteById(int id) { + Map params = Collections.singletonMap("id", id); + namedParameterJdbcOperations.update( + "delete from persons where id = :id", params + ); + } + + private static class PersonMapper implements RowMapper { + + @Override + public Person mapRow(ResultSet resultSet, int i) throws SQLException { + int id = resultSet.getInt("id"); + String name = resultSet.getString("name"); + return new Person(id, name); + } + } +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/java/ru/otus/spring/domain/Person.java b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..e34ae29c --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,20 @@ +package ru.otus.spring.domain; + +public class Person { + + private final int id; + private final String name; + + public Person(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/resources/data.sql b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/resources/data.sql new file mode 100644 index 00000000..240a5b4e --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/resources/data.sql @@ -0,0 +1 @@ +insert into persons (id, `name`) values (1, 'masha'); diff --git a/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/resources/schema.sql b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/resources/schema.sql new file mode 100644 index 00000000..b38e5bc8 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/jdbc-demo-solution-step-final/src/main/resources/schema.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS PERSONS; +CREATE TABLE PERSONS(ID INT PRIMARY KEY, NAME VARCHAR(255)); diff --git a/2019-11/spring-07/jdbc-class-work/pom.xml b/2019-11/spring-07/jdbc-class-work/pom.xml new file mode 100644 index 00000000..4756a248 --- /dev/null +++ b/2019-11/spring-07/jdbc-class-work/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + ru.otus + jdbc-class-work + 1.0 + + pom + + + jdbc-demo-exercise + jdbc-demo-solution-step-1 + jdbc-demo-solution-step-2 + jdbc-demo-solution-step-3 + jdbc-demo-solution-step-4 + jdbc-demo-solution-step-final + + diff --git a/2019-11/spring-08/orm-class-work/.gitignore b/2019-11/spring-08/orm-class-work/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/examples/jpql-demo/.gitignore b/2019-11/spring-08/orm-class-work/mybatis-demo/.gitignore similarity index 100% rename from examples/jpql-demo/.gitignore rename to 2019-11/spring-08/orm-class-work/mybatis-demo/.gitignore diff --git a/2019-11/spring-08/orm-class-work/mybatis-demo/README.md b/2019-11/spring-08/orm-class-work/mybatis-demo/README.md new file mode 100644 index 00000000..44635273 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/mybatis-demo/README.md @@ -0,0 +1,2 @@ +# mybatis-demo +Пример работы с БД через MyBatis \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/mybatis-demo/pom.xml b/2019-11/spring-08/orm-class-work/mybatis-demo/pom.xml new file mode 100644 index 00000000..1fa13a35 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/mybatis-demo/pom.xml @@ -0,0 +1,73 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.1.RELEASE + + + ru.otus.example + mybatis-demo + 0.0.1-SNAPSHOT + mybatis-demo + MyBatis demo + + + 11 + 11 + 11 + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.0.1 + + + + com.h2database + h2 + runtime + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test + + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/MyBatisDemoApplication.java b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/MyBatisDemoApplication.java new file mode 100644 index 00000000..ab5f7513 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/MyBatisDemoApplication.java @@ -0,0 +1,14 @@ +package ru.otus.example.mybatisdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; + +@SpringBootApplication +public class MyBatisDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(MyBatisDemoApplication.class, args); + } + +} diff --git a/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/models/Avatar.java b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/models/Avatar.java new file mode 100644 index 00000000..5c8f4728 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/models/Avatar.java @@ -0,0 +1,13 @@ +package ru.otus.example.mybatisdemo.models; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Avatar { + private long id; + private String photoUrl; +} diff --git a/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/models/Course.java b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/models/Course.java new file mode 100644 index 00000000..6aa8cff7 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/models/Course.java @@ -0,0 +1,13 @@ +package ru.otus.example.mybatisdemo.models; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Course { + private long id; + private String name; +} diff --git a/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/models/EMail.java b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/models/EMail.java new file mode 100644 index 00000000..8fa43ebd --- /dev/null +++ b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/models/EMail.java @@ -0,0 +1,13 @@ +package ru.otus.example.mybatisdemo.models; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class EMail { + private long id; + private String email; +} diff --git a/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/models/OtusStudent.java b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/models/OtusStudent.java new file mode 100644 index 00000000..afb324fb --- /dev/null +++ b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/models/OtusStudent.java @@ -0,0 +1,18 @@ +package ru.otus.example.mybatisdemo.models; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class OtusStudent { + private long id; + private String name; + private Avatar avatar; + private List emails; + private List courses; +} diff --git a/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/repositories/AvatarRepository.java b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/repositories/AvatarRepository.java new file mode 100644 index 00000000..634d1aba --- /dev/null +++ b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/repositories/AvatarRepository.java @@ -0,0 +1,18 @@ +package ru.otus.example.mybatisdemo.repositories; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Result; +import org.apache.ibatis.annotations.Results; +import org.apache.ibatis.annotations.Select; +import ru.otus.example.mybatisdemo.models.Avatar; + +@Mapper +public interface AvatarRepository { + @Select("select * from avatars where id = #{id}") + @Results(value = { + @Result(property = "id", column = "id"), + @Result(property = "photoUrl", column = "photo_url") + }) + Avatar getAvatarById(long id); + +} diff --git a/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/repositories/CourseRepository.java b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/repositories/CourseRepository.java new file mode 100644 index 00000000..96c77681 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/repositories/CourseRepository.java @@ -0,0 +1,15 @@ +package ru.otus.example.mybatisdemo.repositories; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; +import ru.otus.example.mybatisdemo.models.Course; + +import java.util.List; + +@Mapper +public interface CourseRepository { + + @Select("select * from student_courses sc left join courses c on sc.course_id = c.id where sc.student_id = #{studentId}") + List getCoursesByStudentId(long studentId); + +} diff --git a/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/repositories/EmailRepository.java b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/repositories/EmailRepository.java new file mode 100644 index 00000000..989b681d --- /dev/null +++ b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/repositories/EmailRepository.java @@ -0,0 +1,14 @@ +package ru.otus.example.mybatisdemo.repositories; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; +import ru.otus.example.mybatisdemo.models.EMail; + +import java.util.List; + +@Mapper +public interface EmailRepository { + + @Select("select * from emails where student_id = #{studentId}") + List getEmailsByStudentId(long studentId); +} diff --git a/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/repositories/OtusStudentRepository.java b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/repositories/OtusStudentRepository.java new file mode 100644 index 00000000..82a8260b --- /dev/null +++ b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/java/ru/otus/example/mybatisdemo/repositories/OtusStudentRepository.java @@ -0,0 +1,42 @@ +package ru.otus.example.mybatisdemo.repositories; + +import org.apache.ibatis.annotations.*; +import org.apache.ibatis.mapping.FetchType; +import ru.otus.example.mybatisdemo.models.Avatar; +import ru.otus.example.mybatisdemo.models.OtusStudent; + +import java.util.List; + +@Mapper +public interface OtusStudentRepository { + + @Select("select * from otus_students") + @Results(id = "studentAllMap", value = { + @Result(property = "id", column = "id"), + @Result(property = "name", column = "name"), + @Result(property = "avatar", column = "avatar_id", javaType = Avatar.class, + one = @One(select = "ru.otus.example.mybatisdemo.repositories.AvatarRepository.getAvatarById", fetchType = FetchType.EAGER)), + @Result(property = "emails", column = "id", javaType = List.class, + many = @Many(select = "ru.otus.example.mybatisdemo.repositories.EmailRepository.getEmailsByStudentId", fetchType = FetchType.EAGER)), + @Result(property = "courses", column = "id", javaType = List.class, + many = @Many(select = "ru.otus.example.mybatisdemo.repositories.CourseRepository.getCoursesByStudentId", fetchType = FetchType.EAGER)) + }) + List findAllWithAllInfo(); + + @Select("select * from otus_students where id = #{id}") + @ResultMap("studentAllMap") + OtusStudent findById(long id); + + @Select("select count(*) as students_count from otus_students") + long getStudentsCount(); + + @Insert("insert into otus_students(name, avatar_id) values (#{name}, #{avatar.id})") + void insert(OtusStudent student); + + @Update("update otus_students set name = #{name} where id = #{id}") + void updateName(OtusStudent student); + + @Delete("delete from otus_students where id = #{id}") + void deleteById(long id); + +} diff --git a/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/resources/schema.sql b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/resources/schema.sql new file mode 100644 index 00000000..43a684bb --- /dev/null +++ b/2019-11/spring-08/orm-class-work/mybatis-demo/src/main/resources/schema.sql @@ -0,0 +1,31 @@ +create table avatars( + id bigserial, + photo_url varchar(8000), + primary key (id) +); + +create table courses( + id bigserial, + name varchar(255), + primary key (id) +); + +create table otus_students( + id bigserial, + name varchar(255), + avatar_id bigint references avatars (id), + primary key (id) +); + +create table emails( + id bigserial, + student_id bigint references otus_students(id) on delete cascade, + email varchar(255), + primary key (id) +); + +create table student_courses( + student_id bigint references otus_students(id) on delete cascade, + course_id bigint references courses(id), + primary key (student_id, course_id) +); \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/mybatis-demo/src/test/java/ru/otus/example/mybatisdemo/repositories/OtusStudentRepositoryTest.java b/2019-11/spring-08/orm-class-work/mybatis-demo/src/test/java/ru/otus/example/mybatisdemo/repositories/OtusStudentRepositoryTest.java new file mode 100644 index 00000000..210924e6 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/mybatis-demo/src/test/java/ru/otus/example/mybatisdemo/repositories/OtusStudentRepositoryTest.java @@ -0,0 +1,103 @@ +package ru.otus.example.mybatisdemo.repositories; + +import lombok.val; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; +import ru.otus.example.mybatisdemo.models.Avatar; +import ru.otus.example.mybatisdemo.models.OtusStudent; + +import static org.assertj.core.api.Assertions.assertThat; + +@DisplayName("Репозиторий на основе MyBatis для работы со студентами ") +@SpringBootTest +@Transactional +public class OtusStudentRepositoryTest { + + private static final String FIELD_ID = "id"; + private static final String FIELD_PHOTO_URL = "photoUrl"; + private static final String FIELD_NAME = "name"; + + private static final long FIRST_STUDENT_ID = 1L; + private static final long FIRST_AVATAR_ID = 1L; + private static final String FIRST_STUDENT_NAME = "student_01"; + private static final String FIRST_AVATAR_URL = "photoUrl_01"; + private static final String STUDENT_NEW_NAME = "Висусуалий"; + + private static final int EXPECTED_NUMBER_OF_STUDENTS = 10; + private static final long INSERTED_STUDENT_ID = 11L; + private static final int EXPECTED_EMAILS_COUNT = 2; + private static final int EXPECTED_COURSES_COUNT = 3; + + @Autowired + private OtusStudentRepository studentRepositoryMyBatis; + + @DisplayName("должен загружать список всех студентов с полной информацией о них") + @Test + void shouldReturnCorrectStudentsListWithAllInfo() { + val students = studentRepositoryMyBatis.findAllWithAllInfo(); + assertThat(students).isNotNull().hasSize(EXPECTED_NUMBER_OF_STUDENTS) + .allMatch(s -> !s.getName().equals("")) + .allMatch(s -> s.getCourses() != null && s.getCourses().size() > 0) + .allMatch(s -> s.getAvatar() != null) + .allMatch(s -> s.getEmails() != null && s.getEmails().size() > 0); + } + + @DisplayName("должен загружать число студентов в БД") + @Test + void shouldReturnCorrectStudentsCount() { + long studentsCount = studentRepositoryMyBatis.getStudentsCount(); + assertThat(studentsCount).isEqualTo(EXPECTED_NUMBER_OF_STUDENTS); + } + + @DisplayName(" должен загружать информацию о нужном студенте") + @Test + void shouldFindExpectedStudentById(){ + val actualStudent = studentRepositoryMyBatis.findById(FIRST_STUDENT_ID); + + assertThat(actualStudent).isNotNull(); + assertThat(actualStudent.getName()).isEqualTo(FIRST_STUDENT_NAME); + assertThat(actualStudent.getAvatar()).isNotNull() + .hasFieldOrPropertyWithValue(FIELD_ID, FIRST_STUDENT_ID) + .hasFieldOrPropertyWithValue(FIELD_PHOTO_URL, FIRST_AVATAR_URL); + assertThat(actualStudent.getEmails()).isNotNull().hasSize(EXPECTED_EMAILS_COUNT); + assertThat(actualStudent.getCourses()).isNotNull().hasSize(EXPECTED_COURSES_COUNT); + } + + @DisplayName(" должен сохранить, а потом загрузить информацию о нужном студенте") + @Test + void shouldSaveAndLoadCorrectStudent() { + val expectedStudent = new OtusStudent(); + expectedStudent.setName(STUDENT_NEW_NAME); + expectedStudent.setAvatar(new Avatar(FIRST_AVATAR_ID, FIRST_AVATAR_URL)); + studentRepositoryMyBatis.insert(expectedStudent); + val actualStudent = studentRepositoryMyBatis.findById(INSERTED_STUDENT_ID); + + assertThat(actualStudent).isNotNull().isEqualToComparingOnlyGivenFields(expectedStudent, FIELD_NAME); + } + + + @DisplayName(" должен обновлять имя студента в БД") + @Test + void shouldUpdateStudentName() { + val student = studentRepositoryMyBatis.findById(FIRST_STUDENT_ID); + student.setName(STUDENT_NEW_NAME); + studentRepositoryMyBatis.updateName(student); + val actualStudent = studentRepositoryMyBatis.findById(FIRST_STUDENT_ID); + + assertThat(actualStudent).isNotNull().hasFieldOrPropertyWithValue(FIELD_NAME, student.getName()); + } + + @DisplayName("должен удалять студента из БД по id") + @Test + void shouldDeleteStudentFromDbById() { + val studentsCountBefore = studentRepositoryMyBatis.getStudentsCount(); + studentRepositoryMyBatis.deleteById(FIRST_STUDENT_ID); + val studentsCountAfter = studentRepositoryMyBatis.getStudentsCount(); + + assertThat(studentsCountBefore - studentsCountAfter).isEqualTo(1); + } + +} diff --git a/2019-11/spring-08/orm-class-work/mybatis-demo/src/test/resources/application.yml b/2019-11/spring-08/orm-class-work/mybatis-demo/src/test/resources/application.yml new file mode 100644 index 00000000..037f7eae --- /dev/null +++ b/2019-11/spring-08/orm-class-work/mybatis-demo/src/test/resources/application.yml @@ -0,0 +1,18 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + initialization-mode: always + + jpa: + generate-ddl: false + #generate-ddl: true + hibernate: + ddl-auto: none + #ddl-auto: create-drop + + show-sql: true + + +logging: + level: + ru.otus.example.mybatisdemo.repositories: TRACE \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/mybatis-demo/src/test/resources/data.sql b/2019-11/spring-08/orm-class-work/mybatis-demo/src/test/resources/data.sql new file mode 100644 index 00000000..a8db6b85 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/mybatis-demo/src/test/resources/data.sql @@ -0,0 +1,29 @@ +insert into avatars(photo_url) +values ('photoUrl_01'), ('photoUrl_02'), ('photoUrl_03'), ('photoUrl_04'), ('photoUrl_05'), + ('photoUrl_06'), ('photoUrl_07'), ('photoUrl_08'), ('photoUrl_09'), ('photoUrl_10'); + +insert into courses(name) +values ('course_name_01'), ('course_name_02'), ('course_name_03'), ('course_name_04'), ('course_name_05'), + ('course_name_06'), ('course_name_07'), ('course_name_08'), ('course_name_09'), ('course_name_10'), ('not_used_11'); + +insert into otus_students(name, avatar_id) +values ('student_01', 1), ('student_02', 2), ('student_03', 3), ('student_04', 4), ('student_05', 5), + ('student_06', 6), ('student_07', 7), ('student_08', 8), ('student_09', 9), ('student_10', 10); + + +insert into emails(email, student_id) +values ('email_01', 1), ('email_02', 1), ('email_03', 2), ('email_04', 2), ('email_05', 3), ('email_06', 4), + ('email_07', 5), ('email_08', 6), ('email_09', 7), ('email_10', 8), ('email_11', 9), ('email_12', 10); + + +insert into student_courses(student_id, course_id) +values (1, 1), (1, 2), (1, 3), + (2, 2), (2, 4), (2, 5), + (3, 3), (3, 6), (3, 7), + (4, 4), (4, 8), (4, 9), + (5, 5), (5, 10), (5, 1), + (6, 6), (6, 2), (6, 3), + (7, 7), (7, 4), (7, 5), + (8, 8), (8, 6), (8, 7), + (9, 9), (9, 8), (9, 10), + (10, 10), (10, 1), (10, 2); diff --git a/2019-11/spring-08/orm-class-work/orm-demo/.gitignore b/2019-11/spring-08/orm-class-work/orm-demo/.gitignore new file mode 100644 index 00000000..153c9335 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/.gitignore @@ -0,0 +1,29 @@ +HELP.md +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +/build/ + +### VS Code ### +.vscode/ diff --git a/2019-11/spring-08/orm-class-work/orm-demo/README.md b/2019-11/spring-08/orm-class-work/orm-demo/README.md new file mode 100644 index 00000000..a1e907ee --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/README.md @@ -0,0 +1,2 @@ +# orm-demo +Пример работы с БД через ORM \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/orm-demo/pom.xml b/2019-11/spring-08/orm-class-work/orm-demo/pom.xml new file mode 100644 index 00000000..213779ff --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.1.RELEASE + + + ru.otus.example + orm-demo + 0.0.1-SNAPSHOT + orm-demo + Orm demo + + + 11 + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + com.h2database + h2 + runtime + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test + + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/OrmDemoApplication.java b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/OrmDemoApplication.java new file mode 100644 index 00000000..8d4b413c --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/OrmDemoApplication.java @@ -0,0 +1,13 @@ +package ru.otus.example.ormdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class OrmDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(OrmDemoApplication.class, args); + } + +} diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/models/OtusStudent.java b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/models/OtusStudent.java new file mode 100644 index 00000000..bd7f4852 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/models/OtusStudent.java @@ -0,0 +1,42 @@ +package ru.otus.example.ormdemo.models; + +import lombok.*; +import ru.otus.example.ormdemo.models.common.Avatar; +import ru.otus.example.ormdemo.models.common.Course; +import ru.otus.example.ormdemo.models.common.EMail; + +import javax.persistence.*; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity // Указывает, что данный класс является сущностью +@Table(name = "otus_students") // Задает имя таблицы, на которую будет отображаться сущность +public class OtusStudent { + @Id // Позволяет указать какое поле является идентификатором + @GeneratedValue(strategy = GenerationType.IDENTITY) // Стратегия генерации идентификаторов + private long id; + + // Задает имя и некоторые свойства поля таблицы, на которое будет отображаться поле сущности + @Column(name = "name", nullable = false, unique = true) + private String name; + + // Указывает на связь между таблицами "один к одному" + @OneToOne(targetEntity = Avatar.class, cascade = CascadeType.ALL) + // Задает поле, по которому происходит объединение с таблицей для хранения связанной сущности + @JoinColumn(name = "avatar_id") + private Avatar avatar; + + // Указывает на связь между таблицами "один ко многим" + @OneToMany(targetEntity = EMail.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER) + @JoinColumn(name = "student_id") + private List emails; + + // Указывает на связь между таблицами "многие ко многим" + @ManyToMany(targetEntity = Course.class, fetch = FetchType.LAZY /*, cascade = CascadeType.ALL*/) + // Задает таблицу связей между таблицами для хранения родительской и связанной сущностью + @JoinTable(name = "student_courses", joinColumns = @JoinColumn(name = "student_id"), + inverseJoinColumns = @JoinColumn(name = "course_id")) + private List courses; +} diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/models/OtusStudentV2.java b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/models/OtusStudentV2.java new file mode 100644 index 00000000..e7fa06e5 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/models/OtusStudentV2.java @@ -0,0 +1,44 @@ +package ru.otus.example.ormdemo.models; + +import lombok.*; +import org.hibernate.annotations.BatchSize; +import org.hibernate.annotations.Fetch; +import org.hibernate.annotations.FetchMode; +import ru.otus.example.ormdemo.models.common.Avatar; +import ru.otus.example.ormdemo.models.common.Course; +import ru.otus.example.ormdemo.models.common.EMail; + +import javax.persistence.*; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "otus_students") +@NamedEntityGraph(name = "OtusStudentWithAvatarAndEmails", + attributeNodes = {@NamedAttributeNode(value = "avatar"), + @NamedAttributeNode(value = "emails")}) +public class OtusStudentV2 { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column(name = "name", nullable = false, unique = true) + private String name; + + @OneToOne(targetEntity = Avatar.class, cascade = CascadeType.ALL) + @JoinColumn(name = "avatar_id") + private Avatar avatar; + + @OneToMany(targetEntity = EMail.class, cascade = CascadeType.ALL) + @JoinColumn(name = "student_id") + private List emails; + + //@Fetch(FetchMode.SUBSELECT) + //@BatchSize(size = 5) + @ManyToMany(targetEntity = Course.class, fetch = FetchType.LAZY) + @JoinTable(name = "student_courses", joinColumns = @JoinColumn(name = "student_id"), + inverseJoinColumns = @JoinColumn(name = "course_id")) + private List courses; +} diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/models/common/Avatar.java b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/models/common/Avatar.java new file mode 100644 index 00000000..2ed2b5f8 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/models/common/Avatar.java @@ -0,0 +1,21 @@ +package ru.otus.example.ormdemo.models.common; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "avatars") +public class Avatar { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column(name = "photo_url", nullable = false, unique = true) + private String photoUrl; +} diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/models/common/Course.java b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/models/common/Course.java new file mode 100644 index 00000000..6ce8b993 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/models/common/Course.java @@ -0,0 +1,21 @@ +package ru.otus.example.ormdemo.models.common; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "courses") +public class Course { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column(name = "name", nullable = false, unique = true) + private String name; +} diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/models/common/EMail.java b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/models/common/EMail.java new file mode 100644 index 00000000..1bc8cf74 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/models/common/EMail.java @@ -0,0 +1,22 @@ +package ru.otus.example.ormdemo.models.common; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "emails") +public class EMail { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column(name = "email", nullable = false, unique = true) + private String email; +} diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/CourseRepositoryJpa.java b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/CourseRepositoryJpa.java new file mode 100644 index 00000000..dc6d0811 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/CourseRepositoryJpa.java @@ -0,0 +1,7 @@ +package ru.otus.example.ormdemo.repositories; + +import ru.otus.example.ormdemo.models.common.Course; + +public interface CourseRepositoryJpa { + Course save(Course course); +} diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/CourseRepositoryJpaImpl.java b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/CourseRepositoryJpaImpl.java new file mode 100644 index 00000000..d4ce0bd8 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/CourseRepositoryJpaImpl.java @@ -0,0 +1,18 @@ +package ru.otus.example.ormdemo.repositories; + +import ru.otus.example.ormdemo.models.common.Course; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +public class CourseRepositoryJpaImpl implements CourseRepositoryJpa { + + @PersistenceContext + private EntityManager em; + + @Override + public Course save(Course course) { + em.persist(course); + return course; + } +} diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/OtusStudentRepositoryJpa.java b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/OtusStudentRepositoryJpa.java new file mode 100644 index 00000000..ba9eedda --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/OtusStudentRepositoryJpa.java @@ -0,0 +1,14 @@ +package ru.otus.example.ormdemo.repositories; + + +import ru.otus.example.ormdemo.models.OtusStudent; + +import java.util.List; +import java.util.Optional; + +public interface OtusStudentRepositoryJpa { + Optional findById(long id); + List findAll(); + OtusStudent save(OtusStudent student); + +} diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/OtusStudentRepositoryJpaImpl.java b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/OtusStudentRepositoryJpaImpl.java new file mode 100644 index 00000000..5d4760cc --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/OtusStudentRepositoryJpaImpl.java @@ -0,0 +1,36 @@ +package ru.otus.example.ormdemo.repositories; + +import org.springframework.stereotype.Repository; +import ru.otus.example.ormdemo.models.OtusStudent; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.util.List; +import java.util.Optional; + +@Repository +public class OtusStudentRepositoryJpaImpl implements OtusStudentRepositoryJpa { + + @PersistenceContext + private EntityManager em; + + @Override + public Optional findById(long id) { + return Optional.ofNullable(em.find(OtusStudent.class, id)); + } + + @Override + public List findAll() { + return em.createQuery("select s from OtusStudent s", OtusStudent.class).getResultList(); + } + + @Override + public OtusStudent save(OtusStudent student) { + if (student.getId() <= 0) { + em.persist(student); + return student; + } else { + return em.merge(student); + } + } +} diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/OtusStudentV2RepositoryJpa.java b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/OtusStudentV2RepositoryJpa.java new file mode 100644 index 00000000..5893319f --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/OtusStudentV2RepositoryJpa.java @@ -0,0 +1,11 @@ +package ru.otus.example.ormdemo.repositories; + + +import ru.otus.example.ormdemo.models.OtusStudentV2; + +import java.util.List; + +public interface OtusStudentV2RepositoryJpa { + List findAllWithEntityGraph(); + List findAllWithJoinFetch(); +} diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/OtusStudentV2RepositoryJpaImpl.java b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/OtusStudentV2RepositoryJpaImpl.java new file mode 100644 index 00000000..df615f41 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/main/java/ru/otus/example/ormdemo/repositories/OtusStudentV2RepositoryJpaImpl.java @@ -0,0 +1,30 @@ +package ru.otus.example.ormdemo.repositories; + +import org.springframework.stereotype.Repository; +import ru.otus.example.ormdemo.models.OtusStudentV2; + +import javax.persistence.EntityGraph; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.TypedQuery; +import java.util.List; + +@Repository +public class OtusStudentV2RepositoryJpaImpl implements OtusStudentV2RepositoryJpa { + + @PersistenceContext + private EntityManager em; + + @Override + public List findAllWithEntityGraph() { + EntityGraph entityGraph = em.getEntityGraph("OtusStudentWithAvatarAndEmails"); + TypedQuery query = em.createQuery("select s from OtusStudentV2 s", OtusStudentV2.class); + query.setHint("javax.persistence.fetchgraph", entityGraph); + return query.getResultList(); + } + + @Override + public List findAllWithJoinFetch() { + return em.createQuery("select distinct s from OtusStudentV2 s join fetch s.avatar join fetch s.emails", OtusStudentV2.class).getResultList(); + } +} diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/main/resources/schema.sql b/2019-11/spring-08/orm-class-work/orm-demo/src/main/resources/schema.sql new file mode 100644 index 00000000..43a684bb --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/main/resources/schema.sql @@ -0,0 +1,31 @@ +create table avatars( + id bigserial, + photo_url varchar(8000), + primary key (id) +); + +create table courses( + id bigserial, + name varchar(255), + primary key (id) +); + +create table otus_students( + id bigserial, + name varchar(255), + avatar_id bigint references avatars (id), + primary key (id) +); + +create table emails( + id bigserial, + student_id bigint references otus_students(id) on delete cascade, + email varchar(255), + primary key (id) +); + +create table student_courses( + student_id bigint references otus_students(id) on delete cascade, + course_id bigint references courses(id), + primary key (student_id, course_id) +); \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/test/java/ru/otus/example/ormdemo/repositories/OtusStudentRepositoryJpaImplTest.java b/2019-11/spring-08/orm-class-work/orm-demo/src/test/java/ru/otus/example/ormdemo/repositories/OtusStudentRepositoryJpaImplTest.java new file mode 100644 index 00000000..7c9ca9f3 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/test/java/ru/otus/example/ormdemo/repositories/OtusStudentRepositoryJpaImplTest.java @@ -0,0 +1,94 @@ +package ru.otus.example.ormdemo.repositories; + +import lombok.val; +import org.hibernate.SessionFactory; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.context.annotation.Import; +import ru.otus.example.ormdemo.models.OtusStudent; +import ru.otus.example.ormdemo.models.common.Avatar; +import ru.otus.example.ormdemo.models.common.Course; +import ru.otus.example.ormdemo.models.common.EMail; + +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; + +@DisplayName("Репозиторий на основе Jpa для работы со студентами ") +@DataJpaTest +@Import({OtusStudentRepositoryJpaImpl.class, CourseRepositoryJpaImpl.class}) +class OtusStudentRepositoryJpaImplTest { + + private static final int EXPECTED_NUMBER_OF_STUDENTS = 10; + private static final long FIRST_STUDENT_ID = 1L; + + private static final int EXPECTED_QUERIES_COUNT = 31; + + private static final String STUDENT_AVATAR_URL = "где-то там"; + private static final String STUDENT_EMAIL = "any@mail.com"; + private static final String COURSE_NAME = "Spring"; + private static final String STUDENT_NAME = "Вася"; + + @Autowired + private OtusStudentRepositoryJpaImpl repositoryJpa; + + @Autowired + private CourseRepositoryJpaImpl courseRepositoryJpa; + + @Autowired + private TestEntityManager em; + + @DisplayName(" должен загружать информацию о нужном студенте") + @Test + void shouldFindExpectedStudentById() { + val optionalActualStudent = repositoryJpa.findById(FIRST_STUDENT_ID); + val expectedStudent = em.find(OtusStudent.class, FIRST_STUDENT_ID); + assertThat(optionalActualStudent).isPresent().get() + .isEqualToComparingFieldByField(expectedStudent); + } + + @DisplayName("должен загружать список всех студентов с полной информацией о них") + @Test + void shouldReturnCorrectStudentsListWithAllInfo() { + SessionFactory sessionFactory = em.getEntityManager().getEntityManagerFactory() + .unwrap(SessionFactory.class); + sessionFactory.getStatistics().setStatisticsEnabled(true); + + + System.out.println("\n\n\n\n----------------------------------------------------------------------------------------------------------"); + val students = repositoryJpa.findAll(); + assertThat(students).isNotNull().hasSize(EXPECTED_NUMBER_OF_STUDENTS) + .allMatch(s -> !s.getName().equals("")) + .allMatch(s -> s.getCourses() != null && s.getCourses().size() > 0) + .allMatch(s -> s.getAvatar() != null) + .allMatch(s -> s.getEmails() != null && s.getEmails().size() > 0); + System.out.println("----------------------------------------------------------------------------------------------------------\n\n\n\n"); + assertThat(sessionFactory.getStatistics().getPrepareStatementCount()).isEqualTo(EXPECTED_QUERIES_COUNT); + } + + @DisplayName(" должен корректно сохранять всю информацию о студенте") + @Test + void shouldSaveAllStudentInfo() { + val avatar = new Avatar(0, STUDENT_AVATAR_URL); + val email = new EMail(0, STUDENT_EMAIL); + val emails = Collections.singletonList(email); + + val course = new Course(0, COURSE_NAME); + val courses = Collections.singletonList(course); + //courseRepositoryJpa.save(course); + + + val vasya = new OtusStudent(0, STUDENT_NAME, avatar, emails, courses); + repositoryJpa.save(vasya); + assertThat(vasya.getId()).isGreaterThan(0); + + val actualStudent = em.find(OtusStudent.class, vasya.getId()); + assertThat(actualStudent).isNotNull().matches(s -> !s.getName().equals("")) + .matches(s -> s.getCourses() != null && s.getCourses().size() > 0 && s.getCourses().get(0).getId() > 0) + .matches(s -> s.getAvatar() != null) + .matches(s -> s.getEmails() != null && s.getEmails().size() > 0); + } +} \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/test/java/ru/otus/example/ormdemo/repositories/OtusStudentV2RepositoryJpaImplTest.java b/2019-11/spring-08/orm-class-work/orm-demo/src/test/java/ru/otus/example/ormdemo/repositories/OtusStudentV2RepositoryJpaImplTest.java new file mode 100644 index 00000000..041384b3 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/test/java/ru/otus/example/ormdemo/repositories/OtusStudentV2RepositoryJpaImplTest.java @@ -0,0 +1,74 @@ +package ru.otus.example.ormdemo.repositories; + +import org.hibernate.SessionFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.context.annotation.Import; +import ru.otus.example.ormdemo.models.OtusStudentV2; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@DisplayName("Репозиторий v2 на основе Jpa для работы со студентами ") +@DataJpaTest +@Import({OtusStudentV2RepositoryJpaImpl.class}) +class OtusStudentV2RepositoryJpaImplTest { + + private static final int EXPECTED_NUMBER_OF_STUDENTS = 10; + + private static final int EXPECTED_QUERIES_COUNT = 11; // EntityGraph/join fetch + //private static final int EXPECTED_QUERIES_COUNT = 2; // EntityGraph/join fetch + @Fetch(FetchMode.SUBSELECT) + //private static final int EXPECTED_QUERIES_COUNT = 3; // EntityGraph/join fetch + @BatchSize(size = 5) + + @Autowired + private OtusStudentV2RepositoryJpaImpl repositoryJpa; + + @Autowired + private TestEntityManager em; + + private SessionFactory sessionFactory; + + @BeforeEach + void setUp() { + sessionFactory = em.getEntityManager().getEntityManagerFactory() + .unwrap(SessionFactory.class); + sessionFactory.getStatistics().setStatisticsEnabled(true); + sessionFactory.getStatistics().clear(); + } + + @DisplayName(" с помощью EntityGraph должен загружать список всех студентов с полной информацией о них") + @Test + void usingEntityGraphShouldReturnCorrectStudentsListWithWithAllInfo() { + System.out.println("\n\n\n\n----------------------------------------------------------------------------------------------------------"); + List students = repositoryJpa.findAllWithEntityGraph(); + assertThat(students).isNotNull().hasSize(EXPECTED_NUMBER_OF_STUDENTS) + .allMatch(s -> !s.getName().equals("")) + .allMatch(s -> s.getCourses() != null && s.getCourses().size() > 0) + .allMatch(s -> s.getAvatar() != null) + .allMatch(s -> s.getEmails() != null && s.getEmails().size() > 0); + System.out.println("----------------------------------------------------------------------------------------------------------\n\n\n\n"); + assertThat(sessionFactory.getStatistics().getPrepareStatementCount()) + .isEqualTo(EXPECTED_QUERIES_COUNT); + + } + + @DisplayName(" с помощью 'join fetch' должен загружать список всех студентов с полной информацией о них") + @Test + void usingJoinFetchShouldReturnCorrectStudentsListWithWithAllInfo() { + System.out.println("\n\n\n\n----------------------------------------------------------------------------------------------------------"); + List students = repositoryJpa.findAllWithJoinFetch(); + assertThat(students).isNotNull().hasSize(EXPECTED_NUMBER_OF_STUDENTS) + .allMatch(s -> !s.getName().equals("")) + .allMatch(s -> s.getCourses() != null && s.getCourses().size() > 0) + .allMatch(s -> s.getAvatar() != null) + .allMatch(s -> s.getEmails() != null && s.getEmails().size() > 0); + System.out.println("----------------------------------------------------------------------------------------------------------\n\n\n\n"); + assertThat(sessionFactory.getStatistics().getPrepareStatementCount()) + .isEqualTo(EXPECTED_QUERIES_COUNT); + } +} \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/test/resources/application.yml b/2019-11/spring-08/orm-class-work/orm-demo/src/test/resources/application.yml new file mode 100644 index 00000000..d2b811a4 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/test/resources/application.yml @@ -0,0 +1,17 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + initialization-mode: always + + jpa: + generate-ddl: false + #generate-ddl: true + hibernate: + ddl-auto: none + #ddl-auto: create-drop + + #show-sql: true + +logging: + level: + ROOT: ERROR \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/orm-demo/src/test/resources/data.sql b/2019-11/spring-08/orm-class-work/orm-demo/src/test/resources/data.sql new file mode 100644 index 00000000..a8db6b85 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/orm-demo/src/test/resources/data.sql @@ -0,0 +1,29 @@ +insert into avatars(photo_url) +values ('photoUrl_01'), ('photoUrl_02'), ('photoUrl_03'), ('photoUrl_04'), ('photoUrl_05'), + ('photoUrl_06'), ('photoUrl_07'), ('photoUrl_08'), ('photoUrl_09'), ('photoUrl_10'); + +insert into courses(name) +values ('course_name_01'), ('course_name_02'), ('course_name_03'), ('course_name_04'), ('course_name_05'), + ('course_name_06'), ('course_name_07'), ('course_name_08'), ('course_name_09'), ('course_name_10'), ('not_used_11'); + +insert into otus_students(name, avatar_id) +values ('student_01', 1), ('student_02', 2), ('student_03', 3), ('student_04', 4), ('student_05', 5), + ('student_06', 6), ('student_07', 7), ('student_08', 8), ('student_09', 9), ('student_10', 10); + + +insert into emails(email, student_id) +values ('email_01', 1), ('email_02', 1), ('email_03', 2), ('email_04', 2), ('email_05', 3), ('email_06', 4), + ('email_07', 5), ('email_08', 6), ('email_09', 7), ('email_10', 8), ('email_11', 9), ('email_12', 10); + + +insert into student_courses(student_id, course_id) +values (1, 1), (1, 2), (1, 3), + (2, 2), (2, 4), (2, 5), + (3, 3), (3, 6), (3, 7), + (4, 4), (4, 8), (4, 9), + (5, 5), (5, 10), (5, 1), + (6, 6), (6, 2), (6, 3), + (7, 7), (7, 4), (7, 5), + (8, 8), (8, 6), (8, 7), + (9, 9), (9, 8), (9, 10), + (10, 10), (10, 1), (10, 2); diff --git a/2019-11/spring-08/orm-class-work/pom.xml b/2019-11/spring-08/orm-class-work/pom.xml new file mode 100644 index 00000000..f398c0f4 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + + ru.otus + orm-class-work + 1.0 + + pom + + + spring-jdbc-demo + orm-demo + replace-orm-provider-demo + mybatis-demo + + diff --git a/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/.gitignore b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/.gitignore new file mode 100644 index 00000000..153c9335 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/.gitignore @@ -0,0 +1,29 @@ +HELP.md +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +/build/ + +### VS Code ### +.vscode/ diff --git a/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/README.md b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/README.md new file mode 100644 index 00000000..f5eceb6d --- /dev/null +++ b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/README.md @@ -0,0 +1,2 @@ +# replace-orm-provider-demo +Пример замены ORM провайдера \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/pom.xml b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/pom.xml new file mode 100644 index 00000000..b783b3fc --- /dev/null +++ b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/pom.xml @@ -0,0 +1,88 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.1.RELEASE + + + ru.otus.example + replace-orm-provider-demo + 0.0.1-SNAPSHOT + replace-orm-provider-demo + Replace ORM provider demo + + + 11 + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.hibernate + hibernate-entitymanager + + + org.hibernate + hibernate-core + + + + + + org.eclipse.persistence + org.eclipse.persistence.jpa + 2.7.4 + + + + com.h2database + h2 + runtime + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test + + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/ReplaceOrmProviderDemoApplication.java b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/ReplaceOrmProviderDemoApplication.java new file mode 100644 index 00000000..97fee71e --- /dev/null +++ b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/ReplaceOrmProviderDemoApplication.java @@ -0,0 +1,16 @@ +package ru.otus.example.replaceormproviderdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Import; +import ru.otus.example.replaceormproviderdemo.config.EclipseLinkJpaConfiguration; + +@SpringBootApplication +@Import(EclipseLinkJpaConfiguration.class) +public class ReplaceOrmProviderDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(ReplaceOrmProviderDemoApplication.class, args); + } + +} diff --git a/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/config/EclipseLinkJpaConfiguration.java b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/config/EclipseLinkJpaConfiguration.java new file mode 100644 index 00000000..6e14ede9 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/config/EclipseLinkJpaConfiguration.java @@ -0,0 +1,37 @@ +package ru.otus.example.replaceormproviderdemo.config; + +import org.eclipse.persistence.config.PersistenceUnitProperties; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; +import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; +import org.springframework.context.annotation.Configuration; +import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter; +import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter; +import org.springframework.transaction.jta.JtaTransactionManager; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.Map; + +@Configuration +public class EclipseLinkJpaConfiguration extends JpaBaseConfiguration { + @Autowired + protected EclipseLinkJpaConfiguration(DataSource dataSource, JpaProperties properties, + ObjectProvider jtaTransactionManager) { + super(dataSource, properties, jtaTransactionManager); + } + + @Override + protected AbstractJpaVendorAdapter createJpaVendorAdapter() { + return new EclipseLinkJpaVendorAdapter(); + } + + @Override + protected Map getVendorProperties() { + HashMap map = new HashMap<>(); + map.put(PersistenceUnitProperties.WEAVING, "false"); + return map; + } +} diff --git a/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/models/Avatar.java b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/models/Avatar.java new file mode 100644 index 00000000..1a619456 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/models/Avatar.java @@ -0,0 +1,21 @@ +package ru.otus.example.replaceormproviderdemo.models; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "avatars") +public class Avatar { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column(name = "photo_url", nullable = false, unique = true) + private String photoUrl; +} diff --git a/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/models/Course.java b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/models/Course.java new file mode 100644 index 00000000..caecc0c5 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/models/Course.java @@ -0,0 +1,21 @@ +package ru.otus.example.replaceormproviderdemo.models; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "courses") +public class Course { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column(name = "name", nullable = false, unique = true) + private String name; +} diff --git a/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/models/EMail.java b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/models/EMail.java new file mode 100644 index 00000000..8c69afe8 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/models/EMail.java @@ -0,0 +1,22 @@ +package ru.otus.example.replaceormproviderdemo.models; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "emails") +public class EMail { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column(name = "email", nullable = false, unique = true) + private String email; +} diff --git a/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/models/OtusStudent.java b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/models/OtusStudent.java new file mode 100644 index 00000000..534d051e --- /dev/null +++ b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/models/OtusStudent.java @@ -0,0 +1,42 @@ +package ru.otus.example.replaceormproviderdemo.models; + +import lombok.*; +import org.eclipse.persistence.annotations.BatchFetch; +import org.eclipse.persistence.annotations.BatchFetchType; + +import javax.persistence.*; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity // Указывает, что данный класс является сущностью +@Table(name = "otus_students") // Задает имя таблицы, на которую будет отображаться сущность +public class OtusStudent { + @Id // Позволяет указать какое поле является идентификатором + @GeneratedValue(strategy = GenerationType.IDENTITY) // Стратегия генерации идентификаторов + private long id; + + // Задает имя и некоторые свойства поля таблицы, на которое будет отображаться поле сущности + @Column(name = "name", nullable = false, unique = true) + private String name; + + // Указывает на связь между таблицами "один к одному" + @OneToOne(targetEntity = Avatar.class, cascade = CascadeType.ALL) + // Задает поле, по которому происходит объединение с таблицей для хранения связанной сущности + @JoinColumn(name = "avatar_id") + private Avatar avatar; + + // Указывает на связь между таблицами "один ко многим" + @OneToMany(targetEntity = EMail.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER) + @JoinColumn(name = "student_id") + private List emails; + + // Указывает на связь между таблицами "многие ко многим" + @BatchFetch(value = BatchFetchType.IN) + @ManyToMany(targetEntity = Course.class, cascade = CascadeType.ALL, fetch = FetchType.LAZY) + // Задает таблицу связей между таблицами для хранения родительской и связанной сущностью + @JoinTable(name = "student_courses", joinColumns = @JoinColumn(name = "student_id"), + inverseJoinColumns = @JoinColumn(name = "course_id")) + private List courses; +} diff --git a/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/repositories/OtusStudentRepositoryJpa.java b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/repositories/OtusStudentRepositoryJpa.java new file mode 100644 index 00000000..ed2eaf3d --- /dev/null +++ b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/repositories/OtusStudentRepositoryJpa.java @@ -0,0 +1,17 @@ +package ru.otus.example.replaceormproviderdemo.repositories; + + +import ru.otus.example.replaceormproviderdemo.models.OtusStudent; + +import java.util.List; +import java.util.Optional; + +public interface OtusStudentRepositoryJpa { + Optional findById(long id); + List findAll(); + + List findAllWithJoinFetch(); + + OtusStudent save(OtusStudent student); + +} diff --git a/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/repositories/OtusStudentRepositoryJpaImpl.java b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/repositories/OtusStudentRepositoryJpaImpl.java new file mode 100644 index 00000000..196c40a4 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/java/ru/otus/example/replaceormproviderdemo/repositories/OtusStudentRepositoryJpaImpl.java @@ -0,0 +1,49 @@ +package ru.otus.example.replaceormproviderdemo.repositories; + +import org.eclipse.persistence.config.QueryHints; +import org.springframework.stereotype.Repository; +import ru.otus.example.replaceormproviderdemo.models.OtusStudent; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.TypedQuery; +import java.util.List; +import java.util.Optional; + +@Repository +public class OtusStudentRepositoryJpaImpl implements OtusStudentRepositoryJpa { + + private static final int DEFAULT_BATCH_SIZE = 5; + + @PersistenceContext + private EntityManager em; + + @Override + public Optional findById(long id) { + return Optional.ofNullable(em.find(OtusStudent.class, id)); + } + + @Override + public List findAll() { + return em.createQuery("select s from OtusStudent s", OtusStudent.class).getResultList(); + } + + @Override + public List findAllWithJoinFetch() { + TypedQuery query = em.createQuery("select distinct s from OtusStudent s join fetch s.avatar join fetch s.emails", OtusStudent.class); + query.setHint(QueryHints.BATCH_SIZE, DEFAULT_BATCH_SIZE); + return query.getResultList(); + } + + + @Override + public OtusStudent save(OtusStudent student) { + if (student.getId() <= 0) { + em.persist(student); + //em.flush(); + return student; + } else { + return em.merge(student); + } + } +} diff --git a/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/resources/schema.sql b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/resources/schema.sql new file mode 100644 index 00000000..43a684bb --- /dev/null +++ b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/main/resources/schema.sql @@ -0,0 +1,31 @@ +create table avatars( + id bigserial, + photo_url varchar(8000), + primary key (id) +); + +create table courses( + id bigserial, + name varchar(255), + primary key (id) +); + +create table otus_students( + id bigserial, + name varchar(255), + avatar_id bigint references avatars (id), + primary key (id) +); + +create table emails( + id bigserial, + student_id bigint references otus_students(id) on delete cascade, + email varchar(255), + primary key (id) +); + +create table student_courses( + student_id bigint references otus_students(id) on delete cascade, + course_id bigint references courses(id), + primary key (student_id, course_id) +); \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/test/java/ru/otus/example/replaceormproviderdemo/repositories/OtusStudentRepositoryJpaImplTest.java b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/test/java/ru/otus/example/replaceormproviderdemo/repositories/OtusStudentRepositoryJpaImplTest.java new file mode 100644 index 00000000..2f9b2c1e --- /dev/null +++ b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/test/java/ru/otus/example/replaceormproviderdemo/repositories/OtusStudentRepositoryJpaImplTest.java @@ -0,0 +1,94 @@ +package ru.otus.example.replaceormproviderdemo.repositories; + +import lombok.val; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.context.annotation.Import; +import ru.otus.example.replaceormproviderdemo.models.OtusStudent; +import ru.otus.example.replaceormproviderdemo.models.Avatar; +import ru.otus.example.replaceormproviderdemo.models.Course; +import ru.otus.example.replaceormproviderdemo.models.EMail; + +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@DisplayName("Репозиторий на основе Jpa для работы со студентами ") +@DataJpaTest +@Import({OtusStudentRepositoryJpaImpl.class}) +class OtusStudentRepositoryJpaImplTest { + + private static final int EXPECTED_NUMBER_OF_STUDENTS = 10; + private static final long FIRST_STUDENT_ID = 1L; + + private static final String STUDENT_AVATAR_URL = "где-то там"; + private static final String STUDENT_EMAIL = "any@mail.com"; + private static final String COURSE_NAME = "Spring"; + private static final String STUDENT_NAME = "Вася"; + + @Autowired + private OtusStudentRepositoryJpaImpl repositoryJpa; + + @Autowired + private TestEntityManager em; + + @DisplayName(" должен загружать информацию о нужном студенте") + @Test + void shouldFindExpectedStudentById() { + val optionalActualStudent = repositoryJpa.findById(FIRST_STUDENT_ID); + val expectedStudent = em.find(OtusStudent.class, FIRST_STUDENT_ID); + assertThat(optionalActualStudent).isPresent().get() + .isEqualToComparingFieldByField(expectedStudent); + } + + @DisplayName("должен загружать список всех студентов с полной информацией о них") + @Test + void shouldReturnCorrectStudentsListWithAllInfo() { + System.out.println("\n\n\n\n----------------------------------------------------------------------------------------------------------"); + val students = repositoryJpa.findAll(); + assertThat(students).isNotNull().hasSize(EXPECTED_NUMBER_OF_STUDENTS) + .allMatch(s -> !s.getName().equals("")) + .allMatch(s -> s.getCourses() != null && s.getCourses().size() > 0) + .allMatch(s -> s.getAvatar() != null) + .allMatch(s -> s.getEmails() != null && s.getEmails().size() > 0); + System.out.println("----------------------------------------------------------------------------------------------------------\n\n\n\n"); + } + + @DisplayName(" с помощью 'join fetch' должен загружать список всех студентов с полной информацией о них") + @Test + void usingJoinFetchShouldReturnCorrectStudentsListWithWithAllInfo() { + System.out.println("\n\n\n\n----------------------------------------------------------------------------------------------------------"); + List students = repositoryJpa.findAllWithJoinFetch(); + assertThat(students).isNotNull().hasSize(EXPECTED_NUMBER_OF_STUDENTS) + .allMatch(s -> !s.getName().equals("")) + .allMatch(s -> s.getCourses() != null && s.getCourses().size() > 0) + .allMatch(s -> s.getAvatar() != null) + .allMatch(s -> s.getEmails() != null && s.getEmails().size() > 0); + System.out.println("----------------------------------------------------------------------------------------------------------\n\n\n\n"); + } + + + @DisplayName(" должен корректно сохранять всю информацию о студенте") + @Test + void shouldSaveAllStudentInfo() { + val avatar = new Avatar(0, STUDENT_AVATAR_URL); + val email = new EMail(0, STUDENT_EMAIL); + val emails = Collections.singletonList(email); + + val course = new Course(0, COURSE_NAME); + val courses = Collections.singletonList(course); + val vasya = new OtusStudent(0, STUDENT_NAME, avatar, emails, courses); + repositoryJpa.save(vasya); + assertThat(vasya.getId()).isGreaterThan(0); + + val actualStudent = em.find(OtusStudent.class, vasya.getId()); + assertThat(actualStudent).isNotNull().matches(s -> !s.getName().equals("")) + .matches(s -> s.getCourses() != null && s.getCourses().size() > 0 && s.getCourses().get(0).getId() > 0) + .matches(s -> s.getAvatar() != null) + .matches(s -> s.getEmails() != null && s.getEmails().size() > 0); + } +} \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/test/resources/application.yml b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/test/resources/application.yml new file mode 100644 index 00000000..b98cd926 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/test/resources/application.yml @@ -0,0 +1,18 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + initialization-mode: always + + jpa: + show-sql: false + generate-ddl: false + #generate-ddl: true + hibernate: + ddl-auto: none + #ddl-auto: create-drop + + #show-sql: true + +logging: + level: + ROOT: ERROR \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/test/resources/data.sql b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/test/resources/data.sql new file mode 100644 index 00000000..a8db6b85 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/replace-orm-provider-demo/src/test/resources/data.sql @@ -0,0 +1,29 @@ +insert into avatars(photo_url) +values ('photoUrl_01'), ('photoUrl_02'), ('photoUrl_03'), ('photoUrl_04'), ('photoUrl_05'), + ('photoUrl_06'), ('photoUrl_07'), ('photoUrl_08'), ('photoUrl_09'), ('photoUrl_10'); + +insert into courses(name) +values ('course_name_01'), ('course_name_02'), ('course_name_03'), ('course_name_04'), ('course_name_05'), + ('course_name_06'), ('course_name_07'), ('course_name_08'), ('course_name_09'), ('course_name_10'), ('not_used_11'); + +insert into otus_students(name, avatar_id) +values ('student_01', 1), ('student_02', 2), ('student_03', 3), ('student_04', 4), ('student_05', 5), + ('student_06', 6), ('student_07', 7), ('student_08', 8), ('student_09', 9), ('student_10', 10); + + +insert into emails(email, student_id) +values ('email_01', 1), ('email_02', 1), ('email_03', 2), ('email_04', 2), ('email_05', 3), ('email_06', 4), + ('email_07', 5), ('email_08', 6), ('email_09', 7), ('email_10', 8), ('email_11', 9), ('email_12', 10); + + +insert into student_courses(student_id, course_id) +values (1, 1), (1, 2), (1, 3), + (2, 2), (2, 4), (2, 5), + (3, 3), (3, 6), (3, 7), + (4, 4), (4, 8), (4, 9), + (5, 5), (5, 10), (5, 1), + (6, 6), (6, 2), (6, 3), + (7, 7), (7, 4), (7, 5), + (8, 8), (8, 6), (8, 7), + (9, 9), (9, 8), (9, 10), + (10, 10), (10, 1), (10, 2); diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/.gitignore b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/.gitignore new file mode 100644 index 00000000..153c9335 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/.gitignore @@ -0,0 +1,29 @@ +HELP.md +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +/build/ + +### VS Code ### +.vscode/ diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/README.md b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/README.md new file mode 100644 index 00000000..462216c3 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/README.md @@ -0,0 +1,2 @@ +# spring-jdbc-demo +Пример работы с БД через jdbc \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/pom.xml b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/pom.xml new file mode 100644 index 00000000..3d503565 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.1.RELEASE + + + ru.otus.example + spring-jdbc-demo + 0.0.1-SNAPSHOT + spring-jdbc-demo + Spring jdbc demo + + + 11 + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + com.h2database + h2 + runtime + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test + + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/SpringJdbcDemoApplication.java b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/SpringJdbcDemoApplication.java new file mode 100644 index 00000000..28ebfec4 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/SpringJdbcDemoApplication.java @@ -0,0 +1,13 @@ +package ru.otus.example.springjdbcdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringJdbcDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringJdbcDemoApplication.class, args); + } + +} diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/models/Avatar.java b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/models/Avatar.java new file mode 100644 index 00000000..a1963ea4 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/models/Avatar.java @@ -0,0 +1,13 @@ +package ru.otus.example.springjdbcdemo.models; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Avatar { + private long id; + private String photoUrl; +} diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/models/Course.java b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/models/Course.java new file mode 100644 index 00000000..07b6e2c2 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/models/Course.java @@ -0,0 +1,13 @@ +package ru.otus.example.springjdbcdemo.models; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Course { + private long id; + private String name; +} diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/models/EMail.java b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/models/EMail.java new file mode 100644 index 00000000..16985ad5 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/models/EMail.java @@ -0,0 +1,13 @@ +package ru.otus.example.springjdbcdemo.models; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class EMail { + private long id; + private String email; +} diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/models/OtusStudent.java b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/models/OtusStudent.java new file mode 100644 index 00000000..5ae9167c --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/models/OtusStudent.java @@ -0,0 +1,18 @@ +package ru.otus.example.springjdbcdemo.models; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class OtusStudent { + private long id; + private String name; + private Avatar avatar; + private List emails; + private List courses; +} diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/CourseRepositoryJdbc.java b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/CourseRepositoryJdbc.java new file mode 100644 index 00000000..716ab880 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/CourseRepositoryJdbc.java @@ -0,0 +1,9 @@ +package ru.otus.example.springjdbcdemo.repositories; + +import ru.otus.example.springjdbcdemo.models.Course; + +import java.util.List; + +public interface CourseRepositoryJdbc { + List findAllUsed(); +} diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/CourseRepositoryJdbcImpl.java b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/CourseRepositoryJdbcImpl.java new file mode 100644 index 00000000..aedb3ad5 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/CourseRepositoryJdbcImpl.java @@ -0,0 +1,36 @@ +package ru.otus.example.springjdbcdemo.repositories; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Repository; +import ru.otus.example.springjdbcdemo.models.Course; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class CourseRepositoryJdbcImpl implements CourseRepositoryJdbc { + + @Autowired + private final JdbcOperations op; + + @Override + public List findAllUsed() { + return op.query("select c.id, c.name " + + "from courses c inner join student_courses sc on c.id = sc.course_id " + + "group by c.id, c.name " + + "order by c.name", new CourseRowMapper()); + } + + private class CourseRowMapper implements RowMapper { + @Override + public Course mapRow(ResultSet rs, int i) throws SQLException { + return new Course(rs.getLong(1), rs.getString(2)); + } + } + +} diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/OtusStudentRepositoryJdbc.java b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/OtusStudentRepositoryJdbc.java new file mode 100644 index 00000000..0761373d --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/OtusStudentRepositoryJdbc.java @@ -0,0 +1,9 @@ +package ru.otus.example.springjdbcdemo.repositories; + +import ru.otus.example.springjdbcdemo.models.OtusStudent; + +import java.util.List; + +public interface OtusStudentRepositoryJdbc { + List findAllWithAllInfo(); +} diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/OtusStudentRepositoryJdbcImpl.java b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/OtusStudentRepositoryJdbcImpl.java new file mode 100644 index 00000000..05208672 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/OtusStudentRepositoryJdbcImpl.java @@ -0,0 +1,49 @@ +package ru.otus.example.springjdbcdemo.repositories; + +import lombok.RequiredArgsConstructor; +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.stereotype.Repository; +import ru.otus.example.springjdbcdemo.models.Course; +import ru.otus.example.springjdbcdemo.models.OtusStudent; +import ru.otus.example.springjdbcdemo.repositories.ext.OtusStudentResultSetExtractor; +import ru.otus.example.springjdbcdemo.repositories.ext.StudentCourseRelation; + +import java.util.*; +import java.util.stream.Collectors; + +@Repository +@RequiredArgsConstructor +public class OtusStudentRepositoryJdbcImpl implements OtusStudentRepositoryJdbc { + + private final CourseRepositoryJdbc courseRepository; + private final JdbcOperations op; + + @Override + public List findAllWithAllInfo() { + List courses = courseRepository.findAllUsed(); + List relations = getAllRelations(); + Map students = op.query("select os.id, os.name, a.id avatar_id, a.photo_url, e.id email_id, e.email " + + "from (otus_students os left join avatars a on " + + "os.avatar_id = a.id) left join emails e on os.id = e.student_id", + new OtusStudentResultSetExtractor()); + + mergeStudentsInfo(students, courses, relations); + return new ArrayList<>(Objects.requireNonNull(students).values()); + } + + private List getAllRelations() { + return op.query("select student_id, course_id from student_courses sc order by student_id, course_id", + (rs, i) -> new StudentCourseRelation(rs.getLong(1), rs.getLong(2))); + } + + private void mergeStudentsInfo(Map students, List courses, List relations) { + Map coursesMap = courses.stream().collect(Collectors.toMap(Course::getId, c -> c)); + relations.forEach(r -> { + if (students.containsKey(r.getStudentId()) && coursesMap.containsKey(r.getCourseId())) { + students.get(r.getStudentId()).getCourses().add(coursesMap.get(r.getCourseId())); + } + }); + } + + +} diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/ext/OtusStudentResultSetExtractor.java b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/ext/OtusStudentResultSetExtractor.java new file mode 100644 index 00000000..778a46b7 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/ext/OtusStudentResultSetExtractor.java @@ -0,0 +1,37 @@ +package ru.otus.example.springjdbcdemo.repositories.ext; + +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import ru.otus.example.springjdbcdemo.models.Avatar; +import ru.otus.example.springjdbcdemo.models.EMail; +import ru.otus.example.springjdbcdemo.models.OtusStudent; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +public class OtusStudentResultSetExtractor implements + ResultSetExtractor> { + @Override + public Map extractData(ResultSet rs) throws SQLException, + DataAccessException { + + Map students = new HashMap<>(); + while (rs.next()) { + long id = rs.getLong("id"); + OtusStudent student = students.get(id); + if (student == null) { + student = new OtusStudent(id, rs.getString("name"), + new Avatar(rs.getLong("avatar_id"), rs.getString("photo_url")), + new ArrayList<>(), new ArrayList<>()); + students.put(student.getId(), student); + } + + student.getEmails().add(new EMail(rs.getLong("email_id"), + rs.getString("email"))); + } + return students; + } +} diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/ext/StudentCourseRelation.java b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/ext/StudentCourseRelation.java new file mode 100644 index 00000000..408c97d2 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/java/ru/otus/example/springjdbcdemo/repositories/ext/StudentCourseRelation.java @@ -0,0 +1,11 @@ +package ru.otus.example.springjdbcdemo.repositories.ext; + +import lombok.Data; +import lombok.RequiredArgsConstructor; + +@Data +@RequiredArgsConstructor +public class StudentCourseRelation { + private final long studentId; + private final long courseId; +} diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/resources/schema.sql b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/resources/schema.sql new file mode 100644 index 00000000..43a684bb --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/main/resources/schema.sql @@ -0,0 +1,31 @@ +create table avatars( + id bigserial, + photo_url varchar(8000), + primary key (id) +); + +create table courses( + id bigserial, + name varchar(255), + primary key (id) +); + +create table otus_students( + id bigserial, + name varchar(255), + avatar_id bigint references avatars (id), + primary key (id) +); + +create table emails( + id bigserial, + student_id bigint references otus_students(id) on delete cascade, + email varchar(255), + primary key (id) +); + +create table student_courses( + student_id bigint references otus_students(id) on delete cascade, + course_id bigint references courses(id), + primary key (student_id, course_id) +); \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/test/java/ru/otus/example/springjdbcdemo/repositories/OtusStudentRepositoryJdbcImplTest.java b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/test/java/ru/otus/example/springjdbcdemo/repositories/OtusStudentRepositoryJdbcImplTest.java new file mode 100644 index 00000000..09ab23f9 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/test/java/ru/otus/example/springjdbcdemo/repositories/OtusStudentRepositoryJdbcImplTest.java @@ -0,0 +1,34 @@ +package ru.otus.example.springjdbcdemo.repositories; + +import lombok.val; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; +import org.springframework.context.annotation.Import; + + +import static org.assertj.core.api.Assertions.assertThat; + +@DisplayName("Репозиторий на основе Jdbc для работы со студентами ") +@JdbcTest +@Import({OtusStudentRepositoryJdbcImpl.class, CourseRepositoryJdbcImpl.class}) +class OtusStudentRepositoryJdbcImplTest { + + private static final int EXPECTED_NUMBER_OF_STUDENTS = 10; + + @Autowired + private OtusStudentRepositoryJdbcImpl repositoryJdbc; + + @DisplayName("должен загружать список всех студентов с полной информацией о них") + @Test + void shouldReturnCorrectStudentsListWithAllInfo() { + val students = repositoryJdbc.findAllWithAllInfo(); + assertThat(students).isNotNull().hasSize(EXPECTED_NUMBER_OF_STUDENTS) + .allMatch(s -> !s.getName().equals("")) + .allMatch(s -> s.getCourses() != null && s.getCourses().size() > 0) + .allMatch(s -> s.getAvatar() != null) + .allMatch(s -> s.getEmails() != null && s.getEmails().size() > 0); + + } +} \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/test/resources/application.yml b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/test/resources/application.yml new file mode 100644 index 00000000..a91bdbba --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/test/resources/application.yml @@ -0,0 +1,18 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + initialization-mode: always + + jpa: + generate-ddl: false + #generate-ddl: true + hibernate: + ddl-auto: none + #ddl-auto: create-drop + + show-sql: true + + +logging: + level: + ru.otus.example.ormbasicsdemo.repositories.mybatis: TRACE \ No newline at end of file diff --git a/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/test/resources/data.sql b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/test/resources/data.sql new file mode 100644 index 00000000..a8db6b85 --- /dev/null +++ b/2019-11/spring-08/orm-class-work/spring-jdbc-demo/src/test/resources/data.sql @@ -0,0 +1,29 @@ +insert into avatars(photo_url) +values ('photoUrl_01'), ('photoUrl_02'), ('photoUrl_03'), ('photoUrl_04'), ('photoUrl_05'), + ('photoUrl_06'), ('photoUrl_07'), ('photoUrl_08'), ('photoUrl_09'), ('photoUrl_10'); + +insert into courses(name) +values ('course_name_01'), ('course_name_02'), ('course_name_03'), ('course_name_04'), ('course_name_05'), + ('course_name_06'), ('course_name_07'), ('course_name_08'), ('course_name_09'), ('course_name_10'), ('not_used_11'); + +insert into otus_students(name, avatar_id) +values ('student_01', 1), ('student_02', 2), ('student_03', 3), ('student_04', 4), ('student_05', 5), + ('student_06', 6), ('student_07', 7), ('student_08', 8), ('student_09', 9), ('student_10', 10); + + +insert into emails(email, student_id) +values ('email_01', 1), ('email_02', 1), ('email_03', 2), ('email_04', 2), ('email_05', 3), ('email_06', 4), + ('email_07', 5), ('email_08', 6), ('email_09', 7), ('email_10', 8), ('email_11', 9), ('email_12', 10); + + +insert into student_courses(student_id, course_id) +values (1, 1), (1, 2), (1, 3), + (2, 2), (2, 4), (2, 5), + (3, 3), (3, 6), (3, 7), + (4, 4), (4, 8), (4, 9), + (5, 5), (5, 10), (5, 1), + (6, 6), (6, 2), (6, 3), + (7, 7), (7, 4), (7, 5), + (8, 8), (8, 6), (8, 7), + (9, 9), (9, 8), (9, 10), + (10, 10), (10, 1), (10, 2); diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/.gitignore b/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/pom.xml b/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/pom.xml new file mode 100644 index 00000000..8913efa2 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + ru.otus + jpql-demo-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-starter-data-jpa + + + com.h2database + h2 + + + + org.springframework.boot + spring-boot-starter-test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/src/main/java/ru/otus/spring/Main.java b/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..2b71abac --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,23 @@ +package ru.otus.spring; + +import org.h2.tools.Console; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.domain.Person; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) throws Exception { + + ApplicationContext context = SpringApplication.run(Main.class); + PersonRepository repository = context.getBean(PersonRepository.class); + + Person nullPerson = repository.getById(1); + System.out.println(nullPerson); + + Console.main(args); + } +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/src/main/java/ru/otus/spring/domain/Person.java b/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..5393049e --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,45 @@ +package ru.otus.spring.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Person { + + @Id + @GeneratedValue + private long id; + private String name; + + public Person() { + } + + public Person(String name) { + 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; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", name='" + name + '\'' + + '}'; + } +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..6d7188cc --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,18 @@ +package ru.otus.spring.repostory; + +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository { + + //void insert(Person p); + + Person getById(long id); + + //Person getFirst(); + + //List getAll(); + + //Person getByName(String name); +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/src/main/java/ru/otus/spring/repostory/PersonRepositoryJpa.java b/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/src/main/java/ru/otus/spring/repostory/PersonRepositoryJpa.java new file mode 100644 index 00000000..e66b6e62 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-exercise/src/main/java/ru/otus/spring/repostory/PersonRepositoryJpa.java @@ -0,0 +1,24 @@ +package ru.otus.spring.repostory; + +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; +import ru.otus.spring.domain.Person; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.TypedQuery; +import java.util.List; + +@SuppressWarnings("JpaQlInspection") +@Repository +@Transactional +public class PersonRepositoryJpa implements PersonRepository { + + @PersistenceContext + private EntityManager em; + + @Override + public Person getById(long id) { + return em.find(Person.class, id); + } +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/.gitignore b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/pom.xml b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/pom.xml new file mode 100644 index 00000000..a03a55c4 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + ru.otus + jpql-demo-solution-step-1 + 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-starter-data-jpa + + + com.h2database + h2 + + + + org.springframework.boot + spring-boot-starter-test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/src/main/java/ru/otus/spring/Main.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..4eb671d7 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,24 @@ +package ru.otus.spring; + +import org.h2.tools.Console; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.domain.Person; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) throws Exception { + + ApplicationContext context = SpringApplication.run(Main.class); + PersonRepository repository = context.getBean(PersonRepository.class); + + repository.insert(new Person("Вася")); + Person vasya = repository.getById(1); + System.out.println(vasya); + + Console.main(args); + } +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/src/main/java/ru/otus/spring/domain/Person.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..5af7b810 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,46 @@ +package ru.otus.spring.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Person { + + @Id + @GeneratedValue + private long id; + private String name; + + public Person() { + } + + public Person(String name) { + 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; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", name='" + name + '\'' + + '}'; + } + +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..3a890f95 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,18 @@ +package ru.otus.spring.repostory; + +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository { + + void insert(Person p); + + Person getById(long id); + + //Person getFirst(); + + //List getAll(); + + //Person getByName(String name); +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/src/main/java/ru/otus/spring/repostory/PersonRepositoryJpa.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/src/main/java/ru/otus/spring/repostory/PersonRepositoryJpa.java new file mode 100644 index 00000000..6cd0f2ce --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-1/src/main/java/ru/otus/spring/repostory/PersonRepositoryJpa.java @@ -0,0 +1,29 @@ +package ru.otus.spring.repostory; + +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; +import ru.otus.spring.domain.Person; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.TypedQuery; +import java.util.List; + +@SuppressWarnings("JpaQlInspection") +@Repository +@Transactional +public class PersonRepositoryJpa implements PersonRepository { + + @PersistenceContext + private EntityManager em; + + @Override + public void insert(Person p) { + em.persist(p); + } + + @Override + public Person getById(long id) { + return em.find(Person.class, id); + } +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/.gitignore b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/pom.xml b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/pom.xml new file mode 100644 index 00000000..bd8de534 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + ru.otus + jpql-demo-solution-step-2 + 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-starter-data-jpa + + + com.h2database + h2 + + + + org.springframework.boot + spring-boot-starter-test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/src/main/java/ru/otus/spring/Main.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..d6ca73f3 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,31 @@ +package ru.otus.spring; + +import org.h2.tools.Console; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) throws Exception { + + ApplicationContext context = SpringApplication.run(Main.class); + PersonRepository repository = context.getBean(PersonRepository.class); + + repository.insert(new Person("Вася")); + repository.insert(new Person("Юля")); + Person vasya = repository.getFirst(); + System.out.println(vasya); + + List vasyaAndJulia = repository.getAll(); + System.out.println(vasyaAndJulia); + + + Console.main(args); + } +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/src/main/java/ru/otus/spring/domain/Person.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..5af7b810 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,46 @@ +package ru.otus.spring.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Person { + + @Id + @GeneratedValue + private long id; + private String name; + + public Person() { + } + + public Person(String name) { + 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; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", name='" + name + '\'' + + '}'; + } + +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..7a7dc11c --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,18 @@ +package ru.otus.spring.repostory; + +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository { + + void insert(Person p); + + Person getById(long id); + + Person getFirst(); + + List getAll(); + + //Person getByName(String name); +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/src/main/java/ru/otus/spring/repostory/PersonRepositoryJpa.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/src/main/java/ru/otus/spring/repostory/PersonRepositoryJpa.java new file mode 100644 index 00000000..1c5db78d --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-2/src/main/java/ru/otus/spring/repostory/PersonRepositoryJpa.java @@ -0,0 +1,45 @@ +package ru.otus.spring.repostory; + +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; +import ru.otus.spring.domain.Person; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.TypedQuery; +import java.util.List; + +@SuppressWarnings("JpaQlInspection") +@Repository +@Transactional +public class PersonRepositoryJpa implements PersonRepository { + + @PersistenceContext + private EntityManager em; + + @Override + public void insert(Person p) { + em.persist(p); + } + + @Override + public Person getById(long id) { + return em.find(Person.class, id); + } + + @Override + public Person getFirst() { + TypedQuery query = em.createQuery( + "select p from Person p where p.id = 1", + Person.class); + return query.getSingleResult(); + } + + @Override + public List getAll() { + TypedQuery query = em.createQuery( + "select p from Person p", + Person.class); + return query.getResultList(); + } +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/.gitignore b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/pom.xml b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/pom.xml new file mode 100644 index 00000000..3a8973e5 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + ru.otus + jpql-demo-solution-step-3 + 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-starter-data-jpa + + + com.h2database + h2 + + + + org.springframework.boot + spring-boot-starter-test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/src/main/java/ru/otus/spring/Main.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..3e498e43 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,27 @@ +package ru.otus.spring; + +import org.h2.tools.Console; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.domain.Person; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) throws Exception { + + ApplicationContext context = SpringApplication.run(Main.class); + PersonRepository repository = context.getBean(PersonRepository.class); + + Person julia = new Person("Юля"); + repository.insert(julia); + Person juliaFromDB = repository.getByName(julia.getName()); + System.out.println(juliaFromDB); + + + + Console.main(args); + } +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/src/main/java/ru/otus/spring/domain/Person.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..5af7b810 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,46 @@ +package ru.otus.spring.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Person { + + @Id + @GeneratedValue + private long id; + private String name; + + public Person() { + } + + public Person(String name) { + 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; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", name='" + name + '\'' + + '}'; + } + +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..d3ac6371 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,18 @@ +package ru.otus.spring.repostory; + +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository { + + void insert(Person p); + + Person getById(long id); + + Person getFirst(); + + List getAll(); + + Person getByName(String name); +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/src/main/java/ru/otus/spring/repostory/PersonRepositoryJpa.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/src/main/java/ru/otus/spring/repostory/PersonRepositoryJpa.java new file mode 100644 index 00000000..46990ebe --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-3/src/main/java/ru/otus/spring/repostory/PersonRepositoryJpa.java @@ -0,0 +1,54 @@ +package ru.otus.spring.repostory; + +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; +import ru.otus.spring.domain.Person; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.TypedQuery; +import java.util.List; + +@SuppressWarnings("JpaQlInspection") +@Repository +@Transactional +public class PersonRepositoryJpa implements PersonRepository { + + @PersistenceContext + private EntityManager em; + + @Override + public void insert(Person p) { + em.persist(p); + } + + @Override + public Person getById(long id) { + return em.find(Person.class, id); + } + + @Override + public Person getFirst() { + TypedQuery query = em.createQuery( + "select p from Person p where p.id = 1", + Person.class); + return query.getSingleResult(); + } + + @Override + public List getAll() { + TypedQuery query = em.createQuery( + "select p from Person p", + Person.class); + return query.getResultList(); + } + + @Override + public Person getByName(String name) { + TypedQuery query = em.createQuery( + "select p from Person p where p.name = :name", + Person.class); + query.setParameter("name", name); + return query.getSingleResult(); + } +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/.gitignore b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/pom.xml b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/pom.xml new file mode 100644 index 00000000..1d55a432 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + ru.otus + jpql-demo-solution-step-final + 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-starter-data-jpa + + + + com.h2database + h2 + + + + org.springframework.boot + spring-boot-starter-test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/src/main/java/ru/otus/spring/Main.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..b97f0345 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,22 @@ +package ru.otus.spring; + +import org.h2.tools.Console; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.domain.Person; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) throws Exception { + + ApplicationContext context = SpringApplication.run(Main.class); + PersonRepository repository = context.getBean(PersonRepository.class); + + Person nullPerson = repository.getById(1); + + Console.main(args); + } +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/src/main/java/ru/otus/spring/domain/Person.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..5af7b810 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,46 @@ +package ru.otus.spring.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Person { + + @Id + @GeneratedValue + private long id; + private String name; + + public Person() { + } + + public Person(String name) { + 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; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", name='" + name + '\'' + + '}'; + } + +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..d3ac6371 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,18 @@ +package ru.otus.spring.repostory; + +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository { + + void insert(Person p); + + Person getById(long id); + + Person getFirst(); + + List getAll(); + + Person getByName(String name); +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/src/main/java/ru/otus/spring/repostory/PersonRepositoryJpa.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/src/main/java/ru/otus/spring/repostory/PersonRepositoryJpa.java new file mode 100644 index 00000000..46990ebe --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/src/main/java/ru/otus/spring/repostory/PersonRepositoryJpa.java @@ -0,0 +1,54 @@ +package ru.otus.spring.repostory; + +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; +import ru.otus.spring.domain.Person; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.TypedQuery; +import java.util.List; + +@SuppressWarnings("JpaQlInspection") +@Repository +@Transactional +public class PersonRepositoryJpa implements PersonRepository { + + @PersistenceContext + private EntityManager em; + + @Override + public void insert(Person p) { + em.persist(p); + } + + @Override + public Person getById(long id) { + return em.find(Person.class, id); + } + + @Override + public Person getFirst() { + TypedQuery query = em.createQuery( + "select p from Person p where p.id = 1", + Person.class); + return query.getSingleResult(); + } + + @Override + public List getAll() { + TypedQuery query = em.createQuery( + "select p from Person p", + Person.class); + return query.getResultList(); + } + + @Override + public Person getByName(String name) { + TypedQuery query = em.createQuery( + "select p from Person p where p.name = :name", + Person.class); + query.setParameter("name", name); + return query.getSingleResult(); + } +} diff --git a/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/src/test/java/ru/otus/spring/domain/PersonTest.java b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/src/test/java/ru/otus/spring/domain/PersonTest.java new file mode 100644 index 00000000..9c646520 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/jpql-demo-solution-step-final/src/test/java/ru/otus/spring/domain/PersonTest.java @@ -0,0 +1,23 @@ +package ru.otus.spring.domain; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +public class PersonTest { + + @Autowired + private TestEntityManager em; + + @Test + public void saveAndGet() { + Person person = new Person("Ivan"); + Person fromDb = em.persistAndFlush(person); + assertThat(fromDb.getId()).isNotZero(); + assertThat(fromDb.getName()).isEqualTo(person.getName()); + } +} diff --git a/2019-11/spring-09/jpql-class-work/pom.xml b/2019-11/spring-09/jpql-class-work/pom.xml new file mode 100644 index 00000000..6e46f913 --- /dev/null +++ b/2019-11/spring-09/jpql-class-work/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + ru.otus + jpql-class-work + 1.0 + + pom + + + jpql-demo-exercise + jpql-demo-solution-step-1 + jpql-demo-solution-step-2 + jpql-demo-solution-step-3 + jpql-demo-solution-step-4 + jpql-demo-solution-step-final + + diff --git a/2019-11/spring-09/jpql-demo/.gitignore b/2019-11/spring-09/jpql-demo/.gitignore new file mode 100644 index 00000000..153c9335 --- /dev/null +++ b/2019-11/spring-09/jpql-demo/.gitignore @@ -0,0 +1,29 @@ +HELP.md +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +/build/ + +### VS Code ### +.vscode/ diff --git a/examples/jpql-demo/README.md b/2019-11/spring-09/jpql-demo/README.md similarity index 100% rename from examples/jpql-demo/README.md rename to 2019-11/spring-09/jpql-demo/README.md diff --git a/examples/jpql-demo/pom.xml b/2019-11/spring-09/jpql-demo/pom.xml similarity index 100% rename from examples/jpql-demo/pom.xml rename to 2019-11/spring-09/jpql-demo/pom.xml diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/JpqlDemoApplication.java b/2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/JpqlDemoApplication.java similarity index 100% rename from examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/JpqlDemoApplication.java rename to 2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/JpqlDemoApplication.java diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/dto/CitySalary.java b/2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/dto/CitySalary.java similarity index 100% rename from examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/dto/CitySalary.java rename to 2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/dto/CitySalary.java diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/dto/EmployeeProjects.java b/2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/dto/EmployeeProjects.java similarity index 100% rename from examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/dto/EmployeeProjects.java rename to 2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/dto/EmployeeProjects.java diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Address.java b/2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Address.java similarity index 100% rename from examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Address.java rename to 2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Address.java diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Department.java b/2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Department.java similarity index 100% rename from examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Department.java rename to 2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Department.java diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Employee.java b/2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Employee.java similarity index 100% rename from examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Employee.java rename to 2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Employee.java diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Project.java b/2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Project.java similarity index 100% rename from examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Project.java rename to 2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Project.java diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/repositories/EmployeeRepository.java b/2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/repositories/EmployeeRepository.java similarity index 100% rename from examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/repositories/EmployeeRepository.java rename to 2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/repositories/EmployeeRepository.java diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/repositories/EmployeeRepositoryImpl.java b/2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/repositories/EmployeeRepositoryImpl.java similarity index 100% rename from examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/repositories/EmployeeRepositoryImpl.java rename to 2019-11/spring-09/jpql-demo/src/main/java/ru/otus/example/jpql_demo/repositories/EmployeeRepositoryImpl.java diff --git a/examples/jpql-demo/src/main/resources/application.yml b/2019-11/spring-09/jpql-demo/src/main/resources/application.yml similarity index 100% rename from examples/jpql-demo/src/main/resources/application.yml rename to 2019-11/spring-09/jpql-demo/src/main/resources/application.yml diff --git a/examples/jpql-demo/src/main/resources/jpql.sql b/2019-11/spring-09/jpql-demo/src/main/resources/jpql.sql similarity index 100% rename from examples/jpql-demo/src/main/resources/jpql.sql rename to 2019-11/spring-09/jpql-demo/src/main/resources/jpql.sql diff --git a/examples/jpql-demo/src/main/resources/schema.sql b/2019-11/spring-09/jpql-demo/src/main/resources/schema.sql similarity index 100% rename from examples/jpql-demo/src/main/resources/schema.sql rename to 2019-11/spring-09/jpql-demo/src/main/resources/schema.sql diff --git a/examples/jpql-demo/src/test/java/ru/otus/example/jpql_demo/repositories/EmployeeRepositoryImplTest.java b/2019-11/spring-09/jpql-demo/src/test/java/ru/otus/example/jpql_demo/repositories/EmployeeRepositoryImplTest.java similarity index 100% rename from examples/jpql-demo/src/test/java/ru/otus/example/jpql_demo/repositories/EmployeeRepositoryImplTest.java rename to 2019-11/spring-09/jpql-demo/src/test/java/ru/otus/example/jpql_demo/repositories/EmployeeRepositoryImplTest.java diff --git a/examples/jpql-demo/src/test/resources/application.yml b/2019-11/spring-09/jpql-demo/src/test/resources/application.yml similarity index 100% rename from examples/jpql-demo/src/test/resources/application.yml rename to 2019-11/spring-09/jpql-demo/src/test/resources/application.yml diff --git a/examples/jpql-demo/src/test/resources/test-data.sql b/2019-11/spring-09/jpql-demo/src/test/resources/test-data.sql similarity index 100% rename from examples/jpql-demo/src/test/resources/test-data.sql rename to 2019-11/spring-09/jpql-demo/src/test/resources/test-data.sql diff --git a/examples/README.md b/examples/README.md index 9a45c9b6..77699970 100644 --- a/examples/README.md +++ b/examples/README.md @@ -9,5 +9,4 @@ * *docker-test-containers* - TestContainers * *spring-cloud-demo-stvort* - Config server, Eureka, Zuul, Feign client * *spring-mail-integration-demo* - SpringMail SpringIntegration -* *liquibase-demo* - liquibase -* *jpql-demo* - JPQL \ No newline at end of file +* *liquibase-demo* - liquibase \ No newline at end of file