Начало работ над 4-й лабораторной.
This commit is contained in:
parent
c4e3593fa4
commit
2844d545ce
8
.idea/discord.xml
Normal file
8
.idea/discord.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DiscordProjectSettings">
|
||||
<option name="show" value="ASK" />
|
||||
<option name="nameOverrideEnabled" value="true" />
|
||||
<option name="description" value="" />
|
||||
</component>
|
||||
</project>
|
@ -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'
|
||||
}
|
||||
|
||||
|
@ -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("*");
|
||||
}
|
||||
}
|
||||
|
@ -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<Client, Long> {
|
||||
}
|
@ -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<Level, Long> {
|
||||
}
|
@ -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<Nation, Long> {
|
||||
}
|
@ -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<Tank, Long> {
|
||||
}
|
@ -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)
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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<Object> handleException(Throwable e) {
|
||||
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
//при исключении автоматической валидации данных
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<Object> 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<Object> handleUnknownException(Throwable e) {
|
||||
e.printStackTrace();
|
||||
|
||||
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package premium_store.util.validation;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
//класс для передачи списка ошибок, если они возникают
|
||||
public class ValidationException extends RuntimeException {
|
||||
public ValidationException(Set<String> errors) {
|
||||
super(String.join("\n", errors));
|
||||
}
|
||||
}
|
@ -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 <T> void validate(T object) {
|
||||
final Set<ConstraintViolation<T>> errors = validator.validate(object);
|
||||
if (!errors.isEmpty()) {
|
||||
throw new ValidationException(errors.stream()
|
||||
.map(ConstraintViolation::getMessage)
|
||||
.collect(Collectors.toSet()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user