From 0b64998ae71117ab018dec9133f0588e362ac61b Mon Sep 17 00:00:00 2001 From: edmont Date: Tue, 3 Oct 2023 23:00:55 +0300 Subject: [PATCH] Completed all points in Readme --- pom.xml | 22 ++++++ .../controller/CategoryController.java | 49 +++++++++++++ .../datajpa/controller/ProductController.java | 70 +++++++++++++++++++ .../dto/request/CategoryRequestDto.java | 10 +++ .../dto/request/ProductRequestDto.java | 16 +++++ .../dto/response/CategoryResponseDto.java | 9 +++ .../dto/response/ProductResponseDto.java | 12 ++++ .../springboot/datajpa/mapper/DtoMapper.java | 4 ++ .../datajpa/mapper/RequestDtoMapper.java | 5 ++ .../datajpa/mapper/ResponseDtoMapper.java | 5 ++ .../datajpa/mapper/impl/CategoryMapper.java | 26 +++++++ .../datajpa/mapper/impl/ProductMapper.java | 30 ++++++++ .../springboot/datajpa/model/Category.java | 27 +++++++ .../springboot/datajpa/model/Product.java | 28 ++++++++ .../repository/CategoryRepository.java | 9 +++ .../datajpa/repository/ProductRepository.java | 15 ++++ .../datajpa/service/CategoryService.java | 11 +++ .../datajpa/service/ProductService.java | 20 ++++++ .../service/impl/CategoryServiceImpl.java | 30 ++++++++ .../service/impl/ProductServiceImpl.java | 48 +++++++++++++ src/main/resources/application.properties | 8 +++ 21 files changed, 454 insertions(+) create mode 100644 src/main/java/mate/academy/springboot/datajpa/controller/CategoryController.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/controller/ProductController.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/dto/request/CategoryRequestDto.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/dto/request/ProductRequestDto.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/dto/response/CategoryResponseDto.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/dto/response/ProductResponseDto.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/mapper/DtoMapper.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/mapper/RequestDtoMapper.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/mapper/ResponseDtoMapper.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/mapper/impl/CategoryMapper.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/mapper/impl/ProductMapper.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/model/Category.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/model/Product.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/repository/CategoryRepository.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/repository/ProductRepository.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/service/CategoryService.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/service/ProductService.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/service/impl/CategoryServiceImpl.java create mode 100644 src/main/java/mate/academy/springboot/datajpa/service/impl/ProductServiceImpl.java diff --git a/pom.xml b/pom.xml index cf704585..6f9f436e 100644 --- a/pom.xml +++ b/pom.xml @@ -30,6 +30,28 @@ org.springframework.boot spring-boot-autoconfigure + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + org.projectlombok + lombok + true + + + javax.validation + validation-api + 2.0.1.Final + diff --git a/src/main/java/mate/academy/springboot/datajpa/controller/CategoryController.java b/src/main/java/mate/academy/springboot/datajpa/controller/CategoryController.java new file mode 100644 index 00000000..ee8fe929 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/controller/CategoryController.java @@ -0,0 +1,49 @@ +package mate.academy.springboot.datajpa.controller; + +import javax.validation.Valid; +import lombok.AllArgsConstructor; +import mate.academy.springboot.datajpa.dto.request.CategoryRequestDto; +import mate.academy.springboot.datajpa.dto.response.CategoryResponseDto; +import mate.academy.springboot.datajpa.mapper.DtoMapper; +import mate.academy.springboot.datajpa.model.Category; +import mate.academy.springboot.datajpa.service.CategoryService; +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.RestController; + +@AllArgsConstructor +@RestController +@RequestMapping("/categories") +public class CategoryController { + private final CategoryService categoryService; + private final DtoMapper categoryMapper; + + @PostMapping + public CategoryResponseDto create(@RequestBody @Valid CategoryRequestDto categoryRequestDto) { + return categoryMapper.mapToDto(categoryService.save( + categoryMapper.mapToEntity(categoryRequestDto))); + } + + @GetMapping("/{id}") + public CategoryResponseDto get(@PathVariable Long id) { + return categoryMapper.mapToDto(categoryService.getById(id)); + } + + @PutMapping("/{id}") + public CategoryResponseDto update(@PathVariable Long id, + @RequestBody @Valid CategoryRequestDto categoryRequestDto) { + Category category = categoryMapper.mapToEntity(categoryRequestDto); + category.setId(id); + return categoryMapper.mapToDto(categoryService.save(category)); + } + + @DeleteMapping("/{id}") + public void delete(@PathVariable Long id) { + categoryService.deleteById(id); + } +} diff --git a/src/main/java/mate/academy/springboot/datajpa/controller/ProductController.java b/src/main/java/mate/academy/springboot/datajpa/controller/ProductController.java new file mode 100644 index 00000000..0b1ec865 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/controller/ProductController.java @@ -0,0 +1,70 @@ +package mate.academy.springboot.datajpa.controller; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import javax.validation.Valid; +import javax.validation.constraints.Positive; +import lombok.AllArgsConstructor; +import mate.academy.springboot.datajpa.dto.request.ProductRequestDto; +import mate.academy.springboot.datajpa.dto.response.ProductResponseDto; +import mate.academy.springboot.datajpa.mapper.DtoMapper; +import mate.academy.springboot.datajpa.model.Product; +import mate.academy.springboot.datajpa.service.ProductService; +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; + +@AllArgsConstructor +@RestController +@RequestMapping("/products") +public class ProductController { + private final ProductService productService; + private final DtoMapper productMapper; + + @PostMapping + public ProductResponseDto create(@RequestBody @Valid ProductRequestDto productRequestDto) { + Product product = productMapper.mapToEntity(productRequestDto); + return productMapper.mapToDto(productService.save(product)); + } + + @GetMapping("/{id}") + public ProductResponseDto get(@PathVariable Long id) { + return productMapper.mapToDto(productService.getById(id)); + } + + @GetMapping("/by-price") + public List getAllByPrice(@RequestParam @Positive BigDecimal from, + @RequestParam @Positive BigDecimal to) { + return productService.getAllByPricePriceBetween(from, to).stream() + .map(productMapper::mapToDto) + .collect(Collectors.toList()); + } + + @GetMapping("/by-categories") + public List getAllByCategories(@RequestParam Set categoryIds) { + return productService.getAllByCategoryNameIn(categoryIds).stream() + .map(productMapper::mapToDto) + .collect(Collectors.toList()); + } + + @PutMapping("/{id}") + public ProductResponseDto update(@PathVariable Long id, + @RequestBody @Valid ProductRequestDto productRequestDto) { + Product product = productMapper.mapToEntity(productRequestDto); + product.setId(id); + return productMapper.mapToDto(productService.save(product)); + } + + @DeleteMapping("/{id}") + public void delete(@PathVariable Long id) { + productService.deleteById(id); + } +} diff --git a/src/main/java/mate/academy/springboot/datajpa/dto/request/CategoryRequestDto.java b/src/main/java/mate/academy/springboot/datajpa/dto/request/CategoryRequestDto.java new file mode 100644 index 00000000..78c66239 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/dto/request/CategoryRequestDto.java @@ -0,0 +1,10 @@ +package mate.academy.springboot.datajpa.dto.request; + +import javax.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class CategoryRequestDto { + @NotNull + private String name; +} diff --git a/src/main/java/mate/academy/springboot/datajpa/dto/request/ProductRequestDto.java b/src/main/java/mate/academy/springboot/datajpa/dto/request/ProductRequestDto.java new file mode 100644 index 00000000..8e6c3b40 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/dto/request/ProductRequestDto.java @@ -0,0 +1,16 @@ +package mate.academy.springboot.datajpa.dto.request; + +import java.math.BigDecimal; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Positive; +import lombok.Data; + +@Data +public class ProductRequestDto { + @Positive + private BigDecimal price; + @NotNull + private String title; + @Positive + private Long categoryId; +} diff --git a/src/main/java/mate/academy/springboot/datajpa/dto/response/CategoryResponseDto.java b/src/main/java/mate/academy/springboot/datajpa/dto/response/CategoryResponseDto.java new file mode 100644 index 00000000..a0e83a17 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/dto/response/CategoryResponseDto.java @@ -0,0 +1,9 @@ +package mate.academy.springboot.datajpa.dto.response; + +import lombok.Data; + +@Data +public class CategoryResponseDto { + private Long id; + private String name; +} diff --git a/src/main/java/mate/academy/springboot/datajpa/dto/response/ProductResponseDto.java b/src/main/java/mate/academy/springboot/datajpa/dto/response/ProductResponseDto.java new file mode 100644 index 00000000..77371b26 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/dto/response/ProductResponseDto.java @@ -0,0 +1,12 @@ +package mate.academy.springboot.datajpa.dto.response; + +import java.math.BigDecimal; +import lombok.Data; + +@Data +public class ProductResponseDto { + private Long id; + private BigDecimal price; + private String title; + private Long categoriesId; +} diff --git a/src/main/java/mate/academy/springboot/datajpa/mapper/DtoMapper.java b/src/main/java/mate/academy/springboot/datajpa/mapper/DtoMapper.java new file mode 100644 index 00000000..0ebb93bd --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/mapper/DtoMapper.java @@ -0,0 +1,4 @@ +package mate.academy.springboot.datajpa.mapper; + +public interface DtoMapper extends RequestDtoMapper, ResponseDtoMapper { +} diff --git a/src/main/java/mate/academy/springboot/datajpa/mapper/RequestDtoMapper.java b/src/main/java/mate/academy/springboot/datajpa/mapper/RequestDtoMapper.java new file mode 100644 index 00000000..feacd6d5 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/mapper/RequestDtoMapper.java @@ -0,0 +1,5 @@ +package mate.academy.springboot.datajpa.mapper; + +public interface RequestDtoMapper { + T mapToEntity(D dto); +} diff --git a/src/main/java/mate/academy/springboot/datajpa/mapper/ResponseDtoMapper.java b/src/main/java/mate/academy/springboot/datajpa/mapper/ResponseDtoMapper.java new file mode 100644 index 00000000..c31c1ae9 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/mapper/ResponseDtoMapper.java @@ -0,0 +1,5 @@ +package mate.academy.springboot.datajpa.mapper; + +public interface ResponseDtoMapper { + D mapToDto(T entity); +} diff --git a/src/main/java/mate/academy/springboot/datajpa/mapper/impl/CategoryMapper.java b/src/main/java/mate/academy/springboot/datajpa/mapper/impl/CategoryMapper.java new file mode 100644 index 00000000..99bfbe42 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/mapper/impl/CategoryMapper.java @@ -0,0 +1,26 @@ +package mate.academy.springboot.datajpa.mapper.impl; + +import mate.academy.springboot.datajpa.dto.request.CategoryRequestDto; +import mate.academy.springboot.datajpa.dto.response.CategoryResponseDto; +import mate.academy.springboot.datajpa.mapper.DtoMapper; +import mate.academy.springboot.datajpa.model.Category; +import org.springframework.stereotype.Component; + +@Component +public class CategoryMapper implements DtoMapper { + @Override + public Category mapToEntity(CategoryRequestDto dto) { + Category category = new Category(); + category.setName(dto.getName()); + return category; + } + + @Override + public CategoryResponseDto mapToDto(Category entity) { + CategoryResponseDto categoryResponseDto = new CategoryResponseDto(); + categoryResponseDto.setId(entity.getId()); + categoryResponseDto.setName(entity.getName()); + return categoryResponseDto; + } +} diff --git a/src/main/java/mate/academy/springboot/datajpa/mapper/impl/ProductMapper.java b/src/main/java/mate/academy/springboot/datajpa/mapper/impl/ProductMapper.java new file mode 100644 index 00000000..808cf6bd --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/mapper/impl/ProductMapper.java @@ -0,0 +1,30 @@ +package mate.academy.springboot.datajpa.mapper.impl; + +import mate.academy.springboot.datajpa.dto.request.ProductRequestDto; +import mate.academy.springboot.datajpa.dto.response.ProductResponseDto; +import mate.academy.springboot.datajpa.mapper.DtoMapper; +import mate.academy.springboot.datajpa.model.Category; +import mate.academy.springboot.datajpa.model.Product; +import org.springframework.stereotype.Component; + +@Component +public class ProductMapper implements DtoMapper { + @Override + public Product mapToEntity(ProductRequestDto dto) { + Product product = new Product(); + product.setPrice(dto.getPrice()); + product.setTitle(dto.getTitle()); + product.setCategory(new Category(dto.getCategoryId())); + return product; + } + + @Override + public ProductResponseDto mapToDto(Product entity) { + ProductResponseDto productResponseDto = new ProductResponseDto(); + productResponseDto.setId(entity.getId()); + productResponseDto.setTitle(entity.getTitle()); + productResponseDto.setPrice(entity.getPrice()); + productResponseDto.setCategoriesId(entity.getCategory().getId()); + return productResponseDto; + } +} diff --git a/src/main/java/mate/academy/springboot/datajpa/model/Category.java b/src/main/java/mate/academy/springboot/datajpa/model/Category.java new file mode 100644 index 00000000..8b773677 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/model/Category.java @@ -0,0 +1,27 @@ +package mate.academy.springboot.datajpa.model; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@EqualsAndHashCode +@Entity +@Table(name = "categories") +public class Category { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String name; + + public Category(Long categoryId) { + } +} diff --git a/src/main/java/mate/academy/springboot/datajpa/model/Product.java b/src/main/java/mate/academy/springboot/datajpa/model/Product.java new file mode 100644 index 00000000..cff2ba27 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/model/Product.java @@ -0,0 +1,28 @@ +package mate.academy.springboot.datajpa.model; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import java.math.BigDecimal; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@EqualsAndHashCode +@Entity +@Table(name = "products") +public class Product { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String title; + private BigDecimal price; + @ManyToOne(fetch = FetchType.LAZY) + private Category category; +} diff --git a/src/main/java/mate/academy/springboot/datajpa/repository/CategoryRepository.java b/src/main/java/mate/academy/springboot/datajpa/repository/CategoryRepository.java new file mode 100644 index 00000000..ed06bf2b --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/repository/CategoryRepository.java @@ -0,0 +1,9 @@ +package mate.academy.springboot.datajpa.repository; + +import mate.academy.springboot.datajpa.model.Category; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface CategoryRepository extends JpaRepository { +} diff --git a/src/main/java/mate/academy/springboot/datajpa/repository/ProductRepository.java b/src/main/java/mate/academy/springboot/datajpa/repository/ProductRepository.java new file mode 100644 index 00000000..c1d0b8ab --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/repository/ProductRepository.java @@ -0,0 +1,15 @@ +package mate.academy.springboot.datajpa.repository; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; +import mate.academy.springboot.datajpa.model.Product; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ProductRepository extends JpaRepository { + List getAllProductsByPriceBetween(BigDecimal from, BigDecimal to); + + List getAllProductsByCategoryNameIn(Collection categoriesName); +} diff --git a/src/main/java/mate/academy/springboot/datajpa/service/CategoryService.java b/src/main/java/mate/academy/springboot/datajpa/service/CategoryService.java new file mode 100644 index 00000000..86b03f34 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/service/CategoryService.java @@ -0,0 +1,11 @@ +package mate.academy.springboot.datajpa.service; + +import mate.academy.springboot.datajpa.model.Category; + +public interface CategoryService { + Category save(Category categoryMapper); + + Category getById(Long id); + + void deleteById(Long id); +} diff --git a/src/main/java/mate/academy/springboot/datajpa/service/ProductService.java b/src/main/java/mate/academy/springboot/datajpa/service/ProductService.java new file mode 100644 index 00000000..20cb9c32 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/service/ProductService.java @@ -0,0 +1,20 @@ +package mate.academy.springboot.datajpa.service; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Set; +import mate.academy.springboot.datajpa.model.Product; + +public interface ProductService { + Product save(Product product); + + Product getById(Long id); + + void deleteById(Long id); + + List getAll(); + + List getAllByPricePriceBetween(BigDecimal from, BigDecimal to); + + List getAllByCategoryNameIn(Set categories); +} diff --git a/src/main/java/mate/academy/springboot/datajpa/service/impl/CategoryServiceImpl.java b/src/main/java/mate/academy/springboot/datajpa/service/impl/CategoryServiceImpl.java new file mode 100644 index 00000000..a158a61b --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/service/impl/CategoryServiceImpl.java @@ -0,0 +1,30 @@ +package mate.academy.springboot.datajpa.service.impl; + +import mate.academy.springboot.datajpa.model.Category; +import mate.academy.springboot.datajpa.repository.CategoryRepository; +import mate.academy.springboot.datajpa.service.CategoryService; +import org.springframework.stereotype.Service; + +@Service +public class CategoryServiceImpl implements CategoryService { + private final CategoryRepository categoryRepository; + + public CategoryServiceImpl(CategoryRepository categoryRepository) { + this.categoryRepository = categoryRepository; + } + + @Override + public Category save(Category category) { + return categoryRepository.save(category); + } + + @Override + public Category getById(Long id) { + return categoryRepository.getById(id); + } + + @Override + public void deleteById(Long id) { + categoryRepository.deleteById(id); + } +} diff --git a/src/main/java/mate/academy/springboot/datajpa/service/impl/ProductServiceImpl.java b/src/main/java/mate/academy/springboot/datajpa/service/impl/ProductServiceImpl.java new file mode 100644 index 00000000..06059244 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/service/impl/ProductServiceImpl.java @@ -0,0 +1,48 @@ +package mate.academy.springboot.datajpa.service.impl; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Set; +import mate.academy.springboot.datajpa.model.Product; +import mate.academy.springboot.datajpa.repository.ProductRepository; +import mate.academy.springboot.datajpa.service.ProductService; +import org.springframework.stereotype.Service; + +@Service +public class ProductServiceImpl implements ProductService { + private final ProductRepository productRepository; + + public ProductServiceImpl(ProductRepository productRepository) { + this.productRepository = productRepository; + } + + @Override + public Product save(Product product) { + return productRepository.save(product); + } + + @Override + public Product getById(Long id) { + return productRepository.getById(id); + } + + @Override + public void deleteById(Long id) { + productRepository.deleteById(id); + } + + @Override + public List getAll() { + return productRepository.findAll(); + } + + @Override + public List getAllByPricePriceBetween(BigDecimal from, BigDecimal to) { + return productRepository.getAllProductsByPriceBetween(from, to); + } + + @Override + public List getAllByCategoryNameIn(Set categories) { + return productRepository.getAllProductsByCategoryNameIn(categories); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b137891..a535164f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,9 @@ +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=root +spring.datasource.password=373373 +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect +spring.h2.console.enabled=true +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.format_sql=true