diff --git a/README.md b/README.md index 32f74df9..2d8b6b36 100644 --- a/README.md +++ b/README.md @@ -1,82 +1,22 @@ -# Тестовое задание для Java стажеров +Должен быть установлен maven apache. -Привет! +Открываем "Изменение системных переменных среды" на компьютере, внизу нажимаем "Переменные среды", дважды кликаем на Path сверху +и вписываем новый путь к папке bin в папке apache maven, а также новый путь к нашему jdk в папке Java/ -Мы ищем стажера, который в перспективе станет Junior Java-разработчиком в нашей команде. -Чтобы понять, что мы подходим друг другу, предлагаем вам написать простое web-приложение. Такое задание поможет нам понять, что вы: +Запускаем среду разработки IntelliJ IDEA, нажимаем на вкладку File сверху->New->Project from version control->Git. -* можете понимать поставленную задачу; -* умеете находить необходимую техническую информацию для реализации решения; -* просто умеете кодить. +Далее нужно скопировать данную строчку https://github.com/walder86/Storage.git и вставить в поле URL, нажать test и, при успешном выполнении, нажать clone. -На задание у вас уйдет ориентировочно один-два вечера. Главное условие — решение должно быть написано с использованием платформы JVM. Библиотеки и фреймворки можно выбирать на свой вкус. +Перезагружаем копьютер (чтобы установился maven apache). -## Что нужно сделать +Далее снова заходим в IntelliJ IDEA и заходим в терминал в среде и вбиваем в терминал команду: mvn install. -Реализовать приложение для автоматизации учёта носков на складе магазина. Кладовщик должен иметь возможность: +После установки раскрываем справа вкладку Maven Projects, разворачиваем папку Lifecycle и жмём 2 раза на install. -* учесть приход и отпуск носков; -* узнать общее количество носков определенного цвета и состава в данный момент времени. +Если такой вкладки нет, то нажимаем ПКМ на файл pom.xml и выбираем add as maven project и ждём конца сборки. -Внешний интерфейс приложения представлен в виде HTTP API (REST, если хочется). +Должен быть запущен Docker, вбиваем в терминал/командную строку команды: docker run -d -p 3310:3306 vldmrvasiliev/socksbd -## Список URL HTTP-методов +Должен появистся и запуститься контейнер с БД, нужно подождать пока он полностью запустится (ждём надписи ready for connections). -### POST /api/socks/income - -Регистрирует приход носков на склад. - -Параметры запроса передаются в теле запроса в виде JSON-объекта со следующими атрибутами: - -* color — цвет носков, строка (например, black, red, yellow); -* cottonPart — процентное содержание хлопка в составе носков, целое число от 0 до 100 (например, 30, 18, 42); -* quantity — количество пар носков, целое число больше 0. - -Результаты: - -* HTTP 200 — удалось добавить приход; -* HTTP 400 — параметры запроса отсутствуют или имеют некорректный формат; -* HTTP 500 — произошла ошибка, не зависящая от вызывающей стороны (например, база данных недоступна). - -### POST /api/socks/outcome - -Регистрирует отпуск носков со склада. Здесь параметры и результаты аналогичные, но общее количество носков указанного цвета и состава не увеличивается, а уменьшается. - -### GET /api/socks - -Возвращает общее количество носков на складе, соответствующих переданным в параметрах критериям запроса. - -Параметры запроса передаются в URL: - -* color — цвет носков, строка; -* operation — оператор сравнения значения количества хлопка в составе носков, одно значение из: moreThan, lessThan, equal; -* cottonPart — значение процента хлопка в составе носков из сравнения. - -Результаты: - -* HTTP 200 — запрос выполнен, результат в теле ответа в виде строкового представления целого числа; -* HTTP 400 — параметры запроса отсутствуют или имеют некорректный формат; -* HTTP 500 — произошла ошибка, не зависящая от вызывающей стороны (например, база данных недоступна). - -Примеры запросов: - -* /api/socks?color=red&operation=moreThan&cottonPart=90 — должен вернуть общее количество красных носков с долей хлопка более 90%; -* /api/socks?color=black&operation=lessThan?cottonPart=10 — должен вернуть общее количество черных носков с долей хлопка менее 10%. - -Для хранения данных системы можно использовать любую реляционную базу данных. Схему БД желательно хранить в репозитории в любом удобном виде. - -## Как это сделать - -Мы ждем, что решение будет: - -* написано на языке Java; -* standalone - состоять из одного выполняемого компонента верхнего уровня; -* headless - без UI; -* оформлено как форк к репозитарию и создан пул реквест. - -Будет плюсом, если: - -* приложение будет основано на Spring(Boot) Framework; -* для версионирования схемы базы данных будет использоваться Liquibase или Flyway; -* база данных будет подниматься рядом с приложением в докер-контейнере; -* приложение будет развернуто на любом облачном сервисе, например Heroku, и его API будет доступно для вызова. +Можно запускать проект и делать запросы, для этого можно использовать Postman \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..72e3ea89 --- /dev/null +++ b/pom.xml @@ -0,0 +1,101 @@ + + + 4.0.0 + + ru.vasiliev.socks + socks + 1.0-SNAPSHOT + + socks Maven Webapp + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + org.springframework + spring-context + 5.3.11 + + + org.springframework.boot + spring-boot-starter-web + 2.4.5 + + + org.springframework.boot + spring-boot-starter-data-jpa + 2.5.4 + + + org.springframework.boot + spring-boot-starter-validation + 2.5.4 + + + mysql + mysql-connector-java + 8.0.26 + + + ch.qos.logback + logback-classic + 1.2.5 + + + org.projectlombok + lombok-maven-plugin + 1.18.20.0 + provided + + + org.springdoc + springdoc-openapi-ui + 1.5.10 + + + + + socks + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/src/main/java/ru/vasiliev/socks/Error/Exceptions.java b/src/main/java/ru/vasiliev/socks/Error/Exceptions.java new file mode 100644 index 00000000..cd86ccfb --- /dev/null +++ b/src/main/java/ru/vasiliev/socks/Error/Exceptions.java @@ -0,0 +1,29 @@ +package ru.vasiliev.socks.Error; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +@ControllerAdvice +public class Exceptions extends RuntimeException { + + @ExceptionHandler(SocksError.class) + protected ResponseEntity value(){ + return new ResponseEntity<>(new SomeExceptions("Error in the entered parameters", "Invalid value entered"), + HttpStatus.INTERNAL_SERVER_ERROR); + + } + + + @Data + @AllArgsConstructor + private static class SomeExceptions{ + private String Error; + private String message; + } + +} diff --git a/src/main/java/ru/vasiliev/socks/Error/SocksError.java b/src/main/java/ru/vasiliev/socks/Error/SocksError.java new file mode 100644 index 00000000..33f9d59f --- /dev/null +++ b/src/main/java/ru/vasiliev/socks/Error/SocksError.java @@ -0,0 +1,4 @@ +package ru.vasiliev.socks.Error; + +public class SocksError extends RuntimeException { +} diff --git a/src/main/java/ru/vasiliev/socks/controller/SocksController.java b/src/main/java/ru/vasiliev/socks/controller/SocksController.java new file mode 100644 index 00000000..505452ef --- /dev/null +++ b/src/main/java/ru/vasiliev/socks/controller/SocksController.java @@ -0,0 +1,47 @@ +package ru.vasiliev.socks.controller; + + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; +import ru.vasiliev.socks.repository.Socks; +import ru.vasiliev.socks.services.SocksServices; + +import javax.validation.Valid; + +import java.util.List; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +@Slf4j +@RequiredArgsConstructor +@RestController +public class SocksController { + + private final SocksServices socksServices; + + @GetMapping(value = "/socks", produces = APPLICATION_JSON_VALUE) + public List getSocks(@RequestParam("color") String color, + @RequestParam("cottonPath") Integer cottonPath, + @RequestParam("operation") String operation){ + log.info("Get socks"); + return socksServices.getSocks(color,cottonPath,operation); + } + + @PostMapping(value = "/socks/income", produces = APPLICATION_JSON_VALUE) + public Socks income(@Valid @RequestBody Socks socks){ + log.info("Income socks"); + return socksServices.income(socks); + } + + + + @PostMapping(value = "/socks/outcome", produces = APPLICATION_JSON_VALUE) + public void outcome(@Valid @RequestBody Socks socks) { + log.info("Outcome socks"); + socksServices.outcome(socks); + } + + + +} diff --git a/src/main/java/ru/vasiliev/socks/repository/Socks.java b/src/main/java/ru/vasiliev/socks/repository/Socks.java new file mode 100644 index 00000000..c548d3f1 --- /dev/null +++ b/src/main/java/ru/vasiliev/socks/repository/Socks.java @@ -0,0 +1,38 @@ +package ru.vasiliev.socks.repository; + + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.Type; +import org.hibernate.validator.constraints.Range; + +import javax.persistence.*; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Entity +@Table(schema = "socks", name = "socks") +public class Socks { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Integer id; + + @NotNull + private String color; + + @Range(max = 100) + private Integer cottonPath; + + @Min(value = 0) + private Integer quantity; +} diff --git a/src/main/java/ru/vasiliev/socks/repository/SocksRepository.java b/src/main/java/ru/vasiliev/socks/repository/SocksRepository.java new file mode 100644 index 00000000..b00d7b70 --- /dev/null +++ b/src/main/java/ru/vasiliev/socks/repository/SocksRepository.java @@ -0,0 +1,11 @@ +package ru.vasiliev.socks.repository; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface SocksRepository extends CrudRepository { + List findAll(); +} diff --git a/src/main/java/ru/vasiliev/socks/services/SocksServices.java b/src/main/java/ru/vasiliev/socks/services/SocksServices.java new file mode 100644 index 00000000..5c335bb8 --- /dev/null +++ b/src/main/java/ru/vasiliev/socks/services/SocksServices.java @@ -0,0 +1,88 @@ +package ru.vasiliev.socks.services; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; +import ru.vasiliev.socks.Error.SocksError; +import ru.vasiliev.socks.repository.Socks; +import ru.vasiliev.socks.repository.SocksRepository; + +import java.util.ArrayList; +import java.util.List; + + +@Slf4j +@Service +@RequiredArgsConstructor +public class SocksServices { + + private final SocksRepository socksRepository; + + public List getSocks(String color, Integer cottonPath, String operation){ + List socks = new ArrayList<>(); + for (Socks s:socksRepository.findAll()) { + if( color.equals( s.getColor() ) ) { + switch (operation){ + case "moreThan" :{ + if(cottonPaths.getCottonPath()){ + socks.add(s); + } + break; } + case "equal" :{ + if(cottonPath==s.getCottonPath()){ + socks.add(s); + } + break; } + } + } + } + return socks;} + + public Socks income(Socks socks){ + if( check(socks.getColor()) == true){ + throw new SocksError(); + } + for (Socks s:socksRepository.findAll()){ + if( (socks.getColor().equals(s.getColor())) && (socks.getCottonPath().equals(s.getCottonPath())) ){ + s.setQuantity(socks.getQuantity() + s.getQuantity()); + return socksRepository.save(s); + } + } + return socksRepository.save(socks); } + + public void outcome(Socks socks){ + for (Socks s:socksRepository.findAll()){ + if( socks.getColor().equals( s.getColor() ) && socks.getCottonPath().equals( s.getCottonPath() ) ){ + if(s.getQuantity()>socks.getQuantity()) { + s.setQuantity(s.getQuantity() - socks.getQuantity()); + socksRepository.save(s); + } + else if (s.getQuantity()==socks.getQuantity()){ + socksRepository.delete(s); + } + else{ + throw new SocksError(); + } + } + } + throw new SocksError(); + } + + public boolean check(String s){ + try{ + double a = Double.parseDouble(s); + } + catch (NumberFormatException | NullPointerException e){ + return false; + } + return true; + } + +} diff --git a/src/main/java/ru/vasiliev/socks/start.java b/src/main/java/ru/vasiliev/socks/start.java new file mode 100644 index 00000000..ae45c5dd --- /dev/null +++ b/src/main/java/ru/vasiliev/socks/start.java @@ -0,0 +1,11 @@ +package ru.vasiliev.socks; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class start { + public static void main(String[] args) { + SpringApplication.run(start.class); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 00000000..ebcf70b4 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,23 @@ +server: + servlet: + context-path: /api + +spring: + datasource: + driverClassName: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3310/socks + username: root + password: 1234 + jpa: + hibernate: + ddl-auto: update + database-platform: org.hibernate.dialect.MySQL8Dialect + main: + banner-mode: "off" + jackson: + deserialization: + fail-on-unknown-properties: true + +springdoc: + swagger-ui: + path: /swagger-ui-custom.html \ No newline at end of file diff --git a/target/classes/application.yml b/target/classes/application.yml new file mode 100644 index 00000000..ebcf70b4 --- /dev/null +++ b/target/classes/application.yml @@ -0,0 +1,23 @@ +server: + servlet: + context-path: /api + +spring: + datasource: + driverClassName: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3310/socks + username: root + password: 1234 + jpa: + hibernate: + ddl-auto: update + database-platform: org.hibernate.dialect.MySQL8Dialect + main: + banner-mode: "off" + jackson: + deserialization: + fail-on-unknown-properties: true + +springdoc: + swagger-ui: + path: /swagger-ui-custom.html \ No newline at end of file diff --git a/target/classes/ru/vasiliev/socks/Error/Exceptions.class b/target/classes/ru/vasiliev/socks/Error/Exceptions.class new file mode 100644 index 00000000..9e479b3c Binary files /dev/null and b/target/classes/ru/vasiliev/socks/Error/Exceptions.class differ diff --git a/target/classes/ru/vasiliev/socks/Error/SocksError.class b/target/classes/ru/vasiliev/socks/Error/SocksError.class new file mode 100644 index 00000000..07aabf7a Binary files /dev/null and b/target/classes/ru/vasiliev/socks/Error/SocksError.class differ diff --git a/target/classes/ru/vasiliev/socks/controller/SocksController.class b/target/classes/ru/vasiliev/socks/controller/SocksController.class new file mode 100644 index 00000000..f1a5734e Binary files /dev/null and b/target/classes/ru/vasiliev/socks/controller/SocksController.class differ diff --git a/target/classes/ru/vasiliev/socks/repository/Socks.class b/target/classes/ru/vasiliev/socks/repository/Socks.class new file mode 100644 index 00000000..6e6dfd3c Binary files /dev/null and b/target/classes/ru/vasiliev/socks/repository/Socks.class differ diff --git a/target/classes/ru/vasiliev/socks/repository/SocksRepository.class b/target/classes/ru/vasiliev/socks/repository/SocksRepository.class new file mode 100644 index 00000000..063a76bf Binary files /dev/null and b/target/classes/ru/vasiliev/socks/repository/SocksRepository.class differ diff --git a/target/classes/ru/vasiliev/socks/services/SocksServices.class b/target/classes/ru/vasiliev/socks/services/SocksServices.class new file mode 100644 index 00000000..1b4479a1 Binary files /dev/null and b/target/classes/ru/vasiliev/socks/services/SocksServices.class differ diff --git a/target/classes/ru/vasiliev/socks/start.class b/target/classes/ru/vasiliev/socks/start.class new file mode 100644 index 00000000..e7be72dc Binary files /dev/null and b/target/classes/ru/vasiliev/socks/start.class differ diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties new file mode 100644 index 00000000..afbd1f65 --- /dev/null +++ b/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Thu Oct 21 13:44:15 MSK 2021 +version=1.0-SNAPSHOT +groupId=ru.vasiliev.socks +artifactId=socks diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 00000000..b32d6d28 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,3 @@ +ru\vasiliev\socks\Error\Exceptions$SomeExceptions.class +ru\vasiliev\socks\repository\Socks$SocksBuilder.class +ru\vasiliev\socks\repository\Socks.class diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 00000000..8b2049b3 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,7 @@ +C:\cib-interns-test-task\src\main\java\ru\vasiliev\socks\repository\Socks.java +C:\cib-interns-test-task\src\main\java\ru\vasiliev\socks\Error\Exceptions.java +C:\cib-interns-test-task\src\main\java\ru\vasiliev\socks\start.java +C:\cib-interns-test-task\src\main\java\ru\vasiliev\socks\repository\SocksRepository.java +C:\cib-interns-test-task\src\main\java\ru\vasiliev\socks\services\SocksServices.java +C:\cib-interns-test-task\src\main\java\ru\vasiliev\socks\controller\SocksController.java +C:\cib-interns-test-task\src\main\java\ru\vasiliev\socks\Error\SocksError.java diff --git a/target/socks.jar b/target/socks.jar new file mode 100644 index 00000000..d2a50c23 Binary files /dev/null and b/target/socks.jar differ