diff --git a/pom.xml b/pom.xml index cf704585..039a4d31 100644 --- a/pom.xml +++ b/pom.xml @@ -30,6 +30,33 @@ org.springframework.boot spring-boot-autoconfigure + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + mysql + mysql-connector-java + + + org.projectlombok + lombok + 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..b2e48905 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/controller/CategoryController.java @@ -0,0 +1,49 @@ +package mate.academy.springboot.datajpa.controller; + +import lombok.RequiredArgsConstructor; +import mate.academy.springboot.datajpa.dto.CategoryRequestDto; +import mate.academy.springboot.datajpa.dto.CategoryResponseDto; +import mate.academy.springboot.datajpa.dto.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; + +@RestController +@RequestMapping("/categories") +@RequiredArgsConstructor +public class CategoryController { + private final CategoryService categoryService; + private final DtoMapper categoryMapper; + + @PostMapping + public CategoryResponseDto create(@RequestBody CategoryRequestDto requestDto) { + Category category = categoryService.create(categoryMapper.mapToModel(requestDto)); + return categoryMapper.mapToDto(category); + } + + @GetMapping("{id}") + public CategoryResponseDto getById(@PathVariable Long id) { + Category category = categoryService.getById(id); + return categoryMapper.mapToDto(category); + } + + @DeleteMapping("{id}") + public void delete(@PathVariable Long id) { + categoryService.delete(id); + } + + @PutMapping("/{id}") + public CategoryResponseDto update(@PathVariable Long id, + @RequestBody CategoryRequestDto requestDto) { + Category category = categoryMapper.mapToModel(requestDto); + category.setId(id); + return categoryMapper.mapToDto(categoryService.create(category)); + } +} diff --git a/src/main/java/mate/academy/springboot/datajpa/controller/InjectController.java b/src/main/java/mate/academy/springboot/datajpa/controller/InjectController.java new file mode 100644 index 00000000..6bcde5cf --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/controller/InjectController.java @@ -0,0 +1,48 @@ +package mate.academy.springboot.datajpa.controller; + +import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import mate.academy.springboot.datajpa.model.Category; +import mate.academy.springboot.datajpa.model.Product; +import mate.academy.springboot.datajpa.service.CategoryService; +import mate.academy.springboot.datajpa.service.ProductService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@AllArgsConstructor +@RestController +@RequestMapping("/inject") +public class InjectController { + private final ProductService productService; + private final CategoryService categoryService; + + @GetMapping + public String injectData() { + Category phones = new Category(); + phones.setName("Phones"); + categoryService.create(phones); + Category macBook = new Category(); + macBook.setName("Laptop"); + categoryService.create(macBook); + + Product iphoneX = new Product(); + iphoneX.setTitle("Iphone X"); + iphoneX.setPrice(BigDecimal.valueOf(999)); + iphoneX.setCategory(phones); + productService.create(iphoneX); + + Product iphone12 = new Product(); + iphone12.setTitle("Iphone 12"); + iphone12.setPrice(BigDecimal.valueOf(1299)); + iphone12.setCategory(phones); + productService.create(iphone12); + + Product airMax = new Product(); + airMax.setTitle("MacBook Air"); + airMax.setPrice(BigDecimal.valueOf(2100)); + airMax.setCategory(macBook); + productService.create(airMax); + return "Done"; + } +} 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..37f8bc36 --- /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.stream.Collectors; +import lombok.AllArgsConstructor; +import mate.academy.springboot.datajpa.dto.ProductRequestDto; +import mate.academy.springboot.datajpa.dto.ProductResponseDto; +import mate.academy.springboot.datajpa.dto.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 ProductRequestDto productRequestDto) { + Product product = productService.create(productMapper.mapToModel(productRequestDto)); + return productMapper.mapToDto(product); + } + + @GetMapping("/{id}") + public ProductResponseDto getById(@PathVariable Long id) { + return productMapper.mapToDto(productService.getById(id)); + } + + @DeleteMapping("/{id}") + public void delete(@PathVariable Long id) { + productService.delete(id); + } + + @PutMapping("/{id}") + public ProductResponseDto update(@PathVariable Long id, + @RequestBody ProductRequestDto productRequestDto) { + Product product = productMapper.mapToModel(productRequestDto); + product.setId(id); + productService.update(product); + return productMapper.mapToDto(product); + } + + @GetMapping("/price-between") + public List findAllByPriceBetween(@RequestParam BigDecimal from, + @RequestParam BigDecimal to) { + return productService.findAllByPriceBetween(from, to) + .stream() + .map(productMapper::mapToDto) + .collect(Collectors.toList()); + } + + @GetMapping("/by-category") + public List findAllByCategoryIn(@RequestParam List categories) { + return productService.findAllByCategoryNameIn(categories) + .stream() + .map(productMapper::mapToDto) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/mate/academy/springboot/datajpa/dto/CategoryRequestDto.java b/src/main/java/mate/academy/springboot/datajpa/dto/CategoryRequestDto.java new file mode 100644 index 00000000..7a0c33a5 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/dto/CategoryRequestDto.java @@ -0,0 +1,8 @@ +package mate.academy.springboot.datajpa.dto; + +import lombok.Data; + +@Data +public class CategoryRequestDto { + private String name; +} diff --git a/src/main/java/mate/academy/springboot/datajpa/dto/CategoryResponseDto.java b/src/main/java/mate/academy/springboot/datajpa/dto/CategoryResponseDto.java new file mode 100644 index 00000000..4c817782 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/dto/CategoryResponseDto.java @@ -0,0 +1,9 @@ +package mate.academy.springboot.datajpa.dto; + +import lombok.Data; + +@Data +public class CategoryResponseDto { + private Long id; + private String name; +} diff --git a/src/main/java/mate/academy/springboot/datajpa/dto/ProductRequestDto.java b/src/main/java/mate/academy/springboot/datajpa/dto/ProductRequestDto.java new file mode 100644 index 00000000..2df315f9 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/dto/ProductRequestDto.java @@ -0,0 +1,11 @@ +package mate.academy.springboot.datajpa.dto; + +import java.math.BigDecimal; +import lombok.Data; + +@Data +public class ProductRequestDto { + private String title; + private BigDecimal price; + private Long categoryId; +} diff --git a/src/main/java/mate/academy/springboot/datajpa/dto/ProductResponseDto.java b/src/main/java/mate/academy/springboot/datajpa/dto/ProductResponseDto.java new file mode 100644 index 00000000..cd71254e --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/dto/ProductResponseDto.java @@ -0,0 +1,12 @@ +package mate.academy.springboot.datajpa.dto; + +import java.math.BigDecimal; +import lombok.Data; + +@Data +public class ProductResponseDto { + private Long id; + private String title; + private BigDecimal price; + private Long categoryId; +} diff --git a/src/main/java/mate/academy/springboot/datajpa/dto/mapper/CategoryMapper.java b/src/main/java/mate/academy/springboot/datajpa/dto/mapper/CategoryMapper.java new file mode 100644 index 00000000..31150a2e --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/dto/mapper/CategoryMapper.java @@ -0,0 +1,26 @@ +package mate.academy.springboot.datajpa.dto.mapper; + +import mate.academy.springboot.datajpa.dto.CategoryRequestDto; +import mate.academy.springboot.datajpa.dto.CategoryResponseDto; +import mate.academy.springboot.datajpa.model.Category; +import org.springframework.stereotype.Component; + +@Component +public class CategoryMapper implements + DtoMapper { + + @Override + public Category mapToModel(CategoryRequestDto dto) { + Category category = new Category(); + category.setName(dto.getName()); + return category; + } + + @Override + public CategoryResponseDto mapToDto(Category category) { + CategoryResponseDto categoryResponseDto = new CategoryResponseDto(); + categoryResponseDto.setId(category.getId()); + categoryResponseDto.setName(category.getName()); + return categoryResponseDto; + } +} diff --git a/src/main/java/mate/academy/springboot/datajpa/dto/mapper/DtoMapper.java b/src/main/java/mate/academy/springboot/datajpa/dto/mapper/DtoMapper.java new file mode 100644 index 00000000..5172263f --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/dto/mapper/DtoMapper.java @@ -0,0 +1,7 @@ +package mate.academy.springboot.datajpa.dto.mapper; + +public interface DtoMapper { + D mapToDto(M model); + + M mapToModel(R dto); +} diff --git a/src/main/java/mate/academy/springboot/datajpa/dto/mapper/ProductMapper.java b/src/main/java/mate/academy/springboot/datajpa/dto/mapper/ProductMapper.java new file mode 100644 index 00000000..89cc124b --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/dto/mapper/ProductMapper.java @@ -0,0 +1,35 @@ +package mate.academy.springboot.datajpa.dto.mapper; + +import mate.academy.springboot.datajpa.dto.ProductRequestDto; +import mate.academy.springboot.datajpa.dto.ProductResponseDto; +import mate.academy.springboot.datajpa.model.Product; +import mate.academy.springboot.datajpa.service.CategoryService; +import org.springframework.stereotype.Component; + +@Component +public class ProductMapper implements DtoMapper { + private final CategoryService categoryService; + + public ProductMapper(CategoryService categoryService) { + this.categoryService = categoryService; + } + + @Override + public Product mapToModel(ProductRequestDto dto) { + Product product = new Product(); + product.setTitle(dto.getTitle()); + product.setPrice(dto.getPrice()); + product.setCategory(categoryService.getById(dto.getCategoryId())); + return product; + } + + @Override + public ProductResponseDto mapToDto(Product product) { + ProductResponseDto productResponseDto = new ProductResponseDto(); + productResponseDto.setId(product.getId()); + productResponseDto.setTitle(product.getTitle()); + productResponseDto.setPrice(product.getPrice()); + productResponseDto.setCategoryId(product.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..98f76c97 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/model/Category.java @@ -0,0 +1,16 @@ +package mate.academy.springboot.datajpa.model; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.Data; + +@Data +@Entity +public class Category { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String name; +} 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..8b6eaa09 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/model/Product.java @@ -0,0 +1,25 @@ +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.ManyToOne; +import jakarta.persistence.Table; +import java.math.BigDecimal; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Entity +@Table(name = "products") +public class Product { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String title; + private BigDecimal price; + @ManyToOne + 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..b7827b87 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/repository/ProductRepository.java @@ -0,0 +1,14 @@ +package mate.academy.springboot.datajpa.repository; + +import java.math.BigDecimal; +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 findAllByPriceBetween(BigDecimal from, BigDecimal to); + + List findAllByCategoryNameIn(List categories); +} 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..d1ba2b56 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/service/CategoryService.java @@ -0,0 +1,13 @@ +package mate.academy.springboot.datajpa.service; + +import mate.academy.springboot.datajpa.model.Category; + +public interface CategoryService { + Category create(Category category); + + Category getById(Long id); + + void delete(Long id); + + Category update(Category category); +} 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..4c6ed90f --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/service/ProductService.java @@ -0,0 +1,19 @@ +package mate.academy.springboot.datajpa.service; + +import java.math.BigDecimal; +import java.util.List; +import mate.academy.springboot.datajpa.model.Product; + +public interface ProductService { + Product create(Product product); + + Product getById(Long id); + + void delete(Long id); + + Product update(Product product); + + List findAllByPriceBetween(BigDecimal from, BigDecimal to); + + List findAllByCategoryNameIn(List 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..eeb1ba42 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/service/impl/CategoryServiceImpl.java @@ -0,0 +1,39 @@ +package mate.academy.springboot.datajpa.service.impl; + +import java.util.NoSuchElementException; +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 create(Category category) { + return categoryRepository.save(category); + } + + @Override + public Category getById(Long id) { + return categoryRepository.findById(id).orElseThrow( + () -> new NoSuchElementException("Category not found with id " + id)); + } + + @Override + public void delete(Long id) { + categoryRepository.deleteById(id); + } + + @Override + public Category update(Category category) { + Category categoryFromDb = getById(category.getId()); + categoryFromDb.setName(category.getName()); + return categoryRepository.save(categoryFromDb); + } +} 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..7cb4a7c9 --- /dev/null +++ b/src/main/java/mate/academy/springboot/datajpa/service/impl/ProductServiceImpl.java @@ -0,0 +1,53 @@ +package mate.academy.springboot.datajpa.service.impl; + +import java.math.BigDecimal; +import java.util.List; +import java.util.NoSuchElementException; +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 create(Product product) { + return productRepository.save(product); + } + + @Override + public Product getById(Long id) { + return productRepository.findById(id).orElseThrow( + () -> new NoSuchElementException("Could not find product by id " + id)); + } + + @Override + public void delete(Long id) { + productRepository.deleteById(id); + } + + @Override + public Product update(Product product) { + Product productFromDb = getById(product.getId()); + productFromDb.setTitle(product.getTitle()); + productFromDb.setPrice(product.getPrice()); + productFromDb.setCategory(product.getCategory()); + return productRepository.save(productFromDb); + } + + @Override + public List findAllByPriceBetween(BigDecimal from, BigDecimal to) { + return productRepository.findAllByPriceBetween(from, to); + } + + @Override + public List findAllByCategoryNameIn(List categories) { + return productRepository.findAllByCategoryNameIn(categories); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b137891..82c683ad 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,7 @@ +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password=password +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect +spring.h2.console.enabled=true