diff --git a/2021-02/spring-07-jdbc/jdbc-class-work/jdbc-demo-solution-final/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java b/2021-02/spring-07-jdbc/jdbc-class-work/jdbc-demo-solution-final/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java
index f70dffc7..ac9477f5 100644
--- a/2021-02/spring-07-jdbc/jdbc-class-work/jdbc-demo-solution-final/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java
+++ b/2021-02/spring-07-jdbc/jdbc-class-work/jdbc-demo-solution-final/src/main/java/ru/otus/spring/dao/PersonDaoJdbc.java
@@ -21,7 +21,6 @@ public class PersonDaoJdbc implements PersonDao {
public PersonDaoJdbc(NamedParameterJdbcOperations namedParameterJdbcOperations)
{
- // Это просто оставили, чтобы не переписывать код
// В идеале всё должно быть на NamedParameterJdbcOperations
this.jdbc = namedParameterJdbcOperations.getJdbcOperations();
this.namedParameterJdbcOperations = namedParameterJdbcOperations;
diff --git a/2021-02/spring-17-jquery/spring-17-boot-and-react/.gitignore b/2021-02/spring-17-jquery/spring-17-boot-and-react/.gitignore
new file mode 100644
index 00000000..b11e399f
--- /dev/null
+++ b/2021-02/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-02/spring-17-jquery/spring-17-boot-and-react/package.json b/2021-02/spring-17-jquery/spring-17-boot-and-react/package.json
new file mode 100644
index 00000000..f7dc8478
--- /dev/null
+++ b/2021-02/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-02/spring-17-jquery/spring-17-boot-and-react/pom.xml b/2021-02/spring-17-jquery/spring-17-boot-and-react/pom.xml
new file mode 100644
index 00000000..6256e3f1
--- /dev/null
+++ b/2021-02/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-02/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/Main.java b/2021-02/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-02/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-02/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/domain/Person.java b/2021-02/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-02/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-02/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2021-02/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-02/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-02/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/rest/PersonController.java b/2021-02/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-02/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-02/spring-17-jquery/spring-17-boot-and-react/src/main/java/ru/otus/spring/rest/dto/PersonDto.java b/2021-02/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-02/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-02/spring-17-jquery/spring-17-boot-and-react/src/ui/components/App.js b/2021-02/spring-17-jquery/spring-17-boot-and-react/src/ui/components/App.js
new file mode 100644
index 00000000..79f94811
--- /dev/null
+++ b/2021-02/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 (
+
+
+
+
+
+ | ID |
+ Name |
+
+
+
+ {
+ this.state.persons.map((person, i) => (
+
+ | {person.id} |
+ {person.name} |
+
+ ))
+ }
+
+
+
+ )
+ }
+};
diff --git a/2021-02/spring-17-jquery/spring-17-boot-and-react/src/ui/index.html b/2021-02/spring-17-jquery/spring-17-boot-and-react/src/ui/index.html
new file mode 100644
index 00000000..86fc7182
--- /dev/null
+++ b/2021-02/spring-17-jquery/spring-17-boot-and-react/src/ui/index.html
@@ -0,0 +1,15 @@
+
+
+
+ Minimal React Boilerplate
+
+
+
+
+
+
+
+
+
diff --git a/2021-02/spring-17-jquery/spring-17-boot-and-react/src/ui/index.js b/2021-02/spring-17-jquery/spring-17-boot-and-react/src/ui/index.js
new file mode 100644
index 00000000..52a1c724
--- /dev/null
+++ b/2021-02/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-02/spring-17-jquery/spring-17-boot-and-react/webpack.config.js b/2021-02/spring-17-jquery/spring-17-boot-and-react/webpack.config.js
new file mode 100644
index 00000000..654887cc
--- /dev/null
+++ b/2021-02/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-02/spring-17-jquery/spring-17-boot-and-react/webpack.dev.config.js b/2021-02/spring-17-jquery/spring-17-boot-and-react/webpack.dev.config.js
new file mode 100644
index 00000000..97817ef7
--- /dev/null
+++ b/2021-02/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-02/spring-17-jquery/spring-17-jquery/.gitignore b/2021-02/spring-17-jquery/spring-17-jquery/.gitignore
new file mode 100644
index 00000000..4ea52072
--- /dev/null
+++ b/2021-02/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-02/spring-17-jquery/spring-17-jquery/pom.xml b/2021-02/spring-17-jquery/spring-17-jquery/pom.xml
new file mode 100644
index 00000000..cb4de97d
--- /dev/null
+++ b/2021-02/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-02/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/Main.java b/2021-02/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-02/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-02/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/domain/Person.java b/2021-02/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-02/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-02/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/page/PersonPagesController.java b/2021-02/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-02/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-02/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2021-02/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-02/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-02/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/rest/PersonController.java b/2021-02/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-02/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-02/spring-17-jquery/spring-17-jquery/src/main/java/ru/otus/spring/rest/dto/PersonDto.java b/2021-02/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-02/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-02/spring-17-jquery/spring-17-jquery/src/main/resources/templates/list.html b/2021-02/spring-17-jquery/spring-17-jquery/src/main/resources/templates/list.html
new file mode 100644
index 00000000..a782b158
--- /dev/null
+++ b/2021-02/spring-17-jquery/spring-17-jquery/src/main/resources/templates/list.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+ List of all persons
+
+
+
+
+Persons:
+
+
+
+
+ | ID |
+ Name |
+
+
+
+
+
+
+
+
diff --git a/2021-05/junit/.gitignore b/2021-05/junit/.gitignore
new file mode 100644
index 00000000..4ea52072
--- /dev/null
+++ b/2021-05/junit/.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/junit/pom.xml b/2021-05/junit/pom.xml
new file mode 100644
index 00000000..caaa26a8
--- /dev/null
+++ b/2021-05/junit/pom.xml
@@ -0,0 +1,31 @@
+
+
+ 4.0.0
+
+ ru.otus
+ junit
+ 1.0
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.4.6
+
+
+
+
+ 11
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
diff --git a/2021-05/junit/src/main/java/ru/otus/junit/dao/PersonDao.java b/2021-05/junit/src/main/java/ru/otus/junit/dao/PersonDao.java
new file mode 100644
index 00000000..6ff0d1ef
--- /dev/null
+++ b/2021-05/junit/src/main/java/ru/otus/junit/dao/PersonDao.java
@@ -0,0 +1,16 @@
+package ru.otus.junit.dao;
+
+import ru.otus.junit.domain.Person;
+
+import java.util.List;
+
+public interface PersonDao {
+
+ Person getByName(String name) throws PersonNotFoundException;
+
+ List getAll();
+
+ void deleteByName(String name) throws PersonNotFoundException;
+
+ void save(Person person);
+}
diff --git a/2021-05/junit/src/main/java/ru/otus/junit/dao/PersonDaoImpl.java b/2021-05/junit/src/main/java/ru/otus/junit/dao/PersonDaoImpl.java
new file mode 100644
index 00000000..59aa9b5d
--- /dev/null
+++ b/2021-05/junit/src/main/java/ru/otus/junit/dao/PersonDaoImpl.java
@@ -0,0 +1,36 @@
+package ru.otus.junit.dao;
+
+import ru.otus.junit.domain.Person;
+
+import java.util.List;
+
+public class PersonDaoImpl implements PersonDao {
+
+ // здесь будет поле - список Person-ов
+
+ @Override
+ public Person getByName(String name) throws PersonNotFoundException {
+ // TODO: реализовать поиск в списке по имени (по технике Test-First)
+ // TODO: да, этот метод может бросать Exception, и это нужно покрыть другим тестом
+ return null;
+ }
+
+ @Override
+ public List getAll() {
+ // TODO: реализовать получние всех Person (по технике Test-First)
+ return null;
+ }
+
+ @Override
+ public void deleteByName(String name) throws PersonNotFoundException {
+ // TODO: реализовать удаление по имени (по технике Test-First)
+ // TODO: да, этот метод может бросать Exception, и это нужно покрыть другим тестом
+ }
+
+ @Override
+ public void save(Person person) {
+ // TODO: этот метод должен найти по имени в списке
+ // TODO: если такой есть - заменить
+ // TODO: если такого нет - добавить
+ }
+}
diff --git a/2021-05/junit/src/main/java/ru/otus/junit/dao/PersonNotFoundException.java b/2021-05/junit/src/main/java/ru/otus/junit/dao/PersonNotFoundException.java
new file mode 100644
index 00000000..12f78d77
--- /dev/null
+++ b/2021-05/junit/src/main/java/ru/otus/junit/dao/PersonNotFoundException.java
@@ -0,0 +1,8 @@
+package ru.otus.junit.dao;
+
+public class PersonNotFoundException extends RuntimeException {
+
+ public PersonNotFoundException(String message) {
+ super(message);
+ }
+}
diff --git a/2021-05/junit/src/main/java/ru/otus/junit/domain/Person.java b/2021-05/junit/src/main/java/ru/otus/junit/domain/Person.java
new file mode 100644
index 00000000..10d5294c
--- /dev/null
+++ b/2021-05/junit/src/main/java/ru/otus/junit/domain/Person.java
@@ -0,0 +1,32 @@
+package ru.otus.junit.domain;
+
+@SuppressWarnings({"WeakerAccess", "unused"})
+public class Person {
+
+ private int age;
+ private String name;
+
+ public Person(int age, String name) {
+ this.age = age;
+ this.name = name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void birthDay() {
+ this.age++;
+ }
+}
diff --git a/2021-05/junit/src/main/java/ru/otus/junit/service/PersonService.java b/2021-05/junit/src/main/java/ru/otus/junit/service/PersonService.java
new file mode 100644
index 00000000..0cb144f1
--- /dev/null
+++ b/2021-05/junit/src/main/java/ru/otus/junit/service/PersonService.java
@@ -0,0 +1,16 @@
+package ru.otus.junit.service;
+
+import ru.otus.junit.domain.Person;
+
+import java.util.List;
+
+public interface PersonService {
+
+ Person getByName(String name);
+
+ List getAll();
+
+ boolean existsWithName(String name);
+
+ void save(Person p);
+}
diff --git a/2021-05/junit/src/main/java/ru/otus/junit/service/PersonServiceImpl.java b/2021-05/junit/src/main/java/ru/otus/junit/service/PersonServiceImpl.java
new file mode 100644
index 00000000..52b82f10
--- /dev/null
+++ b/2021-05/junit/src/main/java/ru/otus/junit/service/PersonServiceImpl.java
@@ -0,0 +1,37 @@
+package ru.otus.junit.service;
+
+import ru.otus.junit.dao.PersonDao;
+import ru.otus.junit.domain.Person;
+
+import java.util.List;
+
+public class PersonServiceImpl implements PersonService {
+
+ private final PersonDao dao;
+
+ PersonServiceImpl(PersonDao dao) {
+ this.dao = dao;
+ }
+
+ @Override
+ public Person getByName(String name) {
+ return dao.getByName(name);
+ }
+
+ @Override
+ public List getAll() {
+ // TODO: реализовать данный метод по технике Test-First
+ return null;
+ }
+
+ @Override
+ public boolean existsWithName(String name) {
+ // TODO: реализовать данный метод по технике Test-First
+ return false;
+ }
+
+ @Override
+ public void save(Person p) {
+ // TODO: реализовать данный метод по технике Test-First
+ }
+}
diff --git a/2021-05/junit/src/test/java/ru/otus/junit/domain/PersonTest.java b/2021-05/junit/src/test/java/ru/otus/junit/domain/PersonTest.java
new file mode 100644
index 00000000..30366c3f
--- /dev/null
+++ b/2021-05/junit/src/test/java/ru/otus/junit/domain/PersonTest.java
@@ -0,0 +1,23 @@
+package ru.otus.junit.domain;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@DisplayName("Класс Person")
+class PersonTest {
+
+ @DisplayName("корректно создаётся конструктором")
+ @Test
+ void shouldHaveCorrectConstructor() {
+ Person person = new Person(42, "Ivan");
+
+ assertEquals("Ivan", person.getName());
+ assertEquals(42, person.getAge());
+ }
+
+ // TODO: @DisplayName("должен")
+
+ // TODO: @DisplayName("должен увеличивать возраст при вызове birthDay")
+}
diff --git a/2021-05/junit/src/test/java/ru/otus/junit/service/PersonServiceImplTest.java b/2021-05/junit/src/test/java/ru/otus/junit/service/PersonServiceImplTest.java
new file mode 100644
index 00000000..25207d81
--- /dev/null
+++ b/2021-05/junit/src/test/java/ru/otus/junit/service/PersonServiceImplTest.java
@@ -0,0 +1,32 @@
+package ru.otus.junit.service;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import ru.otus.junit.dao.PersonDao;
+import ru.otus.junit.domain.Person;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.BDDMockito.given;
+
+@ExtendWith(MockitoExtension.class)
+class PersonServiceImplTest {
+
+ @Mock
+ private PersonDao personDao;
+ @InjectMocks
+ private PersonServiceImpl personService;
+
+ @Test
+ void getByName() {
+ // TODO: используйте eq() mapper вместо any()
+ given(personDao.getByName(any()))
+ .willReturn(new Person(10, "Ivan"));
+
+ assertThat(personService.getByName("Ivan"))
+ .isNotNull(); // TODO: сравните с помощью equals
+ }
+}
diff --git a/2021-05/spring-01/.gitignore b/2021-05/spring-01/.gitignore
new file mode 100644
index 00000000..4ea52072
--- /dev/null
+++ b/2021-05/spring-01/.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-01/pom.xml b/2021-05/spring-01/pom.xml
new file mode 100644
index 00000000..6658aaa0
--- /dev/null
+++ b/2021-05/spring-01/pom.xml
@@ -0,0 +1,17 @@
+
+
+ 4.0.0
+
+ ru.otus
+ spring-01
+ 1.0
+
+ pom
+
+
+ spring-01-exercise
+ spring-01-solution
+
+
diff --git a/2021-05/spring-01/spring-01-exercise/pom.xml b/2021-05/spring-01/spring-01-exercise/pom.xml
new file mode 100644
index 00000000..e3aa2772
--- /dev/null
+++ b/2021-05/spring-01/spring-01-exercise/pom.xml
@@ -0,0 +1,20 @@
+
+
+ 4.0.0
+
+ ru.otus
+ spring-01-exercise
+ 1.0
+
+
+ 11
+ 11
+ UTF-8
+
+
+
+
+
+
diff --git a/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/Main.java b/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/Main.java
new file mode 100644
index 00000000..e3201a16
--- /dev/null
+++ b/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/Main.java
@@ -0,0 +1,17 @@
+package ru.otus.spring;
+
+//import org.springframework.context.support.ClassPathXmlApplicationContext;
+import ru.otus.spring.domain.Person;
+
+public class Main {
+
+ public static void main(String[] args) {
+ // TODO: создайте здесь класс контекста
+
+ // TODO: Получите Person Service
+
+ // Получите Person "Ivan"
+ Person ivan = null;
+ System.out.println("name: " + ivan.getName() + " age: " + ivan.getAge());
+ }
+}
diff --git a/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/dao/PersonDao.java b/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/dao/PersonDao.java
new file mode 100644
index 00000000..d33939bd
--- /dev/null
+++ b/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/dao/PersonDao.java
@@ -0,0 +1,8 @@
+package ru.otus.spring.dao;
+
+import ru.otus.spring.domain.Person;
+
+public interface PersonDao {
+
+ Person findByName(String name);
+}
diff --git a/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/dao/PersonDaoSimple.java b/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/dao/PersonDaoSimple.java
new file mode 100644
index 00000000..7f7c97c6
--- /dev/null
+++ b/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/dao/PersonDaoSimple.java
@@ -0,0 +1,10 @@
+package ru.otus.spring.dao;
+
+import ru.otus.spring.domain.Person;
+
+public class PersonDaoSimple implements PersonDao {
+
+ public Person findByName(String name) {
+ return new Person(name, 18);
+ }
+}
diff --git a/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/domain/Person.java b/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/domain/Person.java
new file mode 100644
index 00000000..c23be0c6
--- /dev/null
+++ b/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/domain/Person.java
@@ -0,0 +1,20 @@
+package ru.otus.spring.domain;
+
+public class Person {
+
+ private final String name;
+ private final int age;
+
+ public Person(String name, int age) {
+ this.name = name;
+ this.age = age;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+}
diff --git a/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/service/PersonService.java b/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/service/PersonService.java
new file mode 100644
index 00000000..9b83e7de
--- /dev/null
+++ b/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/service/PersonService.java
@@ -0,0 +1,8 @@
+package ru.otus.spring.service;
+
+import ru.otus.spring.domain.Person;
+
+public interface PersonService {
+
+ Person getByName(String name);
+}
diff --git a/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/service/PersonServiceImpl.java b/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/service/PersonServiceImpl.java
new file mode 100644
index 00000000..794c29dd
--- /dev/null
+++ b/2021-05/spring-01/spring-01-exercise/src/main/java/ru/otus/spring/service/PersonServiceImpl.java
@@ -0,0 +1,17 @@
+package ru.otus.spring.service;
+
+import ru.otus.spring.dao.PersonDao;
+import ru.otus.spring.domain.Person;
+
+public class PersonServiceImpl implements PersonService {
+
+ private final PersonDao dao;
+
+ public PersonServiceImpl(PersonDao dao) {
+ this.dao = dao;
+ }
+
+ public Person getByName(String name) {
+ return dao.findByName(name);
+ }
+}
diff --git a/2021-05/spring-01/spring-01-exercise/src/main/resources/spring-context.xml b/2021-05/spring-01/spring-01-exercise/src/main/resources/spring-context.xml
new file mode 100644
index 00000000..2cb9eabe
--- /dev/null
+++ b/2021-05/spring-01/spring-01-exercise/src/main/resources/spring-context.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
diff --git a/2021-05/spring-01/spring-01-solution/pom.xml b/2021-05/spring-01/spring-01-solution/pom.xml
new file mode 100644
index 00000000..e0921a64
--- /dev/null
+++ b/2021-05/spring-01/spring-01-solution/pom.xml
@@ -0,0 +1,26 @@
+
+
+ 4.0.0
+
+ ru.otus
+ spring-01-solution
+ 1.0
+
+
+ 11
+ 11
+ UTF-8
+
+
+
+
+
+ org.springframework
+ spring-context
+ 5.3.7
+
+
+
diff --git a/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/Main.java b/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/Main.java
new file mode 100644
index 00000000..f5b2fafb
--- /dev/null
+++ b/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/Main.java
@@ -0,0 +1,20 @@
+package ru.otus.spring;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import ru.otus.spring.domain.Person;
+import ru.otus.spring.service.PersonService;
+
+public class Main {
+
+ public static void main(String[] args) {
+ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml");
+ PersonService service = context.getBean(PersonService.class);
+ Person ivan = service.getByName("Ivan");
+ System.out.println("name: " + ivan.getName() + " age: " + ivan.getAge());
+
+ // Данная операция, в принципе не нужна.
+ // Мы не работаем пока что с БД, а Spring Boot сделает закрытие за нас
+ // Подробности - через пару занятий
+ context.close();
+ }
+}
diff --git a/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/dao/PersonDao.java b/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/dao/PersonDao.java
new file mode 100644
index 00000000..d33939bd
--- /dev/null
+++ b/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/dao/PersonDao.java
@@ -0,0 +1,8 @@
+package ru.otus.spring.dao;
+
+import ru.otus.spring.domain.Person;
+
+public interface PersonDao {
+
+ Person findByName(String name);
+}
diff --git a/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/dao/PersonDaoSimple.java b/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/dao/PersonDaoSimple.java
new file mode 100644
index 00000000..7f7c97c6
--- /dev/null
+++ b/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/dao/PersonDaoSimple.java
@@ -0,0 +1,10 @@
+package ru.otus.spring.dao;
+
+import ru.otus.spring.domain.Person;
+
+public class PersonDaoSimple implements PersonDao {
+
+ public Person findByName(String name) {
+ return new Person(name, 18);
+ }
+}
diff --git a/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/domain/Person.java b/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/domain/Person.java
new file mode 100644
index 00000000..c23be0c6
--- /dev/null
+++ b/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/domain/Person.java
@@ -0,0 +1,20 @@
+package ru.otus.spring.domain;
+
+public class Person {
+
+ private final String name;
+ private final int age;
+
+ public Person(String name, int age) {
+ this.name = name;
+ this.age = age;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+}
diff --git a/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/service/PersonService.java b/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/service/PersonService.java
new file mode 100644
index 00000000..9b83e7de
--- /dev/null
+++ b/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/service/PersonService.java
@@ -0,0 +1,8 @@
+package ru.otus.spring.service;
+
+import ru.otus.spring.domain.Person;
+
+public interface PersonService {
+
+ Person getByName(String name);
+}
diff --git a/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/service/PersonServiceImpl.java b/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/service/PersonServiceImpl.java
new file mode 100644
index 00000000..794c29dd
--- /dev/null
+++ b/2021-05/spring-01/spring-01-solution/src/main/java/ru/otus/spring/service/PersonServiceImpl.java
@@ -0,0 +1,17 @@
+package ru.otus.spring.service;
+
+import ru.otus.spring.dao.PersonDao;
+import ru.otus.spring.domain.Person;
+
+public class PersonServiceImpl implements PersonService {
+
+ private final PersonDao dao;
+
+ public PersonServiceImpl(PersonDao dao) {
+ this.dao = dao;
+ }
+
+ public Person getByName(String name) {
+ return dao.findByName(name);
+ }
+}
diff --git a/2021-05/spring-01/spring-01-solution/src/main/resources/spring-context.xml b/2021-05/spring-01/spring-01-solution/src/main/resources/spring-context.xml
new file mode 100644
index 00000000..c3541cec
--- /dev/null
+++ b/2021-05/spring-01/spring-01-solution/src/main/resources/spring-context.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+