diff --git a/2021-05/spring-15/spring-mvc-class-work/spring-mvc-exercise/pom.xml b/2021-05/spring-15/spring-mvc-class-work/spring-mvc-exercise/pom.xml index 16ea1058..22c7da8e 100644 --- a/2021-05/spring-15/spring-mvc-class-work/spring-mvc-exercise/pom.xml +++ b/2021-05/spring-15/spring-mvc-class-work/spring-mvc-exercise/pom.xml @@ -20,11 +20,6 @@ - - org.springframework.boot - spring-boot-starter - - org.springframework.boot spring-boot-starter-web diff --git a/2021-05/spring-15/spring-mvc-class-work/spring-mvc-solution/pom.xml b/2021-05/spring-15/spring-mvc-class-work/spring-mvc-solution/pom.xml index 82d2d042..f623329c 100644 --- a/2021-05/spring-15/spring-mvc-class-work/spring-mvc-solution/pom.xml +++ b/2021-05/spring-15/spring-mvc-class-work/spring-mvc-solution/pom.xml @@ -20,11 +20,6 @@ - - org.springframework.boot - spring-boot-starter - - org.springframework.boot spring-boot-starter-web diff --git a/2021-05/spring-16/spring-mvc-view-classwork/.gitignore b/2021-05/spring-16/spring-mvc-view-classwork/.gitignore new file mode 100644 index 00000000..4ea52072 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/.gitignore @@ -0,0 +1,24 @@ +target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ diff --git a/2021-05/spring-16/spring-mvc-view-classwork/pom.xml b/2021-05/spring-16/spring-mvc-view-classwork/pom.xml new file mode 100644 index 00000000..9aba7ff8 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + ru.otus + spring-mvc-view-class-work + 1.0 + + pom + + + spring-mvc-view-exercise + spring-mvc-view-solution + + diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/.gitignore b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/.gitignore new file mode 100644 index 00000000..4ea52072 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/.gitignore @@ -0,0 +1,24 @@ +target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/pom.xml b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/pom.xml new file mode 100644 index 00000000..0a7c8dcc --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + ru.otus + spring-mvc-view-exercise + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + com.h2database + h2 + + + + org.springframework.data + spring-data-jpa + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/java/ru/otus/spring/Main.java b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..395af78d --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,28 @@ +package ru.otus.spring; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import javax.annotation.PostConstruct; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } + + //Чтобы не усложнять пример, делать так нельзя :) + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") + @Autowired + private PersonRepository repository; + + @PostConstruct + public void init() { + repository.save(new Person("Pushkin")); + repository.save(new Person("Lermontov")); + } +} diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/java/ru/otus/spring/domain/Person.java b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..374c55ac --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,37 @@ +package ru.otus.spring.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Person { + + @Id + @GeneratedValue + private int id; + private String name; + + public Person() { + } + + public Person(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..4b20e5b7 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,11 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.CrudRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends CrudRepository { + + List findAll(); +} diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/java/ru/otus/spring/rest/NotFoundException.java b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/java/ru/otus/spring/rest/NotFoundException.java new file mode 100644 index 00000000..463146f3 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/java/ru/otus/spring/rest/NotFoundException.java @@ -0,0 +1,7 @@ +package ru.otus.spring.rest; + +class NotFoundException extends RuntimeException{ + + NotFoundException() { + } +} diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/java/ru/otus/spring/rest/PersonController.java b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/java/ru/otus/spring/rest/PersonController.java new file mode 100644 index 00000000..06f92888 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/java/ru/otus/spring/rest/PersonController.java @@ -0,0 +1,35 @@ +package ru.otus.spring.rest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import java.util.List; +import java.util.stream.Collectors; + +@Controller +public class PersonController { + + private final PersonRepository repository; + + @Autowired + public PersonController(PersonRepository repository) { + this.repository = repository; + } + + @GetMapping("/") + public String listPage(Model model) { + List persons = repository.findAll(); + model.addAttribute("persons", persons); + return "list"; + } + + @GetMapping("/edit") + public String editPage(@RequestParam("id") int id, Model model) { + return null; + } +} diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/resources/templates/edit.html b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/resources/templates/edit.html new file mode 100644 index 00000000..63f74408 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/resources/templates/edit.html @@ -0,0 +1,47 @@ + + + + + Edit person + + + + + +
+

Person Info:

+ +
+ + +
+ +
+ + +
+ +
+ +
+
+ + + diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/resources/templates/list.html b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/resources/templates/list.html new file mode 100644 index 00000000..728467e5 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-exercise/src/main/resources/templates/list.html @@ -0,0 +1,39 @@ + + + + + List of all persons + + + +

Persons:

+ + + + + + + + + + + + + + + + +
IDNameAction
1John Doe + Edit +
+ + diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/.gitignore b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/.gitignore new file mode 100644 index 00000000..4ea52072 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/.gitignore @@ -0,0 +1,24 @@ +target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/pom.xml b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/pom.xml new file mode 100644 index 00000000..e47993b8 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + ru.otus + spring-mvc-view-solution + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + com.h2database + h2 + + + + org.springframework.data + spring-data-jpa + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/java/ru/otus/spring/Main.java b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..d33c8908 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,27 @@ +package ru.otus.spring; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import javax.annotation.PostConstruct; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } + + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") + @Autowired + private PersonRepository repository; + + @PostConstruct + public void init() { + repository.save(new Person("Pushkin")); + repository.save(new Person("Lermontov")); + } +} diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/java/ru/otus/spring/domain/Person.java b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..374c55ac --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,37 @@ +package ru.otus.spring.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Person { + + @Id + @GeneratedValue + private int id; + private String name; + + public Person() { + } + + public Person(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..4b20e5b7 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,11 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.CrudRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends CrudRepository { + + List findAll(); +} diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/java/ru/otus/spring/rest/NotFoundException.java b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/java/ru/otus/spring/rest/NotFoundException.java new file mode 100644 index 00000000..463146f3 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/java/ru/otus/spring/rest/NotFoundException.java @@ -0,0 +1,7 @@ +package ru.otus.spring.rest; + +class NotFoundException extends RuntimeException{ + + NotFoundException() { + } +} diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/java/ru/otus/spring/rest/PersonController.java b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/java/ru/otus/spring/rest/PersonController.java new file mode 100644 index 00000000..a52fb8b4 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/java/ru/otus/spring/rest/PersonController.java @@ -0,0 +1,52 @@ +package ru.otus.spring.rest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ExtendedModelMap; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Controller +public class PersonController { + + private final PersonRepository repository; + + @Autowired + public PersonController(PersonRepository repository) { + this.repository = repository; + } + + @GetMapping("/") + public String listPage(Model model) { + List persons = repository.findAll(); + model.addAttribute("persons", persons); + return "list"; + } + + @GetMapping("/edit") + public String editPage(@RequestParam("id") int id, Model model) { + Person person = repository.findById(id).orElseThrow(NotFoundException::new); + model.addAttribute("person", person); + return "edit"; + } + + @PostMapping("/edit") + public String savePerson( + Person person, + Model model + ) { + Person saved = repository.save(person); + model.addAttribute(saved); + //Ошибка! Нужен редирект! + return "edit"; + } +} diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/resources/templates/edit.html b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/resources/templates/edit.html new file mode 100644 index 00000000..230da682 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/resources/templates/edit.html @@ -0,0 +1,47 @@ + + + + + Edit person + + + + + +
+

Person Info:

+ +
+ + +
+ +
+ + +
+ +
+ +
+
+ + + diff --git a/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/resources/templates/list.html b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/resources/templates/list.html new file mode 100644 index 00000000..c1ccf866 --- /dev/null +++ b/2021-05/spring-16/spring-mvc-view-classwork/spring-mvc-view-solution/src/main/resources/templates/list.html @@ -0,0 +1,39 @@ + + + + + List of all persons + + + +

Persons:

+ + + + + + + + + + + + + + + + +
IDNameAction
1John Doe + Edit +
+ + diff --git a/2021-05/spring-17-jquery/spring-17-boot-and-react/.gitignore b/2021-05/spring-17-jquery/spring-17-boot-and-react/.gitignore new file mode 100644 index 00000000..b11e399f --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-boot-and-react/.gitignore @@ -0,0 +1,30 @@ +target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + + +node/ +/node_modules +/output +package-lock.json diff --git a/2021-05/spring-17-jquery/spring-17-boot-and-react/package.json b/2021-05/spring-17-jquery/spring-17-boot-and-react/package.json new file mode 100644 index 00000000..f7dc8478 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-boot-and-react/package.json @@ -0,0 +1,26 @@ +{ + "name": "client", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "dev": "webpack-dev-server --config webpack.dev.config.js", + "build": "webpack" + }, + "author": "", + "license": "ISC", + "dependencies": { + "react": "^16.2.0", + "react-dom": "^16.2.0" + }, + "devDependencies": { + "babel-core": "^6.26.0", + "babel-loader": "^7.1.2", + "babel-preset-env": "^1.6.1", + "babel-preset-react": "^6.24.1", + "html-webpack-plugin": "^3.2.0", + "webpack": "^3.10.0", + "webpack-cli": "^3.2.3", + "webpack-dev-server": "^2.9.7" + } +} diff --git a/2021-05/spring-17-jquery/spring-17-boot-and-react/pom.xml b/2021-05/spring-17-jquery/spring-17-boot-and-react/pom.xml new file mode 100644 index 00000000..6256e3f1 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-boot-and-react/pom.xml @@ -0,0 +1,88 @@ + + + 4.0.0 + + ru.otus + spring-17-boot-and-react + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.2.4.RELEASE + + + + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + + + com.h2database + h2 + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + com.github.eirslett + frontend-maven-plugin + 1.6 + + + install node and npm + + install-node-and-npm + + + v10.15.1 + 6.4.1 + + + + npm install + + npm + + generate-resources + + install + + + + npm run build + + npm + + generate-resources + + run build + + + + + + + diff --git a/2021-05/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/Main.java b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..d33c8908 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,27 @@ +package ru.otus.spring; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import javax.annotation.PostConstruct; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } + + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") + @Autowired + private PersonRepository repository; + + @PostConstruct + public void init() { + repository.save(new Person("Pushkin")); + repository.save(new Person("Lermontov")); + } +} diff --git a/2021-05/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/domain/Person.java b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..374c55ac --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,37 @@ +package ru.otus.spring.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Person { + + @Id + @GeneratedValue + private int id; + private String name; + + public Person() { + } + + public Person(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/2021-05/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..4b20e5b7 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,11 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.CrudRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends CrudRepository { + + List findAll(); +} diff --git a/2021-05/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/rest/PersonController.java b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/rest/PersonController.java new file mode 100644 index 00000000..8073a615 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/rest/PersonController.java @@ -0,0 +1,30 @@ +package ru.otus.spring.rest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.rest.dto.PersonDto; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +public class PersonController { + + private final PersonRepository repository; + + @Autowired + public PersonController(PersonRepository repository) { + this.repository = repository; + } + + @GetMapping("/api/persons") + public List getAllPersons() { + return repository.findAll().stream().map(PersonDto::toDto) + .collect(Collectors.toList()); + } +} diff --git a/2021-05/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/rest/dto/PersonDto.java b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/rest/dto/PersonDto.java new file mode 100644 index 00000000..03918447 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/rest/dto/PersonDto.java @@ -0,0 +1,50 @@ +/* + * Copyright 2016 Russian Post + * + * This source code is Russian Post Confidential Proprietary. + * This software is protected by copyright. All rights and titles are reserved. + * You shall not use, copy, distribute, modify, decompile, disassemble or reverse engineer the software. + * Otherwise this violation would be treated by law and would be subject to legal prosecution. + * Legal use of the software provides receipt of a license from the right name only. + */ +package ru.otus.spring.rest.dto; + +import ru.otus.spring.domain.Person; + +/** + * DTO that represents Account + */ +@SuppressWarnings("all") +public class PersonDto { + + private int id = -1; + private String name; + + public PersonDto() { + } + + public PersonDto(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public static PersonDto toDto(Person person) { + return new PersonDto(person.getId(), person.getName()); + } +} diff --git a/2021-05/spring-17-jquery/spring-17-boot-and-react/src/ui/components/App.js b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/ui/components/App.js new file mode 100644 index 00000000..79f94811 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/ui/components/App.js @@ -0,0 +1,45 @@ +import React from 'react' + +const Header = (props) => ( +

{props.title}

+); + +export default class App extends React.Component { + + constructor() { + super(); + this.state = {persons: []}; + } + + componentDidMount() { + fetch('/api/persons') + .then(response => response.json()) + .then(persons => this.setState({persons})); + } + + render() { + return ( + +
+ + + + + + + + + { + this.state.persons.map((person, i) => ( + + + + + )) + } + +
IDName
{person.id}{person.name}
+ + ) + } +}; diff --git a/2021-05/spring-17-jquery/spring-17-boot-and-react/src/ui/index.html b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/ui/index.html new file mode 100644 index 00000000..86fc7182 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/ui/index.html @@ -0,0 +1,15 @@ + + + + Minimal React Boilerplate + + + + +
+ + + + diff --git a/2021-05/spring-17-jquery/spring-17-boot-and-react/src/ui/index.js b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/ui/index.js new file mode 100644 index 00000000..52a1c724 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-boot-and-react/src/ui/index.js @@ -0,0 +1,9 @@ +import React from 'react' +import ReactDOM from 'react-dom' + +import App from './components/App' + +ReactDOM.render( + , + document.getElementById('root') +) \ No newline at end of file diff --git a/2021-05/spring-17-jquery/spring-17-boot-and-react/webpack.config.js b/2021-05/spring-17-jquery/spring-17-boot-and-react/webpack.config.js new file mode 100644 index 00000000..654887cc --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-boot-and-react/webpack.config.js @@ -0,0 +1,47 @@ +const HtmlWebpackPlugin = require('html-webpack-plugin') +const path = require('path'); +const webpack = require('webpack'); + +module.exports = { + entry: './src/ui/index.js', + output: { + path: path.resolve(__dirname, 'target/classes/public/'), + filename: 'bundle.min.js', + libraryTarget: 'umd' + }, + + module: { + loaders: [ + { + test: /\.js$/, + exclude: /(node_modules|bower_components|build)/, + use: { + loader: 'babel-loader', + options: { + presets: ['env', 'react'] + } + } + } + ] + }, + + plugins: [ + new webpack.DefinePlugin({ + "process.env": { + NODE_ENV: JSON.stringify("production") + } + }), + new webpack.optimize.UglifyJsPlugin({ + compress: { + warnings: false, + }, + output: { + comments: false, + }, + }), + new HtmlWebpackPlugin({ + filename: 'index.html', + template: 'src/ui/index.html' + }) + ] +} diff --git a/2021-05/spring-17-jquery/spring-17-boot-and-react/webpack.dev.config.js b/2021-05/spring-17-jquery/spring-17-boot-and-react/webpack.dev.config.js new file mode 100644 index 00000000..97817ef7 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-boot-and-react/webpack.dev.config.js @@ -0,0 +1,46 @@ +const HtmlWebpackPlugin = require('html-webpack-plugin') +const path = require('path'); + +module.exports = { + entry: './src/ui/index.js', + devtool: 'inline-source-map', + output: { + path: path.resolve(__dirname), + filename: 'bundle.js', + libraryTarget: 'umd' + }, + + devServer: { + contentBase: path.resolve(__dirname) + '/src/ui', + compress: true, + port: 9000, + host: 'localhost', + open: true, + before: (app) => { + app.get('/api/persons', (req, res) => res.send([ + {id: '1', name: 'Привяу'} + ])); + } + }, + + module: { + loaders: [ + { + test: /\.js$/, + exclude: /(node_modules|bower_components|build)/, + use: { + loader: 'babel-loader', + options: { + presets: ['env', 'react'] + } + } + } + ] + }, + plugins: [ + new HtmlWebpackPlugin({ + filename: 'index.html', + template: 'src/ui/index.html' + }) + ] +} diff --git a/2021-05/spring-17-jquery/spring-17-jquery/.gitignore b/2021-05/spring-17-jquery/spring-17-jquery/.gitignore new file mode 100644 index 00000000..4ea52072 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-jquery/.gitignore @@ -0,0 +1,24 @@ +target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ diff --git a/2021-05/spring-17-jquery/spring-17-jquery/pom.xml b/2021-05/spring-17-jquery/spring-17-jquery/pom.xml new file mode 100644 index 00000000..cb4de97d --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-jquery/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + + ru.otus + spring-17-jquery + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.2.4.RELEASE + + + + 11 + 11 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.webjars + jquery + 3.3.1 + + + + + com.h2database + h2 + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/Main.java b/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..d33c8908 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,27 @@ +package ru.otus.spring; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import javax.annotation.PostConstruct; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } + + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") + @Autowired + private PersonRepository repository; + + @PostConstruct + public void init() { + repository.save(new Person("Pushkin")); + repository.save(new Person("Lermontov")); + } +} diff --git a/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/domain/Person.java b/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..374c55ac --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,37 @@ +package ru.otus.spring.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Person { + + @Id + @GeneratedValue + private int id; + private String name; + + public Person() { + } + + public Person(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/page/PersonPagesController.java b/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/page/PersonPagesController.java new file mode 100644 index 00000000..0f3a2e76 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/page/PersonPagesController.java @@ -0,0 +1,15 @@ +package ru.otus.spring.page; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class PersonPagesController { + + @GetMapping("/") + public String listPage(Model model) { + model.addAttribute("keywords", "list users in Omsk, omsk, list users, list users free"); + return "list"; + } +} diff --git a/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..4b20e5b7 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,11 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.CrudRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends CrudRepository { + + List findAll(); +} diff --git a/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/rest/PersonController.java b/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/rest/PersonController.java new file mode 100644 index 00000000..8073a615 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/rest/PersonController.java @@ -0,0 +1,30 @@ +package ru.otus.spring.rest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; +import ru.otus.spring.rest.dto.PersonDto; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +public class PersonController { + + private final PersonRepository repository; + + @Autowired + public PersonController(PersonRepository repository) { + this.repository = repository; + } + + @GetMapping("/api/persons") + public List getAllPersons() { + return repository.findAll().stream().map(PersonDto::toDto) + .collect(Collectors.toList()); + } +} diff --git a/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/rest/dto/PersonDto.java b/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/rest/dto/PersonDto.java new file mode 100644 index 00000000..03918447 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/rest/dto/PersonDto.java @@ -0,0 +1,50 @@ +/* + * Copyright 2016 Russian Post + * + * This source code is Russian Post Confidential Proprietary. + * This software is protected by copyright. All rights and titles are reserved. + * You shall not use, copy, distribute, modify, decompile, disassemble or reverse engineer the software. + * Otherwise this violation would be treated by law and would be subject to legal prosecution. + * Legal use of the software provides receipt of a license from the right name only. + */ +package ru.otus.spring.rest.dto; + +import ru.otus.spring.domain.Person; + +/** + * DTO that represents Account + */ +@SuppressWarnings("all") +public class PersonDto { + + private int id = -1; + private String name; + + public PersonDto() { + } + + public PersonDto(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public static PersonDto toDto(Person person) { + return new PersonDto(person.getId(), person.getName()); + } +} diff --git a/2021-05/spring-17-jquery/spring-17-jquery/src/main/resources/templates/list.html b/2021-05/spring-17-jquery/spring-17-jquery/src/main/resources/templates/list.html new file mode 100644 index 00000000..a782b158 --- /dev/null +++ b/2021-05/spring-17-jquery/spring-17-jquery/src/main/resources/templates/list.html @@ -0,0 +1,47 @@ + + + + + + List of all persons + + + + +

Persons:

+ + + + + + + + + + +
IDName
+ + + diff --git a/2021-05/spring-18/.gitignore b/2021-05/spring-18/.gitignore new file mode 100644 index 00000000..fbe7a1ed --- /dev/null +++ b/2021-05/spring-18/.gitignore @@ -0,0 +1,7 @@ +.idea/ +*.iml + +target/ + +/node_modules +/output diff --git a/2021-05/spring-18/pom.xml b/2021-05/spring-18/pom.xml new file mode 100644 index 00000000..d4fa3309 --- /dev/null +++ b/2021-05/spring-18/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + ru.otus + spring-18 + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.2.4.RELEASE + + + + 11 + 11 + + + + + io.reactivex.rxjava2 + rxjava + + + com.google.guava + guava + 27.1-jre + + + diff --git a/2021-05/spring-18/src/main/java/ru/otus/CreateExamples.java b/2021-05/spring-18/src/main/java/ru/otus/CreateExamples.java new file mode 100644 index 00000000..b8a21736 --- /dev/null +++ b/2021-05/spring-18/src/main/java/ru/otus/CreateExamples.java @@ -0,0 +1,35 @@ +package ru.otus; + +import io.reactivex.Observable; + +@SuppressWarnings("ResultOfMethodCallIgnored") +public class CreateExamples { + + public static void main(String[] args) { + Observable obs = justExample(); + obs.forEach(System.out::println); + obs.forEach(System.out::println); + } + + public static Observable justExample() { + return Observable.just("one", "two", "three"); + } + + public static Observable createExample() { + return Observable.create(emitter -> { + if (emitter.isDisposed()) { + return; + } + emitter.onNext("one"); + emitter.onNext("two");//! + emitter.onNext("three"); + if (!emitter.isDisposed()) { + emitter.onComplete(); + } + }); + } + + public static Observable deferExample() { + return Observable.defer(() -> Observable.just("one", "two", "three")); + } +} diff --git a/2021-05/spring-18/src/main/java/ru/otus/LiveLikeExample.java b/2021-05/spring-18/src/main/java/ru/otus/LiveLikeExample.java new file mode 100644 index 00000000..3f8e31d4 --- /dev/null +++ b/2021-05/spring-18/src/main/java/ru/otus/LiveLikeExample.java @@ -0,0 +1,26 @@ +package ru.otus; + +import io.reactivex.Observable; + +import java.io.IOException; + +public class LiveLikeExample { + + public static void main(String[] args) throws IOException { + + System.in.read(); + } + + static Observable getName() { + return Observable.just("Jake"); + } + + static Observable getSurname() { + return Observable.just("Foo"); + } + + static Observable save(String fullName) { + System.out.println(fullName + " saved!"); + return Observable.just("OK!"); + } +} diff --git a/2021-05/spring-18/src/main/java/ru/otus/OperatorsExample.java b/2021-05/spring-18/src/main/java/ru/otus/OperatorsExample.java new file mode 100644 index 00000000..92efffa6 --- /dev/null +++ b/2021-05/spring-18/src/main/java/ru/otus/OperatorsExample.java @@ -0,0 +1,79 @@ +package ru.otus; + +import com.google.common.collect.ImmutableList; +import io.reactivex.Observable; +import io.reactivex.ObservableTransformer; +import io.reactivex.schedulers.Schedulers; +import io.reactivex.subjects.PublishSubject; + +import java.time.LocalDate; +import java.util.List; +import java.util.Random; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +@SuppressWarnings("ResultOfMethodCallIgnored") +public class OperatorsExample { + public static void main(String[] args) throws Exception { + simpleExample(); + System.in.read(); + } + + public static void simpleExample() throws Exception { + List persons = ImmutableList.of( + new Person("John", "Dow", "male", LocalDate.of(1992, 3, 12)), + new Person("Jane", "Dow", "female", LocalDate.of(2001, 6, 23)), + new Person("Howard", "Lovecraft", "male", LocalDate.of(1890, 8, 20)), + new Person("Joanne", "Rowling", "female", LocalDate.of(1965, 6, 30))); + + Observable.fromIterable(persons) + .filter( + person -> person.getBirth().isAfter(LocalDate.of(1990, 1, 1)) + ) + .map(p -> p.getFirstName() + " " + p.getLastName()) + .toList() + .subscribe(System.out::println); + } + + public static void publisherExample() throws Exception { + final Observable ob = magicPublisher(); + System.out.println("First subscribed"); + ob.subscribe(System.out::println); + Thread.sleep(5000); + System.out.println("Second subscribed"); + ob.subscribe(System.out::println); + } + + public static Observable magicPublisher() { + Random r = new Random(1); + AtomicInteger i = new AtomicInteger(); + final Observable obs = Observable.generate(emitter -> + emitter.onNext("" + i.incrementAndGet())) + .concatMap(s -> Observable.just(s).delay(r.nextInt(1000), TimeUnit.MILLISECONDS)) + .subscribeOn(Schedulers.newThread()); + PublishSubject subject = PublishSubject.create(); + +// BehaviorSubject subject = BehaviorSubject.create(); + +// AsyncSubject subject = AsyncSubject.create(); +// CompletableFuture.runAsync(() -> { +// try { +// Thread.sleep(7000); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// subject.onComplete(); +// }); + +// ReplaySubject subject = ReplaySubject.create(); + obs.subscribe(subject); + return subject; + } + + //composeExmaple + private static ObservableTransformer filterAndUpperCase() { + return upstream -> upstream + .filter(s -> s.length() >= 4) + .map(String::toUpperCase); + } +} diff --git a/2021-05/spring-18/src/main/java/ru/otus/Person.java b/2021-05/spring-18/src/main/java/ru/otus/Person.java new file mode 100644 index 00000000..72d3f520 --- /dev/null +++ b/2021-05/spring-18/src/main/java/ru/otus/Person.java @@ -0,0 +1,66 @@ +package ru.otus; + +import java.time.LocalDate; +import java.util.Objects; + +public class Person { + private String firstName; + private String lastName; + private String gender; + private LocalDate birth; + + public Person(String firstName, String lastName, String gender, LocalDate birth) { + this.firstName = firstName; + this.lastName = lastName; + this.gender = gender; + this.birth = birth; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + + public LocalDate getBirth() { + return birth; + } + + public void setBirth(LocalDate birth) { + this.birth = birth; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Person person = (Person) o; + return Objects.equals(firstName, person.firstName) && + Objects.equals(lastName, person.lastName) && + Objects.equals(gender, person.gender) && + Objects.equals(birth, person.birth); + } + + @Override + public int hashCode() { + return Objects.hash(firstName, lastName, gender, birth); + } +} diff --git a/2021-05/spring-18/src/main/java/ru/otus/comparison/AsyncComparison.java b/2021-05/spring-18/src/main/java/ru/otus/comparison/AsyncComparison.java new file mode 100644 index 00000000..5b0b227a --- /dev/null +++ b/2021-05/spring-18/src/main/java/ru/otus/comparison/AsyncComparison.java @@ -0,0 +1,40 @@ +package ru.otus.comparison; + +import io.reactivex.Observable; +import io.reactivex.schedulers.Schedulers; + +import java.io.IOException; + +public class AsyncComparison { + + public static void main(String[] args) throws IOException { + final long timeStarted = System.currentTimeMillis(); + final Observable obs = controller(); + obs.subscribe(System.out::println); + System.out.println("Wait time " + (System.currentTimeMillis() - timeStarted)); + System.in.read(); + } + + static Observable controller() { + return service(); + } + + static Observable service() { + return repository(); + } + + static Observable repository() { + return database(); + } + + static Observable database() { + return Observable.defer(() -> { + try { + Thread.sleep(4000); + } catch (Exception e) { + System.out.println("Don't do this"); + } + return Observable.just("Hello world"); + }).subscribeOn(Schedulers.newThread()); + } +} diff --git a/2021-05/spring-18/src/main/java/ru/otus/comparison/SyncComparison.java b/2021-05/spring-18/src/main/java/ru/otus/comparison/SyncComparison.java new file mode 100644 index 00000000..c2bf7077 --- /dev/null +++ b/2021-05/spring-18/src/main/java/ru/otus/comparison/SyncComparison.java @@ -0,0 +1,31 @@ +package ru.otus.comparison; + +public class SyncComparison { + + public static void main(String[] args) { + final long timeStarted = System.currentTimeMillis(); + System.out.println(controller()); + System.out.println(System.currentTimeMillis() - timeStarted); + } + + static String controller() { + return service(); + } + + static String service() { + return repository(); + } + + static String repository() { + return database(); + } + + static String database() { + try { + Thread.sleep(4000); + } catch (Exception e) { + System.out.println("Don't do this"); + } + return "Hello world"; + } +} diff --git a/2021-05/spring-19/.gitignore b/2021-05/spring-19/.gitignore new file mode 100644 index 00000000..4ea52072 --- /dev/null +++ b/2021-05/spring-19/.gitignore @@ -0,0 +1,24 @@ +target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ diff --git a/2021-05/spring-19/pom.xml b/2021-05/spring-19/pom.xml new file mode 100644 index 00000000..06dd04ce --- /dev/null +++ b/2021-05/spring-19/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + ru.otus + spring-19 + 1.0 + + pom + + + spring-19-web-flux + spring-19-reactor + spring-19-reactive-spring-data + + diff --git a/2021-05/spring-19/spring-19-reactive-spring-data/pom.xml b/2021-05/spring-19/spring-19-reactive-spring-data/pom.xml new file mode 100644 index 00000000..5e963c48 --- /dev/null +++ b/2021-05/spring-19/spring-19-reactive-spring-data/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + ru.otus + spring-19-reactive-spring-data + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + + + 13 + 13 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-data-mongodb-reactive + + + org.mongodb + mongodb-driver-reactivestreams + + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2021-05/spring-19/spring-19-reactive-spring-data/src/main/java/ru/otus/spring/Main.java b/2021-05/spring-19/spring-19-reactive-spring-data/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..5929a2e2 --- /dev/null +++ b/2021-05/spring-19/spring-19-reactive-spring-data/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,20 @@ +package ru.otus.spring; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import ru.otus.spring.repostory.AccountRepository; +import ru.otus.spring.repostory.PersonRepository; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) throws InterruptedException { + ApplicationContext context = SpringApplication.run(Main.class); + + PersonRepository repository = context.getBean(PersonRepository.class); + AccountRepository accountRepository = context.getBean(AccountRepository.class); + + Thread.sleep(20000); + } +} diff --git a/2021-05/spring-19/spring-19-reactive-spring-data/src/main/java/ru/otus/spring/domain/Account.java b/2021-05/spring-19/spring-19-reactive-spring-data/src/main/java/ru/otus/spring/domain/Account.java new file mode 100644 index 00000000..2158e0b7 --- /dev/null +++ b/2021-05/spring-19/spring-19-reactive-spring-data/src/main/java/ru/otus/spring/domain/Account.java @@ -0,0 +1,37 @@ +package ru.otus.spring.domain; + +public class Account { + private String id; + private String personId; + private Long amount; + + public Account(String id, String personId, Long amount) { + this.id = id; + this.personId = personId; + this.amount = amount; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getPersonId() { + return personId; + } + + public void setPersonId(String personId) { + this.personId = personId; + } + + public Long getAmount() { + return amount; + } + + public void setAmount(Long amount) { + this.amount = amount; + } +} diff --git a/2021-05/spring-19/spring-19-reactive-spring-data/src/main/java/ru/otus/spring/domain/Person.java b/2021-05/spring-19/spring-19-reactive-spring-data/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..2bdc3894 --- /dev/null +++ b/2021-05/spring-19/spring-19-reactive-spring-data/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,27 @@ +package ru.otus.spring.domain; + +public class Person { + + private String id; + private String name; + + public Person(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/2021-05/spring-19/spring-19-reactive-spring-data/src/main/java/ru/otus/spring/repostory/AccountRepository.java b/2021-05/spring-19/spring-19-reactive-spring-data/src/main/java/ru/otus/spring/repostory/AccountRepository.java new file mode 100644 index 00000000..22bd9275 --- /dev/null +++ b/2021-05/spring-19/spring-19-reactive-spring-data/src/main/java/ru/otus/spring/repostory/AccountRepository.java @@ -0,0 +1,8 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.mongodb.repository.ReactiveMongoRepository; +import ru.otus.spring.domain.Account; +import ru.otus.spring.domain.Person; + +public interface AccountRepository extends ReactiveMongoRepository { +} diff --git a/2021-05/spring-19/spring-19-reactive-spring-data/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2021-05/spring-19/spring-19-reactive-spring-data/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..ddd15cef --- /dev/null +++ b/2021-05/spring-19/spring-19-reactive-spring-data/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,15 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.mongodb.repository.Query; +import org.springframework.data.mongodb.repository.ReactiveMongoRepository; +import org.springframework.data.repository.reactive.ReactiveCrudRepository; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import ru.otus.spring.domain.Person; + +public interface PersonRepository extends ReactiveMongoRepository { + Flux findByName(String name); + + @Query("{ 'name': ?0 }") + Mono findFirstByName(String name); +} diff --git a/2021-05/spring-19/spring-19-reactive-spring-data/src/main/resources/application.yml b/2021-05/spring-19/spring-19-reactive-spring-data/src/main/resources/application.yml new file mode 100644 index 00000000..e69de29b diff --git a/2021-05/spring-19/spring-19-reactor/pom.xml b/2021-05/spring-19/spring-19-reactor/pom.xml new file mode 100644 index 00000000..d66f1f55 --- /dev/null +++ b/2021-05/spring-19/spring-19-reactor/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + ru.otus + spring-19-reactor + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + + + 13 + 13 + + + + + org.springframework.boot + spring-boot-starter + + + io.projectreactor + reactor-core + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2021-05/spring-19/spring-19-reactor/src/main/java/ru/otus/spring/Main.java b/2021-05/spring-19/spring-19-reactor/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..cc406c39 --- /dev/null +++ b/2021-05/spring-19/spring-19-reactor/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,20 @@ +package ru.otus.spring; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import ru.otus.spring.reactor.FluxService; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + ConfigurableApplicationContext context = SpringApplication.run(Main.class); + + FluxService service = context.getBean(FluxService.class); + + service.printHello("Ivan"); + } +} + + diff --git a/2021-05/spring-19/spring-19-reactor/src/main/java/ru/otus/spring/reactor/FluxService.java b/2021-05/spring-19/spring-19-reactor/src/main/java/ru/otus/spring/reactor/FluxService.java new file mode 100644 index 00000000..e2e67f71 --- /dev/null +++ b/2021-05/spring-19/spring-19-reactor/src/main/java/ru/otus/spring/reactor/FluxService.java @@ -0,0 +1,50 @@ +package ru.otus.spring.reactor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import reactor.core.Disposable; +import reactor.core.publisher.DirectProcessor; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Service +public class FluxService { + + private final Logger logger = LoggerFactory.getLogger(FluxService.class); + + private final NonFluxService nonFluxService; + private final DirectProcessor processor; + private final Disposable flow; + + @Autowired + public FluxService(NonFluxService nonFluxService) { + this.nonFluxService = nonFluxService; + // Создаём процессор - это reactor-овская реализация reactive-stream интерфейса + // Direct processor, кстати - это простой последовательный вызов методов) + processor = DirectProcessor.create(); + // Здесь мы настриваем flow + flow = Mono.from(processor) + .map(nonFluxService::nonFluxSayHello) + .subscribe(this::printMessage); + } + + /** + * Этот метод будет инициировать асинзронную обрабтку сообщения + * + * @param name это имя будет приходить из не-reactor окружения + */ + public void printHello(String name) { + processor.onNext(new Message(name)); + } + + /** + * А это терминальный шаг для сообщения + * + * @param message а это финальный шаг для сообщения, отсюда можно вернуть рзультат в не-реактив окружение + */ + private void printMessage(Message message) { + logger.info("Message received: {}", message.getValue()); + } +} diff --git a/2021-05/spring-19/spring-19-reactor/src/main/java/ru/otus/spring/reactor/Message.java b/2021-05/spring-19/spring-19-reactor/src/main/java/ru/otus/spring/reactor/Message.java new file mode 100644 index 00000000..ac58a62c --- /dev/null +++ b/2021-05/spring-19/spring-19-reactor/src/main/java/ru/otus/spring/reactor/Message.java @@ -0,0 +1,14 @@ +package ru.otus.spring.reactor; + +public class Message { + + private final String value; + + public Message(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/2021-05/spring-19/spring-19-reactor/src/main/java/ru/otus/spring/reactor/NonFluxService.java b/2021-05/spring-19/spring-19-reactor/src/main/java/ru/otus/spring/reactor/NonFluxService.java new file mode 100644 index 00000000..1b9be28a --- /dev/null +++ b/2021-05/spring-19/spring-19-reactor/src/main/java/ru/otus/spring/reactor/NonFluxService.java @@ -0,0 +1,24 @@ +package ru.otus.spring.reactor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class NonFluxService { + + private final Logger logger = LoggerFactory.getLogger(NonFluxService.class); + + public Message nonFluxSayHello(Message message) { + logger.info("Message received in non-flux service: {}", message.getValue()); + + final String name = message.getValue(); + final String withHello = "Hello, " + name + "!"; + try { + Thread.sleep(1000); + return new Message(withHello); + } catch (InterruptedException ex) { + return new Message(withHello); + } + } +} diff --git a/2021-05/spring-19/spring-19-web-flux/pom.xml b/2021-05/spring-19/spring-19-web-flux/pom.xml new file mode 100644 index 00000000..15775369 --- /dev/null +++ b/2021-05/spring-19/spring-19-web-flux/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + ru.otus + spring-19-web-flux + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + + + 13 + 13 + + + + + org.springframework.boot + spring-boot-starter-webflux + + + + + io.reactivex.rxjava2 + rxjava + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2021-05/spring-19/spring-19-web-flux/src/main/java/ru/otus/spring/Main.java b/2021-05/spring-19/spring-19-web-flux/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..cad1ae76 --- /dev/null +++ b/2021-05/spring-19/spring-19-web-flux/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,14 @@ +package ru.otus.spring; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } +} + + diff --git a/2021-05/spring-19/spring-19-web-flux/src/main/java/ru/otus/spring/ReactorController.java b/2021-05/spring-19/spring-19-web-flux/src/main/java/ru/otus/spring/ReactorController.java new file mode 100644 index 00000000..537ead63 --- /dev/null +++ b/2021-05/spring-19/spring-19-web-flux/src/main/java/ru/otus/spring/ReactorController.java @@ -0,0 +1,33 @@ +package ru.otus.spring; + +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +@RestController +public class ReactorController { + + @GetMapping("/flux/one") + public Mono one() { + return Mono.just("one"); + } + + @GetMapping("/flux/ten") + public Flux list() { + return Flux.range(1, 10); + } + + @GetMapping(path = "/flux/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public Flux stream() { + return Flux.generate(() -> 0, (state, emitter) -> { + emitter.next(state); + return state + 1; + }) + .delayElements(Duration.ofSeconds(1L)) + .map(Object::toString); + } +} diff --git a/2021-05/spring-19/spring-19-web-flux/src/main/java/ru/otus/spring/RxJava2Controller.java b/2021-05/spring-19/spring-19-web-flux/src/main/java/ru/otus/spring/RxJava2Controller.java new file mode 100644 index 00000000..edf0035f --- /dev/null +++ b/2021-05/spring-19/spring-19-web-flux/src/main/java/ru/otus/spring/RxJava2Controller.java @@ -0,0 +1,20 @@ +package ru.otus.spring; + +import io.reactivex.Flowable; +import io.reactivex.Single; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class RxJava2Controller { + + @GetMapping("/rx/one") + public Single single() { + return Single.just("one"); + } + + @GetMapping("/rx/ten") + public Flowable list() { + return Flowable.range(1, 10); + } +} diff --git a/2021-05/spring-20/.gitignore b/2021-05/spring-20/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2021-05/spring-20/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2021-05/spring-20/pom.xml b/2021-05/spring-20/pom.xml new file mode 100644 index 00000000..8997be90 --- /dev/null +++ b/2021-05/spring-20/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + ru.otus + spring-20 + 1.0 + + pom + + + spring-20-exercise + spring-20-solution + + diff --git a/2021-05/spring-20/spring-20-exercise/pom.xml b/2021-05/spring-20/spring-20-exercise/pom.xml new file mode 100644 index 00000000..7fb51891 --- /dev/null +++ b/2021-05/spring-20/spring-20-exercise/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + ru.otus + spring-20-exercise + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.4.5 + + + + + 11 + 11 + + + + + + org.springframework.boot + spring-boot-starter-webflux + + + + + org.springframework.boot + spring-boot-starter-data-mongodb-reactive + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + + + + + io.projectreactor + reactor-test + test + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2021-05/spring-20/spring-20-exercise/src/main/java/ru/otus/spring/Main.java b/2021-05/spring-20/spring-20-exercise/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..7b3c42bf --- /dev/null +++ b/2021-05/spring-20/spring-20-exercise/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,69 @@ +package ru.otus.spring; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repository.PersonRepository; + +import java.util.Arrays; + +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.web.reactive.function.BodyInserters.fromObject; +import static org.springframework.web.reactive.function.BodyInserters.fromValue; +import static org.springframework.web.reactive.function.server.RequestPredicates.accept; +import static org.springframework.web.reactive.function.server.RequestPredicates.queryParam; +import static org.springframework.web.reactive.function.server.RouterFunctions.route; +import static org.springframework.web.reactive.function.server.ServerResponse.*; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + ApplicationContext context = SpringApplication.run(Main.class); + PersonRepository repository = context.getBean(PersonRepository.class); + + repository.saveAll(Arrays.asList( + new Person("Pushkin", 22), + new Person("Lermontov", 22), + new Person("Tolstoy", 60) + )).subscribe(p -> System.out.println(p.getLastName())); + + } + + @Bean + public RouterFunction composedRoutes(PersonRepository repository) { + return route() + // Обратите внимание на использование хэндлера + .GET("/func/person", accept(APPLICATION_JSON), new PersonHandler(repository)::list) + // Обратите внимание на использование pathVariable + .GET("/func/person/{id}", accept(APPLICATION_JSON), + request -> repository.findById(request.pathVariable("id")) + .flatMap(person -> ok().contentType(APPLICATION_JSON).body(fromValue(person))) + .switchIfEmpty(notFound().build()) + ).build(); + } + + // Это пример хэндлера, который даже не бин + static class PersonHandler { + + private final PersonRepository repository; + + PersonHandler(PersonRepository repository) { + this.repository = repository; + } + + Mono list(ServerRequest request) { + // Обратите внимание на пример другого порядка создания response от Flux + return ok().contentType(APPLICATION_JSON).body(repository.findAll(), Person.class); + } + } +} + + diff --git a/2021-05/spring-20/spring-20-exercise/src/main/java/ru/otus/spring/domain/Person.java b/2021-05/spring-20/spring-20-exercise/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..d40218ec --- /dev/null +++ b/2021-05/spring-20/spring-20-exercise/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,55 @@ +package ru.otus.spring.domain; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + +@Document +public class Person { + + @Id + private String id; + + @JsonProperty("name") + @Field("name") + private String lastName; + + private int age; + + public Person() { + } + + public Person(String lastName) { + this.lastName = lastName; + } + + public Person(String lastName, int age) { + this.lastName = lastName; + this.age = age; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } +} diff --git a/2021-05/spring-20/spring-20-exercise/src/main/java/ru/otus/spring/repository/PersonRepository.java b/2021-05/spring-20/spring-20-exercise/src/main/java/ru/otus/spring/repository/PersonRepository.java new file mode 100644 index 00000000..0584f0cb --- /dev/null +++ b/2021-05/spring-20/spring-20-exercise/src/main/java/ru/otus/spring/repository/PersonRepository.java @@ -0,0 +1,20 @@ +package ru.otus.spring.repository; + +import org.springframework.data.mongodb.repository.ReactiveMongoRepository; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import ru.otus.spring.domain.Person; + +public interface PersonRepository + extends ReactiveMongoRepository { + + Flux findAll(); + + Mono findById(String id); + + Mono save(Mono person); + + Flux findAllByLastName(String lastName); + + Flux findAllByAge(int age); +} diff --git a/2021-05/spring-20/spring-20-exercise/src/main/java/ru/otus/spring/rest/AnnotatedController.java b/2021-05/spring-20/spring-20-exercise/src/main/java/ru/otus/spring/rest/AnnotatedController.java new file mode 100644 index 00000000..fc3bded8 --- /dev/null +++ b/2021-05/spring-20/spring-20-exercise/src/main/java/ru/otus/spring/rest/AnnotatedController.java @@ -0,0 +1,33 @@ +package ru.otus.spring.rest; + +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +@RestController +public class AnnotatedController { + + @GetMapping("/flux/one") + public Mono one() { + return Mono.just("one"); + } + + @GetMapping("/flux/ten") + public Flux list() { + return Flux.range(1, 10).delayElements(Duration.ofSeconds(1)); + } + + @GetMapping(path = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public Flux stream() { + return Flux.generate(() -> 0, (state, emitter) -> { + emitter.next(state); + return state + 1; + }) + .delayElements(Duration.ofSeconds(1L)) + .map(i -> "" + i); + } +} diff --git a/2021-05/spring-20/spring-20-exercise/src/main/java/ru/otus/spring/rest/PersonController.java b/2021-05/spring-20/spring-20-exercise/src/main/java/ru/otus/spring/rest/PersonController.java new file mode 100644 index 00000000..c6f2df03 --- /dev/null +++ b/2021-05/spring-20/spring-20-exercise/src/main/java/ru/otus/spring/rest/PersonController.java @@ -0,0 +1,37 @@ +package ru.otus.spring.rest; + +import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repository.PersonRepository; + +@RestController +public class PersonController { + + private final PersonRepository repository; + + public PersonController(PersonRepository repository) { + this.repository = repository; + } + + @GetMapping("/person") + public Flux all() { + return repository.findAll(); + } + + @GetMapping("/person/{id}") + public Mono byId(@PathVariable("id") String id) { + return repository.findById(id); + } + + @PostMapping("/person") + public Mono save(@RequestBody Mono dto) { + return repository.save(dto); + } + + @GetMapping("/person/find") + public Flux byName(@RequestParam("name") String name) { + return repository.findAllByLastName(name); + } +} diff --git a/2021-05/spring-20/spring-20-exercise/src/test/java/ru/otus/spring/repository/PersonRepositoryTest.java b/2021-05/spring-20/spring-20-exercise/src/test/java/ru/otus/spring/repository/PersonRepositoryTest.java new file mode 100644 index 00000000..2f373b60 --- /dev/null +++ b/2021-05/spring-20/spring-20-exercise/src/test/java/ru/otus/spring/repository/PersonRepositoryTest.java @@ -0,0 +1,28 @@ +package ru.otus.spring.repository; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; +import ru.otus.spring.domain.Person; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@DataMongoTest +public class PersonRepositoryTest { + + @Autowired + private PersonRepository repository; + + @Test + public void shouldSetIdOnSave() { + Mono personMono = repository.save(new Person("Bill", 12)); + + StepVerifier + .create(personMono) + .assertNext(person -> assertNotNull(person.getId())) + .expectComplete() + .verify(); + } +} diff --git a/2021-05/spring-20/spring-20-exercise/src/test/java/ru/otus/spring/rest/PersonControllerTest.java b/2021-05/spring-20/spring-20-exercise/src/test/java/ru/otus/spring/rest/PersonControllerTest.java new file mode 100644 index 00000000..d1504547 --- /dev/null +++ b/2021-05/spring-20/spring-20-exercise/src/test/java/ru/otus/spring/rest/PersonControllerTest.java @@ -0,0 +1,28 @@ +package ru.otus.spring.rest; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.ServerResponse; + +@SpringBootTest +public class PersonControllerTest { + + @Autowired + private RouterFunction route; + + @Test + public void testRoute() { + WebTestClient client = WebTestClient + .bindToRouterFunction(route) + .build(); + + client.get() + .uri("/func/person") + .exchange() + .expectStatus() + .isOk(); + } +} diff --git a/2021-05/spring-20/spring-20-solution/pom.xml b/2021-05/spring-20/spring-20-solution/pom.xml new file mode 100644 index 00000000..60a6d129 --- /dev/null +++ b/2021-05/spring-20/spring-20-solution/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + ru.otus + spring-20-solution + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.4.5 + + + + + 11 + 11 + + + + + + org.springframework.boot + spring-boot-starter-webflux + + + + + org.springframework.boot + spring-boot-starter-data-mongodb-reactive + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + + + + + io.projectreactor + reactor-test + test + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2021-05/spring-20/spring-20-solution/src/main/java/ru/otus/spring/Main.java b/2021-05/spring-20/spring-20-solution/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..8bad8f3d --- /dev/null +++ b/2021-05/spring-20/spring-20-solution/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,82 @@ +package ru.otus.spring; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repository.PersonRepository; + +import java.util.Arrays; + +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.web.reactive.function.BodyInserters.fromObject; +import static org.springframework.web.reactive.function.BodyInserters.fromValue; +import static org.springframework.web.reactive.function.server.RequestPredicates.accept; +import static org.springframework.web.reactive.function.server.RequestPredicates.queryParam; +import static org.springframework.web.reactive.function.server.RouterFunctions.route; +import static org.springframework.web.reactive.function.server.ServerResponse.*; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + ApplicationContext context = SpringApplication.run(Main.class); + PersonRepository repository = context.getBean(PersonRepository.class); + + repository.saveAll(Arrays.asList( + new Person("Pushkin", 22), + new Person("Lermontov", 22), + new Person("Tolstoy", 60) + )).subscribe(p -> System.out.println(p.getLastName())); + } + + @Bean + public RouterFunction composedRoutes(PersonRepository repository) { + return route() + // эта функция должна стоять раньше findAll - порядок следования роутов - важен + .GET("/func/person", queryParam("name", StringUtils::isNotEmpty), + request -> request.queryParam("name") + .map(repository::findAllByLastName) + .map(persons -> ok().body(persons, Person.class)) + .orElse(badRequest().build()) + ) + // пример другой реализации - начиная с запроса репозитория + .GET("/func/person", queryParam("age", StringUtils::isNotEmpty), + req -> repository.findAllByLastName( + req.queryParam("age").orElseThrow(IllegalArgumentException::new) + ) + .collectList() + .flatMap(persons -> ok().body(persons, Person.class))) + // Обратите внимание на использование хэндлера + .GET("/func/person", accept(APPLICATION_JSON), new PersonHandler(repository)::list) + // Обратите внимание на использование pathVariable + .GET("/func/person/{id}", accept(APPLICATION_JSON), + request -> repository.findById(request.pathVariable("id")) + .flatMap(person -> ok().contentType(APPLICATION_JSON).body(fromValue(person))) + .switchIfEmpty(notFound().build()) + ).build(); + } + + // Это пример хэндлера, который даже не бин + static class PersonHandler { + + private final PersonRepository repository; + + PersonHandler(PersonRepository repository) { + this.repository = repository; + } + + Mono list(ServerRequest request) { + // Обратите внимание на пример другого порядка создания response от Flux + return ok().contentType(APPLICATION_JSON).body(repository.findAll(), Person.class); + } + } +} + + diff --git a/2021-05/spring-20/spring-20-solution/src/main/java/ru/otus/spring/domain/Person.java b/2021-05/spring-20/spring-20-solution/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..d40218ec --- /dev/null +++ b/2021-05/spring-20/spring-20-solution/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,55 @@ +package ru.otus.spring.domain; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + +@Document +public class Person { + + @Id + private String id; + + @JsonProperty("name") + @Field("name") + private String lastName; + + private int age; + + public Person() { + } + + public Person(String lastName) { + this.lastName = lastName; + } + + public Person(String lastName, int age) { + this.lastName = lastName; + this.age = age; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } +} diff --git a/2021-05/spring-20/spring-20-solution/src/main/java/ru/otus/spring/repository/PersonRepository.java b/2021-05/spring-20/spring-20-solution/src/main/java/ru/otus/spring/repository/PersonRepository.java new file mode 100644 index 00000000..0584f0cb --- /dev/null +++ b/2021-05/spring-20/spring-20-solution/src/main/java/ru/otus/spring/repository/PersonRepository.java @@ -0,0 +1,20 @@ +package ru.otus.spring.repository; + +import org.springframework.data.mongodb.repository.ReactiveMongoRepository; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import ru.otus.spring.domain.Person; + +public interface PersonRepository + extends ReactiveMongoRepository { + + Flux findAll(); + + Mono findById(String id); + + Mono save(Mono person); + + Flux findAllByLastName(String lastName); + + Flux findAllByAge(int age); +} diff --git a/2021-05/spring-20/spring-20-solution/src/main/java/ru/otus/spring/rest/AnnotatedController.java b/2021-05/spring-20/spring-20-solution/src/main/java/ru/otus/spring/rest/AnnotatedController.java new file mode 100644 index 00000000..184da872 --- /dev/null +++ b/2021-05/spring-20/spring-20-solution/src/main/java/ru/otus/spring/rest/AnnotatedController.java @@ -0,0 +1,34 @@ +package ru.otus.spring.rest; + +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +@RestController +public class AnnotatedController { + + @GetMapping("/flux/one") + public Mono one() { + return Mono.just("one") + .map(String::toUpperCase); + } + + @GetMapping("/flux/ten") + public Flux list() { + return Flux.range(1, 10); + } + + @GetMapping(path = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public Flux stream() { + return Flux.generate(() -> 0, (state, emitter) -> { + emitter.next(state); + return state + 1; + }) + .delayElements(Duration.ofSeconds(1L)) + .map(i -> "" + i); + } +} diff --git a/2021-05/spring-20/spring-20-solution/src/main/java/ru/otus/spring/rest/PersonController.java b/2021-05/spring-20/spring-20-solution/src/main/java/ru/otus/spring/rest/PersonController.java new file mode 100644 index 00000000..2edcaea9 --- /dev/null +++ b/2021-05/spring-20/spring-20-solution/src/main/java/ru/otus/spring/rest/PersonController.java @@ -0,0 +1,42 @@ +package ru.otus.spring.rest; + +import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repository.PersonRepository; + +@RestController +public class PersonController { + + private PersonRepository repository; + + public PersonController(PersonRepository repository) { + this.repository = repository; + } + + @GetMapping("/person") + public Flux all() { + return repository.findAll(); + } + + @GetMapping("/person/{id}") + public Mono byId(@PathVariable("id") String id) { + return repository.findById(id); + } + + @GetMapping("/person/byname") + public Flux byName(@RequestParam("name") String lastName) { + return repository.findAllByLastName(lastName); + } + + @GetMapping("/person/byage") + public Flux byAge(@RequestParam int age) { + return repository.findAllByAge(age); + } + + @PostMapping("/person") + public Mono save(@RequestBody Mono dto) { + return repository.save(dto); + } +} diff --git a/2021-05/spring-20/spring-20-solution/src/test/java/ru/otus/spring/repository/PersonRepositoryTest.java b/2021-05/spring-20/spring-20-solution/src/test/java/ru/otus/spring/repository/PersonRepositoryTest.java new file mode 100644 index 00000000..2f373b60 --- /dev/null +++ b/2021-05/spring-20/spring-20-solution/src/test/java/ru/otus/spring/repository/PersonRepositoryTest.java @@ -0,0 +1,28 @@ +package ru.otus.spring.repository; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; +import ru.otus.spring.domain.Person; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@DataMongoTest +public class PersonRepositoryTest { + + @Autowired + private PersonRepository repository; + + @Test + public void shouldSetIdOnSave() { + Mono personMono = repository.save(new Person("Bill", 12)); + + StepVerifier + .create(personMono) + .assertNext(person -> assertNotNull(person.getId())) + .expectComplete() + .verify(); + } +} diff --git a/2021-05/spring-20/spring-20-solution/src/test/java/ru/otus/spring/rest/PersonControllerTest.java b/2021-05/spring-20/spring-20-solution/src/test/java/ru/otus/spring/rest/PersonControllerTest.java new file mode 100644 index 00000000..d1504547 --- /dev/null +++ b/2021-05/spring-20/spring-20-solution/src/test/java/ru/otus/spring/rest/PersonControllerTest.java @@ -0,0 +1,28 @@ +package ru.otus.spring.rest; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.ServerResponse; + +@SpringBootTest +public class PersonControllerTest { + + @Autowired + private RouterFunction route; + + @Test + public void testRoute() { + WebTestClient client = WebTestClient + .bindToRouterFunction(route) + .build(); + + client.get() + .uri("/func/person") + .exchange() + .expectStatus() + .isOk(); + } +} diff --git a/examples/spring-mail-rabbitmq-demo/user-activity-models/pom.xml b/examples/spring-mail-rabbitmq-demo/user-activity-models/pom.xml index 840cec44..125b378f 100644 --- a/examples/spring-mail-rabbitmq-demo/user-activity-models/pom.xml +++ b/examples/spring-mail-rabbitmq-demo/user-activity-models/pom.xml @@ -32,7 +32,7 @@ org.projectlombok lombok - 1.18.8 + 1.18.20 true