diff --git a/.idea/checkstyle-idea.xml b/.idea/checkstyle-idea.xml new file mode 100644 index 00000000..90a26268 --- /dev/null +++ b/.idea/checkstyle-idea.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 00000000..f3523e62 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/module01/pom.xml b/module01/pom.xml index 932df7e3..ced793e4 100644 --- a/module01/pom.xml +++ b/module01/pom.xml @@ -12,6 +12,37 @@ module01 + + + junit + junit + 4.13.2 + test + + + org.testng + testng + RELEASE + compile + + + org.slf4j + slf4j-api + 1.6.1 + + + org.slf4j + slf4j-simple + 1.6.1 + + + junit + junit + 4.13.2 + compile + + + UTF-8 diff --git a/module01/src/main/java/ru/sberbank/edu/GCD.java b/module01/src/main/java/ru/sberbank/edu/GCD.java new file mode 100644 index 00000000..28096079 --- /dev/null +++ b/module01/src/main/java/ru/sberbank/edu/GCD.java @@ -0,0 +1,43 @@ +package ru.sberbank.edu; + +public class GCD implements CommonDivisor{ + /** + * Метод выводит наибольший общий делитель 2х чисел. (Алгоримт Евклида) + */ + @Override + public int getDivisor(int firstNumber, int secondNumber) { + int simpleCasesValue = simpleCases(firstNumber, secondNumber); + if (simpleCasesValue != -1) { + return simpleCasesValue; + } + int firstNum = firstNumber; + int secondNum = secondNumber; + while (firstNum != 0 && secondNum != 0) { + if (firstNum > secondNum) { + firstNum = firstNum - secondNum; + } + else { + secondNum = secondNum - firstNum; + } + } + return firstNum + secondNum; + } + + + /** + * Метод выводит наибольший общий делитель 2х чисел для простого случая. + */ + private int simpleCases(int firstNumber, int secondNumber) { + if (firstNumber == secondNumber) { + return firstNumber; + } + if (firstNumber == 0) { + return secondNumber; + } + if (secondNumber == 0) { + return firstNumber; + } + return -1; + } +} + diff --git a/module01/src/main/java/ru/sberbank/edu/GreetingImpl.java b/module01/src/main/java/ru/sberbank/edu/GreetingImpl.java new file mode 100644 index 00000000..b2106872 --- /dev/null +++ b/module01/src/main/java/ru/sberbank/edu/GreetingImpl.java @@ -0,0 +1,19 @@ +package ru.sberbank.edu; + +public class GreetingImpl implements Greeting{ + /** + * Метод выводит информацию о разработчике данного класса + */ + @Override + public String getBestHobby() { + String name = "Дмитрий"; + String lastName = "Карпов"; + String post = "Инженер по нагрузочному тестированию"; + String hobby = "Увлекаюсь програмированием на Java, люблю активные виды спорта \n" + + "(волейбол, настольный тенис, катание на велосипеде) и путешествия"; + return "Имя: " + name + ",\n" + + "Фамилия: " + lastName + ",\n" + + "Должность: " + post + ",\n" + + "Хобби: " + hobby; + } +} diff --git a/module01/src/main/java/test/GCDTest.java b/module01/src/main/java/test/GCDTest.java new file mode 100644 index 00000000..03d1dd15 --- /dev/null +++ b/module01/src/main/java/test/GCDTest.java @@ -0,0 +1,39 @@ +package test; + + +import org.testng.annotations.Test; +import static org.junit.Assert.*; + +import ru.sberbank.edu.GCD; + + +public class GCDTest { + @Test + public void WhenGetDivisor100and75Then25() { + GCD gcd = new GCD(); + int ExpectedResult = 25; + assertEquals(ExpectedResult, gcd.getDivisor(100, 75)); + } + + @Test + public void WhenGetDivisor795and70Then25() { + GCD gcd = new GCD(); + int ExpectedResult = 5; + assertEquals(ExpectedResult, gcd.getDivisor(795, 70)); + } + + @Test + public void WhenGetDivisor0and3Then25() { + GCD gcd = new GCD(); + int ExpectedResult = 3; + assertEquals(ExpectedResult, gcd.getDivisor(0, 3)); + } + + @Test + public void WhenGetDivisor300and300Then25() { + GCD gcd = new GCD(); + int ExpectedResult = 300; + assertEquals(ExpectedResult, gcd.getDivisor(300, 300)); + } + +} diff --git a/module01/src/main/java/test/GreetingImplTest.java b/module01/src/main/java/test/GreetingImplTest.java new file mode 100644 index 00000000..7cc03764 --- /dev/null +++ b/module01/src/main/java/test/GreetingImplTest.java @@ -0,0 +1,21 @@ +package test; + +import org.testng.annotations.Test; +import ru.sberbank.edu.GreetingImpl; + +import static org.junit.Assert.assertEquals; + +public class GreetingImplTest { + + @Test + public void getBestHobby() { + GreetingImpl greetingImpl = new GreetingImpl(); + String ExpectedResult = "Имя: Дмитрий,\n" + + "Фамилия: Карпов,\n" + + "Должность: Инженер по нагрузочному тестированию,\n" + + "Хобби: Увлекаюсь програмированием на Java, люблю активные виды спорта \n" + + "(волейбол, настольный тенис, катание на велосипеде) и путешествия"; + assertEquals(ExpectedResult, greetingImpl.getBestHobby()); + + } +} diff --git a/module02/pom.xml b/module02/pom.xml index 45e842be..6af5fff1 100644 --- a/module02/pom.xml +++ b/module02/pom.xml @@ -11,6 +11,26 @@ jar module02 + + + org.testng + testng + RELEASE + test + + + junit + junit + 4.13.2 + test + + + org.junit.jupiter + junit-jupiter + RELEASE + test + + UTF-8 diff --git a/module02/src/main/java/ru/sberbank/edu/App.java b/module02/src/main/java/ru/sberbank/edu/App.java index 5419c026..316686c9 100644 --- a/module02/src/main/java/ru/sberbank/edu/App.java +++ b/module02/src/main/java/ru/sberbank/edu/App.java @@ -1,13 +1,29 @@ package ru.sberbank.edu; -/** - * Hello world! - * - */ +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + + public class App { - public static void main( String[] args ) - { - System.out.println( "Hello World!" ); + public static void main( String[] args ) throws IOException { + FileWriter writer = new FileWriter("file.txt"); + writer.write("Вы помните,\n" + + "Вы всё, конечно, помните,\n" + + "Как я стоял,\n" + + "Приблизившись к стене,\n" + + "Взволнованно ходили вы по комнате\n" + + "И что-то резкое\n" + + "В лицо бросали мне."); + writer.close(); + File file = new File("file.txt"); + StatisticFile statisticFile = new StatisticFile(); + Save saveFile = new SaveFile(); + Save saveDB = new SaveBD(); + statisticFile.save(saveFile, statisticFile.getLineCount(file), + statisticFile.getSpaceCount(file), statisticFile.getLongestLine(file)); + statisticFile.save(saveDB, statisticFile.getLineCount(file), + statisticFile.getSpaceCount(file), statisticFile.getLongestLine(file)); } } diff --git a/module02/src/main/java/ru/sberbank/edu/Save.java b/module02/src/main/java/ru/sberbank/edu/Save.java new file mode 100644 index 00000000..9827c2e2 --- /dev/null +++ b/module02/src/main/java/ru/sberbank/edu/Save.java @@ -0,0 +1,5 @@ +package ru.sberbank.edu; + +public interface Save { + void save(int lineCount, int spaceCount, String line); +} diff --git a/module02/src/main/java/ru/sberbank/edu/SaveBD.java b/module02/src/main/java/ru/sberbank/edu/SaveBD.java new file mode 100644 index 00000000..7ad73583 --- /dev/null +++ b/module02/src/main/java/ru/sberbank/edu/SaveBD.java @@ -0,0 +1,8 @@ +package ru.sberbank.edu; + +public class SaveBD implements Save { + @Override + public void save(int lineCount, int spaceCount, String line) { + System.out.println("Статистика сохранена в базу данных."); + } +} diff --git a/module02/src/main/java/ru/sberbank/edu/SaveFile.java b/module02/src/main/java/ru/sberbank/edu/SaveFile.java new file mode 100644 index 00000000..0df99dea --- /dev/null +++ b/module02/src/main/java/ru/sberbank/edu/SaveFile.java @@ -0,0 +1,18 @@ +package ru.sberbank.edu; + +import java.io.FileWriter; +import java.io.IOException; + +public class SaveFile implements Save{ + @Override + public void save(int lineCount, int spaceCount, String line) { + try (FileWriter writerResult = new FileWriter("ResultFile.txt")){ + writerResult.write("Количество строк в файле: " + lineCount + "\nКоличество пробелов в файле: " + spaceCount + "\nСамая длинная строка: " + line); + System.out.println("Статистика сохранена в файл."); + } + catch (IOException e) { + System.out.println("Что-то пошло не так"); + } + + } +} diff --git a/module02/src/main/java/ru/sberbank/edu/Statistic.java b/module02/src/main/java/ru/sberbank/edu/Statistic.java index 49ef9698..ca386134 100644 --- a/module02/src/main/java/ru/sberbank/edu/Statistic.java +++ b/module02/src/main/java/ru/sberbank/edu/Statistic.java @@ -1,11 +1,16 @@ package ru.sberbank.edu; -// интерфейс можно менять +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + public interface Statistic { - int getLineCount(); - int getSpaceCount(); - String getLongestLine(); - void save(int lineCount, int spaceCount, String line); + int getLineCount(File file) throws IOException; + int getSpaceCount(File file) throws IOException; + String getLongestLine(File file) throws IOException; + + + void save(Save save, int lineCount, int spaceCount, String line) throws IOException; } diff --git a/module02/src/main/java/ru/sberbank/edu/StatisticFile.java b/module02/src/main/java/ru/sberbank/edu/StatisticFile.java new file mode 100644 index 00000000..d692cd86 --- /dev/null +++ b/module02/src/main/java/ru/sberbank/edu/StatisticFile.java @@ -0,0 +1,68 @@ +package ru.sberbank.edu; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +/** + * Класс собирает статистику из файла + */ +public class StatisticFile implements Statistic{ + public StatisticFile() { + } + + /** + * Метод возвращает количество строк в файле + */ + public int getLineCount(File file) throws IOException { + int countLine = 0; + try(BufferedReader fileReader = new BufferedReader(new FileReader(file))) + { + for(String line = fileReader.readLine(); line != null; line = fileReader.readLine()) { + ++countLine; + } + } + return countLine; + } + + /** + * Метод возвращает количество пробелов в файле + */ + public int getSpaceCount(File file) throws IOException { + int countSpace = 0; + try(FileReader fileReader = new FileReader(file)) + { + for(int symbol = fileReader.read(); symbol != -1; symbol = fileReader.read()) { + if (symbol == 32) { + ++countSpace; + } + } + } + return countSpace; + } + + /** + * Метод возвращает самую длинную строку в файле в файле + */ + public String getLongestLine(File file) throws IOException { + String longestLine = ""; + try(BufferedReader fileReader = new BufferedReader(new FileReader(file));) + { + for(String line = fileReader.readLine(); line != null; line = fileReader.readLine()) { + if (longestLine.length() < line.length()) { + longestLine = line; + } + } + } + return longestLine; + } + + /** + * Метод сохраняет статитстику файла в файл или в базу данных на выбор пользователя + */ + public void save(Save save, int lineCount, int spaceCount, String line) { + save.save(lineCount, spaceCount, line); + } +} + diff --git a/module02/src/test/java/ru/sberbank/edu/AppTest.java b/module02/src/test/java/ru/sberbank/edu/AppTest.java deleted file mode 100644 index 895d735c..00000000 --- a/module02/src/test/java/ru/sberbank/edu/AppTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package ru.sberbank.edu; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Unit test for simple App. - */ -public class AppTest - extends TestCase -{ - /** - * Create the test case - * - * @param testName name of the test case - */ - public AppTest( String testName ) - { - super( testName ); - } - - /** - * @return the suite of tests being tested - */ - public static Test suite() - { - return new TestSuite( AppTest.class ); - } - - /** - * Rigourous Test :-) - */ - public void testApp() - { - assertTrue( true ); - } -} diff --git a/module02/src/test/java/ru/sberbank/edu/StatisticFileTest.java b/module02/src/test/java/ru/sberbank/edu/StatisticFileTest.java new file mode 100644 index 00000000..cafe6697 --- /dev/null +++ b/module02/src/test/java/ru/sberbank/edu/StatisticFileTest.java @@ -0,0 +1,66 @@ +package ru.sberbank.edu; + +import org.testng.annotations.Test; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import static org.junit.Assert.*; + + +public class StatisticFileTest { + @Test + public void WhenGetLongestLine() throws IOException { + FileWriter writer = new FileWriter("file.txt"); + writer.write("Вы помните,\n" + + "Вы всё, конечно, помните,\n" + + "Как я стоял,\n" + + "Приблизившись к стене,\n" + + "Взволнованно ходили вы по комнате\n" + + "И что-то резкое\n" + + "В лицо бросали мне."); + writer.close(); + File file = new File("file.txt"); + StatisticFile statisticFile = new StatisticFile(); + String ExpectedResult = "Взволнованно ходили вы по комнате"; + assertEquals(ExpectedResult, statisticFile.getLongestLine(file)); + file.delete(); + } + + @Test + public void WhenGetLineCountThen7() throws IOException { + FileWriter writer = new FileWriter("file.txt"); + writer.write("Вы помните,\n" + + "Вы всё, конечно, помните,\n" + + "Как я стоял,\n" + + "Приблизившись к стене,\n" + + "Взволнованно ходили вы по комнате\n" + + "И что-то резкое\n" + + "В лицо бросали мне."); + writer.close(); + File file = new File("file.txt"); + StatisticFile statisticFile = new StatisticFile(); + int ExpectedResult = 7; + assertEquals(ExpectedResult, statisticFile.getLineCount(file)); + file.delete(); + } + + @Test + public void WhenGetSpaceCountThen17() throws IOException { + FileWriter writer = new FileWriter("file.txt"); + writer.write("Вы помните,\n" + + "Вы всё, конечно, помните,\n" + + "Как я стоял,\n" + + "Приблизившись к стене,\n" + + "Взволнованно ходили вы по комнате\n" + + "И что-то резкое\n" + + "В лицо бросали мне."); + writer.close(); + File file = new File("file.txt"); + StatisticFile statisticFile = new StatisticFile(); + int ExpectedResult = 17; + assertEquals(ExpectedResult, statisticFile.getSpaceCount(file)); + file.delete(); + } +} diff --git a/module03/pom.xml b/module03/pom.xml index 9363c7ed..5273ae47 100644 --- a/module03/pom.xml +++ b/module03/pom.xml @@ -11,6 +11,20 @@ jar module03 + + + org.testng + testng + RELEASE + compile + + + junit + junit + 4.13.2 + compile + + UTF-8 diff --git a/module03/src/main/java/ru/sberbank/edu/App.java b/module03/src/main/java/ru/sberbank/edu/App.java index 5419c026..b7fa8b22 100644 --- a/module03/src/main/java/ru/sberbank/edu/App.java +++ b/module03/src/main/java/ru/sberbank/edu/App.java @@ -1,5 +1,8 @@ package ru.sberbank.edu; +import java.util.ArrayList; +import java.util.Collections; + /** * Hello world! * @@ -8,6 +11,35 @@ public class App { public static void main( String[] args ) { - System.out.println( "Hello World!" ); + CustomArrayImpl arrayList = new CustomArrayImpl<>(0); + Integer[] val = new Integer[] {1,2,3,4,5,6,7,8}; + arrayList.add(10); + System.out.println(arrayList.size()); + arrayList.add(20); + arrayList.add(30); + arrayList.add(40); + arrayList.add(50); + System.out.println(arrayList.size()); + arrayList.remove(3); + System.out.println(arrayList.size()); + System.out.println(arrayList.getCapacity()); + System.out.println("----------"); + arrayList.addAll(2, val); + for (int i = 0; i < arrayList.size(); i++) { + System.out.println(arrayList.get(i)); + } + System.out.println("----------"); + int index = arrayList.indexOf(50); + System.out.println( index ); + System.out.println( arrayList.getCapacity() ); + System.out.println("----------"); + System.out.println("----------"); + boolean inde = arrayList.contains(null); + System.out.println( inde ); + System.out.println("----------"); + arrayList.reverse(); + for (int i = 0; i < arrayList.getCapacity(); i++) { + System.out.println(arrayList.get(i)); + } } } diff --git a/module03/src/main/java/ru/sberbank/edu/CustomArray.java b/module03/src/main/java/ru/sberbank/edu/CustomArray.java index 5b1c4706..e920c428 100644 --- a/module03/src/main/java/ru/sberbank/edu/CustomArray.java +++ b/module03/src/main/java/ru/sberbank/edu/CustomArray.java @@ -1,6 +1,7 @@ package ru.sberbank.edu; import java.util.Collection; +import java.util.Iterator; /** * Simple array. Can store any objects. diff --git a/module03/src/main/java/ru/sberbank/edu/CustomArrayImpl.java b/module03/src/main/java/ru/sberbank/edu/CustomArrayImpl.java new file mode 100644 index 00000000..25e2192a --- /dev/null +++ b/module03/src/main/java/ru/sberbank/edu/CustomArrayImpl.java @@ -0,0 +1,198 @@ +package ru.sberbank.edu; + +import java.util.Collection; + +public class CustomArrayImpl implements CustomArray { + + private static final int DEFAULT_CAPACITY = 10; + private int size = 0; + private Object[] values; + + public CustomArrayImpl(int initialCapacity) { + if (initialCapacity > 0) { + this.values = new Object[initialCapacity]; + } else if (initialCapacity == 0) { + this.values = new Object[0]; + } else { + throw new IllegalArgumentException("Illegal Capacity: "+ + initialCapacity); + } + } + + public CustomArrayImpl() { + this.values = new Object[DEFAULT_CAPACITY]; + } + + @Override + public int size() { + return size; + } + + @Override + public boolean isEmpty() { + return values.length == 0; + } + + @Override + public boolean add(Object item) { + try { + if ((getCapacity() - size()) == 0 ) { + if (getCapacity() == 0) { + ensureCapacity(getCapacity() + 1); + } else + ensureCapacity(getCapacity() * 2); + } + values[size()] = item; + size++; + return true; + } + catch (ClassCastException ex) { + ex.printStackTrace(); + } + return false; + } + + @Override + public boolean addAll(Object[] items) { + try { + if ((getCapacity() - size()) < items.length ) { + ensureCapacity((getCapacity() * 2) + items.length); + } + Object[] temp = values; + System.arraycopy(temp, 0, values, 0, temp.length); + System.arraycopy(items, 0, values, size(), items.length); + size += items.length; + return true; + } + catch (ClassCastException ex) { + ex.printStackTrace(); + } + return false; + } + + @Override + public boolean addAll(Collection items) { + Object[] arrayItem = items.toArray(); + return addAll(arrayItem); + } + + @Override + public boolean addAll(int index, Object[] items) { + try { + if ((getCapacity() - size()) < items.length ) { + ensureCapacity((getCapacity() * 2) + items.length); + } + Object[] temp = new Object[size()]; + System.arraycopy(values, 0, temp, 0, size()); + System.arraycopy(temp, 0, values, 0, index); + System.arraycopy(items, 0, values, index, items.length); + System.arraycopy(temp, index, values, index + items.length, size() - index); + size += items.length; + return true; + } + catch (ClassCastException ex) { + ex.printStackTrace(); + } + return false; + } + + @Override + public Object get(int index) { + return values[index]; + } + + @Override + public Object set(int index, Object item) { + return values[index] = item; + } + + @Override + public void remove(int index) { + try { + Object[] temp = values; + values = new Object[temp.length]; + System.arraycopy(temp, 0, values, 0, index); + System.arraycopy(temp, index + 1, values, index, temp.length - index - 1); + size--; + } + catch (ClassCastException ex) { + ex.printStackTrace(); + } + } + + @Override + public boolean remove(Object item) { + int index = indexOf(item); + if (index != -1) { + remove(index); + return true; + } else + return false; + } + + @Override + public boolean contains(Object item) { + return indexOf(item) != -1; + } + + @Override + public int indexOf(Object item) { + int index = -1; + if (item == null) { + for (int i = 0; i <= values.length - 1;) { + if(values[i] == null) { + index = i; + break; + } + i++; + } + } else { + for (int i = 0; i <= values.length - 1;) { + if(values[i] != null && values[i].equals(item)) { + index = i; + break; + } + i++; + } + } + return index; + } + + @Override + public void ensureCapacity(int newElementsCount) { + Object[] temp = values; + values = new Object[temp.length + newElementsCount]; + System.arraycopy(temp, 0, values, 0, temp.length); + } + + @Override + public int getCapacity() { + return values.length; + } + + @Override + public void reverse() { + try { + Object[] temp = toArray(); + values = new Object[temp.length]; + int j = 0; + for (int i = temp.length - 1; i >= 0; i--) { + values[j] = temp[i]; + j++; + } + } + catch (ClassCastException ex) { + ex.printStackTrace(); + } + + } + + @Override + public Object[] toArray() { + Object[] val = new Object[size()]; + for (int i = 0; i < size(); i++) { + val[i]=values[i]; + } + return val; + } +} diff --git a/module03/src/main/java/test/CustomArrayImplTest.java b/module03/src/main/java/test/CustomArrayImplTest.java new file mode 100644 index 00000000..63ee42b9 --- /dev/null +++ b/module03/src/main/java/test/CustomArrayImplTest.java @@ -0,0 +1,179 @@ +package test; + +import org.testng.annotations.Test; +import static org.junit.Assert.*; + +import ru.sberbank.edu.CustomArrayImpl; + +import java.util.ArrayList; + + +public class CustomArrayImplTest { + @Test + public void WhenAdd() { + CustomArrayImpl array = new CustomArrayImpl<>(); + array.add(15); + array.add(16); + int ExpectedResult_0 = 15; + int ExpectedResult_1 = 16; + assertEquals(ExpectedResult_0, array.get(0)); + assertEquals(ExpectedResult_1, array.get(1)); + } + + @Test + public void WhenAddAllArray() { + Integer[] val = new Integer[] {1,2,3,4,5,6,7,8}; + CustomArrayImpl array = new CustomArrayImpl<>(); + array.add(15); + array.add(16); + array.addAll(val); + Integer[] ExpectedResult = new Integer[]{15,16,1,2,3,4,5,6,7,8}; + assertArrayEquals(ExpectedResult, array.toArray()); + } + + @Test + public void WhenAddAllArrayForIndex() { + Integer[] val = new Integer[] {1,2,3,4,5,6,7,8}; + CustomArrayImpl array = new CustomArrayImpl<>(); + array.add(15); + array.add(16); + array.addAll(1, val); + Integer[] ExpectedResult = new Integer[]{15,1,2,3,4,5,6,7,8,16}; + assertArrayEquals(ExpectedResult, array.toArray()); + assertArrayEquals(ExpectedResult, array.toArray()); + } + + @Test + public void WhenAddAllCollection() { + ArrayList val = new ArrayList<>(); + val.add(3); + val.add(4); + CustomArrayImpl array = new CustomArrayImpl<>(); + array.add(15); + array.add(16); + array.addAll(val); + Integer[] ExpectedResult = new Integer[]{15,16,3,4}; + assertArrayEquals(ExpectedResult, array.toArray()); + } + + @Test + public void WhenSet() { + CustomArrayImpl array = new CustomArrayImpl<>(); + array.add(15); + array.add(16); + array.add(17); + array.add(18); + array.set(2, 20); + int ExpectedResult = 20; + assertEquals(ExpectedResult, array.get(2)); + } + + @Test + public void WhenSize() { + CustomArrayImpl array = new CustomArrayImpl<>(); + array.add(15); + array.add(16); + array.add(17); + array.add(18); + int ExpectedResult = 4; + assertEquals(ExpectedResult, array.size()); + } + + @Test + public void WhenIsEmpty() { + CustomArrayImpl array = new CustomArrayImpl<>(); + array.add(15); + array.add(16); + array.add(17); + array.add(18); + boolean ExpectedResult = false; + assertEquals(ExpectedResult, array.isEmpty()); + } + + @Test + public void WhenIndexOf() { + CustomArrayImpl array = new CustomArrayImpl<>(); + array.add(15); + array.add(16); + array.add(17); + array.add(18); + int ExpectedResult = 2; + assertEquals(ExpectedResult, array.indexOf(17)); + } + + @Test + public void WhenContains() { + CustomArrayImpl array = new CustomArrayImpl<>(); + array.add(15); + array.add(16); + array.add(17); + array.add(18); + boolean ExpectedResult = true; + assertEquals(ExpectedResult, array.contains(16)); + } + + @Test + public void WhenGetCapacity() { + CustomArrayImpl array = new CustomArrayImpl<>(); + array.add(15); + array.add(16); + array.add(17); + array.add(18); + int ExpectedResult = 10; + assertEquals(ExpectedResult, array.getCapacity()); + } + + @Test + public void WhenEnsureCapacity() { + CustomArrayImpl array = new CustomArrayImpl<>(); + array.add(15); + array.add(16); + array.add(17); + array.add(18); + array.ensureCapacity(7); + int ExpectedResult = 17; + assertEquals(ExpectedResult, array.getCapacity()); + } + + @Test + public void WhenRemoveForIndex() { + CustomArrayImpl array = new CustomArrayImpl<>(); + array.add(15); + array.add(16); + array.add(17); + array.add(18); + array.remove(1); + boolean ExpectedResult_1 = false; + int ExpectedResult_2 = 3; + assertEquals(ExpectedResult_1, array.contains(16)); + assertEquals(ExpectedResult_2, array.size()); + } + + @Test + public void WhenRemoveForValue() { + CustomArrayImpl array = new CustomArrayImpl<>(); + array.add(15); + array.add(16); + array.add(17); + array.add(18); + array.remove(new Integer(16)); + boolean ExpectedResult_1 = false; + int ExpectedResult_2 = 3; + assertEquals(ExpectedResult_1, array.contains(16)); + assertEquals(ExpectedResult_2, array.size()); + } + + @Test + public void WhenToArray() { + CustomArrayImpl array = new CustomArrayImpl<>(); + array.add(15); + array.add(16); + array.add(17); + array.add(18); + array.reverse(); + Integer[] ExpectedResult = new Integer[]{18,17,16,15}; + assertArrayEquals(ExpectedResult, array.toArray()); + } + + +} diff --git a/module04/pom.xml b/module04/pom.xml index 7d3e7520..fc6abd21 100644 --- a/module04/pom.xml +++ b/module04/pom.xml @@ -11,6 +11,32 @@ jar module04 + + + + org.apache.maven.plugins + maven-compiler-plugin + + 9 + 9 + + + + + + + org.testng + testng + RELEASE + test + + + junit + junit + 4.13.2 + test + + UTF-8 diff --git a/module04/src/main/java/ru/sberbank/edu/App.java b/module04/src/main/java/ru/sberbank/edu/App.java index 5419c026..6b6a8946 100644 --- a/module04/src/main/java/ru/sberbank/edu/App.java +++ b/module04/src/main/java/ru/sberbank/edu/App.java @@ -1,13 +1,14 @@ package ru.sberbank.edu; /** - * Hello world! - * + * Программа сортирует объекты Person в коллекции сначала по полю city затем по полю name + * В классе CustomDigitComparator реализован компоратор + * который сортирует коллекцию чисел сначала на четные затем на нечетные */ public class App { public static void main( String[] args ) { - System.out.println( "Hello World!" ); + System.out.println("Для проверки ДЗ_4 запускай тесты"); } } diff --git a/module04/src/main/java/ru/sberbank/edu/CustomDigitComparator.java b/module04/src/main/java/ru/sberbank/edu/CustomDigitComparator.java new file mode 100644 index 00000000..e917a265 --- /dev/null +++ b/module04/src/main/java/ru/sberbank/edu/CustomDigitComparator.java @@ -0,0 +1,18 @@ +package ru.sberbank.edu; + +import java.util.Comparator; + +public class CustomDigitComparator implements Comparator { + @Override + public int compare(Integer o1, Integer o2) { + if (o1 == o2) { + return 0; + } + if (o2 % 2 == 0) { + return 1; + } + else { + return -1; + } + } +} diff --git a/module04/src/main/java/ru/sberbank/edu/Person.java b/module04/src/main/java/ru/sberbank/edu/Person.java new file mode 100644 index 00000000..0dfdc726 --- /dev/null +++ b/module04/src/main/java/ru/sberbank/edu/Person.java @@ -0,0 +1,72 @@ +package ru.sberbank.edu; + +import java.util.Locale; +import java.util.Objects; + +public class Person implements Comparable{ + + private String name; + private String city; + private int age; + + @Override + public int compareTo(Person other) { + int result = this.city.compareTo(other.city); + if (result == 0) { + result = this.name.compareTo(other.name); + } + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Person person = (Person) o; + return age == person.age && name.equalsIgnoreCase(person.name) && city.equalsIgnoreCase(person.city); + } + + @Override + public int hashCode() { + return Objects.hash(name.toLowerCase(), city.toLowerCase(), age); + } + + @Override + public String toString() { + return "Person{" + + "name='" + name + '\'' + + ", city='" + city + '\'' + + ", age=" + age + + '}'; + } + + public void setName(String name) { + this.name = name; + } + + public void setCity(String city) { + this.city = city; + } + + public void setAge(int age) { + this.age = age; + } + + public String getName() { + return name; + } + + public String getCity() { + return city; + } + + public int getAge() { + return age; + } + + public Person(String name, String city, int age) { + this.name = name; + this.city = city; + this.age = age; + } +} diff --git a/module04/src/test/java/ru/sberbank/edu/AppTest.java b/module04/src/test/java/ru/sberbank/edu/AppTest.java index 895d735c..af855cce 100644 --- a/module04/src/test/java/ru/sberbank/edu/AppTest.java +++ b/module04/src/test/java/ru/sberbank/edu/AppTest.java @@ -1,38 +1,37 @@ package ru.sberbank.edu; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; +import org.testng.annotations.Test; +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; -/** - * Unit test for simple App. - */ -public class AppTest - extends TestCase -{ - /** - * Create the test case - * - * @param testName name of the test case - */ - public AppTest( String testName ) - { - super( testName ); - } - /** - * @return the suite of tests being tested - */ - public static Test suite() - { - return new TestSuite( AppTest.class ); +public class AppTest { + @Test + public void WhenCompareToByCityAndName() { + List persons = new ArrayList<>(); + persons.add(new Person("Makar", "Moscow", 1)); + persons.add(new Person("Ivan", "Omsk", 55)); + persons.add(new Person("Artyom", "Omsk", 20)); + persons.add(new Person("Boris", "Moscow", 29)); + persons.sort(Person::compareTo); + List expectedListPersons = new ArrayList<>(); + expectedListPersons.add(new Person("Boris", "Moscow", 29)); + expectedListPersons.add(new Person("Makar", "Moscow", 1)); + expectedListPersons.add(new Person("Artyom", "Omsk", 20)); + expectedListPersons.add(new Person("Ivan", "Omsk", 55)); + assertArrayEquals(persons.toArray(), expectedListPersons.toArray()); } - /** - * Rigourous Test :-) - */ - public void testApp() - { - assertTrue( true ); + @Test + public void WhenCustomDigitComparator() { + Integer[] ints = new Integer[]{0, 4, 2, 15, 24, 0, 42, 63, 16, 9}; + List digits = new ArrayList(List.of(ints)); + Comparator cmp = new CustomDigitComparator(); + digits.sort(cmp); + Integer[] result = new Integer[]{0, 4, 2, 24, 0, 42, 16, 9, 63, 15}; + assertArrayEquals(digits.toArray(), result); } } diff --git a/module05/pom.xml b/module05/pom.xml index e64564f4..7b0d08e3 100644 --- a/module05/pom.xml +++ b/module05/pom.xml @@ -11,6 +11,20 @@ jar module05 + + + org.testng + testng + RELEASE + test + + + junit + junit + 4.13.2 + test + + UTF-8 diff --git a/module05/src/main/java/ru/sberbank/edu/App.java b/module05/src/main/java/ru/sberbank/edu/App.java index 5419c026..080e58df 100644 --- a/module05/src/main/java/ru/sberbank/edu/App.java +++ b/module05/src/main/java/ru/sberbank/edu/App.java @@ -8,6 +8,6 @@ public class App { public static void main( String[] args ) { - System.out.println( "Hello World!" ); + System.out.println("Для проверки задаия запускай тесты"); } } diff --git a/module05/src/main/java/ru/sberbank/edu/CityInfo.java b/module05/src/main/java/ru/sberbank/edu/CityInfo.java index f37134e2..c07b983c 100644 --- a/module05/src/main/java/ru/sberbank/edu/CityInfo.java +++ b/module05/src/main/java/ru/sberbank/edu/CityInfo.java @@ -18,4 +18,20 @@ public CityInfo(String name, GeoPosition position) { this.name = name; this.position = position; } + + public String getName() { + return name; + } + + public GeoPosition getPosition() { + return position; + } + + @Override + public String toString() { + return "CityInfo{" + + "name='" + name + '\'' + + ", position=" + position + + '}'; + } } \ No newline at end of file diff --git a/module05/src/main/java/ru/sberbank/edu/GeoPosition.java b/module05/src/main/java/ru/sberbank/edu/GeoPosition.java index 2dc4e21b..b6ed18d4 100644 --- a/module05/src/main/java/ru/sberbank/edu/GeoPosition.java +++ b/module05/src/main/java/ru/sberbank/edu/GeoPosition.java @@ -23,8 +23,36 @@ public class GeoPosition { * Possible values: 55, 55(45'07''), 59(57'00'') */ public GeoPosition(String latitudeGradus, String longitudeGradus) { - // parse and set latitude and longitude in radian + String[] latitudeGradusArray = latitudeGradus.split("[(')]"); + String[] longitudeGradusArray = longitudeGradus.split("[(')]"); + + double latitudeGrad = Integer.parseInt(latitudeGradusArray[0]); + double latitudeMinutes = latitudeGradusArray.length > 1 ? Integer.parseInt(latitudeGradusArray[1]) : 0; + double latitudeSec = latitudeGradusArray.length > 1 ? Integer.parseInt(latitudeGradusArray[2]) : 0; + + double longitudeGrad = Integer.parseInt(longitudeGradusArray[0]); + double longitudeMinutes = longitudeGradusArray.length > 1 ? Integer.parseInt(longitudeGradusArray[1]) : 0; + double longitudeSec = longitudeGradusArray.length > 1 ? Integer.parseInt(longitudeGradusArray[2]) : 0; + + latitude = Math.toRadians(latitudeGrad > 0 ? latitudeGrad + (latitudeMinutes / 60.0) + (latitudeSec / 3600.0) : + latitudeGrad + (-latitudeMinutes / 60.0) + (-latitudeSec / 3600.0)); + longitude = Math.toRadians(longitudeGrad > 0 ? longitudeGrad + (longitudeMinutes / 60.0) + (longitudeSec / 3600.0) : + latitudeGrad + (-latitudeMinutes / 60.0) + (-latitudeSec / 3600.0)); + } + + public double getLatitude() { + return latitude; + } + + public double getLongitude() { + return longitude; } - // getters and toString + @Override + public String toString() { + return "GeoPosition{" + + "latitude=" + latitude + + ", longitude=" + longitude + + '}'; + } } \ No newline at end of file diff --git a/module05/src/main/java/ru/sberbank/edu/TravelService.java b/module05/src/main/java/ru/sberbank/edu/TravelService.java index 830d188c..7c1bc03f 100644 --- a/module05/src/main/java/ru/sberbank/edu/TravelService.java +++ b/module05/src/main/java/ru/sberbank/edu/TravelService.java @@ -2,6 +2,8 @@ import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Travel Service. @@ -9,7 +11,7 @@ public class TravelService { // do not change type - private final List cities = new ArrayList<>(); + private List cities = new ArrayList<>(); /** * Append city info. @@ -17,8 +19,14 @@ public class TravelService { * @param cityInfo - city info * @throws IllegalArgumentException if city already exists */ - public void add(CityInfo cityInfo) { - // do something + public void add(CityInfo cityInfo) throws IllegalArgumentException { + Stream streamOfCities = cities.stream(); + List citiesResult = streamOfCities.filter(x -> cityInfo.getName().equals(x.getName())).collect(Collectors.toList()); + if (citiesResult.toArray().length > 0) { + throw new IllegalArgumentException("City already exists"); + } else { + cities.add(cityInfo); + } } /** @@ -27,15 +35,23 @@ public void add(CityInfo cityInfo) { * @param cityName - city name * @throws IllegalArgumentException if city doesn't exist */ - public void remove(String cityName) { - // do something + public void remove(String cityName) throws IllegalArgumentException { + Stream streamOfCities = cities.stream(); + List citiesResult = streamOfCities.filter(x -> !cityName.equals(x.getName())).collect(Collectors.toList()); + if (citiesResult.toArray().length == cities.toArray().length) { + throw new IllegalArgumentException("City doesn't exist"); + } else { + cities = citiesResult; + } } /** * Get cities names. */ public List citiesNames() { - return null; + Stream streamOfCities = cities.stream(); + return streamOfCities.map(CityInfo::getName) + .collect(Collectors.toList()); } /** @@ -46,8 +62,27 @@ public List citiesNames() { * @param destCityName - destination city * @throws IllegalArgumentException if source or destination city doesn't exist. */ - public int getDistance(String srcCityName, String destCityName) { - return 0; + public double getDistance(String srcCityName, String destCityName) throws IllegalArgumentException { + Stream streamOfCities = cities.stream(); + List citiesResult = streamOfCities.filter(x -> srcCityName.equals(x.getName()) || + destCityName.equals(x.getName())).collect(Collectors.toList()); + if (citiesResult.toArray().length != 2) { + throw new IllegalArgumentException("Source or destination city doesn't exist"); + } else { + GeoPosition geo_1 = citiesResult.get(0).getPosition(); + GeoPosition geo_2 = citiesResult.get(1).getPosition(); + double cl1 = Math.cos(geo_1.getLatitude()); + double cl2 = Math.cos(geo_2.getLatitude()); + double sl1 = Math.sin(geo_1.getLatitude()); + double sl2 = Math.sin(geo_2.getLatitude()); + double delta = geo_1.getLongitude() - geo_2.getLongitude(); + double cDelta = Math.cos(delta); + double sDelta = Math.sin(delta); + double y = Math.sqrt(Math.pow(cl2 * sDelta, 2) + Math.pow(cl1 * sl2 - sl1 * cl2 * cDelta, 2)); + double x = sl1 * sl2 + cl1 * cl2 * cDelta; + double ad = Math.atan2(y, x); + return ad * 6372795.0; + } } /** @@ -57,7 +92,18 @@ public int getDistance(String srcCityName, String destCityName) { * @param radius - radius in kilometers for search * @throws IllegalArgumentException if city with cityName city doesn't exist. */ - public List getCitiesNear(String cityName, int radius) { - return null; + public List getCitiesNear(String cityName, int radius) throws IllegalArgumentException { + Stream streamOfCities = cities.stream(); + List searhCity = streamOfCities.filter(x -> cityName.equals(x.getName())).collect(Collectors.toList()); + if (searhCity.toArray().length == 0) { + throw new IllegalArgumentException("City with cityName city doesn't exis"); + } else { + Stream streamOfCities_2 = cities.stream(); + List citiesResult = streamOfCities_2.filter(x -> !x.getName().equals(searhCity.get(0).getName()) && + getDistance(searhCity.get(0).getName(), x.getName()) <= radius) + .map(CityInfo::getName) + .collect(Collectors.toList()); + return citiesResult; + } } } diff --git a/module05/src/test/java/ru/sberbank/edu/AppTest.java b/module05/src/test/java/ru/sberbank/edu/AppTest.java deleted file mode 100644 index 895d735c..00000000 --- a/module05/src/test/java/ru/sberbank/edu/AppTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package ru.sberbank.edu; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Unit test for simple App. - */ -public class AppTest - extends TestCase -{ - /** - * Create the test case - * - * @param testName name of the test case - */ - public AppTest( String testName ) - { - super( testName ); - } - - /** - * @return the suite of tests being tested - */ - public static Test suite() - { - return new TestSuite( AppTest.class ); - } - - /** - * Rigourous Test :-) - */ - public void testApp() - { - assertTrue( true ); - } -} diff --git a/module05/src/test/java/ru/sberbank/edu/TravelServiceTest.java b/module05/src/test/java/ru/sberbank/edu/TravelServiceTest.java new file mode 100644 index 00000000..3d638c73 --- /dev/null +++ b/module05/src/test/java/ru/sberbank/edu/TravelServiceTest.java @@ -0,0 +1,89 @@ +package ru.sberbank.edu; + +import org.testng.annotations.Test; +import static org.junit.Assert.*; + +import java.util.List; + + +public class TravelServiceTest { + @Test + public void WhenAdd() { + GeoPosition g1 = new GeoPosition("55", "55(45'07'')"); + CityInfo c1 = new CityInfo("Moscow", g1); + GeoPosition g2 = new GeoPosition("55", "55(46'08'')"); + CityInfo c2 = new CityInfo("Tver", g2); + GeoPosition g3 = new GeoPosition("55", "55(55'07'')"); + CityInfo c3 = new CityInfo("Tula", g3); + GeoPosition g4 = new GeoPosition("85", "85(45'07'')"); + CityInfo c4 = new CityInfo("Omsk", g4); + TravelService t1 = new TravelService(); + t1.add(c1); + t1.add(c2); + t1.add(c3); + t1.add(c4); + String[] res = new String[]{"Moscow", "Tver", "Tula", "Omsk"}; + assertArrayEquals(t1.citiesNames().toArray(), res); + } + + @Test + public void WhenRemove() { + GeoPosition g1 = new GeoPosition("55", "55(45'07'')"); + CityInfo c1 = new CityInfo("Moscow", g1); + GeoPosition g2 = new GeoPosition("55", "55(46'08'')"); + CityInfo c2 = new CityInfo("Tver", g2); + GeoPosition g3 = new GeoPosition("55", "55(55'07'')"); + CityInfo c3 = new CityInfo("Tula", g3); + GeoPosition g4 = new GeoPosition("85", "85(45'07'')"); + CityInfo c4 = new CityInfo("Omsk", g4); + TravelService t1 = new TravelService(); + t1.add(c1); + t1.add(c2); + t1.add(c3); + t1.add(c4); + t1.remove("Tver"); + String[] res = new String[]{"Moscow", "Tula", "Omsk"}; + assertArrayEquals(t1.citiesNames().toArray(), res); + } + + @Test + public void WhenGetDistance() { + GeoPosition g1 = new GeoPosition("55", "55(45'07'')"); + CityInfo c1 = new CityInfo("Moscow", g1); + GeoPosition g2 = new GeoPosition("55", "55(46'08'')"); + CityInfo c2 = new CityInfo("Tver", g2); + GeoPosition g3 = new GeoPosition("55", "55(55'07'')"); + CityInfo c3 = new CityInfo("Tula", g3); + GeoPosition g4 = new GeoPosition("85", "85(45'07'')"); + CityInfo c4 = new CityInfo("Omsk", g4); + TravelService t1 = new TravelService(); + t1.add(c1); + t1.add(c2); + t1.add(c3); + t1.add(c4); + t1.getDistance("Tver", "Omsk"); + double res = t1.getDistance("Tver", "Omsk"); + double expectedRes = 3421093.094174924; + assertEquals(res, expectedRes, 0.0001); + } + + @Test + public void WhenGetCitiesNear() { + GeoPosition g1 = new GeoPosition("55", "55(45'07'')"); + CityInfo c1 = new CityInfo("Moscow", g1); + GeoPosition g2 = new GeoPosition("55", "55(46'08'')"); + CityInfo c2 = new CityInfo("Tver", g2); + GeoPosition g3 = new GeoPosition("55", "55(55'07'')"); + CityInfo c3 = new CityInfo("Tula", g3); + GeoPosition g4 = new GeoPosition("85", "85(45'07'')"); + CityInfo c4 = new CityInfo("Omsk", g4); + TravelService t1 = new TravelService(); + t1.add(c1); + t1.add(c2); + t1.add(c3); + t1.add(c4); + List res = t1.getCitiesNear("Tula", 1000000); + String[] expectedRes = new String[]{"Moscow", "Tver"}; + assertArrayEquals(res.toArray(), expectedRes); + } +} diff --git a/module06/pom.xml b/module06/pom.xml index 04ee5cb5..11770fd1 100644 --- a/module06/pom.xml +++ b/module06/pom.xml @@ -11,6 +11,18 @@ jar module06 + + + + org.apache.maven.plugins + maven-compiler-plugin + + 11 + 11 + + + + UTF-8 @@ -22,5 +34,17 @@ h2 2.1.214 + + org.testng + testng + RELEASE + test + + + junit + junit + 4.13.2 + test + diff --git a/module06/src/main/java/ru/sberbank/edu/repository/CarDbRepositoryImpl.java b/module06/src/main/java/ru/sberbank/edu/repository/CarDbRepositoryImpl.java index 0a7a2d25..b4f97f37 100644 --- a/module06/src/main/java/ru/sberbank/edu/repository/CarDbRepositoryImpl.java +++ b/module06/src/main/java/ru/sberbank/edu/repository/CarDbRepositoryImpl.java @@ -3,29 +3,47 @@ import ru.sberbank.edu.model.Car; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; +import java.sql.*; +import java.util.Collection; +import java.util.HashSet; import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class CarDbRepositoryImpl implements CarRepository { private final Connection connection; private static final String CREATE_CAR_SQL = "INSERT INTO car (id, model) VALUES (?,?)"; private static final String UPDATE_CAR_SQL = "UPDATE car SET model = ? WHERE id = ?"; private static final String SELECT_CAR_BY_ID = "SELECT * FROM car WHERE id = ?"; + private static final String SELECT_ALL = "SELECT * FROM car"; + private static final String DELETE_CAR_BY_ID = "DELETE FROM car WHERE id = ?"; + private static final String DELETE_ALL = "DELETE FROM car"; + private static final String SELECT_CAR_BY_MODEL = "SELECT * FROM car WHERE model = ?"; private final PreparedStatement createPreStmt; private final PreparedStatement updatePreStmt; private final PreparedStatement findByIdPreStmt; + private final PreparedStatement findAllPreStmt; + private final PreparedStatement deleteByIdPreStmt; + private final PreparedStatement deleteAllPreStmt; + private final PreparedStatement findByModelPreStmt; public CarDbRepositoryImpl(Connection connection) throws SQLException { this.connection = connection; this.createPreStmt = connection.prepareStatement(CREATE_CAR_SQL); this.updatePreStmt = connection.prepareStatement(UPDATE_CAR_SQL); this.findByIdPreStmt = connection.prepareStatement(SELECT_CAR_BY_ID); + this.findAllPreStmt = connection.prepareStatement(SELECT_ALL); + this.deleteByIdPreStmt = connection.prepareStatement(DELETE_CAR_BY_ID); + this.deleteAllPreStmt = connection.prepareStatement(DELETE_ALL); + this.findByModelPreStmt = connection.prepareStatement(SELECT_CAR_BY_MODEL); } + /** + * Метод обновляет или добавляет авто в таблицу CAR + * принимает на вход объект типа car + */ @Override public Car createOrUpdate(Car car) throws SQLException { Optional optCar = findById(car.getId()); @@ -41,9 +59,40 @@ public Car createOrUpdate(Car car) throws SQLException { return car; } + /** + * Метод обновляет или добавляет авто в таблицу CAR + * принимает на вход коллекцию типа car + * возвращает коллекцию типа car добавленных авто + */ + @Override + public Set createAll(Collection cars) throws SQLException { + Set result = new HashSet<>(); + for (Car car : cars) { + result.add(createOrUpdate(car)); + } + return result; + } + + /** + * Метод возвращает коллекцию типа car всех авто + */ + @Override + public Set findAll() throws SQLException { + Set result = new HashSet<>(); + ResultSet resultSet = findAllPreStmt.executeQuery(); + resultSet.next(); + Car car = new Car(resultSet.getString(1), resultSet.getString(2)); + result.add(car); + return result; + } + + /** + * Метод находит по id авто в таблицу CAR + * принимает на вход строковое значение id + * возвращает объект типа car + */ @Override public Optional findById(String id) throws SQLException { - // validation int rowsCount = countRowsById(id); if (rowsCount > 1) { throw new RuntimeException("Car with id = " + id + " was found many times (" + rowsCount + ")."); @@ -59,11 +108,31 @@ public Optional findById(String id) throws SQLException { return Optional.of(car); } + /** + * Метод удаляет по id авто в таблицу CAR + * принимает на вход строковое значение id + * возвращает значение Boolean + */ @Override - public Boolean deleteById(String id) { - return null; + public Boolean deleteById(String id) throws SQLException { + deleteByIdPreStmt.setString(1, id); + return deleteByIdPreStmt.execute(); } + /** + * Метод удаляет все значения в таблице CAR + * возвращает значение Boolean + */ + @Override + public Boolean deleteAll() throws SQLException { + return deleteAllPreStmt.execute(); + } + + /** + * Метод проверяет сколько в таблице строк с одинаковым id + * принимает на вход строковое значение id + * возвращает значение int количество найденых строк + */ private int countRowsById(String id) throws SQLException { PreparedStatement preparedStatement = connection.prepareStatement("SELECT COUNT(*) FROM car where id = ?"); preparedStatement.setString(1, id); @@ -74,4 +143,20 @@ private int countRowsById(String id) throws SQLException { } return rowCount; } + + /** + * Метод удаляет по значению model авто в таблицу CAR + * принимает на вход строковое значение model + * возвращает значение коллекцию найденых объектов типа car + */ + @Override + public Set findByModel(String model) throws SQLException { + Set result = new HashSet<>(); + findByModelPreStmt.setString(1, model); + ResultSet resultSet = findByModelPreStmt.executeQuery(); + resultSet.next(); + Car car = new Car(resultSet.getString(1), resultSet.getString(2)); + result.add(car); + return result; + } } diff --git a/module06/src/main/java/ru/sberbank/edu/repository/CarRepository.java b/module06/src/main/java/ru/sberbank/edu/repository/CarRepository.java index 7fcad2be..9877c0a5 100644 --- a/module06/src/main/java/ru/sberbank/edu/repository/CarRepository.java +++ b/module06/src/main/java/ru/sberbank/edu/repository/CarRepository.java @@ -2,8 +2,9 @@ import ru.sberbank.edu.model.Car; +import java.sql.SQLException; import java.util.Set; public interface CarRepository extends Repository { - Set findByModel(String model); + Set findByModel(String model) throws SQLException; } diff --git a/module06/src/main/java/ru/sberbank/edu/repository/Repository.java b/module06/src/main/java/ru/sberbank/edu/repository/Repository.java index 0875f22e..9baeb72b 100644 --- a/module06/src/main/java/ru/sberbank/edu/repository/Repository.java +++ b/module06/src/main/java/ru/sberbank/edu/repository/Repository.java @@ -8,11 +8,11 @@ public interface Repository{ T createOrUpdate(T t) throws SQLException; - Set createAll(Collection tCollection); - Set findAll(); + Set createAll(Collection tCollection) throws SQLException; + Set findAll() throws SQLException; Optional findById(I id) throws SQLException; - Boolean deleteById(I id); + Boolean deleteById(I id) throws SQLException; - Boolean deleteAll(); + Boolean deleteAll() throws SQLException; } diff --git a/module06/src/main/java/ru/sberbank/edu/service/CarService.java b/module06/src/main/java/ru/sberbank/edu/service/CarService.java index 3e7b274a..8ac45ec0 100644 --- a/module06/src/main/java/ru/sberbank/edu/service/CarService.java +++ b/module06/src/main/java/ru/sberbank/edu/service/CarService.java @@ -8,6 +8,6 @@ public interface CarService { void editModel(String id, String model) throws SQLException; - void deleteCar(String id); + void deleteCar(String id) throws SQLException; } diff --git a/module06/src/main/java/ru/sberbank/edu/service/CarServiceImpl.java b/module06/src/main/java/ru/sberbank/edu/service/CarServiceImpl.java index e5eb91b4..07d1f4ae 100644 --- a/module06/src/main/java/ru/sberbank/edu/service/CarServiceImpl.java +++ b/module06/src/main/java/ru/sberbank/edu/service/CarServiceImpl.java @@ -14,11 +14,20 @@ public CarServiceImpl(CarRepository carRepository) { this.carRepository = carRepository; } + /** + * Метод добавляет авто в таблицу CAR + * принимает на вход строковое значение id и название модели + */ @Override public void addCar(String id, String model) throws SQLException { carRepository.createOrUpdate(new Car(id, model)); } + /** + * Метод изменяет модель авто в таблице CAR + * принимает на вход строковое значение id по которому осуществляется поиск авто + * и новое название модели + */ @Override public void editModel(String id, String newModel) throws SQLException { Optional optCar = carRepository.findById(id); @@ -26,6 +35,20 @@ public void editModel(String id, String newModel) throws SQLException { updateCarModel(car, newModel); } + /** + * Метод удаляет авто из таблице CAR + * принимает на вход строковое значение id удаляемой позиции + */ + @Override + public void deleteCar(String id) throws SQLException { + carRepository.deleteById(id); + + } + + /** + * Метод обновляет модель авто в таблице CAR + * принимает на вход объект типа car и строковое значение нового названия модели + */ private void updateCarModel(Car car, String newModel) { car.setModel(newModel); try { diff --git a/module06/src/test/java/ru/sberbank/edu/AppTest.java b/module06/src/test/java/ru/sberbank/edu/AppTest.java deleted file mode 100644 index 895d735c..00000000 --- a/module06/src/test/java/ru/sberbank/edu/AppTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package ru.sberbank.edu; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Unit test for simple App. - */ -public class AppTest - extends TestCase -{ - /** - * Create the test case - * - * @param testName name of the test case - */ - public AppTest( String testName ) - { - super( testName ); - } - - /** - * @return the suite of tests being tested - */ - public static Test suite() - { - return new TestSuite( AppTest.class ); - } - - /** - * Rigourous Test :-) - */ - public void testApp() - { - assertTrue( true ); - } -} diff --git a/module06/src/test/java/ru/sberbank/edu/CarBootstrapTest.java b/module06/src/test/java/ru/sberbank/edu/CarBootstrapTest.java new file mode 100644 index 00000000..d3452e96 --- /dev/null +++ b/module06/src/test/java/ru/sberbank/edu/CarBootstrapTest.java @@ -0,0 +1,172 @@ +package ru.sberbank.edu; + +import org.h2.jdbcx.JdbcConnectionPool; +import org.h2.tools.Server; +import org.junit.jupiter.api.AfterEach; +import org.testng.annotations.*; + +import static org.junit.Assert.*; + +import ru.sberbank.edu.dbconnection.H2DbEmbedded; +import ru.sberbank.edu.model.Car; +import ru.sberbank.edu.repository.CarDbRepositoryImpl; +import ru.sberbank.edu.repository.CarRepository; +import ru.sberbank.edu.service.CarService; +import ru.sberbank.edu.service.CarServiceImpl; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.*; + + +public class CarBootstrapTest { + private Server server; + private static H2DbEmbedded h2DbEmbedded; + + @BeforeClass + public void initDBForTests() throws SQLException { + String[] args = new String[]{}; + server = Server.createTcpServer(args).start(); + h2DbEmbedded = new H2DbEmbedded(); + H2DbEmbedded.initDb(); + } + + @AfterEach + void deleteTableCar() throws Exception { + String readAllCarsSql = "DELETE FROM car"; + Statement statement = H2DbEmbedded.getConnection().createStatement(); + statement.executeQuery(readAllCarsSql); + } + + @AfterClass + public void closeDB() throws Exception { + h2DbEmbedded.close(); + server.stop(); + } + + @Test + public void WhenAdd() throws Exception{ + List result = new ArrayList(); + String[] expectedResult = new String[]{"777", "Lada"}; + CarRepository carRepository = new CarDbRepositoryImpl(H2DbEmbedded.getConnection()); + CarService carService = new CarServiceImpl(carRepository); + carService.addCar("777", "Lada"); + String readAllCarsSql = "SELECT * FROM car"; + Statement statement = H2DbEmbedded.getConnection().createStatement(); + ResultSet resultSet = statement.executeQuery(readAllCarsSql); + while (resultSet.next()) { + result.add(resultSet.getString(1)); + result.add(resultSet.getString(2)); + } + assertArrayEquals(expectedResult, result.toArray()); + System.out.println(H2DbEmbedded.getConnection()); + } + + + @Test + public void WhenDeleteById() throws Exception{ + List result = new ArrayList(); + String[] expectedResult = new String[]{"777", "Lada", "35", "Volvo", "55", "KIA", "65", "HONDA"}; + CarRepository carRepository = new CarDbRepositoryImpl(H2DbEmbedded.getConnection()); + CarService carService = new CarServiceImpl(carRepository); + carService.addCar("777", "Lada"); + carService.addCar("35", "Volvo"); + carService.addCar("45", "BMW"); + carService.addCar("55", "KIA"); + carService.addCar("65", "HONDA"); + carService.deleteCar("45"); + String readAllCarsSql = "SELECT * FROM car"; + Statement statement = H2DbEmbedded.getConnection().createStatement(); + ResultSet resultSet = statement.executeQuery(readAllCarsSql); + while (resultSet.next()) { + result.add(resultSet.getString(1)); + result.add(resultSet.getString(2)); + } + assertArrayEquals(expectedResult, result.toArray()); + } + + @Test + public void WhenEditModel() throws Exception{ + List result = new ArrayList(); + String[] expectedResult = new String[]{"777", "Lada", "35","Volvo", "55", "KIA", "65", "HONDA", "45", "Haval"}; + CarRepository carRepository = new CarDbRepositoryImpl(H2DbEmbedded.getConnection()); + CarService carService = new CarServiceImpl(carRepository); + carService.addCar("777", "Lada"); + carService.addCar("35", "Volvo"); + carService.addCar("45", "BMW"); + carService.addCar("55", "KIA"); + carService.addCar("65", "HONDA"); + carService.editModel("45", "Haval"); + String readAllCarsSql = "SELECT * FROM car"; + Statement statement = H2DbEmbedded.getConnection().createStatement(); + ResultSet resultSet = statement.executeQuery(readAllCarsSql); + while (resultSet.next()) { + result.add(resultSet.getString(1)); + result.add(resultSet.getString(2)); + } + System.out.println(Arrays.toString(result.toArray())); + assertArrayEquals(expectedResult, result.toArray()); + } + + @Test + public void WhenCreateAll() throws Exception{ + List result = new ArrayList(); + List forAdd = new ArrayList(); + String[] expectedResult = new String[]{"777", "Lada", "35", "Volvo", "45", "BMW", "55", "KIA", "65", "HONDA"}; + CarRepository carRepository = new CarDbRepositoryImpl(H2DbEmbedded.getConnection()); + forAdd.add(new Car("777", "Lada")); + forAdd.add(new Car("35", "Volvo")); + forAdd.add(new Car("45", "BMW")); + forAdd.add(new Car("55", "KIA")); + forAdd.add(new Car("65", "HONDA")); + carRepository.createAll(forAdd); + String readAllCarsSql = "SELECT * FROM car"; + Statement statement = H2DbEmbedded.getConnection().createStatement(); + ResultSet resultSet = statement.executeQuery(readAllCarsSql); + while (resultSet.next()) { + result.add(resultSet.getString(1)); + result.add(resultSet.getString(2)); + } + assertArrayEquals(expectedResult, result.toArray()); + } + + @Test + public void WhenDeleteAll() throws Exception{ + List result = new ArrayList(); + List forAdd = new ArrayList(); + String[] expectedResult = new String[]{}; + CarRepository carRepository = new CarDbRepositoryImpl(H2DbEmbedded.getConnection()); + forAdd.add(new Car("777", "Lada")); + forAdd.add(new Car("35", "Volvo")); + forAdd.add(new Car("45", "BMW")); + forAdd.add(new Car("55", "KIA")); + forAdd.add(new Car("65", "HONDA")); + carRepository.createAll(forAdd); + carRepository.deleteAll(); + String readAllCarsSql = "SELECT * FROM car"; + Statement statement = H2DbEmbedded.getConnection().createStatement(); + ResultSet resultSet = statement.executeQuery(readAllCarsSql); + while (resultSet.next()) { + result.add(resultSet.getString(1)); + result.add(resultSet.getString(2)); + } + assertArrayEquals(expectedResult, result.toArray()); + } + + @Test + public void WhenFindByModel() throws Exception{ + Set result = new HashSet<>(); + List forAdd = new ArrayList(); + String expectedResult = "Car{id='45', model='BMW'}"; + CarRepository carRepository = new CarDbRepositoryImpl(H2DbEmbedded.getConnection()); + forAdd.add(new Car("777", "Lada")); + forAdd.add(new Car("35", "Volvo")); + forAdd.add(new Car("45", "BMW")); + forAdd.add(new Car("55", "KIA")); + forAdd.add(new Car("65", "HONDA")); + carRepository.createAll(forAdd); + result = carRepository.findByModel("BMW"); + assertEquals(expectedResult, result.toArray()[0].toString()); + } +} diff --git a/module07/pom.xml b/module07/pom.xml index 3a76c8a1..c0d153f0 100644 --- a/module07/pom.xml +++ b/module07/pom.xml @@ -22,5 +22,17 @@ spring-web 3.0.2.RELEASE + + org.testng + testng + RELEASE + test + + + junit + junit + 4.13.2 + test + diff --git a/module07/src/main/java/ru/sberbank/edu/App.java b/module07/src/main/java/ru/sberbank/edu/App.java index 5419c026..608f2d14 100644 --- a/module07/src/main/java/ru/sberbank/edu/App.java +++ b/module07/src/main/java/ru/sberbank/edu/App.java @@ -6,8 +6,23 @@ */ public class App { - public static void main( String[] args ) - { - System.out.println( "Hello World!" ); + public static void main( String[] args ) throws InterruptedException { + WeatherProvider weatherProvider = new WeatherProvider(); + WeatherCache weatherCache = new WeatherCache(weatherProvider); + Runnable task = () -> { + System.out.println(weatherCache.getWeatherInfo("Moscow")); + System.out.println("Task thread=" + getThreadInfo()); + }; + Thread thread = new Thread(task); + thread.start(); + thread.join(); + System.out.println("Main thread=" + getThreadInfo()); } + + private static String getThreadInfo() { + Thread thread = Thread.currentThread(); + long id = thread.getId(); + String name = thread.getName(); + return "Thread{id=" + id + " name=" + name + "}"; +} } diff --git a/module07/src/main/java/ru/sberbank/edu/WeatherCache.java b/module07/src/main/java/ru/sberbank/edu/WeatherCache.java index e0a2d02b..7275c5b1 100644 --- a/module07/src/main/java/ru/sberbank/edu/WeatherCache.java +++ b/module07/src/main/java/ru/sberbank/edu/WeatherCache.java @@ -1,10 +1,12 @@ package ru.sberbank.edu; +import java.time.ZoneId; import java.util.HashMap; import java.util.Map; public class WeatherCache { + private Object monitor = new Object(); private final Map cache = new HashMap<>(); private final WeatherProvider weatherProvider; @@ -27,14 +29,26 @@ public WeatherCache(WeatherProvider weatherProvider) { * @return actual weather info */ public WeatherInfo getWeatherInfo(String city) { - // should be implemented - return null; + synchronized (monitor) { + WeatherInfo newWeatherInfo; + WeatherInfo weatherInfo = cache.get(city); + if (weatherInfo != null && (System.currentTimeMillis() + - weatherInfo.getExpiryTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() < 300000)) { + return weatherInfo; + } else { + newWeatherInfo = weatherProvider.get(city); + cache.put(city, newWeatherInfo); + return newWeatherInfo; + } + } } /** * Remove weather info from cache. **/ public void removeWeatherInfo(String city) { - // should be implemented + synchronized (monitor) { + cache.remove(city); + } } } diff --git a/module07/src/main/java/ru/sberbank/edu/WeatherInfo.java b/module07/src/main/java/ru/sberbank/edu/WeatherInfo.java index 9fcee430..7d17493f 100644 --- a/module07/src/main/java/ru/sberbank/edu/WeatherInfo.java +++ b/module07/src/main/java/ru/sberbank/edu/WeatherInfo.java @@ -43,4 +43,97 @@ public class WeatherInfo { * If current time is above expiry time then current weather info is not actual! */ private LocalDateTime expiryTime; + + public WeatherInfo() { + } + + public WeatherInfo(String city, String shortDescription, String description, double temperature, + double feelsLikeTemperature, double windSpeed, double pressure, LocalDateTime expiryTime) { + this.city = city; + this.shortDescription = shortDescription; + this.description = description; + this.temperature = temperature; + this.feelsLikeTemperature = feelsLikeTemperature; + this.windSpeed = windSpeed; + this.pressure = pressure; + this.expiryTime = expiryTime; + } + + public String getCity() { + return city; + } + + public String getShortDescription() { + return shortDescription; + } + + public String getDescription() { + return description; + } + + public double getTemperature() { + return temperature; + } + + public double getFeelsLikeTemperature() { + return feelsLikeTemperature; + } + + public double getWindSpeed() { + return windSpeed; + } + + public double getPressure() { + return pressure; + } + + public LocalDateTime getExpiryTime() { + return expiryTime; + } + + public void setCity(String city) { + this.city = city; + } + + public void setShortDescription(String shortDescription) { + this.shortDescription = shortDescription; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setTemperature(double temperature) { + this.temperature = temperature; + } + + public void setFeelsLikeTemperature(double feelsLikeTemperature) { + this.feelsLikeTemperature = feelsLikeTemperature; + } + + public void setWindSpeed(double windSpeed) { + this.windSpeed = windSpeed; + } + + public void setPressure(double pressure) { + this.pressure = pressure; + } + + public void setExpiryTime(LocalDateTime expiryTime) { + this.expiryTime = expiryTime; + } + + @Override + public String toString() { + return "WeatherInfo{" + + "city='" + city + '\'' + + ", shortDescription='" + shortDescription + '\'' + + ", description='" + description + '\'' + + ", temperature=" + temperature + + ", feelsLikeTemperature=" + feelsLikeTemperature + + ", windSpeed=" + windSpeed + + ", pressure=" + pressure + + ", expiryTime=" + expiryTime + + '}'; + } } diff --git a/module07/src/main/java/ru/sberbank/edu/WeatherProvider.java b/module07/src/main/java/ru/sberbank/edu/WeatherProvider.java index 5fc6d989..f4cb0897 100644 --- a/module07/src/main/java/ru/sberbank/edu/WeatherProvider.java +++ b/module07/src/main/java/ru/sberbank/edu/WeatherProvider.java @@ -1,8 +1,18 @@ package ru.sberbank.edu; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; +import ru.sberbank.edu.model.MainObj; +import ru.sberbank.edu.model.WeaterObj; + +import java.time.LocalDateTime; + + public class WeatherProvider { - // private RestTemplate restTemplate = null; + private RestTemplate restTemplate = null; /** * Download ACTUAL weather info from internet. @@ -13,6 +23,28 @@ public class WeatherProvider { * @return weather info or null */ public WeatherInfo get(String city) { - return null; + restTemplate = new RestTemplate(); + String fooResourceUrl + = "http://api.openweathermap.org/data/2.5/weather?q=" + city + "&appid=023750cbc3864418bd55bcbbbcc779b8"; + ResponseEntity response + = restTemplate.getForEntity(fooResourceUrl, String.class); + GsonBuilder builder = new GsonBuilder(); + Gson gson = builder.create(); + WeaterObj wheaterObj = gson.fromJson(response.getBody(), WeaterObj.class); + if (response.getStatusCode().value() == 200) { + WeatherInfo weatherInfo = new WeatherInfo(); + weatherInfo.setCity(city); + weatherInfo.setTemperature(wheaterObj.getMain().get("temp")); + weatherInfo.setFeelsLikeTemperature(wheaterObj.getMain().get("feels_like")); + weatherInfo.setPressure(wheaterObj.getMain().get("pressure")); + weatherInfo.setWindSpeed(wheaterObj.getWind().get("speed")); + MainObj shortDescription = (MainObj) wheaterObj.getWeather()[0]; + weatherInfo.setShortDescription(shortDescription.getMain()); + weatherInfo.setDescription(shortDescription.getDescription()); + weatherInfo.setExpiryTime(LocalDateTime.now()); + return weatherInfo; + } else { + return null; + } } } diff --git a/module07/src/main/java/ru/sberbank/edu/model/MainObj.java b/module07/src/main/java/ru/sberbank/edu/model/MainObj.java new file mode 100644 index 00000000..44ca2297 --- /dev/null +++ b/module07/src/main/java/ru/sberbank/edu/model/MainObj.java @@ -0,0 +1,38 @@ +package ru.sberbank.edu.model; + + +public class MainObj { + + private String main; + private String description; + + public MainObj(String main, String description) { + this.main = main; + this.description = description; + } + + public String getMain() { + return main; + } + + public void setMain(String main) { + this.main = main; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "MainObj{" + + "main='" + main + '\'' + + ", description='" + description + '\'' + + '}'; + } + +} diff --git a/module07/src/main/java/ru/sberbank/edu/model/WeaterObj.java b/module07/src/main/java/ru/sberbank/edu/model/WeaterObj.java new file mode 100644 index 00000000..a91c15d4 --- /dev/null +++ b/module07/src/main/java/ru/sberbank/edu/model/WeaterObj.java @@ -0,0 +1,55 @@ +package ru.sberbank.edu.model; + +import java.util.Arrays; +import java.util.Map; + +public class WeaterObj { + + private MainObj[] weather; + private Map main; + private Map wind; + + public Object[] getWeather() { + return weather; + } + + public void setWeather(MainObj[] weather) { + this.weather = weather; + } + + public Map getMain() { + return main; + } + + public void setMain(Map main) { + this.main = main; + } + + public Map getWind() { + return wind; + } + + public void setWind(Map wind) { + this.wind = wind; + } + + public WeaterObj() { + } + + public WeaterObj(MainObj[] weather, Map main, Map wind) { + + this.weather = weather; + this.main = main; + this.wind = wind; + } + + @Override + public String toString() { + return "WeaterObj{" + + "weather=" + Arrays.toString(weather) + + ", main=" + main + + ", wind=" + wind + + '}'; + } + +} diff --git a/module07/src/test/java/ru/sberbank/edu/AppTest.java b/module07/src/test/java/ru/sberbank/edu/AppTest.java deleted file mode 100644 index 895d735c..00000000 --- a/module07/src/test/java/ru/sberbank/edu/AppTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package ru.sberbank.edu; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Unit test for simple App. - */ -public class AppTest - extends TestCase -{ - /** - * Create the test case - * - * @param testName name of the test case - */ - public AppTest( String testName ) - { - super( testName ); - } - - /** - * @return the suite of tests being tested - */ - public static Test suite() - { - return new TestSuite( AppTest.class ); - } - - /** - * Rigourous Test :-) - */ - public void testApp() - { - assertTrue( true ); - } -} diff --git a/module07/src/test/java/ru/sberbank/edu/WeatherProviderTest.java b/module07/src/test/java/ru/sberbank/edu/WeatherProviderTest.java new file mode 100644 index 00000000..a6c9a6c9 --- /dev/null +++ b/module07/src/test/java/ru/sberbank/edu/WeatherProviderTest.java @@ -0,0 +1,47 @@ +package ru.sberbank.edu; + +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.testng.annotations.Test; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + + +public class WeatherProviderTest { + @Test + public void WhenPositiveScenario() { + WeatherProvider weatherProvider = new WeatherProvider(); + WeatherCache weatherCache = new WeatherCache(weatherProvider); + WeatherInfo actualResult = weatherCache.getWeatherInfo("Moscow"); + assertEquals("Moscow", actualResult.getCity()); + assertTrue(actualResult.getTemperature() > 0); + } + + @Test + public void WhenCacheContainsActualInfo() { + WeatherProvider weatherProvider = new WeatherProvider(); + WeatherCache weatherCache = new WeatherCache(weatherProvider); + LocalDateTime actualResult = weatherCache.getWeatherInfo("Moscow").getExpiryTime(); + LocalDateTime expectedResult = weatherCache.getWeatherInfo("Moscow").getExpiryTime(); + assertTrue(actualResult.equals(expectedResult)); + } + + @Test + public void WhenCacheNotContainsActualInfo(){ + WeatherProvider weatherProvider = new WeatherProvider(); + WeatherCache weatherCache = new WeatherCache(weatherProvider); + LocalDateTime data = LocalDateTime.now().minusMinutes(6); + LocalDateTime cacheData; + try (MockedStatic topDateTimeUtilMock = Mockito.mockStatic(LocalDateTime.class)) { + topDateTimeUtilMock.when(() -> LocalDateTime.now()).thenReturn(data); + cacheData = weatherCache.getWeatherInfo("Moscow").getExpiryTime(); + System.out.println(cacheData); + } + LocalDateTime newCacheData = weatherCache.getWeatherInfo("Moscow").getExpiryTime(); + assertTrue((newCacheData.toEpochSecond(ZoneOffset.UTC) - cacheData.toEpochSecond(ZoneOffset.UTC)) > 300); + } +} diff --git a/module08/pom.xml b/module08/pom.xml index 5ab321fb..806bd855 100644 --- a/module08/pom.xml +++ b/module08/pom.xml @@ -8,7 +8,7 @@ 4.0.0 module08 - jar + war module08 http://maven.apache.org @@ -24,5 +24,25 @@ 3.8.1 test + + javax + javaee-web-api + 7.0 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.3.1 + + + diff --git a/module08/src/main/java/ru/sberbank/edu/DepositInfo.java b/module08/src/main/java/ru/sberbank/edu/DepositInfo.java new file mode 100644 index 00000000..08af72d7 --- /dev/null +++ b/module08/src/main/java/ru/sberbank/edu/DepositInfo.java @@ -0,0 +1,38 @@ +package ru.sberbank.edu; + +public class DepositInfo { + + private int sum; + private int percentage; + private int years; + + public DepositInfo() { + } + + public DepositInfo(int sum, int percentage, int years) { + this.sum = sum; + this.percentage = percentage; + this.years = years; + } + + public int getSum() { + return sum; + } + + public int getPercentage() { + return percentage; + } + + public int getYears() { + return years; + } + + @Override + public String toString() { + return "DepositInfo{" + + "sum='" + sum + '\'' + + ", percentage='" + percentage + '\'' + + ", years='" + years + '\'' + + '}'; + } +} diff --git a/module08/src/main/java/ru/sberbank/edu/FinancialServlet.java b/module08/src/main/java/ru/sberbank/edu/FinancialServlet.java index f012968f..1fdd99b9 100644 --- a/module08/src/main/java/ru/sberbank/edu/FinancialServlet.java +++ b/module08/src/main/java/ru/sberbank/edu/FinancialServlet.java @@ -1,13 +1,46 @@ package ru.sberbank.edu; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpSession; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; + /** * Hello world! * */ -public class FinancialServlet -{ - public static void main( String[] args ) - { - System.out.println( "Hello World!" ); +@WebServlet("/finance") +public class FinancialServlet extends HttpServlet { + @Override + protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) + throws IOException, ServletException { + request.getRequestDispatcher("/index.jsp").forward(request, response); + } + + @Override + protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) + throws IOException, ServletException { + try { + DepositInfo depositInfo = new DepositInfo(Integer.parseInt(request.getParameter("sum")), + Integer.parseInt(request.getParameter("percentage")), + Integer.parseInt(request.getParameter("years"))); + if (depositInfo.getSum() > 900000000 || depositInfo.getSum() < 0 + || depositInfo.getPercentage() < 0 + || depositInfo.getYears() < 0) { + request.getRequestDispatcher("/resultError.jsp").forward(request, response); + } else { + if (depositInfo.getSum() >= 50000) { + request.getRequestDispatcher("/resultSucsess.jsp").forward(request, response); + } else { + request.getRequestDispatcher("/resultFail.jsp").forward(request, response); + } + } + } catch (NumberFormatException e) { + request.getRequestDispatcher("/resultError.jsp").forward(request, response); + } } } diff --git a/module08/src/main/maketCar/author.html b/module08/src/main/maketCar/author.html new file mode 100644 index 00000000..149d7c01 --- /dev/null +++ b/module08/src/main/maketCar/author.html @@ -0,0 +1,19 @@ + + + + + Author + + + + +

Автор работы

+ +

Работу выполнил: Карпов Дмитрий Евгеньевич

+ + +
+ +Назад + + \ No newline at end of file diff --git a/module08/src/main/maketCar/css/style.css b/module08/src/main/maketCar/css/style.css new file mode 100644 index 00000000..890b97b8 --- /dev/null +++ b/module08/src/main/maketCar/css/style.css @@ -0,0 +1,13 @@ +body { + background-color: Silver; + margin-left: 10%; + margin-right: 20%; +} +#techId { + margin-left: 5%; + line-height: 40px; +} +#varId { + border: 2px solid; +} + diff --git a/module08/src/main/maketCar/images/imageCar.png b/module08/src/main/maketCar/images/imageCar.png new file mode 100644 index 00000000..7602cdce Binary files /dev/null and b/module08/src/main/maketCar/images/imageCar.png differ diff --git a/module08/src/main/maketCar/index.html b/module08/src/main/maketCar/index.html new file mode 100644 index 00000000..6e86c30e --- /dev/null +++ b/module08/src/main/maketCar/index.html @@ -0,0 +1,59 @@ + + + + + Car market + + + + +

BMW 5 G30

+ + + +

История модели

+

BMW 5 или пятая серия BMW — автомобили бизнес-класса, производимые компанией BMW с 1972 года. +В настоящее время выпускаются автомобили седьмого поколения пятой серии. + Эти автомобили заменили собой ранее выпускавшуюся серию BMW Neue Klasse.

+ +

Первоначально в серии BMW 5 были представлены только автомобили в кузове седан. +Производство кузовов типа универсал, которые получили название Touring, было начато в 1991 году. +В 2009 году также налажено производство автомобилей в кузове фастбэк, они называются Gran Turismo.

+ +

На автомобили первого поколения серии BMW 5 устанавливались атмосферные рядные 4- и 6-цилиндровые бензиновые двигатели. +В последующих поколениях устанавливались рядные 4- и 6-цилиндровые двигатели, 8- и 10-цилиндровые V-образные двигатели как атмосферные, +так и с турбонаддувом. Начиная с 1982 года на автомобили серии также устанавливаются дизельные двигатели.

+ +BMW 5 среди серий BMW занимает второе место по количеству проданных автомобилей, уступая только серии BMW 3. +5-миллионный автомобиль в серии BMW 5 был изготовлен в 2008 году, им стал автомобиль модели 530d Saloon, +окрашенный в цвет Carbon Black Metallic (с англ. — «угольно-черный металлик»). + +С пятой серии начался перевод моделей BMW на обозначения из трех цифр. Во всех поколениях серии, начиная со второго, +представлена M-версия, которая называется BMW M5. +

Технические характеристики

+
Длина 4936 мм
+Ширина 1868 мм
+Высота 1479 мм
+Колёсная база 2975 мм
+Клиренс 144 мм
+Ширина передней колеи 1605 мм
+Ширина задней колеи 1630 мм
+Размер колёс 225/55/R17
+

Варианты исполнения

+
    +
  • 2.0 л, 190 л.с., дизель, АКПП, полный привод (4WD)
  • +
  • 2.0 л, 190 л.с., дизель, АКПП, задний привод
  • +
  • 2.0 л, 184 л.с., бензин, АКПП, задний привод
  • +
  • 2.0 л, 249 л.с., бензин, АКПП, полный привод (4WD)
  • +
  • 2.0 л, 249 л.с., бензин, АКПП, задний привод
  • +
  • 3.0 л, 249 л.с., дизель, АКПП, полный привод (4WD)
  • +
  • 3.0 л, 400 л.с., дизель, АКПП, полный привод (4WD)
  • +
  • 3.0 л, 340 л.с., бензин, АКПП, полный привод (4WD)
  • +
  • 4.4 л, 462 л.с., бензин, АКПП, полный привод (4WD)
  • +
+ +
+ +Автор работы + + \ No newline at end of file diff --git a/module08/src/main/webapp/index.jsp b/module08/src/main/webapp/index.jsp index 667b4541..e41a11cf 100644 --- a/module08/src/main/webapp/index.jsp +++ b/module08/src/main/webapp/index.jsp @@ -1,5 +1,25 @@ +<%@ page contentType="text/html; charset=UTF-8" %> + + Deposit + + + -

Hello World!

+ +

Калькулятор доходности вклада

+ +
+ +
+ +
+ +
+
+ +
+ + \ No newline at end of file diff --git a/module08/src/main/webapp/resultError.jsp b/module08/src/main/webapp/resultError.jsp new file mode 100644 index 00000000..f426916e --- /dev/null +++ b/module08/src/main/webapp/resultError.jsp @@ -0,0 +1,17 @@ + +<%@ page contentType="text/html; charset=UTF-8" %> + + Deposit + + + + + +

Результат

+ +

Неверный формат данных.
+Скорректируйте значения

+ + + + \ No newline at end of file diff --git a/module08/src/main/webapp/resultFail.jsp b/module08/src/main/webapp/resultFail.jsp new file mode 100644 index 00000000..c717de02 --- /dev/null +++ b/module08/src/main/webapp/resultFail.jsp @@ -0,0 +1,17 @@ + +<%@ page contentType="text/html; charset=UTF-8" %> + + Deposit + + + + + +

Ошибка

+ +

Минимальная сумма на момент
+открытия вклада 50 000 рублей

+ + + + \ No newline at end of file diff --git a/module08/src/main/webapp/resultSucsess.jsp b/module08/src/main/webapp/resultSucsess.jsp new file mode 100644 index 00000000..616f582f --- /dev/null +++ b/module08/src/main/webapp/resultSucsess.jsp @@ -0,0 +1,19 @@ + +<%@ page contentType="text/html; charset=UTF-8" %> + + Deposit + + + + + +

Результат

+ +

Итоговая сумма +<%= String.format("%8.2f", Integer.parseInt(request.getParameter("sum")) * + (Math.pow(1.0 + (Integer.parseInt(request.getParameter("percentage")) / 100.0 / 12), + Integer.parseInt(request.getParameter("years")) * 12)))%> рублей

+ + + + \ No newline at end of file diff --git a/module08/src/main/webapp/styleFin.css b/module08/src/main/webapp/styleFin.css new file mode 100644 index 00000000..4e39870a --- /dev/null +++ b/module08/src/main/webapp/styleFin.css @@ -0,0 +1,30 @@ +body { + background-color: Silver; + margin-left: 10%; + margin-right: 20%; +} + + +input[type=submit] { + padding:5px 15px; + background:#4682B4; + cursor:pointer; + font-size: 15px; + +} + +label { +width: 310px; +display:inline-block; +font-size: 18px; +padding:5px; + +} + +p { +font-size: 18px; +} + + + + diff --git a/module09/pom.xml b/module09/pom.xml index 59059ad5..b17854c2 100644 --- a/module09/pom.xml +++ b/module09/pom.xml @@ -6,11 +6,46 @@ 1.0-SNAPSHOT 4.0.0 - module09 jar - module09 + + + org.springframework + spring-web + 5.3.14 + compile + + + org.springframework + spring-context + 5.3.14 + compile + + + org.springframework + spring-core + 5.3.14 + compile + + + org.springframework + spring-beans + 5.3.14 + + + org.testng + testng + RELEASE + test + + + junit + junit + 4.13.2 + test + + UTF-8 diff --git a/module09/src/main/java/ru/sberbank/edu/App.java b/module09/src/main/java/ru/sberbank/edu/App.java index 5419c026..8dd05da7 100644 --- a/module09/src/main/java/ru/sberbank/edu/App.java +++ b/module09/src/main/java/ru/sberbank/edu/App.java @@ -1,13 +1,23 @@ package ru.sberbank.edu; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import ru.sberbank.edu.config.MyConfig; + /** * Hello world! * */ -public class App +public class App { - public static void main( String[] args ) - { - System.out.println( "Hello World!" ); + public static void main( String[] args ) { + + ApplicationContext context = new AnnotationConfigApplicationContext("ru.sberbank.edu"); + + WeatherCache cache = context.getBean(WeatherCache.class); + + WeatherInfo weatherInfo = cache.getWeatherInfo("OMSK"); + System.out.println("GOOD! weather=" + weatherInfo); } + } diff --git a/module09/src/main/java/ru/sberbank/edu/WeatherCache.java b/module09/src/main/java/ru/sberbank/edu/WeatherCache.java index 3f236f72..d2ff63d6 100644 --- a/module09/src/main/java/ru/sberbank/edu/WeatherCache.java +++ b/module09/src/main/java/ru/sberbank/edu/WeatherCache.java @@ -1,5 +1,8 @@ package ru.sberbank.edu; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.ZoneId; import java.util.HashMap; import java.util.Map; @@ -8,13 +11,19 @@ */ public class WeatherCache { + private final Object monitor = new Object(); private final Map cache = new HashMap<>(); private WeatherProvider weatherProvider; /** - * Default constructor. + * Constructor. + * + * @param weatherProvider - weather provider */ - public WeatherCache() { + + @Autowired + public WeatherCache(WeatherProvider weatherProvider) { + this.weatherProvider = weatherProvider; } /** @@ -27,14 +36,26 @@ public WeatherCache() { * @return actual weather info */ public WeatherInfo getWeatherInfo(String city) { - // should be implemented - return null; + synchronized (monitor) { + WeatherInfo newWeatherInfo; + WeatherInfo weatherInfo = cache.get(city); + if (weatherInfo != null && (System.currentTimeMillis() + - weatherInfo.getExpiryTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() < 300000)) { + return weatherInfo; + } else { + newWeatherInfo = weatherProvider.get(city); + cache.put(city, newWeatherInfo); + return newWeatherInfo; + } + } } /** * Remove weather info from cache. **/ public void removeWeatherInfo(String city) { - // should be implemented + synchronized (monitor) { + cache.remove(city); + } } } \ No newline at end of file diff --git a/module09/src/main/java/ru/sberbank/edu/WeatherInfo.java b/module09/src/main/java/ru/sberbank/edu/WeatherInfo.java index 06d81ffc..c3ec945d 100644 --- a/module09/src/main/java/ru/sberbank/edu/WeatherInfo.java +++ b/module09/src/main/java/ru/sberbank/edu/WeatherInfo.java @@ -46,4 +46,97 @@ public class WeatherInfo { * If current time is above expiry time then current weather info is not actual! */ private LocalDateTime expiryTime; + + public WeatherInfo() { + } + + public WeatherInfo(String city, String shortDescription, String description, double temperature, + double feelsLikeTemperature, double windSpeed, double pressure, LocalDateTime expiryTime) { + this.city = city; + this.shortDescription = shortDescription; + this.description = description; + this.temperature = temperature; + this.feelsLikeTemperature = feelsLikeTemperature; + this.windSpeed = windSpeed; + this.pressure = pressure; + this.expiryTime = expiryTime; + } + + public String getCity() { + return city; + } + + public String getShortDescription() { + return shortDescription; + } + + public String getDescription() { + return description; + } + + public double getTemperature() { + return temperature; + } + + public double getFeelsLikeTemperature() { + return feelsLikeTemperature; + } + + public double getWindSpeed() { + return windSpeed; + } + + public double getPressure() { + return pressure; + } + + public LocalDateTime getExpiryTime() { + return expiryTime; + } + + public void setCity(String city) { + this.city = city; + } + + public void setShortDescription(String shortDescription) { + this.shortDescription = shortDescription; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setTemperature(double temperature) { + this.temperature = temperature; + } + + public void setFeelsLikeTemperature(double feelsLikeTemperature) { + this.feelsLikeTemperature = feelsLikeTemperature; + } + + public void setWindSpeed(double windSpeed) { + this.windSpeed = windSpeed; + } + + public void setPressure(double pressure) { + this.pressure = pressure; + } + + public void setExpiryTime(LocalDateTime expiryTime) { + this.expiryTime = expiryTime; + } + + @Override + public String toString() { + return "WeatherInfo{" + + "city='" + city + '\'' + + ", shortDescription='" + shortDescription + '\'' + + ", description='" + description + '\'' + + ", temperature=" + temperature + + ", feelsLikeTemperature=" + feelsLikeTemperature + + ", windSpeed=" + windSpeed + + ", pressure=" + pressure + + ", expiryTime=" + expiryTime + + '}'; + } } diff --git a/module09/src/main/java/ru/sberbank/edu/WeatherProvider.java b/module09/src/main/java/ru/sberbank/edu/WeatherProvider.java index 02a2fb68..4f1f48af 100644 --- a/module09/src/main/java/ru/sberbank/edu/WeatherProvider.java +++ b/module09/src/main/java/ru/sberbank/edu/WeatherProvider.java @@ -1,12 +1,22 @@ package ru.sberbank.edu; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; +import ru.sberbank.edu.model.MainObj; +import ru.sberbank.edu.model.WeaterObj; + +import java.time.LocalDateTime; + /** * Weather provider */ public class WeatherProvider { -// private RestTemplate restTemplate; -// private String appKey; + private RestTemplate restTemplate; + private String apiKey; /** * Download ACTUAL weather info from internet. @@ -16,7 +26,37 @@ public class WeatherProvider { * @param city - city * @return weather info or null */ + + @Autowired + public void setRestTemplate(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + public WeatherInfo get(String city) { - return null; + String fooResourceUrl + = "http://api.openweathermap.org/data/2.5/weather?q=" + city + apiKey; + ResponseEntity response + = restTemplate.getForEntity(fooResourceUrl, String.class); + GsonBuilder builder = new GsonBuilder(); + Gson gson = builder.create(); + WeaterObj wheaterObj = gson.fromJson(response.getBody(), WeaterObj.class); + if (response.getStatusCode().value() == 200) { + WeatherInfo weatherInfo = new WeatherInfo(); + weatherInfo.setCity(city); + weatherInfo.setTemperature(wheaterObj.getMain().get("temp")); + weatherInfo.setFeelsLikeTemperature(wheaterObj.getMain().get("feels_like")); + weatherInfo.setPressure(wheaterObj.getMain().get("pressure")); + weatherInfo.setWindSpeed(wheaterObj.getWind().get("speed")); + MainObj shortDescription = (MainObj) wheaterObj.getWeather()[0]; + weatherInfo.setShortDescription(shortDescription.getMain()); + weatherInfo.setDescription(shortDescription.getDescription()); + weatherInfo.setExpiryTime(LocalDateTime.now()); + return weatherInfo; + } else { + return null; + } } } diff --git a/module09/src/main/java/ru/sberbank/edu/config/MyConfig.java b/module09/src/main/java/ru/sberbank/edu/config/MyConfig.java new file mode 100644 index 00000000..9d15f9a7 --- /dev/null +++ b/module09/src/main/java/ru/sberbank/edu/config/MyConfig.java @@ -0,0 +1,37 @@ +package ru.sberbank.edu.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.web.client.RestTemplate; +import ru.sberbank.edu.WeatherCache; +import ru.sberbank.edu.WeatherProvider; + +@Configuration +@PropertySource("classpath:app.properties") +public class MyConfig { + + + @Value("${apiKey}") + private String apiKey; + + @Bean + public RestTemplate restTemplate() { + RestTemplate restTemplate = new RestTemplate(); + return restTemplate; + } + + @Bean + public WeatherProvider weatherProvider() { + WeatherProvider weatherProvider = new WeatherProvider(); + weatherProvider.setApiKey(apiKey); + return weatherProvider; + } + + @Bean + public WeatherCache weatherCache() { + WeatherCache weatherCache = new WeatherCache(weatherProvider()); + return weatherCache; + } +} diff --git a/module09/src/main/java/ru/sberbank/edu/model/MainObj.java b/module09/src/main/java/ru/sberbank/edu/model/MainObj.java new file mode 100644 index 00000000..44ca2297 --- /dev/null +++ b/module09/src/main/java/ru/sberbank/edu/model/MainObj.java @@ -0,0 +1,38 @@ +package ru.sberbank.edu.model; + + +public class MainObj { + + private String main; + private String description; + + public MainObj(String main, String description) { + this.main = main; + this.description = description; + } + + public String getMain() { + return main; + } + + public void setMain(String main) { + this.main = main; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "MainObj{" + + "main='" + main + '\'' + + ", description='" + description + '\'' + + '}'; + } + +} diff --git a/module09/src/main/java/ru/sberbank/edu/model/WeaterObj.java b/module09/src/main/java/ru/sberbank/edu/model/WeaterObj.java new file mode 100644 index 00000000..a91c15d4 --- /dev/null +++ b/module09/src/main/java/ru/sberbank/edu/model/WeaterObj.java @@ -0,0 +1,55 @@ +package ru.sberbank.edu.model; + +import java.util.Arrays; +import java.util.Map; + +public class WeaterObj { + + private MainObj[] weather; + private Map main; + private Map wind; + + public Object[] getWeather() { + return weather; + } + + public void setWeather(MainObj[] weather) { + this.weather = weather; + } + + public Map getMain() { + return main; + } + + public void setMain(Map main) { + this.main = main; + } + + public Map getWind() { + return wind; + } + + public void setWind(Map wind) { + this.wind = wind; + } + + public WeaterObj() { + } + + public WeaterObj(MainObj[] weather, Map main, Map wind) { + + this.weather = weather; + this.main = main; + this.wind = wind; + } + + @Override + public String toString() { + return "WeaterObj{" + + "weather=" + Arrays.toString(weather) + + ", main=" + main + + ", wind=" + wind + + '}'; + } + +} diff --git a/module09/src/main/resources/app.properties b/module09/src/main/resources/app.properties new file mode 100644 index 00000000..4eaa58b9 --- /dev/null +++ b/module09/src/main/resources/app.properties @@ -0,0 +1 @@ +apiKey=&appid=023750cbc3864418bd55bcbbbcc779b8 \ No newline at end of file diff --git a/module09/src/test/java/ru/sberbank/edu/AppTest.java b/module09/src/test/java/ru/sberbank/edu/AppTest.java deleted file mode 100644 index 895d735c..00000000 --- a/module09/src/test/java/ru/sberbank/edu/AppTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package ru.sberbank.edu; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Unit test for simple App. - */ -public class AppTest - extends TestCase -{ - /** - * Create the test case - * - * @param testName name of the test case - */ - public AppTest( String testName ) - { - super( testName ); - } - - /** - * @return the suite of tests being tested - */ - public static Test suite() - { - return new TestSuite( AppTest.class ); - } - - /** - * Rigourous Test :-) - */ - public void testApp() - { - assertTrue( true ); - } -} diff --git a/module09/src/test/java/ru/sberbank/edu/WeatherProviderTest.java b/module09/src/test/java/ru/sberbank/edu/WeatherProviderTest.java new file mode 100644 index 00000000..731dbb2b --- /dev/null +++ b/module09/src/test/java/ru/sberbank/edu/WeatherProviderTest.java @@ -0,0 +1,52 @@ +package ru.sberbank.edu; + +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.testng.annotations.Test; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + + +public class WeatherProviderTest { + @Test + public void WhenPositiveScenario() { + ApplicationContext context = new AnnotationConfigApplicationContext("ru.sberbank.edu"); + WeatherCache cache = context.getBean(WeatherCache.class); + WeatherInfo actualResult = cache.getWeatherInfo("OMSK"); + assertEquals("OMSK", actualResult.getCity()); + assertTrue(actualResult.getTemperature() > 0); + } + + @Test + public void WhenCacheContainsActualInfo() throws InterruptedException { + ApplicationContext context = new AnnotationConfigApplicationContext("ru.sberbank.edu"); + WeatherCache cache = context.getBean(WeatherCache.class); + LocalDateTime actualResult = cache.getWeatherInfo("Moscow").getExpiryTime(); + TimeUnit.SECONDS.sleep(1); + LocalDateTime expectedResult = cache.getWeatherInfo("Moscow").getExpiryTime(); + assertTrue(actualResult.equals(expectedResult)); + } + + @Test + public void WhenCacheNotContainsActualInfo(){ + ApplicationContext context = new AnnotationConfigApplicationContext("ru.sberbank.edu"); + WeatherCache cache = context.getBean(WeatherCache.class); + LocalDateTime data = LocalDateTime.now().minusMinutes(6); + LocalDateTime cacheData; + try (MockedStatic topDateTimeUtilMock = Mockito.mockStatic(LocalDateTime.class)) { + topDateTimeUtilMock.when(() -> LocalDateTime.now()).thenReturn(data); + cacheData = cache.getWeatherInfo("Moscow").getExpiryTime(); + System.out.println(cacheData); + } + LocalDateTime newCacheData = cache.getWeatherInfo("Moscow").getExpiryTime(); + assertTrue((newCacheData.toEpochSecond(ZoneOffset.UTC) - cacheData.toEpochSecond(ZoneOffset.UTC)) > 300); + } + +} diff --git a/module10/pom.xml b/module10/pom.xml index 96f5c1b2..9ec8e230 100644 --- a/module10/pom.xml +++ b/module10/pom.xml @@ -1,3 +1,5 @@ + + @@ -8,12 +10,51 @@ 4.0.0 module10 - jar + 1.0-SNAPSHOT + war module10 + + http://www.example.com UTF-8 + 1.8 + 1.8 + + 5.3.14 + + + junit + junit + 4.11 + test + + + + org.springframework + spring-core + ${spring.version} + + + + org.springframework + spring-context + ${spring.version} + + + + org.springframework + spring-web + ${spring.version} + + + + org.springframework + spring-webmvc + ${spring.version} + + diff --git a/module10/src/main/java/ru/sberbank/edu/App.java b/module10/src/main/java/ru/sberbank/edu/App.java deleted file mode 100644 index 5419c026..00000000 --- a/module10/src/main/java/ru/sberbank/edu/App.java +++ /dev/null @@ -1,13 +0,0 @@ -package ru.sberbank.edu; - -/** - * Hello world! - * - */ -public class App -{ - public static void main( String[] args ) - { - System.out.println( "Hello World!" ); - } -} diff --git a/module10/src/main/java/ru/sberbank/edu/DepositInfo.java b/module10/src/main/java/ru/sberbank/edu/DepositInfo.java new file mode 100644 index 00000000..08af72d7 --- /dev/null +++ b/module10/src/main/java/ru/sberbank/edu/DepositInfo.java @@ -0,0 +1,38 @@ +package ru.sberbank.edu; + +public class DepositInfo { + + private int sum; + private int percentage; + private int years; + + public DepositInfo() { + } + + public DepositInfo(int sum, int percentage, int years) { + this.sum = sum; + this.percentage = percentage; + this.years = years; + } + + public int getSum() { + return sum; + } + + public int getPercentage() { + return percentage; + } + + public int getYears() { + return years; + } + + @Override + public String toString() { + return "DepositInfo{" + + "sum='" + sum + '\'' + + ", percentage='" + percentage + '\'' + + ", years='" + years + '\'' + + '}'; + } +} diff --git a/module10/src/main/java/ru/sberbank/edu/FinanceController.java b/module10/src/main/java/ru/sberbank/edu/FinanceController.java new file mode 100644 index 00000000..8b051dfa --- /dev/null +++ b/module10/src/main/java/ru/sberbank/edu/FinanceController.java @@ -0,0 +1,55 @@ +package ru.sberbank.edu; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +import java.util.Map; + +@Controller +@RequestMapping(value = "/finance") +public class FinanceController { + + @Value("${minSum}") + private String minSum; + + @GetMapping("/") + public ModelAndView info() { + ModelAndView modelAndView = new ModelAndView(); + modelAndView.setViewName("/finPage.jsp"); + return modelAndView; + } + + @PostMapping("/") + public ModelAndView getResult(@RequestParam Map body) { + ModelAndView modelAndView = new ModelAndView(); + try { + DepositInfo depositInfo = new DepositInfo(Integer.parseInt(body.get("sum")), + Integer.parseInt(body.get("percentage")), + Integer.parseInt(body.get("years"))); + if (depositInfo.getSum() > 900000000 || depositInfo.getSum() < 0 + || depositInfo.getPercentage() < 0 + || depositInfo.getYears() < 0) { + modelAndView.setViewName("/resultError.jsp"); + return modelAndView; + } else { + if (depositInfo.getSum() >= Integer.parseInt(minSum)) { + String sum = String.format("%8.2f", Integer.parseInt(body.get("sum")) * + (Math.pow(1.0 + (Integer.parseInt(body.get("percentage")) / 100.0 / 12), + Integer.parseInt(body.get("years")) * 12))); + modelAndView.addObject("sum", sum); + modelAndView.setViewName("/resultSuccess.jsp"); + return modelAndView; + } else { + modelAndView.addObject("minSum", minSum); + modelAndView.setViewName("/resultFail.jsp"); + return modelAndView; + } + } + } catch (NumberFormatException e) { + modelAndView.setViewName("/resultError.jsp"); + return modelAndView; + } + } +} diff --git a/module10/src/main/resources/app.properties b/module10/src/main/resources/app.properties new file mode 100644 index 00000000..df8b883d --- /dev/null +++ b/module10/src/main/resources/app.properties @@ -0,0 +1 @@ +minSum=40000 \ No newline at end of file diff --git a/module10/src/main/webapp/WEB-INF/beans.xml b/module10/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 00000000..629fa428 --- /dev/null +++ b/module10/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,19 @@ + + + + + + + + + \ No newline at end of file diff --git a/module10/src/main/webapp/WEB-INF/web.xml b/module10/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..d0bbd483 --- /dev/null +++ b/module10/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,33 @@ + + + + + + Archetype Created Web Application + + + + + dispatcher + org.springframework.web.servlet.DispatcherServlet + + contextConfigLocation + /WEB-INF/beans.xml + + 1 + + + + dispatcher + / + + + + + + diff --git a/module10/src/main/webapp/css/styleFin.css b/module10/src/main/webapp/css/styleFin.css new file mode 100644 index 00000000..4e39870a --- /dev/null +++ b/module10/src/main/webapp/css/styleFin.css @@ -0,0 +1,30 @@ +body { + background-color: Silver; + margin-left: 10%; + margin-right: 20%; +} + + +input[type=submit] { + padding:5px 15px; + background:#4682B4; + cursor:pointer; + font-size: 15px; + +} + +label { +width: 310px; +display:inline-block; +font-size: 18px; +padding:5px; + +} + +p { +font-size: 18px; +} + + + + diff --git a/module10/src/main/webapp/finPage.jsp b/module10/src/main/webapp/finPage.jsp new file mode 100644 index 00000000..448085e9 --- /dev/null +++ b/module10/src/main/webapp/finPage.jsp @@ -0,0 +1,25 @@ + +<%@ page contentType="text/html; charset=UTF-8" %> + + Deposit + + + + + +

Калькулятор доходности вклада

+ +
+ +
+ +
+ +
+
+ +
+ + + + \ No newline at end of file diff --git a/module10/src/main/webapp/resultError.jsp b/module10/src/main/webapp/resultError.jsp new file mode 100644 index 00000000..94946b9e --- /dev/null +++ b/module10/src/main/webapp/resultError.jsp @@ -0,0 +1,17 @@ + +<%@ page contentType="text/html; charset=UTF-8" %> + + Deposit + + + + + +

Результат

+ +

Неверный формат данных.
+Скорректируйте значения

+ + + + \ No newline at end of file diff --git a/module10/src/main/webapp/resultFail.jsp b/module10/src/main/webapp/resultFail.jsp new file mode 100644 index 00000000..ef82e787 --- /dev/null +++ b/module10/src/main/webapp/resultFail.jsp @@ -0,0 +1,18 @@ + +<%@ page contentType="text/html; charset=UTF-8" %> +<%@ page isELIgnored="false" %> + + Deposit + + + + + +

Ошибка

+ +

Минимальная сумма на момент
+открытия вклада ${minSum} рублей

+ + + + \ No newline at end of file diff --git a/module10/src/main/webapp/resultSuccess.jsp b/module10/src/main/webapp/resultSuccess.jsp new file mode 100644 index 00000000..c6e6f00e --- /dev/null +++ b/module10/src/main/webapp/resultSuccess.jsp @@ -0,0 +1,17 @@ + +<%@ page contentType="text/html; charset=UTF-8" %> +<%@ page isELIgnored="false" %> + + Deposit + + + + + +

Результат

+ +

Итоговая сумма ${sum} рублей

+ + + + \ No newline at end of file diff --git a/module10/src/test/java/ru/sberbank/edu/AppTest.java b/module10/src/test/java/ru/sberbank/edu/AppTest.java index 895d735c..8b137891 100644 --- a/module10/src/test/java/ru/sberbank/edu/AppTest.java +++ b/module10/src/test/java/ru/sberbank/edu/AppTest.java @@ -1,38 +1 @@ -package ru.sberbank.edu; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Unit test for simple App. - */ -public class AppTest - extends TestCase -{ - /** - * Create the test case - * - * @param testName name of the test case - */ - public AppTest( String testName ) - { - super( testName ); - } - - /** - * @return the suite of tests being tested - */ - public static Test suite() - { - return new TestSuite( AppTest.class ); - } - - /** - * Rigourous Test :-) - */ - public void testApp() - { - assertTrue( true ); - } -} diff --git a/module11/pom.xml b/module11/pom.xml index 3d6f8818..6e304a4c 100644 --- a/module11/pom.xml +++ b/module11/pom.xml @@ -1,41 +1,65 @@ - 4.0.0 - org.springframework.boot - spring-boot-starter-parent - 3.2.0 - + homework-javareboot-2023-group-06 + ru.sberbank.edu + 1.0-SNAPSHOT - com.example + + 4.0.0 module11 - 0.0.1-SNAPSHOT + war module11 - module11 + 17 + org.springframework.boot spring-boot-starter-data-jpa + 2.7.2 + org.springframework.boot spring-boot-starter-web + 2.7.2 + + + + org.springframework.boot + spring-boot-starter-test + 2.7.2 + + + + org.springframework.boot + spring-boot-starter-thymeleaf + 2.7.2 com.h2database h2 + 1.4.199 runtime + - org.springframework.boot - spring-boot-starter-test - test + org.projectlombok + lombok + 1.18.28 + + + org.springdoc + springdoc-openapi-ui + 1.6.14 + + diff --git a/module11/src/main/java/com/example/module11/entity/User.java b/module11/src/main/java/com/example/module11/entity/User.java deleted file mode 100644 index 49c12ffd..00000000 --- a/module11/src/main/java/com/example/module11/entity/User.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.example.module11.entity; - -public class User { - - private Long id; - private String name; - private Integer age; -} diff --git a/module11/src/main/java/com/example/module11/Application.java b/module11/src/main/java/ru/sberbank/edu/Application.java similarity index 90% rename from module11/src/main/java/com/example/module11/Application.java rename to module11/src/main/java/ru/sberbank/edu/Application.java index f6de7930..325e4788 100644 --- a/module11/src/main/java/com/example/module11/Application.java +++ b/module11/src/main/java/ru/sberbank/edu/Application.java @@ -1,4 +1,4 @@ -package com.example.module11; +package ru.sberbank.edu; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/module11/src/main/java/ru/sberbank/edu/MVCConfig.java b/module11/src/main/java/ru/sberbank/edu/MVCConfig.java new file mode 100644 index 00000000..d1d27f40 --- /dev/null +++ b/module11/src/main/java/ru/sberbank/edu/MVCConfig.java @@ -0,0 +1,18 @@ +package ru.sberbank.edu; + + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +@EnableWebMvc +public class MVCConfig implements WebMvcConfigurer { + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/css/**") + .addResourceLocations("classpath:/static/css/"); + } +} \ No newline at end of file diff --git a/module11/src/main/java/ru/sberbank/edu/config/OpenApiConfig.java b/module11/src/main/java/ru/sberbank/edu/config/OpenApiConfig.java new file mode 100644 index 00000000..7d9c9139 --- /dev/null +++ b/module11/src/main/java/ru/sberbank/edu/config/OpenApiConfig.java @@ -0,0 +1,23 @@ +package ru.sberbank.edu.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +// https://habr.com/ru/post/541592/ +@Configuration +public class OpenApiConfig { + @Bean + public OpenAPI customOpenAPI(@Value("${service.description}") String appDescription, @Value("${service.version}") String appVersion) { + return new OpenAPI() + .info(new Info() + .title("User service API") + .version(appVersion) + .description(appDescription) + .termsOfService("http://swagger.io/terms/") + .license(new License().name("Apache 2.0").url("http://springdoc.org"))); + } +} diff --git a/module11/src/main/java/ru/sberbank/edu/controller/ErrorHandler.java b/module11/src/main/java/ru/sberbank/edu/controller/ErrorHandler.java new file mode 100644 index 00000000..7e61c97b --- /dev/null +++ b/module11/src/main/java/ru/sberbank/edu/controller/ErrorHandler.java @@ -0,0 +1,27 @@ +package ru.sberbank.edu.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import ru.sberbank.edu.exception.ItemNotFoundException; +import ru.sberbank.edu.exception.ServiceError; + +import java.util.Date; + +@ControllerAdvice +public class ErrorHandler { + + @ExceptionHandler(ItemNotFoundException.class) + public ResponseEntity handleError(ItemNotFoundException ex) { + ServiceError serviceError = new ServiceError(); + serviceError.setStatus(HttpStatus.NOT_FOUND.value()); + serviceError.setTimeStamp(new Date().getTime()); + serviceError.setDetails(ex.getMessage()); + + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .contentType(MediaType.APPLICATION_JSON) + .body(serviceError); + } +} diff --git a/module11/src/main/java/ru/sberbank/edu/controller/UserController.java b/module11/src/main/java/ru/sberbank/edu/controller/UserController.java new file mode 100644 index 00000000..1f53c470 --- /dev/null +++ b/module11/src/main/java/ru/sberbank/edu/controller/UserController.java @@ -0,0 +1,117 @@ +package ru.sberbank.edu.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.sberbank.edu.entity.User; +import ru.sberbank.edu.exception.ItemNotFoundException; +import ru.sberbank.edu.service.UserService; + +import java.util.List; + +// http://localhost:8080/swagger-ui/index.html#/ +@RestController +@RequestMapping(value = "/api/v1/user", consumes = MediaType.ALL_VALUE) +@RequiredArgsConstructor +@Tag(name = "User", description = "User API") +public class UserController { + private static final Logger logger = LoggerFactory.getLogger(UserController.class); + + private final UserService service; + + @GetMapping("/page") + public ModelAndView info() { + ModelAndView modelAndView = new ModelAndView(); + modelAndView.setViewName("user"); + return modelAndView; + } + + @GetMapping("/getUsersPage") + public ModelAndView getUsers() { + List users = service.findAll(); + ModelAndView modelAndView = new ModelAndView(); + modelAndView.addObject("users", users); + modelAndView.setViewName("getUsers"); + return modelAndView; + } + + @GetMapping("/addUserPage") + public ModelAndView postUserPage() { + ModelAndView modelAndView = new ModelAndView(); + modelAndView.setViewName("postUser"); + return modelAndView; + } + + @PostMapping("/addUser") + public ModelAndView postUser(@RequestParam("id") Long id, + @RequestParam("age") Integer age, + @RequestParam("name") String name) { + ModelAndView modelAndView = new ModelAndView(); + try { + User user = new User(id, name, age); + if (service.findById(user.getId()).getId() == user.getId()) { + modelAndView.setViewName("resultAddError"); + } + return modelAndView; + } catch (ItemNotFoundException e) { + User user = new User(id, name, age); + service.save(user); + modelAndView.setViewName("resultSucsess"); + return modelAndView; + } + } + + @GetMapping("/deleteUserPage") + public ModelAndView deleteUserPage() { + ModelAndView modelAndView = new ModelAndView(); + modelAndView.setViewName("deleteUser"); + return modelAndView; + } + + @PostMapping("/deleteUser") + public ModelAndView deleteUser( + @RequestParam(value = "id", required = false) Long id) { + ModelAndView modelAndView = new ModelAndView(); + try { + service.deleteById(id); + modelAndView.setViewName("resultSucsess"); + return modelAndView; + } catch (ItemNotFoundException e) { + modelAndView.setViewName("resultFail"); + return modelAndView; + } + } + + @GetMapping("/editUserPage") + public ModelAndView editUserPage() { + ModelAndView modelAndView = new ModelAndView(); + modelAndView.setViewName("editUser"); + return modelAndView; + } + + @PostMapping("/editUser") + public ModelAndView editUser(@RequestParam("id") Long id, + @RequestParam("name") String name, + @RequestParam("age") Integer age) { + ModelAndView modelAndView = new ModelAndView(); + try { + User user = new User((long) id, name, age); + if (service.findById(user.getId()).getId() == user.getId()) { + service.update(user); + modelAndView.setViewName("resultSucsess"); + return modelAndView; + } else { + modelAndView.setViewName("resultFail"); + return modelAndView; + + } + } catch (IllegalArgumentException e) { + modelAndView.setViewName("resultError"); + return modelAndView; + } + } +} diff --git a/module11/src/main/java/ru/sberbank/edu/entity/User.java b/module11/src/main/java/ru/sberbank/edu/entity/User.java new file mode 100644 index 00000000..6c3e566a --- /dev/null +++ b/module11/src/main/java/ru/sberbank/edu/entity/User.java @@ -0,0 +1,28 @@ +package ru.sberbank.edu.entity; + + +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Entity +@Table(name = "users") +@Data +@NoArgsConstructor +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + private Integer age; + + + public User(Long id, String name, Integer age) { + this.id = id; + this.name = name; + this.age = age; + } +} diff --git a/module11/src/main/java/ru/sberbank/edu/exception/ItemNotFoundException.java b/module11/src/main/java/ru/sberbank/edu/exception/ItemNotFoundException.java new file mode 100644 index 00000000..b7a3658b --- /dev/null +++ b/module11/src/main/java/ru/sberbank/edu/exception/ItemNotFoundException.java @@ -0,0 +1,15 @@ +package ru.sberbank.edu.exception; + +public class ItemNotFoundException extends RuntimeException{ + + public ItemNotFoundException() { + } + + public ItemNotFoundException(String message) { + super(message); + } + + public ItemNotFoundException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/module11/src/main/java/ru/sberbank/edu/exception/ServiceError.java b/module11/src/main/java/ru/sberbank/edu/exception/ServiceError.java new file mode 100644 index 00000000..57f77408 --- /dev/null +++ b/module11/src/main/java/ru/sberbank/edu/exception/ServiceError.java @@ -0,0 +1,11 @@ +package ru.sberbank.edu.exception; + +import lombok.Data; + +@Data +public class ServiceError { + + private int status; + private String details; + private long timeStamp; +} diff --git a/module11/src/main/java/ru/sberbank/edu/repository/UserRepository.java b/module11/src/main/java/ru/sberbank/edu/repository/UserRepository.java new file mode 100644 index 00000000..b77d028c --- /dev/null +++ b/module11/src/main/java/ru/sberbank/edu/repository/UserRepository.java @@ -0,0 +1,12 @@ +package ru.sberbank.edu.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.sberbank.edu.entity.User; + +import java.util.List; + +@Repository +public interface UserRepository extends JpaRepository { + List findAllByNameOrderByAgeAsc(String name); +} diff --git a/module11/src/main/java/ru/sberbank/edu/service/UserService.java b/module11/src/main/java/ru/sberbank/edu/service/UserService.java new file mode 100644 index 00000000..27df61c3 --- /dev/null +++ b/module11/src/main/java/ru/sberbank/edu/service/UserService.java @@ -0,0 +1,38 @@ +package ru.sberbank.edu.service; + +import lombok.RequiredArgsConstructor; + import org.springframework.stereotype.Service; + import ru.sberbank.edu.entity.User; + import ru.sberbank.edu.exception.ItemNotFoundException; + import ru.sberbank.edu.repository.UserRepository; + + import java.util.List; + +@Service +@RequiredArgsConstructor +public class UserService { + + private final UserRepository repository; + + public List findAll() { + return repository.findAll(); + } + + public User findById(Long id) { + return repository.findById(id).orElseThrow(() -> new ItemNotFoundException("User not found, id = " + id)); + } + + public User save(User user) { + return repository.save(user); + } + + public User update(User user) { + findById(user.getId()); + return repository.save(user); + } + + public void deleteById(Long id) { + findById(id); + repository.deleteById(id); + } +} \ No newline at end of file diff --git a/module11/src/main/resources/application-h2.yml b/module11/src/main/resources/application-h2.yml new file mode 100644 index 00000000..55646e3e --- /dev/null +++ b/module11/src/main/resources/application-h2.yml @@ -0,0 +1,9 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:file:./app.db;AUTO_SERVER=TRUE + username: sa + password: 123456 + h2: + console: + enabled: true \ No newline at end of file diff --git a/module11/src/main/resources/application.properties b/module11/src/main/resources/application.properties deleted file mode 100644 index 8b137891..00000000 --- a/module11/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/module11/src/main/resources/application.yaml b/module11/src/main/resources/application.yaml new file mode 100644 index 00000000..89d5b96f --- /dev/null +++ b/module11/src/main/resources/application.yaml @@ -0,0 +1,29 @@ +spring: + profiles: + active: h2 + jpa: + hibernate: + ddl-auto: create-drop + defer-datasource-initialization: true + show-sql: true + properties: + hibernate: + format_sql: true + sql: + init: + mode: always + +server: + port: 8080 + + +logging: + level: + ru.edu: info + file: + path: UsersLog.log + +service: + description: users + version: 1.0 BETA + diff --git a/module11/src/main/resources/data.sql b/module11/src/main/resources/data.sql new file mode 100644 index 00000000..564b93ec --- /dev/null +++ b/module11/src/main/resources/data.sql @@ -0,0 +1,5 @@ +insert into users(name, age) +values ('Denis', 25), + ('Maksim', 20), + ('Artur', 40), + ('Andrey', 35); \ No newline at end of file diff --git a/module11/src/main/resources/static/css/styleFin.css b/module11/src/main/resources/static/css/styleFin.css new file mode 100644 index 00000000..4e39870a --- /dev/null +++ b/module11/src/main/resources/static/css/styleFin.css @@ -0,0 +1,30 @@ +body { + background-color: Silver; + margin-left: 10%; + margin-right: 20%; +} + + +input[type=submit] { + padding:5px 15px; + background:#4682B4; + cursor:pointer; + font-size: 15px; + +} + +label { +width: 310px; +display:inline-block; +font-size: 18px; +padding:5px; + +} + +p { +font-size: 18px; +} + + + + diff --git a/module11/src/main/resources/templates/deleteUser.html b/module11/src/main/resources/templates/deleteUser.html new file mode 100644 index 00000000..f193578c --- /dev/null +++ b/module11/src/main/resources/templates/deleteUser.html @@ -0,0 +1,21 @@ + + + + User + + + + + +

Страница удаления пользователей

+ + +
+ +
+
+
+
+Вернуться на главную + + \ No newline at end of file diff --git a/module11/src/main/resources/templates/editUser.html b/module11/src/main/resources/templates/editUser.html new file mode 100644 index 00000000..5da90368 --- /dev/null +++ b/module11/src/main/resources/templates/editUser.html @@ -0,0 +1,24 @@ + + + + User + + + + + +

Страница изменения данных о пользователях

+ +
+ +
+ +
+ +
+
+
+
+Вернуться на главную + + \ No newline at end of file diff --git a/module11/src/main/resources/templates/getUsers.html b/module11/src/main/resources/templates/getUsers.html new file mode 100644 index 00000000..1ffa2759 --- /dev/null +++ b/module11/src/main/resources/templates/getUsers.html @@ -0,0 +1,22 @@ + + + + User + + + + + +

Список всех пользователей

+ + + + + +
+ + +
+Вернуться на главную + + \ No newline at end of file diff --git a/module11/src/main/resources/templates/postUser.html b/module11/src/main/resources/templates/postUser.html new file mode 100644 index 00000000..739d368a --- /dev/null +++ b/module11/src/main/resources/templates/postUser.html @@ -0,0 +1,25 @@ + + + + User + + + + + +

Страница добавления пользователя

+ + +
+ +
+ +
+ +
+
+
+
+Вернуться на главную + + \ No newline at end of file diff --git a/module11/src/main/resources/templates/resultAddError.html b/module11/src/main/resources/templates/resultAddError.html new file mode 100644 index 00000000..772a2b6f --- /dev/null +++ b/module11/src/main/resources/templates/resultAddError.html @@ -0,0 +1,19 @@ + + + + User + + + + + +

Результат

+ +

Неверные данные
+Пользователь с таким ID уже существует

+
+Вернуться на главную + + + + \ No newline at end of file diff --git a/module11/src/main/resources/templates/resultError.html b/module11/src/main/resources/templates/resultError.html new file mode 100644 index 00000000..7f60bdd3 --- /dev/null +++ b/module11/src/main/resources/templates/resultError.html @@ -0,0 +1,19 @@ + + + + User + + + + + +

Результат

+ +

Неверный формат данных.
+Скорректируйте значения

+
+Вернуться на главную + + + + \ No newline at end of file diff --git a/module11/src/main/resources/templates/resultFail.html b/module11/src/main/resources/templates/resultFail.html new file mode 100644 index 00000000..306fecb4 --- /dev/null +++ b/module11/src/main/resources/templates/resultFail.html @@ -0,0 +1,19 @@ + + + + User + + + + + + +

Ошибка

+ +

Такого пользователя не существует!

+
+Вернуться на главную + + + + \ No newline at end of file diff --git a/module11/src/main/resources/templates/resultSucsess.html b/module11/src/main/resources/templates/resultSucsess.html new file mode 100644 index 00000000..8ff748ca --- /dev/null +++ b/module11/src/main/resources/templates/resultSucsess.html @@ -0,0 +1,17 @@ + + + + User + + + + + +

Результат

+ +

Действие выполнено успешно!

+
+Вернуться на главную + + + \ No newline at end of file diff --git a/module11/src/main/resources/templates/user.html b/module11/src/main/resources/templates/user.html new file mode 100644 index 00000000..6b728c59 --- /dev/null +++ b/module11/src/main/resources/templates/user.html @@ -0,0 +1,26 @@ + + + + User + + + + + +

Страница управления пользователями

+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/module11/src/test/java/com/example/module11/Module11ApplicationTests.java b/module11/src/test/java/ru/sberbank/edu/Module11ApplicationTests.java similarity index 86% rename from module11/src/test/java/com/example/module11/Module11ApplicationTests.java rename to module11/src/test/java/ru/sberbank/edu/Module11ApplicationTests.java index 0ec40701..46bb8999 100644 --- a/module11/src/test/java/com/example/module11/Module11ApplicationTests.java +++ b/module11/src/test/java/ru/sberbank/edu/Module11ApplicationTests.java @@ -1,4 +1,4 @@ -package com.example.module11; +package ru.sberbank.edu; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; diff --git a/module11/src/test/java/ru/sberbank/edu/controller/UserControllerTest.java b/module11/src/test/java/ru/sberbank/edu/controller/UserControllerTest.java new file mode 100644 index 00000000..c3afdec2 --- /dev/null +++ b/module11/src/test/java/ru/sberbank/edu/controller/UserControllerTest.java @@ -0,0 +1,52 @@ +package ru.sberbank.edu.controller; + +import ru.sberbank.edu.entity.User; +import ru.sberbank.edu.service.UserService; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@WebMvcTest({UserController.class}) +class UserControllerTest { + @Autowired + private MockMvc mockMvc; + + @MockBean + private UserService service; + + + @Test + void getAllUsers() throws Exception { + List users = new ArrayList<>(Arrays.asList( + new User(1L, "Ilia", 25), + new User(2L, "Roman", 35) + )); + when(service.findAll()).thenReturn(users); + mockMvc.perform(get("/api/v1/user/getUsersPage")) + .andDo(print()) + .andExpect(content().contentType("text/html;charset=UTF-8")) + .andExpect(status().isOk()); + } + + + @Test + void deleteUserById() throws Exception { + mockMvc.perform(post("/api/v1/user/deleteUser") + .content("{\"id\": 1}")) + .andDo(print()) + .andExpect(status().isOk()); + } +} diff --git a/module12/pom.xml b/module12/pom.xml index df62b2cb..45ea71b4 100644 --- a/module12/pom.xml +++ b/module12/pom.xml @@ -2,40 +2,74 @@ 4.0.0 + - org.springframework.boot - spring-boot-starter-parent - 3.2.0 - + homework-javareboot-2023-group-06 + ru.sberbank.edu + 1.0-SNAPSHOT + ru.edu module12 0.0.1-SNAPSHOT module12 module12 + 17 + org.springframework.boot spring-boot-starter-data-jpa + 2.7.2 + + + + org.springframework.boot + spring-boot-starter-security + 2.7.2 + + + + org.springframework.security + spring-security-test + 5.7.4 + test + org.springframework.boot spring-boot-starter-web + 2.7.2 com.h2database h2 + 1.4.199 runtime + org.springframework.boot spring-boot-starter-test + 2.7.2 test + + + org.projectlombok + lombok + 1.18.28 + + + + org.springdoc + springdoc-openapi-ui + 1.6.14 + diff --git a/module12/src/main/java/ru/edu/module12/Application.java b/module12/src/main/java/ru/edu/module12/Application.java index 45fd2fdb..a267b7ea 100644 --- a/module12/src/main/java/ru/edu/module12/Application.java +++ b/module12/src/main/java/ru/edu/module12/Application.java @@ -8,6 +8,7 @@ public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); + } } diff --git a/module12/src/main/java/ru/edu/module12/config/OpenApiConfig.java b/module12/src/main/java/ru/edu/module12/config/OpenApiConfig.java new file mode 100644 index 00000000..18a5179a --- /dev/null +++ b/module12/src/main/java/ru/edu/module12/config/OpenApiConfig.java @@ -0,0 +1,22 @@ +package ru.edu.module12.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class OpenApiConfig { + @Bean + public OpenAPI customOpenAPI(@Value("${service.description}") String appDescription, @Value("${service.version}") String appVersion) { + return new OpenAPI() + .info(new Info() + .title("User service API") + .version(appVersion) + .description(appDescription) + .termsOfService("http://swagger.io/terms/") + .license(new License().name("Apache 2.0").url("http://springdoc.org"))); + } +} diff --git a/module12/src/main/java/ru/edu/module12/config/SecurityConfig.java b/module12/src/main/java/ru/edu/module12/config/SecurityConfig.java new file mode 100644 index 00000000..10f6ebc7 --- /dev/null +++ b/module12/src/main/java/ru/edu/module12/config/SecurityConfig.java @@ -0,0 +1,30 @@ +package ru.edu.module12.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.password.NoOpPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +@EnableWebSecurity +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests() + .antMatchers("/api/v1/users/*").permitAll() + //.antMatchers("/api/v1/admin/*").hasAnyRole("ADMIN") + .anyRequest().authenticated() + .and() + .formLogin(); + + } + @Bean + public PasswordEncoder passwordEncoder() { + return NoOpPasswordEncoder.getInstance(); + } + +} diff --git a/module12/src/main/java/ru/edu/module12/controller/AdminController.java b/module12/src/main/java/ru/edu/module12/controller/AdminController.java new file mode 100644 index 00000000..91581846 --- /dev/null +++ b/module12/src/main/java/ru/edu/module12/controller/AdminController.java @@ -0,0 +1,54 @@ +package ru.edu.module12.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import ru.edu.module12.entity.User; +import ru.edu.module12.service.UserService; + +import java.util.List; + +// http://localhost:8080/swagger-ui/index.html#/ +@RestController +@RequestMapping(value = "api/v1/admin/", produces = MediaType.APPLICATION_JSON_VALUE) +@RequiredArgsConstructor +@Tag(name = "User", description = "User API") +public class AdminController { + + private static final Logger logger = LoggerFactory.getLogger(AdminController.class); + private final UserService service; + + + @PostMapping + @Operation(summary = "Create a new user") + public ResponseEntity createUser(@RequestBody User user) { + service.save(user); + HttpHeaders headers = new HttpHeaders(); + headers.add("Location", "api/v1/users/" + user.getId()); + return new ResponseEntity<>(null, headers, HttpStatus.CREATED); + + } + + @PutMapping + @Operation(summary = "Update a user") + public ResponseEntity updateUser(@RequestBody User user) { + service.update(user); + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/{userId}") + @Operation(summary = "Delete a user by id") + public ResponseEntity deleteById(@PathVariable long userId) { + service.deleteById(userId); + return ResponseEntity.ok().build(); + } + + +} diff --git a/module12/src/main/java/ru/edu/module12/controller/ErrorHandler.java b/module12/src/main/java/ru/edu/module12/controller/ErrorHandler.java new file mode 100644 index 00000000..d9658eea --- /dev/null +++ b/module12/src/main/java/ru/edu/module12/controller/ErrorHandler.java @@ -0,0 +1,27 @@ +package ru.edu.module12.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import ru.edu.module12.exception.ItemNotFoundException; +import ru.edu.module12.exception.ServiceError; + +import java.util.Date; + +@ControllerAdvice +public class ErrorHandler { + + @ExceptionHandler(ItemNotFoundException.class) + public ResponseEntity handleError(ItemNotFoundException ex) { + ServiceError serviceError = new ServiceError(); + serviceError.setStatus(HttpStatus.NOT_FOUND.value()); + serviceError.setTimeStamp(new Date().getTime()); + serviceError.setDetails(ex.getMessage()); + + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .contentType(MediaType.APPLICATION_JSON) + .body(serviceError); + } +} diff --git a/module12/src/main/java/ru/edu/module12/controller/UserController.java b/module12/src/main/java/ru/edu/module12/controller/UserController.java new file mode 100644 index 00000000..217e49d4 --- /dev/null +++ b/module12/src/main/java/ru/edu/module12/controller/UserController.java @@ -0,0 +1,43 @@ +package ru.edu.module12.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import ru.edu.module12.entity.User; +import ru.edu.module12.service.UserService; + +import java.util.List; + +// http://localhost:8080/swagger-ui/index.html#/ +@RestController +@RequestMapping(value = "api/v1/users/", produces = MediaType.APPLICATION_JSON_VALUE) +@RequiredArgsConstructor +@Tag(name = "User", description = "User API") +public class UserController { + + private static final Logger logger = LoggerFactory.getLogger(UserController.class); + private final UserService service; + + @GetMapping + @Operation(summary = "Get all users") + public ResponseEntity> findAll() { + List users = service.findAll(); + logger.info("getting user list {}", users); + return new ResponseEntity<>(users, HttpStatus.OK); + } + + @GetMapping("/{id}") + @Operation(summary = "Get user details") + public User getUserById(@PathVariable("id") long userId) { + return service.findById(userId); + } + + +} diff --git a/module12/src/main/java/ru/edu/module12/entity/User.java b/module12/src/main/java/ru/edu/module12/entity/User.java index 15345bc8..65172238 100644 --- a/module12/src/main/java/ru/edu/module12/entity/User.java +++ b/module12/src/main/java/ru/edu/module12/entity/User.java @@ -1,7 +1,24 @@ package ru.edu.module12.entity; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Entity +@Table(name = "users") +@Data +@NoArgsConstructor public class User { + public User(Long id, String name, Integer age) { + this.id = id; + this.name = name; + this.age = age; + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private Integer age; diff --git a/module12/src/main/java/ru/edu/module12/exception/ItemNotFoundException.java b/module12/src/main/java/ru/edu/module12/exception/ItemNotFoundException.java new file mode 100644 index 00000000..404c085d --- /dev/null +++ b/module12/src/main/java/ru/edu/module12/exception/ItemNotFoundException.java @@ -0,0 +1,15 @@ +package ru.edu.module12.exception; + +public class ItemNotFoundException extends RuntimeException{ + + public ItemNotFoundException() { + } + + public ItemNotFoundException(String message) { + super(message); + } + + public ItemNotFoundException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/module12/src/main/java/ru/edu/module12/exception/ServiceError.java b/module12/src/main/java/ru/edu/module12/exception/ServiceError.java new file mode 100644 index 00000000..34ff3b13 --- /dev/null +++ b/module12/src/main/java/ru/edu/module12/exception/ServiceError.java @@ -0,0 +1,11 @@ +package ru.edu.module12.exception; + +import lombok.Data; + +@Data +public class ServiceError { + + private int status; + private String details; + private long timeStamp; +} diff --git a/module12/src/main/java/ru/edu/module12/repository/UserRepository.java b/module12/src/main/java/ru/edu/module12/repository/UserRepository.java new file mode 100644 index 00000000..129b4280 --- /dev/null +++ b/module12/src/main/java/ru/edu/module12/repository/UserRepository.java @@ -0,0 +1,11 @@ +package ru.edu.module12.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.edu.module12.entity.User; + +import java.util.List; + +@Repository +public interface UserRepository extends JpaRepository { +} diff --git a/module12/src/main/java/ru/edu/module12/service/UserCache.java b/module12/src/main/java/ru/edu/module12/service/UserCache.java new file mode 100644 index 00000000..f67d5654 --- /dev/null +++ b/module12/src/main/java/ru/edu/module12/service/UserCache.java @@ -0,0 +1,26 @@ +package ru.edu.module12.service; + +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.Map; + +@Component +public class UserCache { + + private Map cache = new HashMap<>(); + + public UserInfo get(String id) { + return cache.get(id); + } + private void create(UserInfo info) { + cache.put(info.getLogin(), info); + } + + @PostConstruct + public void init() { + create(new UserInfo("admin", "123456", "Dmitry Ivanov", "ADMIN")); + create(new UserInfo("denis", "denis", "Denis Petrov", "MANAGER")); + } +} diff --git a/module12/src/main/java/ru/edu/module12/service/UserDetailedService.java b/module12/src/main/java/ru/edu/module12/service/UserDetailedService.java new file mode 100644 index 00000000..271e48a9 --- /dev/null +++ b/module12/src/main/java/ru/edu/module12/service/UserDetailedService.java @@ -0,0 +1,35 @@ +package ru.edu.module12.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collection; + +@Component +public class UserDetailedService implements UserDetailsService { + + private UserCache userCache; + + @Autowired + public UserDetailedService(UserCache userCache) { + this.userCache = userCache; + } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + UserInfo info = userCache.get(username); + if (info == null) { + throw new UsernameNotFoundException("User id= " + username + " not found"); + } + Collection authorities = new ArrayList<>(); + authorities.add(new SimpleGrantedAuthority("ROLE_" + info.getRole())); + return new User(info.getLogin(), info.getPassword(), authorities); + } +} diff --git a/module12/src/main/java/ru/edu/module12/service/UserInfo.java b/module12/src/main/java/ru/edu/module12/service/UserInfo.java new file mode 100644 index 00000000..e0e040b7 --- /dev/null +++ b/module12/src/main/java/ru/edu/module12/service/UserInfo.java @@ -0,0 +1,52 @@ +package ru.edu.module12.service; + +public class UserInfo { + + private String login; + private String password; + private String name; + private String role; + + + public UserInfo() { + } + + public UserInfo(String login, String password, String name, String role) { + this.login = login; + this.password = password; + this.name = name; + this.role = role; + } + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } +} diff --git a/module12/src/main/java/ru/edu/module12/service/UserService.java b/module12/src/main/java/ru/edu/module12/service/UserService.java new file mode 100644 index 00000000..bae8b40e --- /dev/null +++ b/module12/src/main/java/ru/edu/module12/service/UserService.java @@ -0,0 +1,38 @@ +package ru.edu.module12.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.edu.module12.entity.User; +import ru.edu.module12.exception.ItemNotFoundException; +import ru.edu.module12.repository.UserRepository; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class UserService { + + private final UserRepository repository; + + public List findAll() { + return repository.findAll(); + } + + public User findById(Long id) { + return repository.findById(id).orElseThrow(() -> new ItemNotFoundException("User not found, id = " + id)); + } + + public User save(User user) { + return repository.save(user); + } + + public User update(User user) { + findById(user.getId()); + return repository.save(user); + } + + public void deleteById(Long id) { + findById(id); + repository.deleteById(id); + } +} diff --git a/module12/src/main/resources/application-h2.yml b/module12/src/main/resources/application-h2.yml new file mode 100644 index 00000000..55646e3e --- /dev/null +++ b/module12/src/main/resources/application-h2.yml @@ -0,0 +1,9 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:file:./app.db;AUTO_SERVER=TRUE + username: sa + password: 123456 + h2: + console: + enabled: true \ No newline at end of file diff --git a/module12/src/main/resources/application.yml b/module12/src/main/resources/application.yml new file mode 100644 index 00000000..6aea78f5 --- /dev/null +++ b/module12/src/main/resources/application.yml @@ -0,0 +1,25 @@ +spring: + profiles: + active: h2 + jpa: + hibernate: + ddl-auto: create-drop + defer-datasource-initialization: true + show-sql: true + properties: + hibernate: + format_sql: true + sql: + init: + mode: always + +server: + port: 8080 + +logging: + level: + ru.edu.module12: info + +service: + description: User service + version: 1.0 BETA \ No newline at end of file diff --git a/module12/src/main/resources/data.sql b/module12/src/main/resources/data.sql new file mode 100644 index 00000000..f875d646 --- /dev/null +++ b/module12/src/main/resources/data.sql @@ -0,0 +1,3 @@ +INSERT INTO users(name, age) +VALUES('Igor', 32), +('Ivan', 33); diff --git a/module12/src/test/java/ru/edu/module12/controller/UserControllerTest.java b/module12/src/test/java/ru/edu/module12/controller/UserControllerTest.java new file mode 100644 index 00000000..b90d8cd4 --- /dev/null +++ b/module12/src/test/java/ru/edu/module12/controller/UserControllerTest.java @@ -0,0 +1,129 @@ +package ru.edu.module12.controller; + + import com.fasterxml.jackson.databind.ObjectMapper; + import lombok.SneakyThrows; + import org.hamcrest.Matchers; + import org.junit.jupiter.api.AfterEach; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.DisplayName; + import org.junit.jupiter.api.Test; + import org.mockito.InjectMocks; + import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; + import org.springframework.boot.test.mock.mockito.MockBean; + import org.springframework.http.MediaType; + import org.springframework.security.test.context.support.WithMockUser; + import org.springframework.test.web.servlet.MockMvc; + import ru.edu.module12.entity.User; + import ru.edu.module12.service.UserService; + + import java.util.ArrayList; + import java.util.Arrays; + import java.util.List; + + import static org.mockito.Mockito.*; + import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; + import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; + import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; + import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; + import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +@WebMvcTest({UserController.class}) +class UserControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private UserService service; + + @InjectMocks + ObjectMapper mapper; + + @BeforeEach + void setUp() { + } + + @AfterEach + void tearDown() { + } + + @Test + @DisplayName("check receiving all users") + void getAllUsers() throws Exception { + List users = new ArrayList<>(Arrays.asList( + new User(1L, "Anton", 30), + new User(2L, "Nikita", 38) + )); + + when(service.findAll()).thenReturn(users); + + mockMvc.perform(get("/api/v1/users/")) + .andDo(print()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.*", Matchers.hasSize(2))); + } + + @Test + @DisplayName("check receiving single user details") + void getUserById() throws Exception { + User user = new User(1L, "Anton", 30); + + when(service.findById(anyLong())).thenReturn(user); + + mockMvc.perform(get("/api/v1/users/1")) + .andDo(print()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.*", Matchers.hasSize(3))) + .andExpect(jsonPath("$.name").value("Anton")) + .andExpect(status().isOk()); + } + + @SneakyThrows + @Test + @DisplayName("check adding a new user") + void createUser() throws Exception { + User user = new User(1L, "Anton", 30); + + when(service.save(any(User.class))).thenReturn(user); + + mockMvc.perform(post("/api/v1/admin/") + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(user)) + ) + .andDo(print()) + //.andExpect(header().string("Location", "api/v1/admin/" + user.getId())) + .andExpect(jsonPath("$").doesNotExist()) + .andExpect(status().is4xxClientError()); + } + + @Test + @DisplayName("check updating a user") + void updateUser() throws Exception { + User user = new User(1L, "Anton", 30); + + when(service.update(any(User.class))).thenReturn(user); + + mockMvc.perform(put("/api/v1/admin/") + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(user)) + ) + .andDo(print()) + .andExpect(jsonPath("$").doesNotExist()) + .andExpect(status().is4xxClientError()); + } + + @Test + @DisplayName("check deleting a user by id") + @WithMockUser(username = "admin", roles = "ADMIN") + void deleteUserById() throws Exception { + + doNothing().when(service).deleteById(anyLong()); + + mockMvc.perform(delete("/api/v1/admin/1")) + .andDo(print()) + .andExpect(jsonPath("$").doesNotExist()) + .andExpect(status().isOk()); + } +} diff --git a/module12/src/test/java/ru/edu/module12/service/UserServiceTest.java b/module12/src/test/java/ru/edu/module12/service/UserServiceTest.java new file mode 100644 index 00000000..3881e9ff --- /dev/null +++ b/module12/src/test/java/ru/edu/module12/service/UserServiceTest.java @@ -0,0 +1,98 @@ +package ru.edu.module12.service; + +import org.junit.jupiter.api.AfterEach; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.Mock; + import org.mockito.junit.jupiter.MockitoExtension; + import ru.edu.module12.entity.User; + import ru.edu.module12.exception.ItemNotFoundException; + import ru.edu.module12.repository.UserRepository; + +import java.util.ArrayList; + import java.util.Arrays; + import java.util.List; + import java.util.Optional; + + import static org.assertj.core.api.Assertions.assertThat; + import static org.junit.jupiter.api.Assertions.*; + + import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class UserServiceTest { + + @Mock + private UserRepository repository; + + private UserService service; + + @BeforeEach + void setUp() { + service = new UserService(repository); + } + + @AfterEach + void tearDown() { + } + + @Test + void findAll() { + List cars = new ArrayList<>(Arrays.asList( + new User(1L, "Anton", 25), + new User(2L, "Dmitry", 35) + )); + + when(repository.findAll()).thenReturn(cars); + + List allUsers = service.findAll(); + assertThat(allUsers.size()).isGreaterThan(0); + } + + @Test + void findById() { + User user = new User(1L, "Anton", 25); + + when(repository.findById(anyLong())).thenReturn(Optional.of(user)); + + User singleUser = service.findById(1L); + assertThat(singleUser).isNotNull().isEqualTo(user); + } + + @Test + void save() { + User user = new User(1L, "Anton", 25); + + when(repository.save(user)).thenReturn(user); + User savedCar = service.save(user); + assertThat(savedCar.getName()).isNotNull(); + } + + @Test + void update() { + User user = new User(1L, "Anton", 25); + + when(repository.save(user)).thenReturn(user); + + User savedCar = service.save(user); + assertThat(savedCar.getName()).isNotNull(); + } + + @Test + void deleteById() { + User user = new User(1L, "Anton", 25); + + when(repository.findById(anyLong())).thenReturn(Optional.of(user)); + doNothing().when(repository).deleteById(anyLong()); + + service.deleteById(1L); + verify(repository, times(1)).deleteById(anyLong()); + } + + @Test + void itemNotFoundException() { + ItemNotFoundException exception = assertThrows(ItemNotFoundException.class, () -> service.deleteById(1L)); + assertEquals("User not found, id = 1", exception.getMessage()); + } +} diff --git a/module13/devops/Dockerfile b/module13/devops/Dockerfile new file mode 100644 index 00000000..183c4d8e --- /dev/null +++ b/module13/devops/Dockerfile @@ -0,0 +1,4 @@ +FROM openjdk:17-jdk-slim +WORKDIR /app +COPY module13-1.0-SNAPSHOT.jar /app +ENTRYPOINT ["java", "-jar", "/app/module13-1.0-SNAPSHOT.jar"] \ No newline at end of file diff --git a/module13/devops/docker-compose.yml b/module13/devops/docker-compose.yml new file mode 100644 index 00000000..4322e454 --- /dev/null +++ b/module13/devops/docker-compose.yml @@ -0,0 +1,17 @@ +services: + db: + image: postgres:13.2-alpine + volumes: + - E:/8.IDEA_project/JavaRebootModule12BD:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + ports: + - 8089:5432 + User-service: + image: my_user_app_image + environment: + SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/postgres + ports: + - 8080:8080 + depends_on: + - db \ No newline at end of file diff --git a/module13/devops/module13-1.0-SNAPSHOT.jar b/module13/devops/module13-1.0-SNAPSHOT.jar new file mode 100644 index 00000000..d507baed Binary files /dev/null and b/module13/devops/module13-1.0-SNAPSHOT.jar differ diff --git a/module13/pom.xml b/module13/pom.xml index 03e95137..f0c62c94 100644 --- a/module13/pom.xml +++ b/module13/pom.xml @@ -5,6 +5,7 @@ ru.sberbank.edu 1.0-SNAPSHOT + 4.0.0 module13 @@ -14,6 +15,74 @@ UTF-8 + 17 + + + + org.springframework.boot + spring-boot-starter-data-jpa + 2.7.2 + + + + org.springframework.boot + spring-boot-starter-security + 2.7.2 + + + + org.springframework.security + spring-security-test + 5.7.4 + test + + + + org.springframework.boot + spring-boot-starter-web + 2.7.2 + + + + org.springframework.boot + spring-boot-starter-test + 2.7.2 + test + + + + org.postgresql + postgresql + 42.7.1 + runtime + + + org.projectlombok + lombok + 1.18.28 + compile + + + + org.springdoc + springdoc-openapi-ui + 1.7.0 + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/module13/src/main/java/ru/sberbank/edu/App.java b/module13/src/main/java/ru/sberbank/edu/App.java index 5419c026..4e985b8e 100644 --- a/module13/src/main/java/ru/sberbank/edu/App.java +++ b/module13/src/main/java/ru/sberbank/edu/App.java @@ -1,13 +1,19 @@ package ru.sberbank.edu; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; + /** * Hello world! * */ -public class App -{ + +@SpringBootApplication +public class App { public static void main( String[] args ) { - System.out.println( "Hello World!" ); + + SpringApplication.run(App.class, args); } } diff --git a/module13/src/main/java/ru/sberbank/edu/config/OpenApiConfig.java b/module13/src/main/java/ru/sberbank/edu/config/OpenApiConfig.java new file mode 100644 index 00000000..8d0e3bc0 --- /dev/null +++ b/module13/src/main/java/ru/sberbank/edu/config/OpenApiConfig.java @@ -0,0 +1,22 @@ +package ru.sberbank.edu.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class OpenApiConfig { + @Bean + public OpenAPI customOpenAPI(@Value("${service.description}") String appDescription, @Value("${service.version}") String appVersion) { + return new OpenAPI() + .info(new Info() + .title("User service API") + .version(appVersion) + .description(appDescription) + .termsOfService("http://swagger.io/terms/") + .license(new License().name("Apache 2.0").url("http://springdoc.org"))); + } +} diff --git a/module13/src/main/java/ru/sberbank/edu/config/SecurityConfig.java b/module13/src/main/java/ru/sberbank/edu/config/SecurityConfig.java new file mode 100644 index 00000000..7e97c310 --- /dev/null +++ b/module13/src/main/java/ru/sberbank/edu/config/SecurityConfig.java @@ -0,0 +1,30 @@ +package ru.sberbank.edu.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.password.NoOpPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +@EnableWebSecurity +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests() + .antMatchers("/api/v1/users/*").permitAll() + //.antMatchers("/api/v1/admin/*").hasAnyRole("ADMIN") + .anyRequest().authenticated() + .and() + .formLogin(); + + } + @Bean + public PasswordEncoder passwordEncoder() { + return NoOpPasswordEncoder.getInstance(); + } + +} diff --git a/module13/src/main/java/ru/sberbank/edu/controller/AdminController.java b/module13/src/main/java/ru/sberbank/edu/controller/AdminController.java new file mode 100644 index 00000000..bf1304b4 --- /dev/null +++ b/module13/src/main/java/ru/sberbank/edu/controller/AdminController.java @@ -0,0 +1,55 @@ +package ru.sberbank.edu.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import ru.sberbank.edu.entity.User; +import ru.sberbank.edu.service.UserService; + + +import java.util.List; + +// http://localhost:8080/swagger-ui/index.html#/ +@RestController +@RequestMapping(value = "api/v1/admin/", produces = MediaType.APPLICATION_JSON_VALUE) +@RequiredArgsConstructor +@Tag(name = "User", description = "User API") +public class AdminController { + + private static final Logger logger = LoggerFactory.getLogger(AdminController.class); + private final UserService service; + + + @PostMapping + @Operation(summary = "Create a new user") + public ResponseEntity createUser(@RequestBody User user) { + service.save(user); + HttpHeaders headers = new HttpHeaders(); + headers.add("Location", "api/v1/users/" + user.getId()); + return new ResponseEntity<>(null, headers, HttpStatus.CREATED); + + } + + @PutMapping + @Operation(summary = "Update a user") + public ResponseEntity updateUser(@RequestBody User user) { + service.update(user); + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/{userId}") + @Operation(summary = "Delete a user by id") + public ResponseEntity deleteById(@PathVariable long userId) { + service.deleteById(userId); + return ResponseEntity.ok().build(); + } + + +} diff --git a/module13/src/main/java/ru/sberbank/edu/controller/ErrorHandler.java b/module13/src/main/java/ru/sberbank/edu/controller/ErrorHandler.java new file mode 100644 index 00000000..7e61c97b --- /dev/null +++ b/module13/src/main/java/ru/sberbank/edu/controller/ErrorHandler.java @@ -0,0 +1,27 @@ +package ru.sberbank.edu.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import ru.sberbank.edu.exception.ItemNotFoundException; +import ru.sberbank.edu.exception.ServiceError; + +import java.util.Date; + +@ControllerAdvice +public class ErrorHandler { + + @ExceptionHandler(ItemNotFoundException.class) + public ResponseEntity handleError(ItemNotFoundException ex) { + ServiceError serviceError = new ServiceError(); + serviceError.setStatus(HttpStatus.NOT_FOUND.value()); + serviceError.setTimeStamp(new Date().getTime()); + serviceError.setDetails(ex.getMessage()); + + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .contentType(MediaType.APPLICATION_JSON) + .body(serviceError); + } +} diff --git a/module13/src/main/java/ru/sberbank/edu/controller/UserController.java b/module13/src/main/java/ru/sberbank/edu/controller/UserController.java new file mode 100644 index 00000000..0dfa9930 --- /dev/null +++ b/module13/src/main/java/ru/sberbank/edu/controller/UserController.java @@ -0,0 +1,42 @@ +package ru.sberbank.edu.controller; + +import ru.sberbank.edu.entity.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ru.sberbank.edu.service.UserService; + +import java.util.List; + +@RestController +@RequestMapping(value="api/v1/users/", produces = MediaType.APPLICATION_JSON_VALUE) +@RequiredArgsConstructor +@Tag(name = "user", description = "User API") +public class UserController { + + private static final Logger logger = LoggerFactory.getLogger(UserController.class); + private final UserService service; + + @GetMapping + @Operation(summary = "Get all users") + public ResponseEntity> findAll() { + List users = service.findAll(); + return new ResponseEntity<>(users, HttpStatus.OK); + } + + @GetMapping("/{id}") + @Operation(summary = "Get user details") + public User getUserById(@PathVariable("id") long userId) { + return service.findById(userId); + } + +} diff --git a/module13/src/main/java/ru/sberbank/edu/entity/User.java b/module13/src/main/java/ru/sberbank/edu/entity/User.java new file mode 100644 index 00000000..d9262fd8 --- /dev/null +++ b/module13/src/main/java/ru/sberbank/edu/entity/User.java @@ -0,0 +1,25 @@ +package ru.sberbank.edu.entity; + +import javax.persistence.*; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Entity +@Table(name = "users") +@Data +@NoArgsConstructor +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + private Integer age; + + public User(Long id, String name, Integer age) { + this.id = id; + this.name = name; + this.age = age; + } +} diff --git a/module13/src/main/java/ru/sberbank/edu/exception/ItemNotFoundException.java b/module13/src/main/java/ru/sberbank/edu/exception/ItemNotFoundException.java new file mode 100644 index 00000000..b7a3658b --- /dev/null +++ b/module13/src/main/java/ru/sberbank/edu/exception/ItemNotFoundException.java @@ -0,0 +1,15 @@ +package ru.sberbank.edu.exception; + +public class ItemNotFoundException extends RuntimeException{ + + public ItemNotFoundException() { + } + + public ItemNotFoundException(String message) { + super(message); + } + + public ItemNotFoundException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/module13/src/main/java/ru/sberbank/edu/exception/ServiceError.java b/module13/src/main/java/ru/sberbank/edu/exception/ServiceError.java new file mode 100644 index 00000000..57f77408 --- /dev/null +++ b/module13/src/main/java/ru/sberbank/edu/exception/ServiceError.java @@ -0,0 +1,11 @@ +package ru.sberbank.edu.exception; + +import lombok.Data; + +@Data +public class ServiceError { + + private int status; + private String details; + private long timeStamp; +} diff --git a/module13/src/main/java/ru/sberbank/edu/repository/UserRepository.java b/module13/src/main/java/ru/sberbank/edu/repository/UserRepository.java new file mode 100644 index 00000000..6a4fa19f --- /dev/null +++ b/module13/src/main/java/ru/sberbank/edu/repository/UserRepository.java @@ -0,0 +1,9 @@ +package ru.sberbank.edu.repository; + +import ru.sberbank.edu.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends JpaRepository { +} diff --git a/module13/src/main/java/ru/sberbank/edu/service/UserCache.java b/module13/src/main/java/ru/sberbank/edu/service/UserCache.java new file mode 100644 index 00000000..7b4aa60a --- /dev/null +++ b/module13/src/main/java/ru/sberbank/edu/service/UserCache.java @@ -0,0 +1,26 @@ +package ru.sberbank.edu.service; + +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.Map; + +@Component +public class UserCache { + + private Map cache = new HashMap<>(); + + public UserInfo get(String id) { + return cache.get(id); + } + private void create(UserInfo info) { + cache.put(info.getLogin(), info); + } + + @PostConstruct + public void init() { + create(new UserInfo("admin", "123456", "Dmitry Ivanov", "ADMIN")); + create(new UserInfo("denis", "denis", "Denis Petrov", "MANAGER")); + } +} diff --git a/module13/src/main/java/ru/sberbank/edu/service/UserDetailedService.java b/module13/src/main/java/ru/sberbank/edu/service/UserDetailedService.java new file mode 100644 index 00000000..983e1c5d --- /dev/null +++ b/module13/src/main/java/ru/sberbank/edu/service/UserDetailedService.java @@ -0,0 +1,35 @@ +package ru.sberbank.edu.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collection; + +@Component +public class UserDetailedService implements UserDetailsService { + + private UserCache userCache; + + @Autowired + public UserDetailedService(UserCache userCache) { + this.userCache = userCache; + } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + UserInfo info = userCache.get(username); + if (info == null) { + throw new UsernameNotFoundException("User id= " + username + " not found"); + } + Collection authorities = new ArrayList<>(); + authorities.add(new SimpleGrantedAuthority("ROLE_" + info.getRole())); + return new User(info.getLogin(), info.getPassword(), authorities); + } +} diff --git a/module13/src/main/java/ru/sberbank/edu/service/UserInfo.java b/module13/src/main/java/ru/sberbank/edu/service/UserInfo.java new file mode 100644 index 00000000..b0cd1cd7 --- /dev/null +++ b/module13/src/main/java/ru/sberbank/edu/service/UserInfo.java @@ -0,0 +1,52 @@ +package ru.sberbank.edu.service; + +public class UserInfo { + + private String login; + private String password; + private String name; + private String role; + + + public UserInfo() { + } + + public UserInfo(String login, String password, String name, String role) { + this.login = login; + this.password = password; + this.name = name; + this.role = role; + } + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } +} diff --git a/module13/src/main/java/ru/sberbank/edu/service/UserService.java b/module13/src/main/java/ru/sberbank/edu/service/UserService.java new file mode 100644 index 00000000..f3563d75 --- /dev/null +++ b/module13/src/main/java/ru/sberbank/edu/service/UserService.java @@ -0,0 +1,40 @@ +package ru.sberbank.edu.service; + +import ru.sberbank.edu.entity.User; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.sberbank.edu.exception.ItemNotFoundException; +import ru.sberbank.edu.repository.UserRepository; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class UserService { + + private final UserRepository repository; + + public List findAll() { + return repository.findAll(); + } + + public User findById(Long id) { + return repository.findById(id).orElseThrow(() -> new ItemNotFoundException("User not found, id = " + id)); + } + + public User save(User user) { + return repository.save(user); + } + + public User update(User user) { + findById(user.getId()); + return repository.save(user); + } + + public void deleteById(Long id) { + findById(id); + repository.deleteById(id); + } + + +} diff --git a/module13/src/main/resources/application.yml b/module13/src/main/resources/application.yml new file mode 100644 index 00000000..2b8440d9 --- /dev/null +++ b/module13/src/main/resources/application.yml @@ -0,0 +1,9 @@ +spring: + datasource: + url: jdbc:postgresql://localhost:8089/postgres + username: postgres + password: password + +service: + description: User service + version: 1.0 BETA \ No newline at end of file diff --git a/module13/src/main/resources/data.sql b/module13/src/main/resources/data.sql new file mode 100644 index 00000000..4b84f1a0 --- /dev/null +++ b/module13/src/main/resources/data.sql @@ -0,0 +1,3 @@ +INSERT INTO users(name, age) +VALUES('Igor', 32), + ('Ivan', 33); \ No newline at end of file diff --git a/module13/src/test/java/ru/sberbank/edu/AppTest.java b/module13/src/test/java/ru/sberbank/edu/AppTest.java deleted file mode 100644 index 895d735c..00000000 --- a/module13/src/test/java/ru/sberbank/edu/AppTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package ru.sberbank.edu; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Unit test for simple App. - */ -public class AppTest - extends TestCase -{ - /** - * Create the test case - * - * @param testName name of the test case - */ - public AppTest( String testName ) - { - super( testName ); - } - - /** - * @return the suite of tests being tested - */ - public static Test suite() - { - return new TestSuite( AppTest.class ); - } - - /** - * Rigourous Test :-) - */ - public void testApp() - { - assertTrue( true ); - } -} diff --git a/module13/src/test/java/ru/sberbank/edu/controller/UserControllerTest.java b/module13/src/test/java/ru/sberbank/edu/controller/UserControllerTest.java new file mode 100644 index 00000000..675c0e74 --- /dev/null +++ b/module13/src/test/java/ru/sberbank/edu/controller/UserControllerTest.java @@ -0,0 +1,129 @@ +package ru.sberbank.edu.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; +import ru.sberbank.edu.entity.User; +import ru.sberbank.edu.service.UserService; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +@WebMvcTest({UserController.class}) +class UserControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private UserService service; + + @InjectMocks + ObjectMapper mapper; + + @BeforeEach + void setUp() { + } + + @AfterEach + void tearDown() { + } + + @Test + @DisplayName("check receiving all users") + void getAllUsers() throws Exception { + List users = new ArrayList<>(Arrays.asList( + new User(1L, "Anton", 30), + new User(2L, "Nikita", 38) + )); + + when(service.findAll()).thenReturn(users); + + mockMvc.perform(get("/api/v1/users/")) + .andDo(print()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.*", Matchers.hasSize(2))); + } + + @Test + @DisplayName("check receiving single user details") + void getUserById() throws Exception { + User user = new User(1L, "Anton", 30); + + when(service.findById(anyLong())).thenReturn(user); + + mockMvc.perform(get("/api/v1/users/1")) + .andDo(print()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.*", Matchers.hasSize(3))) + .andExpect(jsonPath("$.name").value("Anton")) + .andExpect(status().isOk()); + } + + @SneakyThrows + @Test + @DisplayName("check adding a new user") + void createUser() throws Exception { + User user = new User(1L, "Anton", 30); + + when(service.save(any(User.class))).thenReturn(user); + + mockMvc.perform(post("/api/v1/admin/") + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(user)) + ) + .andDo(print()) + //.andExpect(header().string("Location", "api/v1/admin/" + user.getId())) + .andExpect(jsonPath("$").doesNotExist()) + .andExpect(status().is4xxClientError()); + } + + @Test + @DisplayName("check updating a user") + void updateUser() throws Exception { + User user = new User(1L, "Anton", 30); + + when(service.update(any(User.class))).thenReturn(user); + + mockMvc.perform(put("/api/v1/admin/") + .contentType(MediaType.APPLICATION_JSON) + .content(mapper.writeValueAsString(user)) + ) + .andDo(print()) + .andExpect(jsonPath("$").doesNotExist()) + .andExpect(status().is4xxClientError()); + } + + @Test + @DisplayName("check deleting a user by id") + @WithMockUser(username = "admin", roles = "ADMIN") + void deleteUserById() throws Exception { + + doNothing().when(service).deleteById(anyLong()); + + mockMvc.perform(delete("/api/v1/admin/1")) + .andDo(print()) + .andExpect(jsonPath("$").doesNotExist()) + .andExpect(status().is4xxClientError()); + } +} diff --git a/module13/src/test/java/ru/sberbank/edu/service/UserServiceTest.java b/module13/src/test/java/ru/sberbank/edu/service/UserServiceTest.java new file mode 100644 index 00000000..55c9e832 --- /dev/null +++ b/module13/src/test/java/ru/sberbank/edu/service/UserServiceTest.java @@ -0,0 +1,98 @@ +package ru.sberbank.edu.service; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import ru.sberbank.edu.entity.User; +import ru.sberbank.edu.exception.ItemNotFoundException; +import ru.sberbank.edu.repository.UserRepository; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class UserServiceTest { + + @Mock + private UserRepository repository; + + private UserService service; + + @BeforeEach + void setUp() { + service = new UserService(repository); + } + + @AfterEach + void tearDown() { + } + + @Test + void findAll() { + List cars = new ArrayList<>(Arrays.asList( + new User(1L, "Anton", 25), + new User(2L, "Dmitry", 35) + )); + + when(repository.findAll()).thenReturn(cars); + + List allUsers = service.findAll(); + assertThat(allUsers.size()).isGreaterThan(0); + } + + @Test + void findById() { + User user = new User(1L, "Anton", 25); + + when(repository.findById(anyLong())).thenReturn(Optional.of(user)); + + User singleUser = service.findById(1L); + assertThat(singleUser).isNotNull().isEqualTo(user); + } + + @Test + void save() { + User user = new User(1L, "Anton", 25); + + when(repository.save(user)).thenReturn(user); + User savedCar = service.save(user); + assertThat(savedCar.getName()).isNotNull(); + } + + @Test + void update() { + User user = new User(1L, "Anton", 25); + + when(repository.save(user)).thenReturn(user); + + User savedCar = service.save(user); + assertThat(savedCar.getName()).isNotNull(); + } + + @Test + void deleteById() { + User user = new User(1L, "Anton", 25); + + when(repository.findById(anyLong())).thenReturn(Optional.of(user)); + doNothing().when(repository).deleteById(anyLong()); + + service.deleteById(1L); + verify(repository, times(1)).deleteById(anyLong()); + } + + @Test + void itemNotFoundException() { + ItemNotFoundException exception = assertThrows(ItemNotFoundException.class, () -> service.deleteById(1L)); + assertEquals("User not found, id = 1", exception.getMessage()); + } +} diff --git a/pom.xml b/pom.xml index f978a54f..24b21c6a 100644 --- a/pom.xml +++ b/pom.xml @@ -22,24 +22,34 @@ pom + + org.springframework.boot + spring-boot-starter-parent + 2.7.2 + + homework-javareboot-2023-group-06 UTF-8 17 17 - 5.9.2 + 5.7.2 5.5.0 5.3.1 3.24.2 + + com.google.code.gson + gson + 2.8.0 + org.junit.jupiter junit-jupiter-engine ${junit.version} - test org.mockito