diff --git a/.gitignore b/.gitignore index c2065bc..c9e91d9 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,5 @@ out/ ### VS Code ### .vscode/ + +data.*.db \ No newline at end of file diff --git a/README.md b/README.md index e3dad08..fb3e830 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,18 @@ -# Internet_Programming_PIbd-21_Rodionov_I_A_Backend +Swagger UI: \ +http://localhost:8080/swagger-ui/index.html +H2 Console: \ +http://localhost:8080/h2-console + +JDBC URL: jdbc:h2:file:./data \ +User Name: sa \ +Password: password + +Почитать: + +- Односторонние и двусторонние связи https://www.baeldung.com/jpa-hibernate-associations +- Getters и Setters для двусторонних связей https://en.wikifoods.org/wiki/Java_Persistence/OneToMany#Getters_and_Setters +- Многие-ко-многим с доп. атрибутами https://thorben-janssen.com/hibernate-tip-many-to-many-association-with-additional-attributes/ +- Многие-ко-многим с доп. атрибутами https://www.baeldung.com/jpa-many-to-many +- Каскадное удаление сущностей со связями многие-ко-многим https://www.baeldung.com/jpa-remove-entity-many-to-many +- Выбор типа коллекции для отношений вида ко-многим в JPA https://thorben-janssen.com/association-mappings-bag-list-set/ diff --git a/build.gradle b/build.gradle index 988a6f6..42a3cac 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,23 @@ plugins { id 'java' - id 'org.springframework.boot' version '3.2.4' + id 'org.springframework.boot' version '3.2.5' id 'io.spring.dependency-management' version '1.1.4' } group = 'com.example' version = '0.0.1-SNAPSHOT' +defaultTasks 'bootRun' + +jar { + enabled = false +} + +bootJar { + archiveFileName = String.format('%s-%s.jar', rootProject.name, version) +} + +assert System.properties['java.specification.version'] == '17' || '21' java { sourceCompatibility = '17' } @@ -17,13 +28,16 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' implementation 'org.modelmapper:modelmapper:3.2.0' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'com.h2database:h2:2.2.224' + testImplementation 'org.springframework.boot:spring-boot-starter-test' } tasks.named('test') { useJUnitPlatform() } - diff --git a/src/main/java/com/example/backend/DemoApplication.java b/src/main/java/com/example/backend/DemoApplication.java new file mode 100644 index 0000000..d07195a --- /dev/null +++ b/src/main/java/com/example/backend/DemoApplication.java @@ -0,0 +1,88 @@ +package com.example.backend; + +import java.util.Arrays; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import com.example.backend.core.utils.Formatter; +import com.example.backend.foods.model.FoodEntity; +import com.example.backend.foods.service.FoodService; +import com.example.backend.users.model.UserEntity; +import com.example.backend.users.service.UserService; +import com.example.backend.orders.model.OrderEntity; +import com.example.backend.orders.service.OrderService; +import com.example.backend.types.model.TypeEntity; +import com.example.backend.types.service.TypeService; + +@SpringBootApplication +public class DemoApplication implements CommandLineRunner { + private final Logger log = LoggerFactory.getLogger(DemoApplication.class); + + private final TypeService typeService; + private final FoodService foodService; + private final UserService userService; + private final OrderService orderService; + + public DemoApplication(TypeService typeService, FoodService foodService, UserService userService, + OrderService orderService) { + this.typeService = typeService; + this.foodService = foodService; + this.userService = userService; + this.orderService = orderService; + } + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + + @Override + public void run(String... args) throws Exception { + if (args.length > 0 && Arrays.asList(args).contains("--populate")) { + log.info("Create default categories values"); + final var type1 = typeService.create(new TypeEntity("Бургер")); + final var type2 = typeService.create(new TypeEntity("Шаурма")); + final var type3 = typeService.create(new TypeEntity("Напиток")); + + log.info("Create default foods values"); + final var food1 = foodService.create(new FoodEntity(type1, "Бургер с говядиной", + 700.00, Formatter.parse("2021-09-11"), 5000)); + + final var food2 = foodService.create(new FoodEntity(type2, "Спец шаурма", + 300.00, Formatter.parse("2021-11-11"), 1000)); + + final var food3 = foodService.create(new FoodEntity(type2, "Шаурма с курицей", + 200.00, Formatter.parse("2021-10-11"), 4000)); + + final var food4 = foodService.create(new FoodEntity(type3, "Кола", + 70.00, Formatter.parse("2021-04-11"), 3000)); + final var food5 = foodService.create(new FoodEntity(type3, "Чай", + 50.00, Formatter.parse("2021-05-11"), 2000)); + + log.info("Create default users values"); + final var user1 = userService + .create(new UserEntity("Dan", "Daniil@gmail.com", "danil123", "admin")); + final var user2 = userService + .create(new UserEntity("Ilya", "Ilya@gmail.com", "ilya123", "user")); + final var user3 = userService + .create(new UserEntity("Test", "Test@gmail.com", "Test123", "user")); + + log.info("Create default orders values"); + orderService + .create(user1.getId(), new OrderEntity("Выполняется"), + Map.of(food1.getId(), 6, food2.getId(), 1, food4.getId(), 3)); + orderService + .create(user2.getId(), + new OrderEntity("Выдан"), + Map.of(food4.getId(), 5, food3.getId(), 3)); + orderService + .create(user3.getId(), + new OrderEntity("Готов"), + Map.of(food2.getId(), 1, food5.getId(), 1)); + } + } +} diff --git a/src/main/java/com/example/backend/core/api/PageDto.java b/src/main/java/com/example/backend/core/api/PageDto.java new file mode 100644 index 0000000..b0ea6e2 --- /dev/null +++ b/src/main/java/com/example/backend/core/api/PageDto.java @@ -0,0 +1,97 @@ +package com.example.backend.core.api; + +import java.util.ArrayList; +import java.util.List; + +public class PageDto { + private List items = new ArrayList<>(); + private int itemsCount; + private int currentPage; + private int currentSize; + private int totalPages; + private long totalItems; + private boolean isFirst; + private boolean isLast; + private boolean hasNext; + private boolean hasPrevious; + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + + public int getItemsCount() { + return itemsCount; + } + + public void setItemsCount(int itemsCount) { + this.itemsCount = itemsCount; + } + + public int getCurrentPage() { + return currentPage; + } + + public void setCurrentPage(int currentPage) { + this.currentPage = currentPage; + } + + public int getCurrentSize() { + return currentSize; + } + + public void setCurrentSize(int currentSize) { + this.currentSize = currentSize; + } + + public int getTotalPages() { + return totalPages; + } + + public void setTotalPages(int totalPages) { + this.totalPages = totalPages; + } + + public long getTotalItems() { + return totalItems; + } + + public void setTotalItems(long totalItems) { + this.totalItems = totalItems; + } + + public boolean isFirst() { + return isFirst; + } + + public void setFirst(boolean isFirst) { + this.isFirst = isFirst; + } + + public boolean isLast() { + return isLast; + } + + public void setLast(boolean isLast) { + this.isLast = isLast; + } + + public boolean isHasNext() { + return hasNext; + } + + public void setHasNext(boolean hasNext) { + this.hasNext = hasNext; + } + + public boolean isHasPrevious() { + return hasPrevious; + } + + public void setHasPrevious(boolean hasPrevious) { + this.hasPrevious = hasPrevious; + } +} diff --git a/src/main/java/com/example/backend/core/api/PageDtoMapper.java b/src/main/java/com/example/backend/core/api/PageDtoMapper.java new file mode 100644 index 0000000..102ab70 --- /dev/null +++ b/src/main/java/com/example/backend/core/api/PageDtoMapper.java @@ -0,0 +1,25 @@ +package com.example.backend.core.api; + +import java.util.function.Function; + +import org.springframework.data.domain.Page; + +public class PageDtoMapper { + private PageDtoMapper() { + } + + public static PageDto toDto(Page page, Function mapper) { + final PageDto dto = new PageDto<>(); + dto.setItems(page.getContent().stream().map(mapper::apply).toList()); + dto.setItemsCount(page.getNumberOfElements()); + dto.setCurrentPage(page.getNumber()); + dto.setCurrentSize(page.getSize()); + dto.setTotalPages(page.getTotalPages()); + dto.setTotalItems(page.getTotalElements()); + dto.setFirst(page.isFirst()); + dto.setLast(page.isLast()); + dto.setHasNext(page.hasNext()); + dto.setHasPrevious(page.hasPrevious()); + return dto; + } +} diff --git a/src/main/java/com/example/backend/core/configuration/Constants.java b/src/main/java/com/example/backend/core/configuration/Constants.java new file mode 100644 index 0000000..8bc3573 --- /dev/null +++ b/src/main/java/com/example/backend/core/configuration/Constants.java @@ -0,0 +1,12 @@ +package com.example.backend.core.configuration; + +public class Constants { + public static final String SEQUENCE_NAME = "hibernate_sequence"; + + public static final String API_URL = "/api/1.0"; + + public static final String DEFAULT_PAGE_SIZE = "5"; + + private Constants() { + } +} diff --git a/src/main/java/com/example/backend/core/configuration/MapperConfiguration.java b/src/main/java/com/example/backend/core/configuration/MapperConfiguration.java new file mode 100644 index 0000000..429b4ed --- /dev/null +++ b/src/main/java/com/example/backend/core/configuration/MapperConfiguration.java @@ -0,0 +1,18 @@ +package com.example.backend.core.configuration; + +import org.modelmapper.ModelMapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.example.backend.orders.api.OrderDto; +import com.example.backend.orders.model.OrderEntity; + +@Configuration +public class MapperConfiguration { + @Bean + ModelMapper modelMapper() { + ModelMapper modelMapper = new ModelMapper(); + modelMapper.typeMap(OrderEntity.class, OrderDto.class).addMappings(mapper -> mapper.skip(OrderDto::setFoods)); + return modelMapper; + } +} diff --git a/src/main/java/com/example/demo/core/configuration/WebConfiguration.java b/src/main/java/com/example/backend/core/configuration/WebConfiguration.java similarity index 91% rename from src/main/java/com/example/demo/core/configuration/WebConfiguration.java rename to src/main/java/com/example/backend/core/configuration/WebConfiguration.java index 762e85a..33afc53 100644 --- a/src/main/java/com/example/demo/core/configuration/WebConfiguration.java +++ b/src/main/java/com/example/backend/core/configuration/WebConfiguration.java @@ -1,4 +1,4 @@ -package com.example.demo.core.configuration; +package com.example.backend.core.configuration; import org.springframework.context.annotation.Configuration; import org.springframework.lang.NonNull; diff --git a/src/main/java/com/example/backend/core/error/NotFoundException.java b/src/main/java/com/example/backend/core/error/NotFoundException.java new file mode 100644 index 0000000..0b7ddcb --- /dev/null +++ b/src/main/java/com/example/backend/core/error/NotFoundException.java @@ -0,0 +1,7 @@ +package com.example.backend.core.error; + +public class NotFoundException extends RuntimeException { + public NotFoundException(Class clazz, Long id) { + super(String.format("%s with id [%s] is not found or not exists", clazz.getSimpleName(), id)); + } +} diff --git a/src/main/java/com/example/backend/core/model/BaseEntity.java b/src/main/java/com/example/backend/core/model/BaseEntity.java new file mode 100644 index 0000000..83d0d17 --- /dev/null +++ b/src/main/java/com/example/backend/core/model/BaseEntity.java @@ -0,0 +1,28 @@ +package com.example.backend.core.model; + +import com.example.backend.core.configuration.Constants; + +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.SequenceGenerator; + +@MappedSuperclass +public abstract class BaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = Constants.SEQUENCE_NAME) + @SequenceGenerator(name = Constants.SEQUENCE_NAME, sequenceName = Constants.SEQUENCE_NAME, allocationSize = 1) + protected Long id; + + protected BaseEntity() { + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } +} diff --git a/src/main/java/com/example/demo/core/utils/Formatter.java b/src/main/java/com/example/backend/core/utils/Formatter.java similarity index 73% rename from src/main/java/com/example/demo/core/utils/Formatter.java rename to src/main/java/com/example/backend/core/utils/Formatter.java index be50bdd..be35427 100644 --- a/src/main/java/com/example/demo/core/utils/Formatter.java +++ b/src/main/java/com/example/backend/core/utils/Formatter.java @@ -1,4 +1,4 @@ -package com.example.demo.core.utils; +package com.example.backend.core.utils; import java.util.Date; import java.text.ParseException; @@ -8,7 +8,7 @@ public final class Formatter { private Formatter() { } - private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd"); + private static SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd"); public static String format(Date date) { return dateFormatter.format(date); diff --git a/src/main/java/com/example/demo/foods/api/FoodController.java b/src/main/java/com/example/backend/foods/api/FoodController.java similarity index 64% rename from src/main/java/com/example/demo/foods/api/FoodController.java rename to src/main/java/com/example/backend/foods/api/FoodController.java index 6f4f234..cbe5996 100644 --- a/src/main/java/com/example/demo/foods/api/FoodController.java +++ b/src/main/java/com/example/backend/foods/api/FoodController.java @@ -1,8 +1,4 @@ -package com.example.demo.foods.api; - -import java.text.ParseException; -import java.util.Date; -import java.util.List; +package com.example.backend.foods.api; import org.modelmapper.ModelMapper; import org.springframework.web.bind.annotation.DeleteMapping; @@ -15,11 +11,12 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import com.example.demo.core.configuration.Constants; -import com.example.demo.core.utils.Formatter; -import com.example.demo.foods.model.FoodEntity; -import com.example.demo.foods.service.FoodService; -import com.example.demo.types.service.TypeService; +import com.example.backend.core.api.PageDto; +import com.example.backend.core.api.PageDtoMapper; +import com.example.backend.foods.model.FoodEntity; +import com.example.backend.foods.service.FoodService; +import com.example.backend.types.service.TypeService; +import com.example.backend.core.configuration.Constants; import jakarta.validation.Valid; @@ -37,23 +34,21 @@ public class FoodController { } private FoodDto toDto(FoodEntity entity) { - final FoodDto dto = modelMapper.map(entity, FoodDto.class); - String date = Formatter.format(entity.getDate()); - dto.setDate(date); - return dto; + return modelMapper.map(entity, FoodDto.class); } - private FoodEntity toEntity(FoodDto dto) throws ParseException { + private FoodEntity toEntity(FoodDto dto) { final FoodEntity entity = modelMapper.map(dto, FoodEntity.class); - Date date = Formatter.parse(dto.getDate()); - entity.setDate(date); entity.setType(typeService.get(dto.getTypeId())); return entity; } @GetMapping - public List getAll(@RequestParam(name = "typeId", defaultValue = "0") Long typeId) { - return foodService.getAll(typeId).stream().map(this::toDto).toList(); + public PageDto getAll( + @RequestParam(name = "typeId", defaultValue = "0") Long typeId, + @RequestParam(name = "page", defaultValue = "0") int page, + @RequestParam(name = "size", defaultValue = Constants.DEFAULT_PAGE_SIZE) int size) { + return PageDtoMapper.toDto(foodService.getAll(typeId, page, size), this::toDto); } @GetMapping("/{id}") @@ -62,12 +57,12 @@ public class FoodController { } @PostMapping - public FoodDto create(@RequestBody @Valid FoodDto dto) throws ParseException { + public FoodDto create(@RequestBody @Valid FoodDto dto) { return toDto(foodService.create(toEntity(dto))); } @PutMapping("/{id}") - public FoodDto update(@PathVariable(name = "id") Long id, @RequestBody FoodDto dto) throws ParseException { + public FoodDto update(@PathVariable(name = "id") Long id, @RequestBody @Valid FoodDto dto) { return toDto(foodService.update(id, toEntity(dto))); } diff --git a/src/main/java/com/example/demo/foods/api/FoodDto.java b/src/main/java/com/example/backend/foods/api/FoodDto.java similarity index 93% rename from src/main/java/com/example/demo/foods/api/FoodDto.java rename to src/main/java/com/example/backend/foods/api/FoodDto.java index f2542ae..a39f613 100644 --- a/src/main/java/com/example/demo/foods/api/FoodDto.java +++ b/src/main/java/com/example/backend/foods/api/FoodDto.java @@ -1,29 +1,29 @@ -package com.example.demo.foods.api; +package com.example.backend.foods.api; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; public class FoodDto { + @JsonProperty(access = JsonProperty.Access.READ_ONLY) private Long id; @NotNull @Min(1) private Long typeId; + @NotBlank + private String name; @NotNull @Min(1) private Double price; @NotNull @Min(1) - private String name; - @NotNull - @Min(1) private String date; @NotNull @Min(1) private Integer count; - @JsonProperty(access = JsonProperty.Access.READ_ONLY) public Long getId() { return id; } @@ -40,6 +40,14 @@ public class FoodDto { this.typeId = typeId; } + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + public Double getPrice() { return price; } @@ -64,14 +72,6 @@ public class FoodDto { this.count = count; } - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - @JsonProperty(access = JsonProperty.Access.READ_ONLY) public Double getSum() { return price * count; diff --git a/src/main/java/com/example/demo/foods/model/FoodEntity.java b/src/main/java/com/example/backend/foods/model/FoodEntity.java similarity index 53% rename from src/main/java/com/example/demo/foods/model/FoodEntity.java rename to src/main/java/com/example/backend/foods/model/FoodEntity.java index 07a94c1..ac5e46f 100644 --- a/src/main/java/com/example/demo/foods/model/FoodEntity.java +++ b/src/main/java/com/example/backend/foods/model/FoodEntity.java @@ -1,27 +1,47 @@ -package com.example.demo.foods.model; +package com.example.backend.foods.model; import java.util.Date; +import java.util.HashSet; import java.util.Objects; +import java.util.Set; -import com.example.demo.core.model.BaseEntity; -import com.example.demo.types.model.TypeEntity; +import com.example.backend.core.model.BaseEntity; +import com.example.backend.ordersfoods.model.OrderFoodEntity; +import com.example.backend.types.model.TypeEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OrderBy; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + +@Entity +@Table(name = "foods") public class FoodEntity extends BaseEntity { + @ManyToOne + @JoinColumn(name = "typeId", nullable = false) private TypeEntity type; - private Double price; + @Column(nullable = false) private String name; + @Column(nullable = false) + private Double price; + @Column(nullable = false) private Date date; + @Column(nullable = false) private Integer count; + @OneToMany(mappedBy = "food") + @OrderBy("id ASC") + private Set orderFoods = new HashSet<>(); public FoodEntity() { - super(); } - public FoodEntity(Long id, TypeEntity type, Double price, String name, Date date, Integer count) { - super(id); + public FoodEntity(TypeEntity type, String name, Double price, Date date, Integer count) { this.type = type; - this.price = price; this.name = name; + this.price = price; this.date = date; this.count = count; } @@ -34,14 +54,6 @@ public class FoodEntity extends BaseEntity { this.type = type; } - public Double getPrice() { - return price; - } - - public void setPrice(Double price) { - this.price = price; - } - public String getName() { return name; } @@ -50,6 +62,14 @@ public class FoodEntity extends BaseEntity { this.name = name; } + public Double getPrice() { + return price; + } + + public void setPrice(Double price) { + this.price = price; + } + public Date getDate() { return date; } @@ -66,9 +86,24 @@ public class FoodEntity extends BaseEntity { this.count = count; } + public void setOrderFoods(Set orderFoods) { + this.orderFoods = orderFoods; + } + + public Set getOrderFoods() { + return orderFoods; + } + + public void addOrder(OrderFoodEntity orderFood) { + if (orderFood.getFood() != this) { + orderFood.setFood(this); + } + orderFoods.add(orderFood); + } + @Override public int hashCode() { - return Objects.hash(id, type, price, count); + return Objects.hash(id, type, name, price, date, count); } @Override @@ -80,6 +115,7 @@ public class FoodEntity extends BaseEntity { final FoodEntity other = (FoodEntity) obj; return Objects.equals(other.getId(), id) && Objects.equals(other.getType(), type) + && Objects.equals(other.getName(), name) && Objects.equals(other.getPrice(), price) && Objects.equals(other.getDate(), date) && Objects.equals(other.getCount(), count); diff --git a/src/main/java/com/example/backend/foods/repository/FoodRepository.java b/src/main/java/com/example/backend/foods/repository/FoodRepository.java new file mode 100644 index 0000000..ee6dab5 --- /dev/null +++ b/src/main/java/com/example/backend/foods/repository/FoodRepository.java @@ -0,0 +1,17 @@ +package com.example.backend.foods.repository; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; + +import com.example.backend.foods.model.FoodEntity; + +public interface FoodRepository extends CrudRepository, PagingAndSortingRepository { + List findByTypeId(long typeId); + + Page findByTypeId(long typeId, Pageable pageable); + +} diff --git a/src/main/java/com/example/backend/foods/service/FoodService.java b/src/main/java/com/example/backend/foods/service/FoodService.java new file mode 100644 index 0000000..1029fd2 --- /dev/null +++ b/src/main/java/com/example/backend/foods/service/FoodService.java @@ -0,0 +1,77 @@ +package com.example.backend.foods.service; + +import java.util.List; +import java.util.stream.StreamSupport; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.example.backend.core.error.NotFoundException; +import com.example.backend.foods.model.FoodEntity; +import com.example.backend.foods.repository.FoodRepository; + +@Service +public class FoodService { + private final FoodRepository repository; + + public FoodService(FoodRepository repository) { + this.repository = repository; + } + + @Transactional(readOnly = true) + public List getAll(long typeId) { + if (typeId <= 0L) { + return StreamSupport.stream(repository.findAll().spliterator(), false).toList(); + } + return repository.findByTypeId(typeId); + } + + @Transactional(readOnly = true) + public List getAllById(List foodIds) { + return StreamSupport.stream(repository.findAllById(foodIds).spliterator(), false).toList(); + } + + @Transactional(readOnly = true) + public Page getAll(long typeId, int page, int size) { + final Pageable pageRequest = PageRequest.of(page, size); + if (typeId <= 0L) { + return repository.findAll(pageRequest); + } + return repository.findByTypeId(typeId, pageRequest); + } + + @Transactional(readOnly = true) + public FoodEntity get(long id) { + return repository.findById(id) + .orElseThrow(() -> new NotFoundException(FoodEntity.class, id)); + } + + @Transactional + public FoodEntity create(FoodEntity entity) { + if (entity == null) { + throw new IllegalArgumentException("Entity is null"); + } + return repository.save(entity); + } + + @Transactional + public FoodEntity update(Long id, FoodEntity entity) { + final FoodEntity existsEntity = get(id); + existsEntity.setType(entity.getType()); + existsEntity.setName(entity.getName()); + existsEntity.setDate(entity.getDate()); + existsEntity.setPrice(entity.getPrice()); + existsEntity.setCount(entity.getCount()); + return repository.save(existsEntity); + } + + @Transactional + public FoodEntity delete(Long id) { + final FoodEntity existsEntity = get(id); + repository.delete(existsEntity); + return existsEntity; + } +} diff --git a/src/main/java/com/example/backend/orders/api/OrderController.java b/src/main/java/com/example/backend/orders/api/OrderController.java new file mode 100644 index 0000000..61597b2 --- /dev/null +++ b/src/main/java/com/example/backend/orders/api/OrderController.java @@ -0,0 +1,94 @@ +package com.example.backend.orders.api; + +import java.text.ParseException; + +import java.util.Date; +import java.util.Map; +import java.util.stream.Collectors; + +import org.modelmapper.ModelMapper; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.example.backend.core.api.PageDto; +import com.example.backend.core.api.PageDtoMapper; +import com.example.backend.orders.model.OrderEntity; +import com.example.backend.orders.service.OrderService; +import com.example.backend.core.configuration.Constants; +import com.example.backend.core.utils.Formatter; +import com.example.backend.foods.api.FoodDto; +import com.example.backend.foods.model.FoodEntity; + +import jakarta.validation.Valid; + +@RestController +@RequestMapping(Constants.API_URL + "/user/{user}/order") +public class OrderController { + private final OrderService orderService; + private final ModelMapper modelMapper; + + public OrderController(OrderService orderService, ModelMapper modelMapper) { + this.orderService = orderService; + this.modelMapper = modelMapper; + } + + private OrderDto toDto(OrderEntity entity) { + final OrderDto dto = modelMapper.map(entity, OrderDto.class); + dto.setDate(Formatter.format(entity.getDate())); + dto.setSum(orderService.getSum(entity.getUser().getId(), entity.getId())); + dto.setCount(orderService.getFullCount(entity.getUser().getId(), entity.getId())); + dto.setFoods(orderService.getOrderFoods(entity.getUser().getId(), entity + .getId()).stream() + .map(orderFood -> toFoodDto(orderFood.getFood())) + .toList()); + return dto; + } + + private OrderEntity toEntity(OrderDto dto) throws ParseException { + final OrderEntity entity = modelMapper.map(dto, OrderEntity.class); + entity.setDate(Formatter.parse(dto.getDate())); + return entity; + } + + private FoodDto toFoodDto(FoodEntity entity) { + return modelMapper.map(entity, FoodDto.class); + } + + @GetMapping + public PageDto getAll( + @PathVariable(name = "user") Long userId, + @RequestParam(name = "page", defaultValue = "0") int page, + @RequestParam(name = "size", defaultValue = Constants.DEFAULT_PAGE_SIZE) int size) { + return PageDtoMapper.toDto(orderService.getAll(userId, page, size), this::toDto); + } + + @GetMapping("/{id}") + public OrderDto get( + @PathVariable(name = "user") Long userId, + @PathVariable(name = "id") Long id) { + return toDto(orderService.get(userId, id)); + } + + @PostMapping + public OrderDto create( + @PathVariable(name = "user") Long userId, + @RequestBody @Valid OrderDto dto) throws ParseException { + dto.setDate(Formatter.format(new Date())); + Map foodsIdsCount = dto.getOrderInfo().stream() + .collect(Collectors.toMap(OrderFoodDto::getFoodId, OrderFoodDto::getCount)); + return toDto(orderService.create(userId, toEntity(dto), foodsIdsCount)); + } + + @DeleteMapping("/{id}") + public OrderDto delete( + @PathVariable(name = "user") Long userId, + @PathVariable(name = "id") Long id) { + return toDto(orderService.delete(userId, id)); + } +} diff --git a/src/main/java/com/example/demo/orders/api/OrderDto.java b/src/main/java/com/example/backend/orders/api/OrderDto.java similarity index 54% rename from src/main/java/com/example/demo/orders/api/OrderDto.java rename to src/main/java/com/example/backend/orders/api/OrderDto.java index 8ee6f47..f8c92ac 100644 --- a/src/main/java/com/example/demo/orders/api/OrderDto.java +++ b/src/main/java/com/example/backend/orders/api/OrderDto.java @@ -1,35 +1,28 @@ -package com.example.demo.orders.api; +package com.example.backend.orders.api; -import java.util.List; +import com.example.backend.foods.api.FoodDto; import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.NotNull; +import java.util.List; + import jakarta.validation.constraints.NotBlank; -import com.example.demo.ordersfoods.api.OrderFoodDto; - public class OrderDto { + @JsonProperty(access = JsonProperty.Access.READ_ONLY) private Long id; + @JsonProperty(access = JsonProperty.Access.READ_ONLY) private Double sum; - @NotNull - @Min(1) - private Long userId; - @NotBlank + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + private Integer count; + @JsonProperty(access = JsonProperty.Access.READ_ONLY) private String date; @NotBlank private String status; - private List foods; - - public List getFoods() { - return foods; - } - - public void setFoods(List foods) { - this.foods = foods; - } - + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private List orderInfo; @JsonProperty(access = JsonProperty.Access.READ_ONLY) + private List foods; + public Long getId() { return id; } @@ -38,12 +31,20 @@ public class OrderDto { this.id = id; } - public Long getUserId() { - return userId; + public Double getSum() { + return sum; } - public void setUserId(Long userId) { - this.userId = userId; + public void setSum(Double sum) { + this.sum = sum; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; } public String getDate() { @@ -62,12 +63,19 @@ public class OrderDto { this.status = status; } - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public Double getSum() { - return sum; + public List getOrderInfo() { + return orderInfo; } - public void setSum(Double sum) { - this.sum = sum; + public void setOrderInfo(List orderInfo) { + this.orderInfo = orderInfo; + } + + public List getFoods() { + return foods; + } + + public void setFoods(List foods) { + this.foods = foods; } } diff --git a/src/main/java/com/example/backend/orders/api/OrderFoodDto.java b/src/main/java/com/example/backend/orders/api/OrderFoodDto.java new file mode 100644 index 0000000..2439108 --- /dev/null +++ b/src/main/java/com/example/backend/orders/api/OrderFoodDto.java @@ -0,0 +1,22 @@ +package com.example.backend.orders.api; + +public class OrderFoodDto { + private Long foodId; + private Integer count; + + public Long getFoodId() { + return foodId; + } + + public void setFoodId(Long foodId) { + this.foodId = foodId; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } +} diff --git a/src/main/java/com/example/backend/orders/model/OrderEntity.java b/src/main/java/com/example/backend/orders/model/OrderEntity.java new file mode 100644 index 0000000..bad1187 --- /dev/null +++ b/src/main/java/com/example/backend/orders/model/OrderEntity.java @@ -0,0 +1,105 @@ +package com.example.backend.orders.model; + +import java.util.Date; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import com.example.backend.users.model.UserEntity; +import com.example.backend.core.model.BaseEntity; +import com.example.backend.ordersfoods.model.OrderFoodEntity; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OrderBy; +import jakarta.persistence.Table; + +@Entity +@Table(name = "orders") +public class OrderEntity extends BaseEntity { + @ManyToOne + @JoinColumn(name = "userId", nullable = false) + private UserEntity user; + @Column(nullable = false) + private Date date; + @Column(nullable = false, length = 20) + private String status; + @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true) + @OrderBy("id ASC") + private Set orderFoods = new HashSet<>(); + + public OrderEntity() { + } + + public OrderEntity(String status) { + this.status = status; + this.date = new Date(); + } + + public UserEntity getUser() { + return user; + } + + public void setUser(UserEntity user) { + this.user = user; + if (!user.getOrders().contains(this)) { + user.getOrders().add(this); + } + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Set getOrderFoods() { + return orderFoods; + } + + public void addFood(OrderFoodEntity orderFood) { + if (orderFood.getOrder() != this) { + orderFood.setOrder(this); + } + orderFoods.add(orderFood); + } + + public void deleteFood(OrderFoodEntity orderFood) { + if (orderFood.getOrder() != this) { + return; + } + orderFoods.remove(orderFood); + } + + @Override + public int hashCode() { + return Objects.hash(id, user.getId(), date, status); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + final OrderEntity other = (OrderEntity) obj; + return Objects.equals(other.getId(), id) + && Objects.equals(other.getUser().getId(), user.getId()) + && Objects.equals(other.getDate(), date) + && Objects.equals(other.getStatus(), status); + } +} diff --git a/src/main/java/com/example/backend/orders/repository/OrderRepository.java b/src/main/java/com/example/backend/orders/repository/OrderRepository.java new file mode 100644 index 0000000..1e2a3e2 --- /dev/null +++ b/src/main/java/com/example/backend/orders/repository/OrderRepository.java @@ -0,0 +1,20 @@ +package com.example.backend.orders.repository; + +import java.util.List; +import java.util.Optional; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; + +import com.example.backend.orders.model.OrderEntity; + +public interface OrderRepository + extends CrudRepository, PagingAndSortingRepository { + Optional findOneByUserIdAndId(long userId, long id); + + List findByUserId(long userId); + + Page findByUserId(long userId, Pageable pageable); +} diff --git a/src/main/java/com/example/backend/orders/service/OrderService.java b/src/main/java/com/example/backend/orders/service/OrderService.java new file mode 100644 index 0000000..45b2a87 --- /dev/null +++ b/src/main/java/com/example/backend/orders/service/OrderService.java @@ -0,0 +1,101 @@ +package com.example.backend.orders.service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.example.backend.core.error.NotFoundException; +import com.example.backend.foods.model.FoodEntity; +import com.example.backend.foods.service.FoodService; +import com.example.backend.orders.model.OrderEntity; +import com.example.backend.orders.repository.OrderRepository; +import com.example.backend.ordersfoods.model.OrderFoodEntity; +import com.example.backend.users.model.UserEntity; +import com.example.backend.users.service.UserService; + +@Service +public class OrderService { + private final OrderRepository repository; + private final UserService userService; + private final FoodService foodService; + + public OrderService(OrderRepository repository, UserService userService, FoodService foodService) { + this.repository = repository; + this.userService = userService; + this.foodService = foodService; + } + + @Transactional(readOnly = true) + public List getAll(Long userId) { + userService.get(userId); + return repository.findByUserId(userId); + } + + @Transactional(readOnly = true) + public Page getAll(long userId, int page, int size) { + final Pageable pageRequest = PageRequest.of(page, size); + userService.get(userId); + return repository.findByUserId(userId, pageRequest); + } + + @Transactional(readOnly = true) + public OrderEntity get(long userId, long id) { + userService.get(userId); + return repository.findOneByUserIdAndId(userId, id) + .orElseThrow(() -> new NotFoundException(OrderEntity.class, id)); + } + + @Transactional + public OrderEntity create(long userId, OrderEntity entity, Map foodsIdsCount) { + if (entity == null) { + throw new IllegalArgumentException("Entity is null"); + } + final UserEntity existsUser = userService.get(userId); + entity.setUser(existsUser); + List foodIds = new ArrayList(foodsIdsCount.keySet()); + List result = foodService.getAllById(foodIds); + result.forEach(food -> { + final OrderFoodEntity orderFood = new OrderFoodEntity(entity, food, foodsIdsCount.get(food.getId())); + orderFood.setOrder(entity); + orderFood.setFood(food); + }); + return repository.save(entity); + } + + @Transactional + public OrderEntity delete(long userId, long id) { + userService.get(userId); + final OrderEntity existsEntity = get(userId, id); + repository.delete(existsEntity); + return existsEntity; + } + + @Transactional(readOnly = true) + public Double getSum(long userId, long id) { + userService.get(userId); + return get(userId, id).getOrderFoods().stream() + .mapToDouble(orderFood -> orderFood.getCount() * orderFood.getFood().getPrice()) + .sum(); + } + + @Transactional(readOnly = true) + public Integer getFullCount(long userId, long id) { + userService.get(userId); + return get(userId, id).getOrderFoods().stream() + .mapToInt(OrderFoodEntity::getCount) + .sum(); + } + + @Transactional(readOnly = true) + public List getOrderFoods(long userId, long id) { + userService.get(userId); + return get(userId, id).getOrderFoods().stream() + .toList(); + } +} diff --git a/src/main/java/com/example/backend/ordersfoods/model/OrderFoodEntity.java b/src/main/java/com/example/backend/ordersfoods/model/OrderFoodEntity.java new file mode 100644 index 0000000..93f794e --- /dev/null +++ b/src/main/java/com/example/backend/ordersfoods/model/OrderFoodEntity.java @@ -0,0 +1,96 @@ +package com.example.backend.ordersfoods.model; + +import java.util.Objects; + +import com.example.backend.foods.model.FoodEntity; +import com.example.backend.orders.model.OrderEntity; + +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapsId; +import jakarta.persistence.Table; + +@Entity +@Table(name = "orders_foods") +public class OrderFoodEntity { + @EmbeddedId + private OrderFoodId id = new OrderFoodId(); + @ManyToOne + @MapsId("orderId") + @JoinColumn(name = "order_id") + private OrderEntity order; + @ManyToOne + @MapsId("foodId") + @JoinColumn(name = "food_id") + private FoodEntity food; + @Column(nullable = false) + private Integer count; + + public OrderFoodEntity() { + } + + public OrderFoodEntity(OrderEntity order, FoodEntity food, Integer count) { + this.order = order; + this.food = food; + this.count = count; + } + + public OrderFoodId getId() { + return id; + } + + public void setId(OrderFoodId id) { + this.id = id; + } + + public OrderEntity getOrder() { + return order; + } + + public void setOrder(OrderEntity order) { + this.order = order; + if (!order.getOrderFoods().contains(this)) { + order.getOrderFoods().add(this); + } + } + + public FoodEntity getFood() { + return food; + } + + public void setFood(FoodEntity food) { + this.food = food; + if (!food.getOrderFoods().contains(this)) { + food.getOrderFoods().add(this); + } + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + @Override + public int hashCode() { + return Objects.hash(id, order.getId(), food.getId(), count); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + OrderFoodEntity other = (OrderFoodEntity) obj; + return Objects.equals(id, other.id) + && Objects.equals(order.getId(), other.order.getId()) + && Objects.equals(food.getId(), other.food.getId()) + && count == other.count; + } +} diff --git a/src/main/java/com/example/backend/ordersfoods/model/OrderFoodId.java b/src/main/java/com/example/backend/ordersfoods/model/OrderFoodId.java new file mode 100644 index 0000000..9c13233 --- /dev/null +++ b/src/main/java/com/example/backend/ordersfoods/model/OrderFoodId.java @@ -0,0 +1,55 @@ +package com.example.backend.ordersfoods.model; + +import java.util.Objects; +import java.util.Optional; + +import jakarta.persistence.Embeddable; + +@Embeddable +public class OrderFoodId { + private Long orderId; + private Long foodId; + + public OrderFoodId() { + } + + public OrderFoodId(Long orderId, Long foodId) { + this.orderId = orderId; + this.foodId = foodId; + } + + public Long getOrderId() { + return orderId; + } + + public void setOrderId(Long orderId) { + this.orderId = orderId; + } + + public Long getFoodId() { + return foodId; + } + + public void setFoodId(Long foodId) { + this.foodId = foodId; + } + + @Override + public int hashCode() { + return Objects.hash( + Optional.ofNullable(orderId).orElse(0L), + Optional.ofNullable(foodId).orElse(0L)); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + OrderFoodId other = (OrderFoodId) obj; + return Objects.equals(orderId, other.orderId) + && Objects.equals(foodId, other.foodId); + } + +} diff --git a/src/main/java/com/example/demo/types/api/TypeController.java b/src/main/java/com/example/backend/types/api/TypeController.java similarity index 88% rename from src/main/java/com/example/demo/types/api/TypeController.java rename to src/main/java/com/example/backend/types/api/TypeController.java index 81f07cf..d4c2f74 100644 --- a/src/main/java/com/example/demo/types/api/TypeController.java +++ b/src/main/java/com/example/backend/types/api/TypeController.java @@ -1,4 +1,4 @@ -package com.example.demo.types.api; +package com.example.backend.types.api; import java.util.List; @@ -12,9 +12,9 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.example.demo.core.configuration.Constants; -import com.example.demo.types.model.TypeEntity; -import com.example.demo.types.service.TypeService; +import com.example.backend.core.configuration.Constants; +import com.example.backend.types.model.TypeEntity; +import com.example.backend.types.service.TypeService; import jakarta.validation.Valid; @@ -53,7 +53,7 @@ public class TypeController { } @PutMapping("/{id}") - public TypeDto update(@PathVariable(name = "id") Long id, @RequestBody TypeDto dto) { + public TypeDto update(@PathVariable(name = "id") Long id, @RequestBody @Valid TypeDto dto) { return toDto(typeService.update(id, toEntity(dto))); } diff --git a/src/main/java/com/example/demo/types/api/TypeDto.java b/src/main/java/com/example/backend/types/api/TypeDto.java similarity index 81% rename from src/main/java/com/example/demo/types/api/TypeDto.java rename to src/main/java/com/example/backend/types/api/TypeDto.java index c559680..48df7cd 100644 --- a/src/main/java/com/example/demo/types/api/TypeDto.java +++ b/src/main/java/com/example/backend/types/api/TypeDto.java @@ -1,15 +1,17 @@ -package com.example.demo.types.api; +package com.example.backend.types.api; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; public class TypeDto { + @JsonProperty(access = JsonProperty.Access.READ_ONLY) private Long id; @NotBlank + @Size(min = 3, max = 50) private String name; - @JsonProperty(access = JsonProperty.Access.READ_ONLY) public Long getId() { return id; } diff --git a/src/main/java/com/example/demo/types/model/TypeEntity.java b/src/main/java/com/example/backend/types/model/TypeEntity.java similarity index 69% rename from src/main/java/com/example/demo/types/model/TypeEntity.java rename to src/main/java/com/example/backend/types/model/TypeEntity.java index fd90bdb..be563e6 100644 --- a/src/main/java/com/example/demo/types/model/TypeEntity.java +++ b/src/main/java/com/example/backend/types/model/TypeEntity.java @@ -1,18 +1,23 @@ -package com.example.demo.types.model; +package com.example.backend.types.model; import java.util.Objects; -import com.example.demo.core.model.BaseEntity; +import com.example.backend.core.model.BaseEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; + +@Entity +@Table(name = "categories") public class TypeEntity extends BaseEntity { + @Column(nullable = false, unique = true, length = 50) private String name; public TypeEntity() { - super(); } - public TypeEntity(Long id, String name) { - super(id); + public TypeEntity(String name) { this.name = name; } diff --git a/src/main/java/com/example/backend/types/repository/TypeRepository.java b/src/main/java/com/example/backend/types/repository/TypeRepository.java new file mode 100644 index 0000000..5ced5c2 --- /dev/null +++ b/src/main/java/com/example/backend/types/repository/TypeRepository.java @@ -0,0 +1,11 @@ +package com.example.backend.types.repository; + +import java.util.Optional; + +import org.springframework.data.repository.CrudRepository; + +import com.example.backend.types.model.TypeEntity; + +public interface TypeRepository extends CrudRepository { + Optional findByNameIgnoreCase(String name); +} diff --git a/src/main/java/com/example/backend/types/service/TypeService.java b/src/main/java/com/example/backend/types/service/TypeService.java new file mode 100644 index 0000000..8782e6e --- /dev/null +++ b/src/main/java/com/example/backend/types/service/TypeService.java @@ -0,0 +1,61 @@ +package com.example.backend.types.service; + +import java.util.List; +import java.util.stream.StreamSupport; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.example.backend.core.error.NotFoundException; +import com.example.backend.types.model.TypeEntity; +import com.example.backend.types.repository.TypeRepository; + +@Service +public class TypeService { + private final TypeRepository repository; + + public TypeService(TypeRepository repository) { + this.repository = repository; + } + + private void checkName(String name) { + if (repository.findByNameIgnoreCase(name).isPresent()) { + throw new IllegalArgumentException( + String.format("Type with name %s is already exists", name)); + } + } + + @Transactional(readOnly = true) + public List getAll() { + return StreamSupport.stream(repository.findAll().spliterator(), false).toList(); + } + + @Transactional(readOnly = true) + public TypeEntity get(long id) { + return repository.findById(id) + .orElseThrow(() -> new NotFoundException(TypeEntity.class, id)); + } + + @Transactional + public TypeEntity create(TypeEntity entity) { + if (entity == null) { + throw new IllegalArgumentException("Entity is null"); + } + checkName(entity.getName()); + return repository.save(entity); + } + + @Transactional + public TypeEntity update(long id, TypeEntity entity) { + final TypeEntity existsEntity = get(id); + existsEntity.setName(entity.getName()); + return repository.save(existsEntity); + } + + @Transactional + public TypeEntity delete(long id) { + final TypeEntity existsEntity = get(id); + repository.delete(existsEntity); + return existsEntity; + } +} diff --git a/src/main/java/com/example/demo/users/api/UserController.java b/src/main/java/com/example/backend/users/api/UserController.java similarity index 71% rename from src/main/java/com/example/demo/users/api/UserController.java rename to src/main/java/com/example/backend/users/api/UserController.java index f330d2f..b1a1515 100644 --- a/src/main/java/com/example/demo/users/api/UserController.java +++ b/src/main/java/com/example/backend/users/api/UserController.java @@ -1,6 +1,4 @@ -package com.example.demo.users.api; - -import java.util.List; +package com.example.backend.users.api; import org.modelmapper.ModelMapper; import org.springframework.web.bind.annotation.DeleteMapping; @@ -10,11 +8,14 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import com.example.demo.users.model.UserEntity; -import com.example.demo.users.service.UserService; -import com.example.demo.core.configuration.Constants; +import com.example.backend.core.api.PageDto; +import com.example.backend.core.api.PageDtoMapper; +import com.example.backend.users.model.UserEntity; +import com.example.backend.users.service.UserService; +import com.example.backend.core.configuration.Constants; import jakarta.validation.Valid; @@ -38,8 +39,10 @@ public class UserController { } @GetMapping - public List getAll() { - return userService.getAll().stream().map(this::toDto).toList(); + public PageDto getAll( + @RequestParam(name = "page", defaultValue = "0") int page, + @RequestParam(name = "size", defaultValue = Constants.DEFAULT_PAGE_SIZE) int size) { + return PageDtoMapper.toDto(userService.getAll(page, size), this::toDto); } @GetMapping("/{id}") @@ -53,7 +56,7 @@ public class UserController { } @PutMapping("/{id}") - public UserDto update(@PathVariable(name = "id") Long id, @RequestBody UserDto dto) { + public UserDto update(@PathVariable(name = "id") Long id, @RequestBody @Valid UserDto dto) { return toDto(userService.update(id, toEntity(dto))); } diff --git a/src/main/java/com/example/demo/users/api/UserDto.java b/src/main/java/com/example/backend/users/api/UserDto.java similarity index 57% rename from src/main/java/com/example/demo/users/api/UserDto.java rename to src/main/java/com/example/backend/users/api/UserDto.java index f4b49fe..414fc24 100644 --- a/src/main/java/com/example/demo/users/api/UserDto.java +++ b/src/main/java/com/example/backend/users/api/UserDto.java @@ -1,22 +1,26 @@ -package com.example.demo.users.api; +package com.example.backend.users.api; import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; public class UserDto { + @JsonProperty(access = JsonProperty.Access.READ_ONLY) private Long id; @NotBlank - private String name; + @Size(min = 3, max = 20) + private String login; @NotBlank + @Size(min = 5, max = 254) private String email; @NotBlank + @Size(min = 6, max = 16) private String password; - @NotNull - private Boolean isAdmin; + @NotBlank + @Size(min = 1, max = 20) + private String accessLevel; - @JsonProperty(access = JsonProperty.Access.READ_ONLY) public Long getId() { return id; } @@ -25,12 +29,12 @@ public class UserDto { this.id = id; } - public String getName() { - return name; + public String getLogin() { + return login; } - public void setName(String name) { - this.name = name; + public void setLogin(String name) { + this.login = name; } public String getEmail() { @@ -49,11 +53,11 @@ public class UserDto { this.password = password; } - public Boolean getIsAdmin() { - return isAdmin; + public String getAccessLevel() { + return accessLevel; } - public void setIsAdmin(Boolean isAdmin) { - this.isAdmin = isAdmin; + public void setAccessLevel(String accessLevel) { + this.accessLevel = accessLevel; } } diff --git a/src/main/java/com/example/backend/users/model/UserEntity.java b/src/main/java/com/example/backend/users/model/UserEntity.java new file mode 100644 index 0000000..5ff6163 --- /dev/null +++ b/src/main/java/com/example/backend/users/model/UserEntity.java @@ -0,0 +1,103 @@ +package com.example.backend.users.model; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OrderBy; +import jakarta.persistence.Table; + +import com.example.backend.core.model.BaseEntity; +import com.example.backend.orders.model.OrderEntity; + +@Entity +@Table(name = "users") +public class UserEntity extends BaseEntity { + @Column(nullable = false, unique = true, length = 20) + private String login; + @Column(nullable = false, unique = true, length = 254) + private String email; + @Column(nullable = false, length = 16) + private String password; + @Column(nullable = false, length = 20) + private String accessLevel; + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) + @OrderBy("id ASC") + private Set orders = new HashSet<>(); + + public UserEntity() { + } + + public UserEntity(String login, String email, String password, String accessLevel) { + this.login = login; + this.email = email; + this.password = password; + this.accessLevel = accessLevel; + } + + public String getLogin() { + return login; + } + + public void setLogin(String name) { + this.login = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getAccessLevel() { + return accessLevel; + } + + public void setAccessLevel(String accessLevel) { + this.accessLevel = accessLevel; + } + + public Set getOrders() { + return orders; + } + + public void addOrder(OrderEntity order) { + if (order.getUser() != this) { + order.setUser(this); + } + orders.add(order); + } + + @Override + public int hashCode() { + return Objects.hash(id, login, email, password, accessLevel); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + UserEntity other = (UserEntity) obj; + return Objects.equals(other.getId(), id) + && Objects.equals(other.getLogin(), login) + && Objects.equals(other.getEmail(), email) + && Objects.equals(other.getPassword(), password) + && Objects.equals(other.getAccessLevel(), accessLevel); + } +} diff --git a/src/main/java/com/example/backend/users/repository/UserRepository.java b/src/main/java/com/example/backend/users/repository/UserRepository.java new file mode 100644 index 0000000..9b74a21 --- /dev/null +++ b/src/main/java/com/example/backend/users/repository/UserRepository.java @@ -0,0 +1,13 @@ +package com.example.backend.users.repository; + +import java.util.Optional; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; + +import com.example.backend.users.model.UserEntity; + +public interface UserRepository + extends CrudRepository, PagingAndSortingRepository { + Optional findByLoginIgnoreCase(String login); +} diff --git a/src/main/java/com/example/backend/users/service/UserService.java b/src/main/java/com/example/backend/users/service/UserService.java new file mode 100644 index 0000000..c41b75d --- /dev/null +++ b/src/main/java/com/example/backend/users/service/UserService.java @@ -0,0 +1,72 @@ +package com.example.backend.users.service; + +import java.util.List; +import java.util.stream.StreamSupport; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.example.backend.users.model.UserEntity; +import com.example.backend.users.repository.UserRepository; +import com.example.backend.core.error.NotFoundException; + +@Service +public class UserService { + private final UserRepository repository; + + public UserService(UserRepository repository) { + this.repository = repository; + } + + private void checkLogin(String login) { + if (repository.findByLoginIgnoreCase(login).isPresent()) { + throw new IllegalArgumentException( + String.format("User with login %s is already exists", login)); + } + } + + @Transactional(readOnly = true) + public List getAll() { + return StreamSupport.stream(repository.findAll().spliterator(), false).toList(); + } + + @Transactional(readOnly = true) + public Page getAll(int page, int size) { + return repository.findAll(PageRequest.of(page, size)); + } + + @Transactional(readOnly = true) + public UserEntity get(long id) { + return repository.findById(id) + .orElseThrow(() -> new NotFoundException(UserEntity.class, id)); + } + + @Transactional + public UserEntity create(UserEntity entity) { + if (entity == null) { + throw new IllegalArgumentException("Entity is null"); + } + checkLogin(entity.getLogin()); + return repository.save(entity); + } + + @Transactional + public UserEntity update(long id, UserEntity entity) { + final UserEntity existsEntity = get(id); + existsEntity.setLogin(entity.getLogin()); + existsEntity.setEmail(entity.getEmail()); + existsEntity.setPassword(entity.getPassword()); + existsEntity.setAccessLevel(entity.getAccessLevel()); + repository.save(existsEntity); + return existsEntity; + } + + @Transactional + public UserEntity delete(long id) { + final UserEntity existsEntity = get(id); + repository.delete(existsEntity); + return existsEntity; + } +} diff --git a/src/main/java/com/example/demo/DemoApplication.java b/src/main/java/com/example/demo/DemoApplication.java deleted file mode 100644 index 39a6d78..0000000 --- a/src/main/java/com/example/demo/DemoApplication.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.example.demo; - -import java.util.Objects; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.CommandLineRunner; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -import com.example.demo.foods.model.FoodEntity; -import com.example.demo.foods.service.FoodService; -import com.example.demo.types.model.TypeEntity; -import com.example.demo.types.service.TypeService; -import com.example.demo.core.utils.Formatter; -import com.example.demo.users.model.UserEntity; -import com.example.demo.users.service.UserService; -import com.example.demo.orders.model.OrderEntity; -import com.example.demo.orders.service.OrderService; -import com.example.demo.ordersfoods.model.OrderFoodEntity; -import com.example.demo.ordersfoods.service.OrderFoodService; - -@SpringBootApplication -public class DemoApplication implements CommandLineRunner { - private final Logger log = LoggerFactory.getLogger(DemoApplication.class); - - private final TypeService typeService; - private final FoodService foodService; - private final UserService userService; - private final OrderService orderService; - private final OrderFoodService orderFoodService; - - public DemoApplication(TypeService typeService, FoodService foodService, UserService userService, - OrderService orderService, OrderFoodService orderFoodService) { - this.typeService = typeService; - this.foodService = foodService; - this.userService = userService; - this.orderService = orderService; - this.orderFoodService = orderFoodService; - } - - public static void main(String[] args) { - SpringApplication.run(DemoApplication.class, args); - } - - @Override - public void run(String... args) throws Exception { - if (args.length > 0 && Objects.equals("--populate", args[0])) { - log.info("Create default types values"); - final var type1 = typeService.create(new TypeEntity(null, "Бургер")); - final var type2 = typeService.create(new TypeEntity(null, "Напиток")); - final var type3 = typeService.create(new TypeEntity(null, "Салат")); - - log.info("Create default foods values"); - final var food1 = foodService - .create(new FoodEntity(null, type1, 145.00, "Греческий бургер", Formatter.parse("2021-10-11"), 10)); - final var food2 = foodService - .create(new FoodEntity(null, type2, 99.00, "Кола", Formatter.parse("2021-10-11"), 40)); - final var food3 = foodService - .create(new FoodEntity(null, type3, 199.00, "Японский салат", Formatter.parse("2021-10-11"), 4)); - final var food4 = foodService.create( - new FoodEntity(null, type1, 299.00, "Бургер с говядиной", Formatter.parse("2021-10-11"), 3)); - final var food5 = foodService - .create(new FoodEntity(null, type3, 109.00, "Греческий салат", Formatter.parse("2021-10-11"), 24)); - log.info("Create default users values"); - final var user1 = userService - .create(new UserEntity(null, "Chief", "forum98761@gmail.com", "bth4323", true)); - final var user2 = userService - .create(new UserEntity(null, "Dude23", "ovalinartem25@gmail.com", "dsre32462", false)); - final var user3 = userService - .create(new UserEntity(null, "TestUser", "user53262@gmail.com", "lawy7728", false)); - - log.info("Create default orders values"); - final var order1 = orderService - .create(new OrderEntity(null, user1, Formatter.parse("2024-03-28"), "Выполняется")); - final var order2 = orderService - .create(new OrderEntity(null, user2, Formatter.parse("2022-09-07"), "Выдан")); - final var order3 = orderService - .create(new OrderEntity(null, user3, Formatter.parse("2024-03-15"), "Готов")); - - log.info("Create default ordersFoods values"); - orderFoodService.create(new OrderFoodEntity(null, order1, food1, 4)); - orderFoodService.create(new OrderFoodEntity(null, order1, food3, 1)); - orderFoodService.create(new OrderFoodEntity(null, order1, food4, 2)); - orderFoodService.create(new OrderFoodEntity(null, order2, food2, 1)); - orderFoodService.create(new OrderFoodEntity(null, order2, food5, 1)); - orderFoodService.create(new OrderFoodEntity(null, order3, food3, 3)); - } - } -} diff --git a/src/main/java/com/example/demo/core/configuration/Constants.java b/src/main/java/com/example/demo/core/configuration/Constants.java deleted file mode 100644 index d9c6b7c..0000000 --- a/src/main/java/com/example/demo/core/configuration/Constants.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.example.demo.core.configuration; - -public class Constants { - public static final String API_URL = "/api/1.0"; - - private Constants() { - } -} diff --git a/src/main/java/com/example/demo/core/configuration/MapperConfiguration.java b/src/main/java/com/example/demo/core/configuration/MapperConfiguration.java deleted file mode 100644 index a5ad6f3..0000000 --- a/src/main/java/com/example/demo/core/configuration/MapperConfiguration.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.example.demo.core.configuration; - -import org.modelmapper.ModelMapper; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class MapperConfiguration { - @Bean - ModelMapper modelMapper() { - return new ModelMapper(); - } -} diff --git a/src/main/java/com/example/demo/core/error/NotFoundException.java b/src/main/java/com/example/demo/core/error/NotFoundException.java deleted file mode 100644 index 586af3c..0000000 --- a/src/main/java/com/example/demo/core/error/NotFoundException.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.example.demo.core.error; - -public class NotFoundException extends RuntimeException { - public NotFoundException(Long id) { - super(String.format("Entity with id [%s] is not found or not exists", id)); - } -} diff --git a/src/main/java/com/example/demo/core/model/BaseEntity.java b/src/main/java/com/example/demo/core/model/BaseEntity.java deleted file mode 100644 index 674ddfb..0000000 --- a/src/main/java/com/example/demo/core/model/BaseEntity.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.example.demo.core.model; - -public abstract class BaseEntity { - protected Long id; - - protected BaseEntity() { - } - - protected BaseEntity(Long id) { - this.id = id; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } -} diff --git a/src/main/java/com/example/demo/core/repository/CommonRepository.java b/src/main/java/com/example/demo/core/repository/CommonRepository.java deleted file mode 100644 index 85e1e6d..0000000 --- a/src/main/java/com/example/demo/core/repository/CommonRepository.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.example.demo.core.repository; - -import java.util.List; - -public interface CommonRepository { - List getAll(); - - E get(T id); - - E create(E entity); - - E update(E entity); - - E delete(E entity); - - void deleteAll(); -} diff --git a/src/main/java/com/example/demo/core/repository/MapRepository.java b/src/main/java/com/example/demo/core/repository/MapRepository.java deleted file mode 100644 index 6809ac2..0000000 --- a/src/main/java/com/example/demo/core/repository/MapRepository.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.example.demo.core.repository; - -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -import com.example.demo.core.model.BaseEntity; - -public abstract class MapRepository implements CommonRepository { - private final Map entities = new TreeMap<>(); - private Long lastId = 0L; - - protected MapRepository() { - } - - @Override - public List getAll() { - return entities.values().stream().toList(); - } - - @Override - public E get(Long id) { - return entities.get(id); - } - - @Override - public E create(E entity) { - lastId++; - entity.setId(lastId); - entities.put(lastId, entity); - return entity; - } - - @Override - public E update(E entity) { - if (get(entity.getId()) == null) { - return null; - } - entities.put(entity.getId(), entity); - return entity; - } - - @Override - public E delete(E entity) { - if (get(entity.getId()) == null) { - return null; - } - entities.remove(entity.getId()); - return entity; - } - - @Override - public void deleteAll() { - lastId = 0L; - entities.clear(); - } -} diff --git a/src/main/java/com/example/demo/foods/repository/FoodRepository.java b/src/main/java/com/example/demo/foods/repository/FoodRepository.java deleted file mode 100644 index bce9b8f..0000000 --- a/src/main/java/com/example/demo/foods/repository/FoodRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.example.demo.foods.repository; - -import org.springframework.stereotype.Repository; - -import com.example.demo.core.repository.MapRepository; -import com.example.demo.foods.model.FoodEntity; - -@Repository -public class FoodRepository extends MapRepository { -} diff --git a/src/main/java/com/example/demo/foods/service/FoodService.java b/src/main/java/com/example/demo/foods/service/FoodService.java deleted file mode 100644 index 1db7563..0000000 --- a/src/main/java/com/example/demo/foods/service/FoodService.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.example.demo.foods.service; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -import org.springframework.stereotype.Service; - -import com.example.demo.core.error.NotFoundException; -import com.example.demo.foods.model.FoodEntity; -import com.example.demo.foods.repository.FoodRepository; - -@Service -public class FoodService { - private final FoodRepository repository; - - public FoodService(FoodRepository repository) { - this.repository = repository; - } - - public List getAll(Long typeId) { - if (Objects.equals(typeId, 0L)) { - return repository.getAll(); - } - return repository.getAll().stream() - .filter(item -> item.getType().getId().equals(typeId)) - .toList(); - } - - public FoodEntity get(Long id) { - return Optional.ofNullable(repository.get(id)) - .orElseThrow(() -> new NotFoundException(id)); - } - - public FoodEntity create(FoodEntity entity) { - return repository.create(entity); - } - - public FoodEntity update(Long id, FoodEntity entity) { - final FoodEntity existsEntity = get(id); - existsEntity.setType(entity.getType()); - existsEntity.setPrice(entity.getPrice()); - existsEntity.setDate(entity.getDate()); - existsEntity.setCount(entity.getCount()); - return repository.update(existsEntity); - } - - public FoodEntity delete(Long id) { - final FoodEntity existsEntity = get(id); - return repository.delete(existsEntity); - } -} diff --git a/src/main/java/com/example/demo/orders/api/OrderController.java b/src/main/java/com/example/demo/orders/api/OrderController.java deleted file mode 100644 index d55e68e..0000000 --- a/src/main/java/com/example/demo/orders/api/OrderController.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.example.demo.orders.api; - -import java.text.ParseException; -import java.util.List; - -import org.modelmapper.ModelMapper; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import com.example.demo.orders.model.OrderEntity; -import com.example.demo.orders.service.OrderService; -import com.example.demo.ordersfoods.api.OrderFoodDto; -import com.example.demo.ordersfoods.model.OrderFoodEntity; -import com.example.demo.ordersfoods.service.OrderFoodService; -import com.example.demo.users.service.UserService; -import com.example.demo.core.configuration.Constants; -import com.example.demo.core.utils.Formatter; - -import jakarta.validation.Valid; - -@RestController -@RequestMapping(Constants.API_URL + "/order") -public class OrderController { - private final OrderService orderService; - private final UserService userService; - private final ModelMapper modelMapper; - private final OrderFoodService orderFoodService; - - public OrderController(OrderService orderService, UserService userService, ModelMapper modelMapper, - OrderFoodService orderFoodService) { - this.orderService = orderService; - this.userService = userService; - this.modelMapper = modelMapper; - this.orderFoodService = orderFoodService; - } - - private OrderFoodDto toFoodDto(OrderFoodEntity entity) { - return modelMapper.map(entity, OrderFoodDto.class); - } - - private OrderDto toDto(OrderEntity entity) { - final OrderDto dto = modelMapper.map(entity, OrderDto.class); - dto.setDate(Formatter.format(entity.getDate())); - dto.setSum(orderService.getFullSum(entity.getId())); - dto.setFoods(orderFoodService.getAll(entity.getId(), 0L).stream().map(this::toFoodDto).toList()); - return dto; - } - - private OrderEntity toEntity(OrderDto dto) throws ParseException { - final OrderEntity entity = modelMapper.map(dto, OrderEntity.class); - entity.setUser(userService.get(dto.getUserId())); - entity.setDate(Formatter.parse(dto.getDate())); - return entity; - } - - @GetMapping - public List getAll(@RequestParam(name = "userId", defaultValue = "0") Long userId) { - return orderService.getAll(userId).stream().map(this::toDto).toList(); - } - - @GetMapping("/{id}") - public OrderDto get(@PathVariable(name = "id") Long id) { - return toDto(orderService.get(id)); - } - - @PostMapping - public OrderDto create(@RequestBody @Valid OrderDto dto) throws ParseException { - return toDto(orderService.create(toEntity(dto))); - } - - @PutMapping("/{id}") - public OrderDto update(@PathVariable(name = "id") Long id, @RequestBody OrderDto dto) throws ParseException { - return toDto(orderService.update(id, toEntity(dto))); - } - - @DeleteMapping("/{id}") - public OrderDto delete(@PathVariable(name = "id") Long id) { - return toDto(orderService.delete(id)); - } -} diff --git a/src/main/java/com/example/demo/orders/model/OrderEntity.java b/src/main/java/com/example/demo/orders/model/OrderEntity.java deleted file mode 100644 index 99017b4..0000000 --- a/src/main/java/com/example/demo/orders/model/OrderEntity.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.example.demo.orders.model; - -import java.util.Date; -import java.util.Objects; - -import com.example.demo.users.model.UserEntity; -import com.example.demo.core.model.BaseEntity; - -public class OrderEntity extends BaseEntity { - private UserEntity user; - private Date date; - private String status; - - public OrderEntity() { - super(); - } - - public OrderEntity(Long id, UserEntity user, Date date, String status) { - super(id); - this.user = user; - this.date = date; - this.status = status; - } - - public UserEntity getUser() { - return user; - } - - public void setUser(UserEntity user) { - this.user = user; - } - - public Date getDate() { - return date; - } - - public void setDate(Date date) { - this.date = date; - } - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - - @Override - public int hashCode() { - return Objects.hash(id, user, date, status); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null || getClass() != obj.getClass()) - return false; - final OrderEntity other = (OrderEntity) obj; - return Objects.equals(other.getId(), id) - && Objects.equals(other.getUser(), user) - && Objects.equals(other.getDate(), date) - && Objects.equals(other.getStatus(), status); - } -} diff --git a/src/main/java/com/example/demo/orders/repository/OrderRepository.java b/src/main/java/com/example/demo/orders/repository/OrderRepository.java deleted file mode 100644 index ec00c20..0000000 --- a/src/main/java/com/example/demo/orders/repository/OrderRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.example.demo.orders.repository; - -import org.springframework.stereotype.Repository; - -import com.example.demo.orders.model.OrderEntity; -import com.example.demo.core.repository.MapRepository; - -@Repository -public class OrderRepository extends MapRepository { -} diff --git a/src/main/java/com/example/demo/orders/service/OrderService.java b/src/main/java/com/example/demo/orders/service/OrderService.java deleted file mode 100644 index 2dd6592..0000000 --- a/src/main/java/com/example/demo/orders/service/OrderService.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.example.demo.orders.service; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -import org.springframework.stereotype.Service; - -import com.example.demo.orders.model.OrderEntity; -import com.example.demo.orders.repository.OrderRepository; -import com.example.demo.ordersfoods.service.OrderFoodService; -import com.example.demo.core.error.NotFoundException; - -@Service -public class OrderService { - private final OrderRepository repository; - private final OrderFoodService orderFoodService; - - public OrderService(OrderRepository repository, OrderFoodService orderFoodService) { - this.repository = repository; - this.orderFoodService = orderFoodService; - } - - public List getAll(Long userId) { - if (Objects.equals(userId, 0L)) { - return repository.getAll(); - } - return repository.getAll().stream() - .filter(order -> order.getUser().getId().equals(userId)) - .toList(); - } - - public OrderEntity get(Long id) { - return Optional.ofNullable(repository.get(id)) - .orElseThrow(() -> new NotFoundException(id)); - } - - public OrderEntity create(OrderEntity entity) { - return repository.create(entity); - } - - public OrderEntity update(Long id, OrderEntity entity) { - final OrderEntity existsEntity = get(id); - existsEntity.setUser(entity.getUser()); - existsEntity.setDate(entity.getDate()); - existsEntity.setStatus(entity.getStatus()); - return repository.update(existsEntity); - } - - public OrderEntity delete(Long id) { - final OrderEntity existsEntity = get(id); - return repository.delete(existsEntity); - } - - public Double getFullSum(Long id) { - return orderFoodService.getAll(id, 0L).stream() - .mapToDouble(orderFood -> orderFoodService.getSum(orderFood.getId())) - .sum(); - } -} diff --git a/src/main/java/com/example/demo/ordersfoods/api/OrderFoodController.java b/src/main/java/com/example/demo/ordersfoods/api/OrderFoodController.java deleted file mode 100644 index d28b009..0000000 --- a/src/main/java/com/example/demo/ordersfoods/api/OrderFoodController.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.example.demo.ordersfoods.api; - -import java.util.List; - -import org.modelmapper.ModelMapper; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import com.example.demo.ordersfoods.model.OrderFoodEntity; -import com.example.demo.ordersfoods.service.OrderFoodService; -import com.example.demo.orders.service.OrderService; -import com.example.demo.foods.service.FoodService; -import com.example.demo.core.configuration.Constants; - -import jakarta.validation.Valid; - -@RestController -@RequestMapping(Constants.API_URL + "/orderfood") -public class OrderFoodController { - private final OrderFoodService orderFoodService; - private final OrderService orderService; - private final FoodService foodService; - private final ModelMapper modelMapper; - - public OrderFoodController(OrderFoodService orderFoodService, OrderService orderService, FoodService foodService, - ModelMapper modelMapper) { - this.orderFoodService = orderFoodService; - this.orderService = orderService; - this.foodService = foodService; - this.modelMapper = modelMapper; - } - - private OrderFoodDto toDto(OrderFoodEntity entity) { - return modelMapper.map(entity, OrderFoodDto.class); - } - - private OrderFoodEntity toEntity(OrderFoodDto dto) { - final OrderFoodEntity entity = modelMapper.map(dto, OrderFoodEntity.class); - entity.setOrder(orderService.get(dto.getOrderId())); - entity.setFood(foodService.get(dto.getFoodId())); - return entity; - } - - @GetMapping - public List getAll(@RequestParam(name = "orderId", defaultValue = "0") Long orderId, - @RequestParam(name = "foodId", defaultValue = "0") Long foodId) { - return orderFoodService.getAll(orderId, foodId).stream().map(this::toDto).toList(); - } - - @GetMapping("/{id}") - public OrderFoodDto get(@PathVariable(name = "id") Long id) { - return toDto(orderFoodService.get(id)); - } - - @PostMapping - public OrderFoodDto create(@RequestBody @Valid OrderFoodDto dto) { - return toDto(orderFoodService.create(toEntity(dto))); - } - - @PutMapping("/{id}") - public OrderFoodDto update(@PathVariable(name = "id") Long id, @RequestBody OrderFoodDto dto) { - return toDto(orderFoodService.update(id, toEntity(dto))); - } - - @DeleteMapping("/{id}") - public OrderFoodDto delete(@PathVariable(name = "id") Long id) { - return toDto(orderFoodService.delete(id)); - } -} diff --git a/src/main/java/com/example/demo/ordersfoods/api/OrderFoodDto.java b/src/main/java/com/example/demo/ordersfoods/api/OrderFoodDto.java deleted file mode 100644 index 8e0da40..0000000 --- a/src/main/java/com/example/demo/ordersfoods/api/OrderFoodDto.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.example.demo.ordersfoods.api; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.NotNull; - -public class OrderFoodDto { - private Long id; - @NotNull - @Min(1) - private Long orderId; - @NotNull - @Min(1) - private Long bookId; - @NotNull - @Min(1) - private Integer count; - - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Long getOrderId() { - return orderId; - } - - public void setOrderId(Long orderId) { - this.orderId = orderId; - } - - public Long getFoodId() { - return bookId; - } - - public void setFoodId(Long bookId) { - this.bookId = bookId; - } - - public Integer getCount() { - return count; - } - - public void setCount(Integer count) { - this.count = count; - } -} diff --git a/src/main/java/com/example/demo/ordersfoods/model/OrderFoodEntity.java b/src/main/java/com/example/demo/ordersfoods/model/OrderFoodEntity.java deleted file mode 100644 index b82104a..0000000 --- a/src/main/java/com/example/demo/ordersfoods/model/OrderFoodEntity.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.example.demo.ordersfoods.model; - -import java.util.Objects; - -import com.example.demo.foods.model.FoodEntity; -import com.example.demo.orders.model.OrderEntity; -import com.example.demo.core.model.BaseEntity; - -public class OrderFoodEntity extends BaseEntity { - private OrderEntity order; - private FoodEntity food; - private Integer count; - - public OrderFoodEntity() { - super(); - } - - public OrderFoodEntity(Long id, OrderEntity order, FoodEntity food, Integer count) { - super(id); - this.order = order; - this.food = food; - this.count = count; - } - - public OrderEntity getOrder() { - return order; - } - - public void setOrder(OrderEntity order) { - this.order = order; - } - - public FoodEntity getFood() { - return food; - } - - public void setFood(FoodEntity food) { - this.food = food; - } - - public Integer getCount() { - return count; - } - - public void setCount(Integer count) { - this.count = count; - } - - @Override - public int hashCode() { - return Objects.hash(id, order, food, count); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null || getClass() != obj.getClass()) - return false; - final OrderFoodEntity other = (OrderFoodEntity) obj; - return Objects.equals(other.getId(), id) - && Objects.equals(other.getOrder(), order) - && Objects.equals(other.getFood(), food) - && Objects.equals(other.getCount(), count); - } -} diff --git a/src/main/java/com/example/demo/ordersfoods/repository/OrderFoodRepository.java b/src/main/java/com/example/demo/ordersfoods/repository/OrderFoodRepository.java deleted file mode 100644 index 2642d53..0000000 --- a/src/main/java/com/example/demo/ordersfoods/repository/OrderFoodRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.example.demo.ordersfoods.repository; - -import org.springframework.stereotype.Repository; - -import com.example.demo.core.repository.MapRepository; -import com.example.demo.ordersfoods.model.OrderFoodEntity; - -@Repository -public class OrderFoodRepository extends MapRepository { -} diff --git a/src/main/java/com/example/demo/ordersfoods/service/OrderFoodService.java b/src/main/java/com/example/demo/ordersfoods/service/OrderFoodService.java deleted file mode 100644 index 9e885f6..0000000 --- a/src/main/java/com/example/demo/ordersfoods/service/OrderFoodService.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.example.demo.ordersfoods.service; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -import org.springframework.stereotype.Service; - -import com.example.demo.core.error.NotFoundException; -import com.example.demo.ordersfoods.model.OrderFoodEntity; -import com.example.demo.ordersfoods.repository.OrderFoodRepository; - -@Service -public class OrderFoodService { - private final OrderFoodRepository repository; - - public OrderFoodService(OrderFoodRepository repository) { - this.repository = repository; - } - - public List getAll(Long orderId, Long foodId) { - if (Objects.equals(orderId, 0L) && Objects.equals(foodId, 0L)) { - return repository.getAll(); - } - return repository.getAll().stream() - .filter(order -> order.getOrder().getId().equals(orderId) || order.getFood().getId().equals(foodId)) - .toList(); - } - - public OrderFoodEntity get(Long id) { - return Optional.ofNullable(repository.get(id)) - .orElseThrow(() -> new NotFoundException(id)); - } - - public OrderFoodEntity create(OrderFoodEntity entity) { - return repository.create(entity); - } - - public OrderFoodEntity update(Long id, OrderFoodEntity entity) { - final OrderFoodEntity existsEntity = get(id); - existsEntity.setOrder(entity.getOrder()); - existsEntity.setFood(entity.getFood()); - existsEntity.setCount(entity.getCount()); - return repository.update(existsEntity); - } - - public OrderFoodEntity delete(Long id) { - final OrderFoodEntity existsEntity = get(id); - return repository.delete(existsEntity); - } - - public Double getSum(Long id) { - final OrderFoodEntity entity = get(id); - return entity.getCount() * entity.getFood().getPrice(); - } -} diff --git a/src/main/java/com/example/demo/types/repository/TypeRepository.java b/src/main/java/com/example/demo/types/repository/TypeRepository.java deleted file mode 100644 index 1c29ea2..0000000 --- a/src/main/java/com/example/demo/types/repository/TypeRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.example.demo.types.repository; - -import org.springframework.stereotype.Repository; - -import com.example.demo.core.repository.MapRepository; -import com.example.demo.types.model.TypeEntity; - -@Repository -public class TypeRepository extends MapRepository { -} diff --git a/src/main/java/com/example/demo/types/service/TypeService.java b/src/main/java/com/example/demo/types/service/TypeService.java deleted file mode 100644 index e71b030..0000000 --- a/src/main/java/com/example/demo/types/service/TypeService.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.example.demo.types.service; - -import java.util.List; -import java.util.Optional; - -import org.springframework.stereotype.Service; - -import com.example.demo.core.error.NotFoundException; -import com.example.demo.types.model.TypeEntity; -import com.example.demo.types.repository.TypeRepository; - -@Service -public class TypeService { - private final TypeRepository repository; - - public TypeService(TypeRepository repository) { - this.repository = repository; - } - - public List getAll() { - return repository.getAll(); - } - - public TypeEntity get(Long id) { - return Optional.ofNullable(repository.get(id)) - .orElseThrow(() -> new NotFoundException(id)); - } - - public TypeEntity create(TypeEntity entity) { - return repository.create(entity); - } - - public TypeEntity update(Long id, TypeEntity entity) { - final TypeEntity existsEntity = get(id); - existsEntity.setName(entity.getName()); - return repository.update(existsEntity); - } - - public TypeEntity delete(Long id) { - final TypeEntity existsEntity = get(id); - return repository.delete(existsEntity); - } -} diff --git a/src/main/java/com/example/demo/users/model/UserEntity.java b/src/main/java/com/example/demo/users/model/UserEntity.java deleted file mode 100644 index 2f37c95..0000000 --- a/src/main/java/com/example/demo/users/model/UserEntity.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.example.demo.users.model; - -import java.util.Objects; - -import com.example.demo.core.model.BaseEntity; - -public class UserEntity extends BaseEntity { - private String name; - private String email; - private String password; - private Boolean isAdmin; - - public UserEntity() { - super(); - } - - public UserEntity(Long id, String name, String email, String password, Boolean isAdmin) { - super(id); - this.name = name; - this.email = email; - this.password = password; - this.isAdmin = isAdmin; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public Boolean getIsAdmin() { - return isAdmin; - } - - public void setIsAdmin(Boolean isAdmin) { - this.isAdmin = isAdmin; - } - - @Override - public int hashCode() { - return Objects.hash(id, name, email, password, isAdmin); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null || getClass() != obj.getClass()) - return false; - final UserEntity other = (UserEntity) obj; - return Objects.equals(other.getId(), id) - && Objects.equals(other.getName(), name) - && Objects.equals(other.getEmail(), email) - && Objects.equals(other.getPassword(), password) - && Objects.equals(other.getIsAdmin(), isAdmin); - } -} diff --git a/src/main/java/com/example/demo/users/repository/UserRepository.java b/src/main/java/com/example/demo/users/repository/UserRepository.java deleted file mode 100644 index fa4b654..0000000 --- a/src/main/java/com/example/demo/users/repository/UserRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.example.demo.users.repository; - -import org.springframework.stereotype.Repository; - -import com.example.demo.core.repository.MapRepository; -import com.example.demo.users.model.UserEntity; - -@Repository -public class UserRepository extends MapRepository { -} diff --git a/src/main/java/com/example/demo/users/service/UserService.java b/src/main/java/com/example/demo/users/service/UserService.java deleted file mode 100644 index df2e096..0000000 --- a/src/main/java/com/example/demo/users/service/UserService.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.example.demo.users.service; - -import java.util.List; -import java.util.Optional; - -import org.springframework.stereotype.Service; - -import com.example.demo.users.model.UserEntity; -import com.example.demo.users.repository.UserRepository; -import com.example.demo.core.error.NotFoundException; - -@Service -public class UserService { - private final UserRepository repository; - - public UserService(UserRepository repository) { - this.repository = repository; - } - - public List getAll() { - return repository.getAll(); - } - - public UserEntity get(Long id) { - return Optional.ofNullable(repository.get(id)) - .orElseThrow(() -> new NotFoundException(id)); - } - - public UserEntity create(UserEntity entity) { - return repository.create(entity); - } - - public UserEntity update(Long id, UserEntity entity) { - final UserEntity existsEntity = get(id); - existsEntity.setName(entity.getName()); - existsEntity.setEmail(entity.getEmail()); - existsEntity.setPassword(entity.getPassword()); - existsEntity.setIsAdmin(entity.getIsAdmin()); - return repository.update(existsEntity); - } - - public UserEntity delete(Long id) { - final UserEntity existsEntity = get(id); - return repository.delete(existsEntity); - } -} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b13789..62ab433 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,20 @@ +# Server +spring.main.banner-mode=off +server.port=8080 +# Logger settings +# Available levels are: TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF +logging.level.com.example.demo=DEBUG + +# JPA Settings +spring.datasource.url=jdbc:h2:file:./data +spring.datasource.username=sa +spring.datasource.password=password +spring.datasource.driver-class-name=org.h2.Driver +spring.jpa.hibernate.ddl-auto=create +spring.jpa.open-in-view=false +# spring.jpa.show-sql=true +# spring.jpa.properties.hibernate.format_sql=true + +# H2 console +spring.h2.console.enabled=true \ No newline at end of file diff --git a/src/test/java/com/example/backend/FoodServiceTests.java b/src/test/java/com/example/backend/FoodServiceTests.java new file mode 100644 index 0000000..6b20205 --- /dev/null +++ b/src/test/java/com/example/backend/FoodServiceTests.java @@ -0,0 +1,99 @@ +package com.example.backend; + +import java.text.ParseException; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.transaction.annotation.Transactional; + +import com.example.backend.core.error.NotFoundException; +import com.example.backend.core.utils.Formatter; +import com.example.backend.foods.model.FoodEntity; +import com.example.backend.foods.service.FoodService; +import com.example.backend.types.model.TypeEntity; +import com.example.backend.types.service.TypeService; + +@SpringBootTest +class FoodServiceTests { + @Autowired + private TypeService typeService; + + @Autowired + private FoodService foodService; + + private FoodEntity food; + + @BeforeEach + void createData() throws ParseException { + removeData(); + + final var type1 = typeService.create(new TypeEntity("Бургер")); + final var type2 = typeService.create(new TypeEntity("Шаурма")); + final var type3 = typeService.create(new TypeEntity("Напиток")); + + food = foodService.create(new FoodEntity(type1, "Бургер с ветчиной", + 700.00, Formatter.parse("2021-04-11"), 5624)); + foodService.create(new FoodEntity(type2, "Шаурма с курицей", + 775.00, Formatter.parse("2021-04-11"), 1240)); + foodService.create(new FoodEntity(type3, "Кола", + 977.00, Formatter.parse("2021-04-11"), 635)); + } + + @AfterEach + void removeData() { + foodService.getAll(0L).forEach(item -> foodService.delete(item.getId())); + typeService.getAll().forEach(item -> typeService.delete(item.getId())); + } + + @Test + void getTest() { + Assertions.assertThrows(NotFoundException.class, () -> foodService.get(0L)); + } + + @Transactional + @Test + void createTest() { + Assertions.assertEquals(3, foodService.getAll(0L).size()); + Assertions.assertEquals(food, foodService.get(food.getId())); + } + + @Test + void createNullableTest() throws ParseException { + final FoodEntity nullableFood = new FoodEntity(null, null, + 700.00, Formatter.parse("2021-04-11"), 5624); + Assertions.assertThrows(DataIntegrityViolationException.class, () -> foodService.create(nullableFood)); + } + + @Transactional + @Test + void updateTest() throws ParseException { + final String test = "TEST"; + final TypeEntity newType = typeService.create(new TypeEntity("Детективы")); + final String oldName = food.getName(); + final TypeEntity oldType = food.getType(); + final FoodEntity newEntity = foodService.update(food.getId(), new FoodEntity(newType, test, + 700.00, Formatter.parse("2021-04-11"), 5624)); + Assertions.assertEquals(3, foodService.getAll(0L).size()); + Assertions.assertEquals(newEntity, foodService.get(food.getId())); + Assertions.assertEquals(test, newEntity.getName()); + Assertions.assertEquals(newType, newEntity.getType()); + Assertions.assertNotEquals(oldName, newEntity.getName()); + Assertions.assertNotEquals(oldType, newEntity.getType()); + } + + @Test + void deleteTest() { + foodService.delete(food.getId()); + Assertions.assertEquals(2, foodService.getAll(0L).size()); + + final FoodEntity newEntity = foodService.create(new FoodEntity(food.getType(), food.getName(), + food.getPrice(), food.getDate(), food.getCount())); + Assertions.assertEquals(3, typeService.getAll().size()); + Assertions.assertNotEquals(food.getId(), newEntity.getId()); + } +} diff --git a/src/test/java/com/example/backend/OrderServiceTests.java b/src/test/java/com/example/backend/OrderServiceTests.java new file mode 100644 index 0000000..30898f5 --- /dev/null +++ b/src/test/java/com/example/backend/OrderServiceTests.java @@ -0,0 +1,130 @@ +package com.example.backend; + +import java.text.ParseException; +import java.util.Map; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.transaction.annotation.Transactional; + +import com.example.backend.orders.model.OrderEntity; +import com.example.backend.orders.service.OrderService; +import com.example.backend.types.model.TypeEntity; +import com.example.backend.types.service.TypeService; +import com.example.backend.users.model.UserEntity; +import com.example.backend.users.service.UserService; +import com.example.backend.core.error.NotFoundException; +import com.example.backend.core.utils.Formatter; +import com.example.backend.foods.model.FoodEntity; +import com.example.backend.foods.service.FoodService; + +@SpringBootTest +class OrderServiceTests { + @Autowired + private TypeService typeService; + + @Autowired + private FoodService foodService; + + @Autowired + private UserService userService; + + @Autowired + private OrderService orderService; + + private OrderEntity order; + + private UserEntity user; + + private FoodEntity food1; + private FoodEntity food2; + private FoodEntity food3; + + @BeforeEach + void createData() throws ParseException { + removeData(); + + final var type = typeService.create(new TypeEntity("Бургер")); + food1 = foodService.create(new FoodEntity(type, "Бургер с салатом", + 700.00, Formatter.parse("2021-04-11"), 5624)); + food2 = foodService.create(new FoodEntity(type, "Бургер с говядиной", + 775.00, Formatter.parse("2021-04-11"), 1240)); + food3 = foodService.create(new FoodEntity(type, "Бургер с курицей", + 977.00, Formatter.parse("2021-04-11"), 635)); + user = userService + .create(new UserEntity("Chief", "forum98761@gmail.com", "bth4323", "admin")); + order = orderService + .create(user.getId(), new OrderEntity("Выполняется"), + Map.of(food1.getId(), 3, food2.getId(), 1, food3.getId(), 2)); + orderService + .create(user.getId(), + new OrderEntity("Выдан"), + Map.of(food1.getId(), 5)); + orderService + .create(user.getId(), + new OrderEntity("Готов"), + Map.of(food2.getId(), 1, food3.getId(), 1)); + } + + @AfterEach + void removeData() { + userService.getAll().forEach(item -> userService.delete(item.getId())); + foodService.getAll(0L).forEach(item -> foodService.delete(item.getId())); + typeService.getAll().forEach(item -> typeService.delete(item.getId())); + } + + @Test + void getTest() { + Assertions.assertThrows(NotFoundException.class, () -> orderService.get(user.getId(), 0L)); + } + + @Transactional + @Test + void createTest() { + Assertions.assertEquals(3, orderService.getAll(user.getId()).size()); + Assertions.assertEquals(order, orderService.get(user.getId(), order.getId())); + } + + @Test + void createNullableTest() { + final OrderEntity nullableOrder = new OrderEntity(null); + Assertions.assertThrows(DataIntegrityViolationException.class, + () -> orderService.create(user.getId(), nullableOrder, + Map.of(food1.getId(), 3, food2.getId(), 1, food3.getId(), 2))); + } + + @Test + void deleteTest() { + orderService.delete(user.getId(), order.getId()); + Assertions.assertEquals(2, orderService.getAll(user.getId()).size()); + + final OrderEntity newEntity = orderService.create(user.getId(), + new OrderEntity(order.getStatus()), + Map.of(food1.getId(), 3, food2.getId(), 1, food3.getId(), 2)); + Assertions.assertEquals(3, orderService.getAll(user.getId()).size()); + Assertions.assertNotEquals(order.getId(), newEntity.getId()); + } + + @Test + void getSumTest() { + Double sum = orderService.getSum(user.getId(), order.getId()); + Assertions.assertEquals(food1.getPrice() * 3 + food2.getPrice() + food3.getPrice() * 2, sum); + } + + @Test + void getFullCountTest() { + Integer count = orderService.getFullCount(user.getId(), order.getId()); + Assertions.assertEquals(6, count); + } + + @Transactional + @Test + void getOrderFoodsTest() { + Assertions.assertEquals(3, orderService.getOrderFoods(user.getId(), order.getId()).size()); + } +} diff --git a/src/test/java/com/example/backend/TypeServiceTests.java b/src/test/java/com/example/backend/TypeServiceTests.java new file mode 100644 index 0000000..6f533d0 --- /dev/null +++ b/src/test/java/com/example/backend/TypeServiceTests.java @@ -0,0 +1,79 @@ +package com.example.backend; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.dao.DataIntegrityViolationException; + +import com.example.backend.core.error.NotFoundException; +import com.example.backend.types.model.TypeEntity; +import com.example.backend.types.service.TypeService; + +@SpringBootTest +class TypeServiceTests { + @Autowired + private TypeService typeService; + + private TypeEntity type; + + @BeforeEach + void createData() { + removeData(); + + type = typeService.create(new TypeEntity("Фэнтези")); + typeService.create(new TypeEntity("Художественная литература")); + typeService.create(new TypeEntity("Книги для подростков")); + } + + @AfterEach + void removeData() { + typeService.getAll().forEach(item -> typeService.delete(item.getId())); + } + + @Test + void getTest() { + Assertions.assertThrows(NotFoundException.class, () -> typeService.get(0L)); + } + + @Test + void createTest() { + Assertions.assertEquals(3, typeService.getAll().size()); + Assertions.assertEquals(type, typeService.get(type.getId())); + } + + @Test + void createNotUniqueTest() { + final TypeEntity nonUniqueType = new TypeEntity("Фэнтези"); + Assertions.assertThrows(IllegalArgumentException.class, () -> typeService.create(nonUniqueType)); + } + + @Test + void createNullableTest() { + final TypeEntity nullableType = new TypeEntity(null); + Assertions.assertThrows(DataIntegrityViolationException.class, () -> typeService.create(nullableType)); + } + + @Test + void updateTest() { + final String test = "TEST"; + final String oldName = type.getName(); + final TypeEntity newEntity = typeService.update(type.getId(), new TypeEntity(test)); + Assertions.assertEquals(3, typeService.getAll().size()); + Assertions.assertEquals(newEntity, typeService.get(type.getId())); + Assertions.assertEquals(test, newEntity.getName()); + Assertions.assertNotEquals(oldName, newEntity.getName()); + } + + @Test + void deleteTest() { + typeService.delete(type.getId()); + Assertions.assertEquals(2, typeService.getAll().size()); + + final TypeEntity newEntity = typeService.create(new TypeEntity(type.getName())); + Assertions.assertEquals(3, typeService.getAll().size()); + Assertions.assertNotEquals(type.getId(), newEntity.getId()); + } +} diff --git a/src/test/java/com/example/backend/UserServiceTests.java b/src/test/java/com/example/backend/UserServiceTests.java new file mode 100644 index 0000000..1326825 --- /dev/null +++ b/src/test/java/com/example/backend/UserServiceTests.java @@ -0,0 +1,84 @@ +package com.example.backend; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.transaction.annotation.Transactional; + +import com.example.backend.users.model.UserEntity; +import com.example.backend.users.service.UserService; +import com.example.backend.core.error.NotFoundException; + +@SpringBootTest +class UserServiceTests { + @Autowired + private UserService userService; + + private UserEntity user; + + @BeforeEach + void createData() { + removeData(); + + user = userService.create(new UserEntity("Chief", "forum98761@gmail.com", "bth4323", "admin")); + userService.create(new UserEntity("Dude23", "ovalinartem25@gmail.com", "dsre32462", "user")); + userService.create(new UserEntity("TestUser", "user53262@gmail.com", "lawy7728", "user")); + } + + @AfterEach + void removeData() { + userService.getAll().forEach(item -> userService.delete(item.getId())); + } + + @Test + void getTest() { + Assertions.assertThrows(NotFoundException.class, () -> userService.get(0L)); + } + + @Transactional + @Test + void createTest() { + Assertions.assertEquals(3, userService.getAll().size()); + Assertions.assertEquals(user, userService.get(user.getId())); + } + + @Test + void createNotUniqueTest() { + final UserEntity nonUniqueUser = new UserEntity("Chief", "forum98761@gmail.com", "bth4323", "admin"); + Assertions.assertThrows(IllegalArgumentException.class, () -> userService.create(nonUniqueUser)); + } + + @Test + void createNullableTest() { + final UserEntity nullableUser = new UserEntity(null, "forum98761@gmail.com", "bth4323", "admin"); + Assertions.assertThrows(DataIntegrityViolationException.class, () -> userService.create(nullableUser)); + } + + @Transactional + @Test + void updateTest() { + final String test = "TEST"; + final String oldLogin = user.getLogin(); + final UserEntity newEntity = userService.update(user.getId(), + new UserEntity(test, "forum98761@gmail.com", "bth4323", "admin")); + Assertions.assertEquals(3, userService.getAll().size()); + Assertions.assertEquals(newEntity, userService.get(user.getId())); + Assertions.assertEquals(test, newEntity.getLogin()); + Assertions.assertNotEquals(oldLogin, newEntity.getLogin()); + } + + @Test + void deleteTest() { + userService.delete(user.getId()); + Assertions.assertEquals(2, userService.getAll().size()); + + final UserEntity newEntity = userService + .create(new UserEntity("Chief", "forum98761@gmail.com", "bth4323", "admin")); + Assertions.assertEquals(3, userService.getAll().size()); + Assertions.assertNotEquals(user.getId(), newEntity.getId()); + } +} diff --git a/src/test/java/com/example/demo/FoodServiceTests.java b/src/test/java/com/example/demo/FoodServiceTests.java deleted file mode 100644 index f6014e6..0000000 --- a/src/test/java/com/example/demo/FoodServiceTests.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.example.demo; - -import java.text.ParseException; -import java.text.SimpleDateFormat; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; - -import com.example.demo.core.error.NotFoundException; -import com.example.demo.foods.service.FoodService; -import com.example.demo.types.model.TypeEntity; -import com.example.demo.types.service.TypeService; -import com.example.demo.foods.model.FoodEntity; - -@SpringBootTest -@TestMethodOrder(OrderAnnotation.class) -class FoodServiceTests { - @Autowired - private FoodService foodService; - @Autowired - private TypeService typeService; - - private final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); - - @Test - void getTest() { - Assertions.assertThrows(NotFoundException.class, () -> foodService.get(0L)); - } - - @Test - @Order(1) - void createTest() throws ParseException { - final var type1 = typeService.create(new TypeEntity(null, "Шаурма")); - final var type2 = typeService.create(new TypeEntity(null, "Напиток")); - final var type3 = typeService.create(new TypeEntity(null, "Бургер")); - foodService - .create(new FoodEntity(null, type1, 49999.00, "Бургер с говядиной", formatter.parse("2021-10-11"), 20)); - foodService.create(new FoodEntity(null, type2, 129999.00, "Кола", formatter.parse("2021-10-11"), 3)); - final FoodEntity last = foodService - .create(new FoodEntity(null, type3, 149999.00, "Греческий салат", formatter.parse("2021-11-11"), 5)); - Assertions.assertEquals(3, foodService.getAll(0L).size()); - Assertions.assertEquals(last, foodService.get(3L)); - } - - @Test - @Order(2) - void updateTest() throws ParseException { - final var type3 = typeService.create(new TypeEntity(null, "Бургер")); - final int test = 10; - final FoodEntity entity = foodService.get(3L); - final int oldName = entity.getCount(); - final FoodEntity newEntity = foodService.update(3L, - new FoodEntity(1L, type3, 129999.00, "Греческий бургер", formatter.parse("2021-11-11"), test)); - Assertions.assertEquals(3, foodService.getAll(0L).size()); - Assertions.assertEquals(newEntity, foodService.get(3L)); - Assertions.assertEquals(test, newEntity.getCount()); - Assertions.assertNotEquals(oldName, newEntity.getCount()); - } - - @Test - @Order(3) - void deleteTest() throws ParseException { - foodService.delete(3L); - Assertions.assertEquals(2, foodService.getAll(0L).size()); - final FoodEntity last = foodService.get(2L); - Assertions.assertEquals(2L, last.getId()); - - final var type1 = typeService.create(new TypeEntity(null, "Шаурма")); - - final FoodEntity newEntity = foodService - .create(new FoodEntity(null, type1, 129999.00, "Шаурма с курицей", formatter.parse("2021-10-11"), 3)); - Assertions.assertEquals(3, foodService.getAll(0L).size()); - Assertions.assertEquals(4L, newEntity.getId()); - } -} diff --git a/src/test/java/com/example/demo/OrderFoodServiceTests.java b/src/test/java/com/example/demo/OrderFoodServiceTests.java deleted file mode 100644 index bb1a690..0000000 --- a/src/test/java/com/example/demo/OrderFoodServiceTests.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.example.demo; - -import java.text.ParseException; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; - -import com.example.demo.users.model.UserEntity; -import com.example.demo.users.service.UserService; -import com.example.demo.types.model.TypeEntity; -import com.example.demo.types.service.TypeService; -import com.example.demo.orders.model.OrderEntity; -import com.example.demo.orders.service.OrderService; -import com.example.demo.ordersfoods.model.OrderFoodEntity; -import com.example.demo.ordersfoods.service.OrderFoodService; -import com.example.demo.foods.model.FoodEntity; -import com.example.demo.foods.service.FoodService; -import com.example.demo.core.error.NotFoundException; -import com.example.demo.core.utils.Formatter; - -@SpringBootTest -@TestMethodOrder(OrderAnnotation.class) -class OrderFoodServiceTests { - @Autowired - private UserService userService; - - @Autowired - private TypeService typeService; - - @Autowired - private OrderService orderService; - - @Autowired - private FoodService foodService; - - @Autowired - private OrderFoodService orderFoodService; - - @Test - void getTest() { - Assertions.assertThrows(NotFoundException.class, () -> orderFoodService.get(0L)); - } - - @Test - @Order(1) - void createTest() throws ParseException { - final var type = typeService.create(new TypeEntity(null, "Бургер")); - final var user = userService - .create(new UserEntity(null, "TestUser", "user53262@gmail.com", "lawy7728", false)); - final var order1 = orderService - .create(new OrderEntity(null, user, Formatter.parse("2024-03-28"), "Выполняется")); - final var order2 = orderService - .create(new OrderEntity(null, user, Formatter.parse("2022-09-07"), "Выдан")); - final var food1 = foodService.create(new FoodEntity(null, type, 145.00, "бургер", - Formatter.parse("2021-10-11"), 10)); - final var food2 = foodService.create(new FoodEntity(null, type, 145.00, "Греческий бургер", - Formatter.parse("2021-10-11"), 10)); - - orderFoodService.create(new OrderFoodEntity(null, order1, food1, 4)); - orderFoodService.create(new OrderFoodEntity(null, order1, food2, 1)); - final OrderFoodEntity last = orderFoodService.create(new OrderFoodEntity(null, order2, food1, 2)); - Assertions.assertEquals(3, orderFoodService.getAll(0L, 0L).size()); - Assertions.assertEquals(last, orderFoodService.get(3L)); - } - - @Test - @Order(2) - void updateTest() throws ParseException { - final var type = typeService.create(new TypeEntity(null, "Художественная литература")); - final var user = userService - .create(new UserEntity(null, "TestUser", "user53262@gmail.com", "lawy7728", false)); - final var order1 = orderService - .create(new OrderEntity(null, user, Formatter.parse("2024-03-28"), "Выполняется")); - final var food2 = foodService.create(new FoodEntity(null, type, 145.00, "Греческий бургер", - Formatter.parse("2021-10-11"), 10)); - final Integer newCount = 6; - final OrderFoodEntity entity = orderFoodService.get(3L); - final Integer oldCount = entity.getCount(); - final OrderFoodEntity newEntity = orderFoodService.update(3L, - new OrderFoodEntity(null, order1, food2, newCount)); - Assertions.assertEquals(3, orderFoodService.getAll(0L, 0L).size()); - Assertions.assertEquals(newEntity, orderFoodService.get(3L)); - Assertions.assertEquals(newCount, newEntity.getCount()); - Assertions.assertNotEquals(oldCount, newEntity.getCount()); - } - - @Test - @Order(3) - void deleteTest() throws ParseException { - final var type = typeService.create(new TypeEntity(null, "Художественная литература")); - final var user = userService - .create(new UserEntity(null, "TestUser", "user53262@gmail.com", "lawy7728", false)); - final var order2 = orderService - .create(new OrderEntity(null, user, Formatter.parse("2022-09-07"), "Выдан")); - final var food1 = foodService.create(new FoodEntity(null, type, 145.00, "Греческий бургер", - Formatter.parse("2021-10-11"), 10)); - - orderFoodService.delete(3L); - Assertions.assertEquals(2, orderFoodService.getAll(0L, 0L).size()); - final OrderFoodEntity last = orderFoodService.get(2L); - Assertions.assertEquals(2L, last.getId()); - - final OrderFoodEntity newEntity = orderFoodService.create(new OrderFoodEntity(null, order2, food1, 2)); - Assertions.assertEquals(3, orderFoodService.getAll(0L, 0L).size()); - Assertions.assertEquals(4L, newEntity.getId()); - } -} diff --git a/src/test/java/com/example/demo/OrderServiceTests.java b/src/test/java/com/example/demo/OrderServiceTests.java deleted file mode 100644 index 630f831..0000000 --- a/src/test/java/com/example/demo/OrderServiceTests.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.example.demo; - -import java.text.ParseException; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; - -import com.example.demo.orders.model.OrderEntity; -import com.example.demo.orders.service.OrderService; -import com.example.demo.users.model.UserEntity; -import com.example.demo.users.service.UserService; -import com.example.demo.core.error.NotFoundException; -import com.example.demo.core.utils.Formatter; - -@SpringBootTest -@TestMethodOrder(OrderAnnotation.class) -class OrderServiceTests { - @Autowired - private UserService userService; - - @Autowired - private OrderService orderService; - - @Test - void getTest() { - Assertions.assertThrows(NotFoundException.class, () -> orderService.get(0L)); - } - - @Test - @Order(1) - void createTest() throws ParseException { - final UserEntity user = userService.create( - new UserEntity(null, "TestUser", "user53262@gmail.com", "lawy7728", false)); - - orderService.create(new OrderEntity(null, user, Formatter.parse("2024-03-28"), "Выполняется")); - orderService.create(new OrderEntity(null, user, Formatter.parse("2022-09-07"), "Выдан")); - final OrderEntity last = orderService - .create(new OrderEntity(null, user, Formatter.parse("2024-03-15"), "Готов")); - Assertions.assertEquals(3, orderService.getAll(0L).size()); - Assertions.assertEquals(last, orderService.get(3L)); - } - - @Test - @Order(2) - void updateTest() throws ParseException { - final UserEntity user = userService.create( - new UserEntity(null, "Chief", "forum98761@gmail.com", "bth4323", true)); - final String test = "TEST"; - final OrderEntity entity = orderService.get(3L); - final UserEntity oldUser = entity.getUser(); - final String oldStatus = entity.getStatus(); - final OrderEntity newEntity = orderService.update(3L, - new OrderEntity(null, user, Formatter.parse("2024-03-15"), test)); - Assertions.assertEquals(3, orderService.getAll(0L).size()); - Assertions.assertEquals(newEntity, orderService.get(3L)); - Assertions.assertEquals(test, newEntity.getStatus()); - Assertions.assertEquals(user, newEntity.getUser()); - Assertions.assertNotEquals(oldStatus, newEntity.getStatus()); - Assertions.assertNotEquals(oldUser, newEntity.getUser()); - } - - @Test - @Order(3) - void deleteTest() throws ParseException { - orderService.delete(3L); - Assertions.assertEquals(2, orderService.getAll(0L).size()); - final OrderEntity last = orderService.get(2L); - Assertions.assertEquals(2L, last.getId()); - - final UserEntity user = userService.create( - new UserEntity(null, "TestUser", "user53262@gmail.com", "lawy7728", false)); - final OrderEntity newEntity = orderService.create( - new OrderEntity(null, user, Formatter.parse("2024-03-15"), "Готов")); - Assertions.assertEquals(3, orderService.getAll(0L).size()); - Assertions.assertEquals(4L, newEntity.getId()); - } -} \ No newline at end of file diff --git a/src/test/java/com/example/demo/TypeServiceTests.java b/src/test/java/com/example/demo/TypeServiceTests.java deleted file mode 100644 index 4efde35..0000000 --- a/src/test/java/com/example/demo/TypeServiceTests.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.example.demo; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; - -import com.example.demo.core.error.NotFoundException; -import com.example.demo.types.model.TypeEntity; -import com.example.demo.types.service.TypeService; - -@SpringBootTest -@TestMethodOrder(OrderAnnotation.class) -class TypeServiceTests { - @Autowired - private TypeService typeService; - - @Test - void getTest() { - Assertions.assertThrows(NotFoundException.class, () -> typeService.get(0L)); - } - - @Test - @Order(1) - void createTest() { - typeService.create(new TypeEntity(null, "Шаурма")); - typeService.create(new TypeEntity(null, "Напиток")); - final TypeEntity last = typeService.create(new TypeEntity(null, "Игровая приставка")); - Assertions.assertEquals(3, typeService.getAll().size()); - Assertions.assertEquals(last, typeService.get(3L)); - } - - @Test - @Order(2) - void updateTest() { - final String test = "TEST"; - final TypeEntity entity = typeService.get(3L); - final String oldName = entity.getName(); - final TypeEntity newEntity = typeService.update(3L, new TypeEntity(1L, test)); - Assertions.assertEquals(3, typeService.getAll().size()); - Assertions.assertEquals(newEntity, typeService.get(3L)); - Assertions.assertEquals(test, newEntity.getName()); - Assertions.assertNotEquals(oldName, newEntity.getName()); - } - - @Test - @Order(3) - void deleteTest() { - typeService.delete(3L); - Assertions.assertEquals(2, typeService.getAll().size()); - final TypeEntity last = typeService.get(2L); - Assertions.assertEquals(2L, last.getId()); - - final TypeEntity newEntity = typeService.create(new TypeEntity(null, "Игровая приставка")); - Assertions.assertEquals(3, typeService.getAll().size()); - Assertions.assertEquals(4L, newEntity.getId()); - } -} diff --git a/src/test/java/com/example/demo/UserServiceTests.java b/src/test/java/com/example/demo/UserServiceTests.java deleted file mode 100644 index 1cefe92..0000000 --- a/src/test/java/com/example/demo/UserServiceTests.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.example.demo; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; - -import com.example.demo.users.model.UserEntity; -import com.example.demo.users.service.UserService; -import com.example.demo.core.error.NotFoundException; - -@SpringBootTest -@TestMethodOrder(OrderAnnotation.class) -class UserServiceTests { - @Autowired - private UserService userService; - - @Test - void getTest() { - Assertions.assertThrows(NotFoundException.class, () -> userService.get(0L)); - } - - @Test - @Order(1) - void createTest() { - userService.create(new UserEntity(null, "Chief", "forum98761@gmail.com", "bth4323", true)); - userService.create(new UserEntity(null, "Dude23", "ovalinartem25@gmail.com", "dsre32462", false)); - final UserEntity last = userService.create(new UserEntity(null, "TestUser", "user53262@gmail.com", - "lawy7728", false)); - Assertions.assertEquals(3, userService.getAll().size()); - Assertions.assertEquals(last, userService.get(3L)); - } - - @Test - @Order(2) - void updateTest() { - final String test = "TEST"; - final UserEntity entity = userService.get(3L); - final String oldName = entity.getName(); - final UserEntity newEntity = userService.update(3L, new UserEntity(1L, test, "user53262@gmail.com", - "lawy7728", false)); - Assertions.assertEquals(3, userService.getAll().size()); - Assertions.assertEquals(newEntity, userService.get(3L)); - Assertions.assertEquals(test, newEntity.getName()); - Assertions.assertNotEquals(oldName, newEntity.getName()); - } - - @Test - @Order(3) - void deleteTest() { - userService.delete(3L); - Assertions.assertEquals(2, userService.getAll().size()); - final UserEntity last = userService.get(2L); - Assertions.assertEquals(2L, last.getId()); - - final UserEntity newEntity = userService.create(new UserEntity(null, "TestUser", "user53262@gmail.com", - "lawy7728", false)); - Assertions.assertEquals(3, userService.getAll().size()); - Assertions.assertEquals(4L, newEntity.getId()); - } -} diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties new file mode 100644 index 0000000..d5f355c --- /dev/null +++ b/src/test/resources/application.properties @@ -0,0 +1,14 @@ +# Server +spring.main.banner-mode=off + +# Logger settings +# Available levels are: TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF +logging.level.com.example.demo=DEBUG + +# JPA Settings +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.username=sa +spring.datasource.password=password +spring.datasource.driver-class-name=org.h2.Driver +spring.jpa.hibernate.ddl-auto=create +spring.jpa.open-in-view=false \ No newline at end of file