mirror of
https://github.com/OtusTeam/Spring.git
synced 2026-05-30 10:50:42 +00:00
Merge branch 'master' of github.com:OtusTeam/Spring
This commit is contained in:
@@ -20,11 +20,6 @@
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
|
||||
@@ -20,11 +20,6 @@
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
|
||||
@@ -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/
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>ru.otus</groupId>
|
||||
<artifactId>spring-mvc-view-class-work</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>spring-mvc-view-exercise</module>
|
||||
<module>spring-mvc-view-solution</module>
|
||||
</modules>
|
||||
</project>
|
||||
@@ -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/
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>ru.otus</groupId>
|
||||
<artifactId>spring-mvc-view-exercise</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.2.6.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+28
@@ -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"));
|
||||
}
|
||||
}
|
||||
+37
@@ -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;
|
||||
}
|
||||
}
|
||||
+11
@@ -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<Person, Integer> {
|
||||
|
||||
List<Person> findAll();
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package ru.otus.spring.rest;
|
||||
|
||||
class NotFoundException extends RuntimeException{
|
||||
|
||||
NotFoundException() {
|
||||
}
|
||||
}
|
||||
+35
@@ -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<Person> persons = repository.findAll();
|
||||
model.addAttribute("persons", persons);
|
||||
return "list";
|
||||
}
|
||||
|
||||
@GetMapping("/edit")
|
||||
public String editPage(@RequestParam("id") int id, Model model) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>Edit person</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
padding: 50px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
input:read-only {
|
||||
background: lightgray;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Person edition -->
|
||||
<form id="edit-form" action="edit.html">
|
||||
<h1>Person Info:</h1>
|
||||
|
||||
<div class="row">
|
||||
<label for="id-input">ID:</label>
|
||||
<input id="id-input" type="text" readonly="readonly" value="1"/>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<label for="holder-input">Name:</label>
|
||||
<input id="holder-input" name="name" type="text" value="John Doe"/>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<button type="submit">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>List of all persons</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
padding: 50px;
|
||||
}
|
||||
|
||||
.persons, .persons td {
|
||||
border: 1px solid lightgray;
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Persons:</h1>
|
||||
|
||||
<table class="persons">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>John Doe</td>
|
||||
<td>
|
||||
<a href="edit.html">Edit</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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/
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>ru.otus</groupId>
|
||||
<artifactId>spring-mvc-view-solution</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.2.6.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+27
@@ -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"));
|
||||
}
|
||||
}
|
||||
+37
@@ -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;
|
||||
}
|
||||
}
|
||||
+11
@@ -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<Person, Integer> {
|
||||
|
||||
List<Person> findAll();
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package ru.otus.spring.rest;
|
||||
|
||||
class NotFoundException extends RuntimeException{
|
||||
|
||||
NotFoundException() {
|
||||
}
|
||||
}
|
||||
+52
@@ -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<Person> 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";
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>Edit person</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
padding: 50px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
input:read-only {
|
||||
background: lightgray;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Person edition -->
|
||||
<form id="edit-form" th:action="@{/edit(id=${person.id})}" th:method="post" action="edit.html">
|
||||
<h1>Person Info:</h1>
|
||||
|
||||
<div class="row">
|
||||
<label for="id-input">ID:</label>
|
||||
<input id="id-input" type="text" readonly="readonly" th:value="${person.id}" value="1"/>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<label for="holder-input">Name:</label>
|
||||
<input id="holder-input" name="name" type="text" th:value="${person.name}" value="John Doe"/>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<button type="submit">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>List of all persons</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
padding: 50px;
|
||||
}
|
||||
|
||||
.persons, .persons td {
|
||||
border: 1px solid lightgray;
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Persons:</h1>
|
||||
|
||||
<table class="persons">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="person : ${persons}">
|
||||
<td th:text="${person.id}">1</td>
|
||||
<td th:text="${person.name}">John Doe</td>
|
||||
<td>
|
||||
<a th:href="@{/edit(id=${person.id})}" href="edit.html">Edit</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>ru.otus</groupId>
|
||||
<artifactId>spring-17-boot-and-react</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.2.4.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.github.eirslett</groupId>
|
||||
<artifactId>frontend-maven-plugin</artifactId>
|
||||
<version>1.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>install node and npm</id>
|
||||
<goals>
|
||||
<goal>install-node-and-npm</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<nodeVersion>v10.15.1</nodeVersion>
|
||||
<npmVersion>6.4.1</npmVersion>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>npm install</id>
|
||||
<goals>
|
||||
<goal>npm</goal>
|
||||
</goals>
|
||||
<phase>generate-resources</phase>
|
||||
<configuration>
|
||||
<arguments>install</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>npm run build</id>
|
||||
<goals>
|
||||
<goal>npm</goal>
|
||||
</goals>
|
||||
<phase>generate-resources</phase>
|
||||
<configuration>
|
||||
<arguments>run build</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+27
@@ -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"));
|
||||
}
|
||||
}
|
||||
+37
@@ -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;
|
||||
}
|
||||
}
|
||||
+11
@@ -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<Person, Integer> {
|
||||
|
||||
List<Person> findAll();
|
||||
}
|
||||
+30
@@ -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<PersonDto> getAllPersons() {
|
||||
return repository.findAll().stream().map(PersonDto::toDto)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+50
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import React from 'react'
|
||||
|
||||
const Header = (props) => (
|
||||
<h1>{props.title}</h1>
|
||||
);
|
||||
|
||||
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 (
|
||||
<React.Fragment>
|
||||
<Header title={'Persons'}/>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
this.state.persons.map((person, i) => (
|
||||
<tr key={i}>
|
||||
<td>{person.id}</td>
|
||||
<td>{person.name}</td>
|
||||
</tr>
|
||||
))
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Minimal React Boilerplate</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
|
||||
<div id="root"></div>
|
||||
|
||||
<script src="./bundle.js" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
|
||||
import App from './components/App'
|
||||
|
||||
ReactDOM.render(
|
||||
<App />,
|
||||
document.getElementById('root')
|
||||
)
|
||||
@@ -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'
|
||||
})
|
||||
]
|
||||
}
|
||||
@@ -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'
|
||||
})
|
||||
]
|
||||
}
|
||||
@@ -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/
|
||||
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>ru.otus</groupId>
|
||||
<artifactId>spring-17-jquery</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.2.4.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>jquery</artifactId>
|
||||
<version>3.3.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
+37
@@ -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;
|
||||
}
|
||||
}
|
||||
+15
@@ -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";
|
||||
}
|
||||
}
|
||||
+11
@@ -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<Person, Integer> {
|
||||
|
||||
List<Person> findAll();
|
||||
}
|
||||
+30
@@ -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<PersonDto> getAllPersons() {
|
||||
return repository.findAll().stream().map(PersonDto::toDto)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+50
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="keywords" th:content="${keywords}"/>
|
||||
<title>List of all persons</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
padding: 50px;
|
||||
}
|
||||
|
||||
.persons, .persons td {
|
||||
border: 1px solid lightgray;
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
||||
<script src="/webjars/jquery/3.3.1/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Persons:</h1>
|
||||
|
||||
<table class="persons">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<script>
|
||||
$(function () {
|
||||
$.get('/api/persons').done(function (persons) {
|
||||
persons.forEach(function (person) {
|
||||
$('tbody').append(`
|
||||
<tr>
|
||||
<td>${person.id}</td>
|
||||
<td>${person.name}</td>
|
||||
</tr>
|
||||
`)
|
||||
});
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,7 @@
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
target/
|
||||
|
||||
/node_modules
|
||||
/output
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>ru.otus</groupId>
|
||||
<artifactId>spring-18</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.2.4.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.reactivex.rxjava2</groupId>
|
||||
<artifactId>rxjava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>27.1-jre</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,35 @@
|
||||
package ru.otus;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
public class CreateExamples {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Observable<String> obs = justExample();
|
||||
obs.forEach(System.out::println);
|
||||
obs.forEach(System.out::println);
|
||||
}
|
||||
|
||||
public static Observable<String> justExample() {
|
||||
return Observable.just("one", "two", "three");
|
||||
}
|
||||
|
||||
public static Observable<String> 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<String> deferExample() {
|
||||
return Observable.defer(() -> Observable.just("one", "two", "three"));
|
||||
}
|
||||
}
|
||||
@@ -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<String> getName() {
|
||||
return Observable.just("Jake");
|
||||
}
|
||||
|
||||
static Observable<String> getSurname() {
|
||||
return Observable.just("Foo");
|
||||
}
|
||||
|
||||
static Observable<String> save(String fullName) {
|
||||
System.out.println(fullName + " saved!");
|
||||
return Observable.just("OK!");
|
||||
}
|
||||
}
|
||||
@@ -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<Person> 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<String> 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<String> magicPublisher() {
|
||||
Random r = new Random(1);
|
||||
AtomicInteger i = new AtomicInteger();
|
||||
final Observable<String> obs = Observable.<String>generate(emitter ->
|
||||
emitter.onNext("" + i.incrementAndGet()))
|
||||
.concatMap(s -> Observable.just(s).delay(r.nextInt(1000), TimeUnit.MILLISECONDS))
|
||||
.subscribeOn(Schedulers.newThread());
|
||||
PublishSubject<String> subject = PublishSubject.create();
|
||||
|
||||
// BehaviorSubject<String> subject = BehaviorSubject.create();
|
||||
|
||||
// AsyncSubject<String> subject = AsyncSubject.create();
|
||||
// CompletableFuture.runAsync(() -> {
|
||||
// try {
|
||||
// Thread.sleep(7000);
|
||||
// } catch (InterruptedException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// subject.onComplete();
|
||||
// });
|
||||
|
||||
// ReplaySubject<String> subject = ReplaySubject.create();
|
||||
obs.subscribe(subject);
|
||||
return subject;
|
||||
}
|
||||
|
||||
//composeExmaple
|
||||
private static ObservableTransformer<String, String> filterAndUpperCase() {
|
||||
return upstream -> upstream
|
||||
.filter(s -> s.length() >= 4)
|
||||
.map(String::toUpperCase);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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<String> obs = controller();
|
||||
obs.subscribe(System.out::println);
|
||||
System.out.println("Wait time " + (System.currentTimeMillis() - timeStarted));
|
||||
System.in.read();
|
||||
}
|
||||
|
||||
static Observable<String> controller() {
|
||||
return service();
|
||||
}
|
||||
|
||||
static Observable<String> service() {
|
||||
return repository();
|
||||
}
|
||||
|
||||
static Observable<String> repository() {
|
||||
return database();
|
||||
}
|
||||
|
||||
static Observable<String> 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());
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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/
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>ru.otus</groupId>
|
||||
<artifactId>spring-19</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>spring-19-web-flux</module>
|
||||
<module>spring-19-reactor</module>
|
||||
<module>spring-19-reactive-spring-data</module>
|
||||
</modules>
|
||||
</project>
|
||||
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>ru.otus</groupId>
|
||||
<artifactId>spring-19-reactive-spring-data</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.2.6.RELEASE</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.target>13</maven.compiler.target>
|
||||
<maven.compiler.source>13</maven.compiler.source>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongodb-driver-reactivestreams</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>de.flapdoodle.embed</groupId>
|
||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+20
@@ -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);
|
||||
}
|
||||
}
|
||||
+37
@@ -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;
|
||||
}
|
||||
}
|
||||
+27
@@ -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;
|
||||
}
|
||||
}
|
||||
+8
@@ -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<Account, String> {
|
||||
}
|
||||
+15
@@ -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<Person, String> {
|
||||
Flux<Person> findByName(String name);
|
||||
|
||||
@Query("{ 'name': ?0 }")
|
||||
Mono<Person> findFirstByName(String name);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>ru.otus</groupId>
|
||||
<artifactId>spring-19-reactor</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.2.6.RELEASE</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.target>13</maven.compiler.target>
|
||||
<maven.compiler.source>13</maven.compiler.source>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+50
@@ -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<Message> 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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
+24
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>ru.otus</groupId>
|
||||
<artifactId>spring-19-web-flux</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.2.6.RELEASE</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.target>13</maven.compiler.target>
|
||||
<maven.compiler.source>13</maven.compiler.source>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- работает и без неё, но нужна нам, для RxJava методов -->
|
||||
<dependency>
|
||||
<groupId>io.reactivex.rxjava2</groupId>
|
||||
<artifactId>rxjava</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+33
@@ -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<String> one() {
|
||||
return Mono.just("one");
|
||||
}
|
||||
|
||||
@GetMapping("/flux/ten")
|
||||
public Flux<Integer> list() {
|
||||
return Flux.range(1, 10);
|
||||
}
|
||||
|
||||
@GetMapping(path = "/flux/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
public Flux<String> stream() {
|
||||
return Flux.generate(() -> 0, (state, emitter) -> {
|
||||
emitter.next(state);
|
||||
return state + 1;
|
||||
})
|
||||
.delayElements(Duration.ofSeconds(1L))
|
||||
.map(Object::toString);
|
||||
}
|
||||
}
|
||||
+20
@@ -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<String> single() {
|
||||
return Single.just("one");
|
||||
}
|
||||
|
||||
@GetMapping("/rx/ten")
|
||||
public Flowable<Integer> list() {
|
||||
return Flowable.range(1, 10);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
target/
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>ru.otus</groupId>
|
||||
<artifactId>spring-20</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>spring-20-exercise</module>
|
||||
<module>spring-20-solution</module>
|
||||
</modules>
|
||||
</project>
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>ru.otus</groupId>
|
||||
<artifactId>spring-20-exercise</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.4.5</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Зависимости WebFlux -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Зависимости Reactive SpringData -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.flapdoodle.embed</groupId>
|
||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Тестирование -->
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -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<ServerResponse> 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<ServerResponse> list(ServerRequest request) {
|
||||
// Обратите внимание на пример другого порядка создания response от Flux
|
||||
return ok().contentType(APPLICATION_JSON).body(repository.findAll(), Person.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
+20
@@ -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<Person, String> {
|
||||
|
||||
Flux<Person> findAll();
|
||||
|
||||
Mono<Person> findById(String id);
|
||||
|
||||
Mono<Person> save(Mono<Person> person);
|
||||
|
||||
Flux<Person> findAllByLastName(String lastName);
|
||||
|
||||
Flux<Person> findAllByAge(int age);
|
||||
}
|
||||
+33
@@ -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<String> one() {
|
||||
return Mono.just("one");
|
||||
}
|
||||
|
||||
@GetMapping("/flux/ten")
|
||||
public Flux<Integer> list() {
|
||||
return Flux.range(1, 10).delayElements(Duration.ofSeconds(1));
|
||||
}
|
||||
|
||||
@GetMapping(path = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
public Flux<String> stream() {
|
||||
return Flux.generate(() -> 0, (state, emitter) -> {
|
||||
emitter.next(state);
|
||||
return state + 1;
|
||||
})
|
||||
.delayElements(Duration.ofSeconds(1L))
|
||||
.map(i -> "" + i);
|
||||
}
|
||||
}
|
||||
+37
@@ -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<Person> all() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
@GetMapping("/person/{id}")
|
||||
public Mono<Person> byId(@PathVariable("id") String id) {
|
||||
return repository.findById(id);
|
||||
}
|
||||
|
||||
@PostMapping("/person")
|
||||
public Mono<Person> save(@RequestBody Mono<Person> dto) {
|
||||
return repository.save(dto);
|
||||
}
|
||||
|
||||
@GetMapping("/person/find")
|
||||
public Flux<Person> byName(@RequestParam("name") String name) {
|
||||
return repository.findAllByLastName(name);
|
||||
}
|
||||
}
|
||||
+28
@@ -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<Person> personMono = repository.save(new Person("Bill", 12));
|
||||
|
||||
StepVerifier
|
||||
.create(personMono)
|
||||
.assertNext(person -> assertNotNull(person.getId()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
}
|
||||
+28
@@ -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<ServerResponse> route;
|
||||
|
||||
@Test
|
||||
public void testRoute() {
|
||||
WebTestClient client = WebTestClient
|
||||
.bindToRouterFunction(route)
|
||||
.build();
|
||||
|
||||
client.get()
|
||||
.uri("/func/person")
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>ru.otus</groupId>
|
||||
<artifactId>spring-20-solution</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.4.5</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Зависимости WebFlux -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Зависимости Reactive SpringData -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.flapdoodle.embed</groupId>
|
||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Тестирование -->
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -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<ServerResponse> 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<ServerResponse> list(ServerRequest request) {
|
||||
// Обратите внимание на пример другого порядка создания response от Flux
|
||||
return ok().contentType(APPLICATION_JSON).body(repository.findAll(), Person.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
+20
@@ -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<Person, String> {
|
||||
|
||||
Flux<Person> findAll();
|
||||
|
||||
Mono<Person> findById(String id);
|
||||
|
||||
Mono<Person> save(Mono<Person> person);
|
||||
|
||||
Flux<Person> findAllByLastName(String lastName);
|
||||
|
||||
Flux<Person> findAllByAge(int age);
|
||||
}
|
||||
+34
@@ -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<String> one() {
|
||||
return Mono.just("one")
|
||||
.map(String::toUpperCase);
|
||||
}
|
||||
|
||||
@GetMapping("/flux/ten")
|
||||
public Flux<Integer> list() {
|
||||
return Flux.range(1, 10);
|
||||
}
|
||||
|
||||
@GetMapping(path = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
public Flux<String> stream() {
|
||||
return Flux.generate(() -> 0, (state, emitter) -> {
|
||||
emitter.next(state);
|
||||
return state + 1;
|
||||
})
|
||||
.delayElements(Duration.ofSeconds(1L))
|
||||
.map(i -> "" + i);
|
||||
}
|
||||
}
|
||||
+42
@@ -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<Person> all() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
@GetMapping("/person/{id}")
|
||||
public Mono<Person> byId(@PathVariable("id") String id) {
|
||||
return repository.findById(id);
|
||||
}
|
||||
|
||||
@GetMapping("/person/byname")
|
||||
public Flux<Person> byName(@RequestParam("name") String lastName) {
|
||||
return repository.findAllByLastName(lastName);
|
||||
}
|
||||
|
||||
@GetMapping("/person/byage")
|
||||
public Flux<Person> byAge(@RequestParam int age) {
|
||||
return repository.findAllByAge(age);
|
||||
}
|
||||
|
||||
@PostMapping("/person")
|
||||
public Mono<Person> save(@RequestBody Mono<Person> dto) {
|
||||
return repository.save(dto);
|
||||
}
|
||||
}
|
||||
+28
@@ -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<Person> personMono = repository.save(new Person("Bill", 12));
|
||||
|
||||
StepVerifier
|
||||
.create(personMono)
|
||||
.assertNext(person -> assertNotNull(person.getId()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
}
|
||||
+28
@@ -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<ServerResponse> route;
|
||||
|
||||
@Test
|
||||
public void testRoute() {
|
||||
WebTestClient client = WebTestClient
|
||||
.bindToRouterFunction(route)
|
||||
.build();
|
||||
|
||||
client.get()
|
||||
.uri("/func/person")
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk();
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.8</version>
|
||||
<version>1.18.20</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
Reference in New Issue
Block a user