diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index bb087f3..09f7e11 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -9,7 +9,7 @@
-
+
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index e7c6a5b..b9a1078 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -2,7 +2,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -26,102 +39,81 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ asc
+
+
@@ -144,17 +141,20 @@
@@ -165,7 +165,24 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -258,6 +275,15 @@
+
+
+
+
+
+
+
+
+
@@ -284,7 +310,7 @@
-
+
@@ -353,33 +379,34 @@
1547322958782
-
+
-
+
-
+
+
-
+
-
+
-
-
+
+
-
+
-
+
@@ -388,7 +415,7 @@
-
+
@@ -452,78 +479,31 @@
-
+
-
-
+
+
-
-
+
+
-
+
-
-
-
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -537,10 +517,105 @@
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index 83ac68a..613f30a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,6 +49,15 @@
org.springframework.boot
spring-boot-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.0
+
+ 11
+
+
diff --git a/src/main/java/com/dino/scrum/sysmag/controller/ProductController.java b/src/main/java/com/dino/scrum/sysmag/controller/ProductController.java
index 3f0ce5e..84c6361 100644
--- a/src/main/java/com/dino/scrum/sysmag/controller/ProductController.java
+++ b/src/main/java/com/dino/scrum/sysmag/controller/ProductController.java
@@ -3,12 +3,15 @@ package com.dino.scrum.sysmag.controller;
import com.dino.scrum.sysmag.model.Product;
import com.dino.scrum.sysmag.model.dto.IdDto;
import com.dino.scrum.sysmag.model.dto.QuantityChange;
-import com.dino.scrum.sysmag.service.ProductService;
import com.dino.scrum.sysmag.service.ProductServiceImpl;
+import com.dino.scrum.sysmag.validator.QuantityChangeValidator;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Controller;
+import org.springframework.data.domain.Pageable;
+import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
+import org.springframework.web.server.ResponseStatusException;
+import javax.validation.Valid;
import java.util.Collections;
import java.util.Map;
@@ -16,53 +19,70 @@ import java.util.Map;
* Created by prgres on 2019-01-12.
*/
-@Controller
+@RestController
@RequestMapping(value = "/api")
public class ProductController {
- private final ProductServiceImpl productService;
+ private final
+ ProductServiceImpl productService;
+ private final
+ QuantityChangeValidator quantityChangeValidator;
@Autowired
- public ProductController(ProductServiceImpl productService) {
+ public ProductController(ProductServiceImpl productService, QuantityChangeValidator quantityChangeValidator) {
this.productService = productService;
+ this.quantityChangeValidator = quantityChangeValidator;
}
@GetMapping(value = "/get-all")
- public @ResponseBody
- Iterable getAll(){
- return productService.getAllProducts();
+ public Iterable getAll(Pageable pageable) {
+ return productService.getAll(pageable);
}
-
@GetMapping(value = "/get-price-of-all")
- public @ResponseBody
+ public
Map getPriceOfAllProducts(){
- return Collections.singletonMap("price-of-all", productService.getPriceOfAllProducts());
+ return Collections.singletonMap("price-of-all", productService.getPriceOfAll());
}
@PostMapping(value = "/product/add")
- public @ResponseBody
- Product addProduct(@RequestBody Product product){
- return productService.addProduct(product);
+ public Product addProduct(@Valid @RequestBody Product product) {
+ try {
+ return productService.add(product);
+ } catch (Exception e) {
+ throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.toString());
+ }
}
@DeleteMapping(value = "/product/delete")
- public @ResponseBody
+ public
String deleteProduct(@RequestBody IdDto id){
- productService.deleteProduct(id.getId());
- return "Deleted" + id;
+ try {
+ productService.delete(id.getId());
+ return "Deleted" + id;
+ } catch (Exception e) {
+ throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.toString());
+ }
}
@GetMapping(value = "/product/get-by-id")
- public @ResponseBody
+ public
Product getById(@RequestBody IdDto id){
- return productService.getById(id.getId());
+ try {
+ return productService.getById(id.getId());
+ } catch (Exception e) {
+ throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.toString());
+ }
}
@PostMapping(value = "/product/change-quantity")
- public @ResponseBody
+ public
Product changeQuantity(@RequestBody QuantityChange quantityChange){
- return productService.changeQuantity(quantityChange);
+ try {
+ quantityChangeValidator.validate(quantityChange);
+ return productService.changeQuantity(quantityChange);
+ } catch (Exception e) {
+ throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.toString());
+ }
}
-
}
\ No newline at end of file
diff --git a/src/main/java/com/dino/scrum/sysmag/exception/ProductNotFoundException.java b/src/main/java/com/dino/scrum/sysmag/exception/ProductNotFoundException.java
new file mode 100644
index 0000000..bf339b6
--- /dev/null
+++ b/src/main/java/com/dino/scrum/sysmag/exception/ProductNotFoundException.java
@@ -0,0 +1,8 @@
+package com.dino.scrum.sysmag.exception;
+
+/**
+ * Created by prgres on 2019-01-21.
+ */
+
+public class ProductNotFoundException extends ClassNotFoundException {
+}
diff --git a/src/main/java/com/dino/scrum/sysmag/model/Product.java b/src/main/java/com/dino/scrum/sysmag/model/Product.java
index bc2d178..d67df37 100644
--- a/src/main/java/com/dino/scrum/sysmag/model/Product.java
+++ b/src/main/java/com/dino/scrum/sysmag/model/Product.java
@@ -5,6 +5,10 @@ import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
+import javax.validation.constraints.DecimalMin;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
import java.math.BigDecimal;
/**
@@ -23,16 +27,33 @@ public class Product {
@Column(name = "id")
private Long id;
+ @NotNull(message = "name cannot be null")
+ @Size(min = 2, message = "name cannot be shorter that 2")
@Column(name = "name")
private String name;
+ @NotNull(message = "price cannot be null")
+ @DecimalMin(value = "0.00", message = "price cannot be under 0.00")
@Column(name = "price")
private BigDecimal price;
+ @NotNull(message = "quantity cannot be null")
+ @Min(value = 0, message = "quantity cannot be under 0")
@Column(name = "quantity")
private long quantity;
+ @NotNull(message = "quantityMax cannot be null")
+ @Min(value = 1, message = "quantityMax cannot be under 1")
+ @Column(name = "quantityMax")
+ private long quantityMax;
+
+ @NotNull(message = "image_link cannot be null")
@Column(name = "image_link")
private String imageLink;
+ public Product setChangeQuantity(long change) {
+ this.quantity += change;
+ return this;
+ }
+
}
diff --git a/src/main/java/com/dino/scrum/sysmag/model/dto/IdDto.java b/src/main/java/com/dino/scrum/sysmag/model/dto/IdDto.java
index 0b5e89c..f8e2f26 100644
--- a/src/main/java/com/dino/scrum/sysmag/model/dto/IdDto.java
+++ b/src/main/java/com/dino/scrum/sysmag/model/dto/IdDto.java
@@ -8,5 +8,6 @@ import lombok.Getter;
@Getter
public class IdDto {
+
long id;
}
diff --git a/src/main/java/com/dino/scrum/sysmag/model/dto/QuantityChange.java b/src/main/java/com/dino/scrum/sysmag/model/dto/QuantityChange.java
index 62718fc..81d2881 100644
--- a/src/main/java/com/dino/scrum/sysmag/model/dto/QuantityChange.java
+++ b/src/main/java/com/dino/scrum/sysmag/model/dto/QuantityChange.java
@@ -1,5 +1,6 @@
package com.dino.scrum.sysmag.model.dto;
+import lombok.EqualsAndHashCode;
import lombok.Getter;
/**
@@ -7,6 +8,7 @@ import lombok.Getter;
*/
@Getter
+@EqualsAndHashCode
public class QuantityChange {
long id;
long change;
diff --git a/src/main/java/com/dino/scrum/sysmag/repository/ProductRepository.java b/src/main/java/com/dino/scrum/sysmag/repository/ProductRepository.java
index f1b5f0f..f9aebcb 100644
--- a/src/main/java/com/dino/scrum/sysmag/repository/ProductRepository.java
+++ b/src/main/java/com/dino/scrum/sysmag/repository/ProductRepository.java
@@ -1,16 +1,19 @@
package com.dino.scrum.sysmag.repository;
import com.dino.scrum.sysmag.model.Product;
-import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.repository.PagingAndSortingRepository;
+import org.springframework.stereotype.Repository;
-import java.math.BigDecimal;
-import java.util.List;
import java.util.Optional;
/**
* Created by prgres on 2019-01-12.
*/
+@Repository
+public interface ProductRepository extends PagingAndSortingRepository {
+ boolean existsByName(String name);
-public interface ProductRepository extends CrudRepository {
- List findAll();
+ Optional findByName(String name);
+
+ Product findById(long id);
}
diff --git a/src/main/java/com/dino/scrum/sysmag/service/ProductService.java b/src/main/java/com/dino/scrum/sysmag/service/ProductService.java
index 869e29e..77434e9 100644
--- a/src/main/java/com/dino/scrum/sysmag/service/ProductService.java
+++ b/src/main/java/com/dino/scrum/sysmag/service/ProductService.java
@@ -2,19 +2,24 @@ package com.dino.scrum.sysmag.service;
import com.dino.scrum.sysmag.model.Product;
import com.dino.scrum.sysmag.model.dto.QuantityChange;
-
-import java.util.List;
-import java.util.Optional;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Slice;
/**
* Created by prgres on 2019-01-12.
*/
public interface ProductService {
- List getAllProducts();
- Product changeQuantity(QuantityChange quantityChange);
- Product getById(Long id);
- float getPriceOfAllProducts();
- Product addProduct(Product product);
- void deleteProduct(long id);
+ Slice getAll(Pageable pageable);
+
+ Product changeQuantity(QuantityChange quantityChange) throws Exception;
+
+ Product getById(Long id) throws Exception;
+
+ Product add(Product product) throws Exception;
+
+ float getPriceOfAll();
+
+ void delete(long id) throws Exception;
}
+
diff --git a/src/main/java/com/dino/scrum/sysmag/service/ProductServiceImpl.java b/src/main/java/com/dino/scrum/sysmag/service/ProductServiceImpl.java
index 1c77e15..f1569ad 100644
--- a/src/main/java/com/dino/scrum/sysmag/service/ProductServiceImpl.java
+++ b/src/main/java/com/dino/scrum/sysmag/service/ProductServiceImpl.java
@@ -3,14 +3,15 @@ package com.dino.scrum.sysmag.service;
import com.dino.scrum.sysmag.model.Product;
import com.dino.scrum.sysmag.model.dto.QuantityChange;
import com.dino.scrum.sysmag.repository.ProductRepository;
+import com.dino.scrum.sysmag.validator.ProductValidator;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Slice;
+import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
-import javax.persistence.EntityNotFoundException;
import java.math.BigDecimal;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
/**
* Created by prgres on 2019-01-12.
@@ -19,57 +20,60 @@ import java.util.stream.Collectors;
@Service
public class ProductServiceImpl implements ProductService {
- private final ProductRepository productRepository;
+ private final
+ ProductRepository productRepository;
+
+ private final
+ ProductValidator productValidator;
@Autowired
- public ProductServiceImpl(ProductRepository productRepository) {
+ public ProductServiceImpl(ProductRepository productRepository, ProductValidator productValidator) {
this.productRepository = productRepository;
+ this.productValidator = productValidator;
}
@Override
- public List getAllProducts() {
- return productRepository.findAll();
+ public Slice getAll(Pageable pageable) {
+ if (pageable.getSort().isUnsorted()) {
+ pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), new Sort(Sort.Direction.ASC, "id"));
+ }
+ return productRepository.findAll(pageable);
}
@Override
- public Product changeQuantity(QuantityChange quantityChange) {
- return productRepository.findById(quantityChange.getId())
- .map(product -> {
- product.setQuantity(
- product.getQuantity() + quantityChange.getChange()
- );
- return productRepository.save(product);
- }).orElse(null);
+ public Product changeQuantity(QuantityChange quantityChange) throws Exception {
+ productValidator.checkIfExists(quantityChange.getId());
+ return productRepository.findById(quantityChange.getId()).setChangeQuantity(quantityChange.getChange());
}
@Override
- public Product getById(Long id) {
- return productRepository.findById(id).orElse(null);
+ public Product getById(Long id) throws Exception {
+ productValidator.checkIfExists(id);
+ return productRepository.findById(id.longValue());
}
@Override
- public float getPriceOfAllProducts() {
+ public float getPriceOfAll() {
BigDecimal result = new BigDecimal(0);
- List tempProductList = productRepository.findAll();
+ Iterable tempProductList = productRepository.findAll();
for (Product product : tempProductList) {
result = result.add(
product.getPrice()
.multiply( new BigDecimal(product.getQuantity())));
}
-
return result.floatValue();
-
}
@Override
- public Product addProduct(Product product) {
+ public Product add(Product product) throws Exception {
+ productValidator.checkIfExists(product.getName());
return productRepository.save(product);
}
@Override
- public void deleteProduct(long id) {
+ public void delete(long id) throws Exception {
+ productValidator.checkIfExists(id);
productRepository.deleteById(id);
}
-
}
diff --git a/src/main/java/com/dino/scrum/sysmag/validator/ProductValidator.java b/src/main/java/com/dino/scrum/sysmag/validator/ProductValidator.java
new file mode 100644
index 0000000..45556dd
--- /dev/null
+++ b/src/main/java/com/dino/scrum/sysmag/validator/ProductValidator.java
@@ -0,0 +1,38 @@
+package com.dino.scrum.sysmag.validator;
+
+import com.dino.scrum.sysmag.repository.ProductRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * Created by prgres on 2019-01-22.
+ */
+
+@Component
+public class ProductValidator {
+
+ private final ProductRepository productRepository;
+
+ @Autowired
+ public ProductValidator(ProductRepository productRepository) {
+ this.productRepository = productRepository;
+ }
+
+ private boolean existsById(long id) {
+ return productRepository.existsById(id);
+ }
+
+ private boolean existsByName(String name) {
+ return productRepository.existsByName(name);
+ }
+
+ public void checkIfExists(long id) throws Exception {
+ if (existsById(id))
+ throw new Exception("Product with id: " + id + " not found");
+ }
+
+ public void checkIfExists(String name) throws Exception {
+ if (existsByName(name))
+ throw new Exception("Product " + name + " already exists");
+ }
+}
diff --git a/src/main/java/com/dino/scrum/sysmag/validator/QuantityChangeValidator.java b/src/main/java/com/dino/scrum/sysmag/validator/QuantityChangeValidator.java
new file mode 100644
index 0000000..915a051
--- /dev/null
+++ b/src/main/java/com/dino/scrum/sysmag/validator/QuantityChangeValidator.java
@@ -0,0 +1,44 @@
+package com.dino.scrum.sysmag.validator;
+
+import com.dino.scrum.sysmag.model.Product;
+import com.dino.scrum.sysmag.model.dto.QuantityChange;
+import com.dino.scrum.sysmag.service.ProductServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * Created by prgres on 2019-01-20.
+ */
+
+@Component
+public class QuantityChangeValidator {
+
+ private final
+ ProductServiceImpl productService;
+
+ @Autowired
+ public QuantityChangeValidator(ProductServiceImpl productService) {
+ this.productService = productService;
+ }
+
+ public void validate(QuantityChange quantityChange) throws Exception {
+
+ Product product = productService.getById(quantityChange.getId());
+
+ if (ifUnderStock(product.getQuantity(), quantityChange.getChange())) {
+ throw new RuntimeException("Too low product with id: " + quantityChange.getId() + " on stock");
+ }
+
+ if (ifAboveMaxLimitStock(product.getQuantity(), product.getQuantityMax(), quantityChange.getChange())) {
+ throw new RuntimeException("Over max quantity limit of product with id: " + quantityChange.getId());
+ }
+ }
+
+ private boolean ifUnderStock(long quantityOfProduct, long quantityChange) {
+ return ((quantityOfProduct + quantityChange) < 0);
+ }
+
+ private boolean ifAboveMaxLimitStock(long quantityOfProduct, long maxQuantityOfProduct, long quantityChange) {
+ return ((quantityOfProduct + quantityChange) > maxQuantityOfProduct);
+ }
+}
\ No newline at end of file