From 2844d545ce7a5624876136db7e4eee75286a7dde Mon Sep 17 00:00:00 2001 From: Programmist73 Date: Sat, 8 Apr 2023 23:01:18 +0400 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B0=D1=87=D0=B0=D0=BB=D0=BE=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=20=D0=BD=D0=B0=D0=B4=204-=D0=B9=20?= =?UTF-8?q?=D0=BB=D0=B0=D0=B1=D0=BE=D1=80=D0=B0=D1=82=D0=BE=D1=80=D0=BD?= =?UTF-8?q?=D0=BE=D0=B9.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/discord.xml | 8 +++ spring_online_calculator/build.gradle | 3 ++ .../java/premium_store/WebConfiguration.java | 15 ++++++ .../repository/ClientRepository.java | 7 +++ .../repository/LevelRepository.java | 9 ++++ .../repository/NationRepository.java | 9 ++++ .../repository/TankRepository.java | 7 +++ .../premium_store/service/LevelService.java | 19 ++++--- .../exception/ClientNotFoundException.java | 7 +++ .../exception/LevelNotFoundException.java | 10 ++++ .../exception/NationNotFoundException.java | 7 +++ .../exception/TankNotFoundException.java | 7 +++ .../util/error/AdviceController.java | 50 +++++++++++++++++++ .../util/validation/ValidationException.java | 10 ++++ .../util/validation/ValidatorUtil.java | 32 ++++++++++++ .../src/main/resources/application.properties | 2 +- 16 files changed, 194 insertions(+), 8 deletions(-) create mode 100644 .idea/discord.xml create mode 100644 spring_online_calculator/src/main/java/premium_store/WebConfiguration.java create mode 100644 spring_online_calculator/src/main/java/premium_store/repository/ClientRepository.java create mode 100644 spring_online_calculator/src/main/java/premium_store/repository/LevelRepository.java create mode 100644 spring_online_calculator/src/main/java/premium_store/repository/NationRepository.java create mode 100644 spring_online_calculator/src/main/java/premium_store/repository/TankRepository.java create mode 100644 spring_online_calculator/src/main/java/premium_store/service/exception/ClientNotFoundException.java create mode 100644 spring_online_calculator/src/main/java/premium_store/service/exception/LevelNotFoundException.java create mode 100644 spring_online_calculator/src/main/java/premium_store/service/exception/NationNotFoundException.java create mode 100644 spring_online_calculator/src/main/java/premium_store/service/exception/TankNotFoundException.java create mode 100644 spring_online_calculator/src/main/java/premium_store/util/error/AdviceController.java create mode 100644 spring_online_calculator/src/main/java/premium_store/util/validation/ValidationException.java create mode 100644 spring_online_calculator/src/main/java/premium_store/util/validation/ValidatorUtil.java diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 0000000..6f1cd93 --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/spring_online_calculator/build.gradle b/spring_online_calculator/build.gradle index 8e502c9..8d28b84 100644 --- a/spring_online_calculator/build.gradle +++ b/spring_online_calculator/build.gradle @@ -20,6 +20,9 @@ dependencies { implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5' + implementation 'org.hibernate.validator:hibernate-validator' + implementation 'org.springdoc:springdoc-openapi-ui:1.6.5' + testImplementation 'org.springframework.boot:spring-boot-starter-test' } diff --git a/spring_online_calculator/src/main/java/premium_store/WebConfiguration.java b/spring_online_calculator/src/main/java/premium_store/WebConfiguration.java new file mode 100644 index 0000000..6c4b7c4 --- /dev/null +++ b/spring_online_calculator/src/main/java/premium_store/WebConfiguration.java @@ -0,0 +1,15 @@ +package premium_store; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +//отключение Cors фильтра - не позволяет организовавыть взаимодействие с разных доменов +@Configuration +class WebConfiguration implements WebMvcConfigurer { + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**").allowedMethods("*"); + } +} + diff --git a/spring_online_calculator/src/main/java/premium_store/repository/ClientRepository.java b/spring_online_calculator/src/main/java/premium_store/repository/ClientRepository.java new file mode 100644 index 0000000..65ad5c6 --- /dev/null +++ b/spring_online_calculator/src/main/java/premium_store/repository/ClientRepository.java @@ -0,0 +1,7 @@ +package premium_store.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import premium_store.model.Client; + +public interface ClientRepository extends JpaRepository { +} diff --git a/spring_online_calculator/src/main/java/premium_store/repository/LevelRepository.java b/spring_online_calculator/src/main/java/premium_store/repository/LevelRepository.java new file mode 100644 index 0000000..99cb366 --- /dev/null +++ b/spring_online_calculator/src/main/java/premium_store/repository/LevelRepository.java @@ -0,0 +1,9 @@ +package premium_store.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import premium_store.model.Level; + +//класс для взаимодействия с БД вместо низкоуровневого EntityManager +//передаём тип класса и тип id его элементов +public interface LevelRepository extends JpaRepository { +} diff --git a/spring_online_calculator/src/main/java/premium_store/repository/NationRepository.java b/spring_online_calculator/src/main/java/premium_store/repository/NationRepository.java new file mode 100644 index 0000000..b47db8c --- /dev/null +++ b/spring_online_calculator/src/main/java/premium_store/repository/NationRepository.java @@ -0,0 +1,9 @@ +package premium_store.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import premium_store.model.Nation; + +//класс для взаимодействия с БД вместо низкоуровневого EntityManager +//передаём тип класса и тип id его элементов +public interface NationRepository extends JpaRepository { +} diff --git a/spring_online_calculator/src/main/java/premium_store/repository/TankRepository.java b/spring_online_calculator/src/main/java/premium_store/repository/TankRepository.java new file mode 100644 index 0000000..1317ec8 --- /dev/null +++ b/spring_online_calculator/src/main/java/premium_store/repository/TankRepository.java @@ -0,0 +1,7 @@ +package premium_store.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import premium_store.model.Tank; + +public interface TankRepository extends JpaRepository { +} diff --git a/spring_online_calculator/src/main/java/premium_store/service/LevelService.java b/spring_online_calculator/src/main/java/premium_store/service/LevelService.java index 350e06c..dfc3d9f 100644 --- a/spring_online_calculator/src/main/java/premium_store/service/LevelService.java +++ b/spring_online_calculator/src/main/java/premium_store/service/LevelService.java @@ -3,27 +3,32 @@ package premium_store.service; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import premium_store.model.Level; +import premium_store.repository.LevelRepository; +import premium_store.util.validation.ValidatorUtil; import javax.persistence.EntityManager; import javax.persistence.EntityNotFoundException; import javax.persistence.PersistenceContext; import java.util.List; +//сервис после удаления EntityManager и добавления нашего репозитория. То есть у него уже все методы работы с полями прописаны за нас? @Service public class LevelService { @PersistenceContext - private EntityManager em; + private final LevelRepository levelRepository; + private final ValidatorUtil validatorUtil; + + public LevelService(LevelRepository levelRepository, ValidatorUtil validatorUtil){ + this.levelRepository = levelRepository; + this.validatorUtil = validatorUtil; + } @Transactional public Level addLevel(int newLevel) { - if (newLevel <= 0) { - throw new IllegalArgumentException("Level name is zero or less"); - } - final Level level = new Level(newLevel); - em.persist(level); + validatorUtil.validate(level); - return level; + return levelRepository.save(level); } @Transactional(readOnly = true) diff --git a/spring_online_calculator/src/main/java/premium_store/service/exception/ClientNotFoundException.java b/spring_online_calculator/src/main/java/premium_store/service/exception/ClientNotFoundException.java new file mode 100644 index 0000000..22d3864 --- /dev/null +++ b/spring_online_calculator/src/main/java/premium_store/service/exception/ClientNotFoundException.java @@ -0,0 +1,7 @@ +package premium_store.service.exception; + +public class ClientNotFoundException extends RuntimeException { + public ClientNotFoundException(Long id) { + super(String.format("Student with id [%s] is not found", id)); + } +} \ No newline at end of file diff --git a/spring_online_calculator/src/main/java/premium_store/service/exception/LevelNotFoundException.java b/spring_online_calculator/src/main/java/premium_store/service/exception/LevelNotFoundException.java new file mode 100644 index 0000000..83e271e --- /dev/null +++ b/spring_online_calculator/src/main/java/premium_store/service/exception/LevelNotFoundException.java @@ -0,0 +1,10 @@ +package premium_store.service.exception; + +//класс-обработчик ошибки, когда вытаемся вытащить студента из бд по некорректному id +//наследуем от RuntimeException, т. к. он позволяет его проще вызывать +public class LevelNotFoundException extends RuntimeException { + public LevelNotFoundException(Long id) { + super(String.format("Level with id [%s] is not found", id)); + } +} + diff --git a/spring_online_calculator/src/main/java/premium_store/service/exception/NationNotFoundException.java b/spring_online_calculator/src/main/java/premium_store/service/exception/NationNotFoundException.java new file mode 100644 index 0000000..b2b4078 --- /dev/null +++ b/spring_online_calculator/src/main/java/premium_store/service/exception/NationNotFoundException.java @@ -0,0 +1,7 @@ +package premium_store.service.exception; + +public class NationNotFoundException extends RuntimeException { + public NationNotFoundException(Long id) { + super(String.format("Student with id [%s] is not found", id)); + } +} diff --git a/spring_online_calculator/src/main/java/premium_store/service/exception/TankNotFoundException.java b/spring_online_calculator/src/main/java/premium_store/service/exception/TankNotFoundException.java new file mode 100644 index 0000000..d78f08a --- /dev/null +++ b/spring_online_calculator/src/main/java/premium_store/service/exception/TankNotFoundException.java @@ -0,0 +1,7 @@ +package premium_store.service.exception; + +public class TankNotFoundException extends RuntimeException { + public TankNotFoundException(Long id) { + super(String.format("Student with id [%s] is not found", id)); + } +} \ No newline at end of file diff --git a/spring_online_calculator/src/main/java/premium_store/util/error/AdviceController.java b/spring_online_calculator/src/main/java/premium_store/util/error/AdviceController.java new file mode 100644 index 0000000..18577c3 --- /dev/null +++ b/spring_online_calculator/src/main/java/premium_store/util/error/AdviceController.java @@ -0,0 +1,50 @@ +package premium_store.util.error; + +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import premium_store.service.exception.ClientNotFoundException; +import premium_store.service.exception.LevelNotFoundException; +import premium_store.service.exception.NationNotFoundException; +import premium_store.service.exception.TankNotFoundException; +import premium_store.util.validation.ValidationException; + +import java.util.stream.Collectors; + +//контроллер для обработки разнообразных ошибок при работе с запросами к БД +@ControllerAdvice +public class AdviceController { + //метод handleException будет вызываться при возникновении исключений типа LevelNotFoundException и т. д. + @ExceptionHandler({ + LevelNotFoundException.class, + NationNotFoundException.class, + ClientNotFoundException.class, + TankNotFoundException.class, + ValidationException.class + }) + public ResponseEntity handleException(Throwable e) { + return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST); + } + + //при исключении автоматической валидации данных + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity handleBindException(MethodArgumentNotValidException e) { + final ValidationException validationException = new ValidationException( + e.getBindingResult().getAllErrors().stream() + .map(DefaultMessageSourceResolvable::getDefaultMessage) + .collect(Collectors.toSet())); + + return handleException(validationException); + } + + //обработка неизвестных ошибок + @ExceptionHandler(Exception.class) + public ResponseEntity handleUnknownException(Throwable e) { + e.printStackTrace(); + + return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } +} \ No newline at end of file diff --git a/spring_online_calculator/src/main/java/premium_store/util/validation/ValidationException.java b/spring_online_calculator/src/main/java/premium_store/util/validation/ValidationException.java new file mode 100644 index 0000000..9aff6a2 --- /dev/null +++ b/spring_online_calculator/src/main/java/premium_store/util/validation/ValidationException.java @@ -0,0 +1,10 @@ +package premium_store.util.validation; + +import java.util.Set; + +//класс для передачи списка ошибок, если они возникают +public class ValidationException extends RuntimeException { + public ValidationException(Set errors) { + super(String.join("\n", errors)); + } +} \ No newline at end of file diff --git a/spring_online_calculator/src/main/java/premium_store/util/validation/ValidatorUtil.java b/spring_online_calculator/src/main/java/premium_store/util/validation/ValidatorUtil.java new file mode 100644 index 0000000..caf166e --- /dev/null +++ b/spring_online_calculator/src/main/java/premium_store/util/validation/ValidatorUtil.java @@ -0,0 +1,32 @@ +package premium_store.util.validation; + +import org.springframework.stereotype.Component; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; +import java.util.Set; +import java.util.stream.Collectors; + +//компонент для ручной валидации данных (проверка на заполнение или пустоту, выход за допустимые диапазоны значений и т. д.) +@Component +public class ValidatorUtil { + private final Validator validator; + + public ValidatorUtil() { + try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) { + this.validator = factory.getValidator(); + } + } + + public void validate(T object) { + final Set> errors = validator.validate(object); + if (!errors.isEmpty()) { + throw new ValidationException(errors.stream() + .map(ConstraintViolation::getMessage) + .collect(Collectors.toSet())); + } + } +} + diff --git a/spring_online_calculator/src/main/resources/application.properties b/spring_online_calculator/src/main/resources/application.properties index ccc05e8..14d2c47 100644 --- a/spring_online_calculator/src/main/resources/application.properties +++ b/spring_online_calculator/src/main/resources/application.properties @@ -1,5 +1,5 @@ spring.main.banner-mode=off -#server.port=8080 +server.port=8080 spring.datasource.url=jdbc:h2:file:./data spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa