Angular - checkout-page component

Θα δημιουργήσουμε το Angular checkout-page component, στο οποίο ο χρήστης θα συμπληρώνει τα στοιχεία του και θα ολοκληρώνει την παραγγελία του.

Spring Boot

Αρχικά, θα δημιουργήσουμε τέσσερις πίνακες : billing_info, shipping_info, order και order_products

Δημιουργούμε τον πίνακα billing_info, o οποίος θα περιέχει τα στοιχεία χρέωσης της παραγγελίας.

Billing Info

Δημιουργούμε το entity BillingInfo στο springeshop.model

                
                        @Entity
                        @Table(name = "billing_info")
                        public class BillingInfo{

                           @Id
                           @GeneratedValue(strategy = GenerationType.IDENTITY)
                           @Column(name = "id")
                           private int id;

                           @Column(name = "first_name")
                           @NotNull(message = "Please provide first name")
                           @Size(min = 3, max = 200, message = "First Name must be between 3 and 200 characters")
                           private String first_name;

                           @Column(name = "last_name")
                           @NotNull(message = "Please provide last name")
                           @Size(min = 3, max = 200, message = "Last Name must be between 3 and 200 characters")
                           private String last_name;

                           @Column(name = "street")
                           @NotNull(message = "Please provide street name")
                           @Size(min = 3, max = 200, message = "street must be between 3 and 200 characters")
                           private String street;

                           @Column(name = "post_code")
                           @NotNull(message = "Please provide post code")
                           private String post_code;

                           @Column(name = "city")
                           @NotNull(message = "Please provide city")
                           @Size(min = 3, max = 200, message = "City must be between 3 and 200 characters")
                           private String city;

                           @Column(name = "phone")
                           @NotNull(message = "Please provide phone")
                           private String phone;

                           @Column(name = "method")
                           @NotNull(message = "Please provide method")
                           private String method;

                           public BillingInfo() {}

                           //Getters - Setters ...

                        } 
                
            

Δημιουργούμε τον πίνακα shipping_info, ο οποίος περιέχει τα στοιχεία αποστολής της παραγγελίας και το entity ShippingInfo στο springeshop.model

ShippingInfo
                
                        @Entity
                        @Table(name = "shipping_info")
                        public class ShippingInfo{

                           @Id
                           @GeneratedValue(strategy = GenerationType.IDENTITY)
                           @Column(name = "id")
                           private int id;

                           @Column(name = "first_name")
                           @NotNull(message = "Please provide first name")
                           @Size(min = 3, max = 200, message = "First Name must be between 3 and 200 characters")
                           private String first_name;

                           @Column(name = "last_name")
                           @NotNull(message = "Please provide last name")
                           @Size(min = 3, max = 200, message = "Last Name must be between 3 and 200 characters")
                           private String last_name;

                           @Column(name = "street")
                           @NotNull(message = "Please provide street name")
                           @Size(min = 3, max = 200, message = "street must be between 3 and 200 characters")
                           private String street;

                           @Column(name = "post_code")
                           @NotNull(message = "Please provide post code")
                           private String post_code;

                           @Column(name = "city")
                           @NotNull(message = "Please provide city")
                           @Size(min = 3, max = 200, message = "City must be between 3 and 200 characters")
                           private String city;

                           @Column(name = "phone")
                           @NotNull(message = "Please provide phone")
                           private String phone;

                           @Column(name = "method")
                           @NotNull(message = "Please provide method")
                           private String method;

                           public ShippingInfo() {}

                           //Getters - Setters ...

                        } 
                
            

Δημιουργούμε τον πίνακα orders, ο οποίος περιέχει τις παραγγελίες και το entity Order στο springeshop.model

Order
                
                        @Entity
                        @Table(name = "orders")
                        public class Order{

                           @Id
                           @GeneratedValue(strategy = GenerationType.IDENTITY)
                           @Column(name = "id")
                           private int id;

                           @OneToOne(fetch = FetchType.LAZY)
                           @JoinColumn(name = "user_id")
                           private User user;

                           @Column(name = "email")
                           @NotNull(message = "Please provide email")
                           @Email
                           private String email;

                           @Column(name = "status")
                           @NotNull(message = "Please provide status")
                           private String status;

                           @Column(name = "order_date")
                           private Timestamp order_date;

                           @Column(name = "payment_date")
                           private Timestamp payment_date;

                           @Column(name = "shipping_date")
                           private Timestamp shipping_date;

                           @OneToOne(fetch = FetchType.LAZY)
                           @JoinColumn(name = "shipping_info_id")
                           private ShippingInfo shippingInfo;

                           @OneToOne(fetch = FetchType.LAZY)
                           @JoinColumn(name = "billing_info_id")
                           private BillingInfo billingInfo;

                           public Order() {}

                           //Getters - Setters ...

                        } 
                
            

Δημιουργούμε τον πίνακα order_products, ο οποίος περιέχει τα προιόντα της κάθε παραγγελίας, το σύνθετο πρωτεύον κλειδί OrderProductPrimaryKey και το entity OrderProduct στο springeshop.model

Order Products
                
                        @Embeddable
                        public class OrderProductPrimaryKey implements Serializable{

                           private int orderId;
                           private int productId;

                           public OrderProductPrimaryKey() {}

                           //Getters - Setters ...

                           @Override
                           public boolean equals(Object o) {
                             if (this == o) return true;
                             if (!(o instanceof OrderProductPrimaryKey)) return false;
                             OrderProductPrimaryKey that = (OrderProductPrimaryKey) o;
                             return Objects.equals(getOrderId(), that.getOrderId()) && Objects.equals(getProductId(), that.getProductId());
                           }

                           @Override
                           public int hashCode() {
                             return Objects.hash(getOrderId(), getProductId());  
                           }

                        } 
                
            
                
                        @Entity
                        @Table(name = "order_products")
                        public class OrderProduct{

                           @EmbeddedId
                           private OrderProductPrimaryKey id;

                           @OneToOne(fetch = FetchType.LAZY)
                           @MapsId("orderId")
                           private Order order;

                           @OneToOne(fetch = FetchType.LAZY)
                           @MapsId("productId")
                           private Product  product;

                           @Column(name = "quantity")
                           @NotNull(message = "Please provide quantity")
                           private int  quantity;

                           public OrderProduct() {}

                           //Getters - Setters ...

                        } 
                
            

Δημιουργούμε το OrderDetails στο springeshop.model

                
                        public class OrderDetails{

                           @Email
                           private String email;

                           @Valid
                           private ShippingInfo shipping_info ;

                           @Valid
                           private BillingInfo billing_info;

                           private boolean isBillingAddressSameWithShippingAddress;

                           private List<CartProduct> cartProducts;

                           public OrderDetails() {}

                           //Getters - Setters ...

                        } 
                
            

Δημιουργούμε τα repositories BillingInfoRepository, ShippingInfoRepository.

                
                        package springeshop.repositories;

                        @Repository
                        public interface BillingInfoRepository  extends JpaRepository<BillingInfo, Integer>  {

                        } 
                
            
                
                        package springeshop.repositories;

                        @Repository
                        public interface ShippingInfoRepository  extends JpaRepository<ShippingInfo, Integer>  {

                        } 
                
            

Δημιουργούμε τα BillingInfoService, ShippingInfoService, BillingInfoServiceImpl, ShippingInfoServiceImplστο springeshop.service .

                
                        package springeshop.service;

                        public interface BillingInfoService{
                          boolean saveBillingInfoAndIsSuccess(BillingInfo billingInfo);
                        } 
                
            
                
                        package springeshop.service;

                        public interface ShippingInfoService{
                          boolean saveShippingInfoAndIsSuccess(ShippingInfo shippingInfo);
                        } 
                
            
                
                            package springeshop.service;

                            @Service("billingInfoService")
                            @Transactional
                            public class BillingInfoServiceImpl implements BillingInfoService{

                              @Autowired
                              private  BillingInfoRepository billingInfoRepository;

                              @Override
                              public boolean saveBillingInfoAndIsSuccess(BillingInfo billingInfo) {
                                 boolean isSuccess = false;

                                try {
                                  billingInfoRepository.save(billingInfo);
                                  isSuccess = true;
                                } catch (DataAccessException exception) {
                                  System.out.println(exception);
                                  isSuccess = false;
                                } 

                                return isSuccess;
                              }

                        }
                
            
                
                            package springeshop.service;

                            @Service("shippingInfoService")
                            @Transactional
                            public class ShippingInfoServiceImpl implements ShippingInfoService{

                              @Autowired
                              private  ShippingInfoRepository shippingInfoRepository;

                              @Override
                              public boolean saveShippingInfoAndIsSuccess(ShippingInfo shippingInfo) {
                                 boolean isSuccess = false;

                                try {
                                  shippingInfoRepository.save(shippingInfo);
                                  isSuccess = true;
                                } catch (DataAccessException exception) {
                                  System.out.println(exception);
                                  isSuccess = false;
                                } 

                                return isSuccess;
                              }

                        }
                
            

Δημιουργούμε τα repositories OrderRepository, OrderProductRepository.

                
                        package springeshop.repositories;

                        @Repository
                        public interface OrderRepository  extends JpaRepository<Order, Integer>  {

                          @Query("select order from Order order where order.user.id = :userid")
                          List<Order> findUserOrders(@Param("userid") int userid);
                        } 
                
            
                
                        package springeshop.repositories;

                        @Repository
                        public interface OrderProductRepository  extends JpaRepository<OrderProduct, Integer>  {

                          @Query("select prod from OrderProduct prod where prod.order.id = :orderid")
                          List<Product> findOrderProducts(@Param("orderid") int orderid);
                        } 
                
            

Δημιουργούμε τα OrderService, OrderProductService, OrderServiceImpl, OrderProductServiceImpl στο springeshop.service .

                
                        package springeshop.service;

                        public interface OrderService{
                          boolean saveOrderAndIsSuccess(Order order);
                          List<Order> findUserOrders(int userid);
                        } 
                
            
                
                        package springeshop.service;

                        public interface OrderProductService{
                          void saveOrderProduct(OrderProduct orderProduct);
                          boolean saveOrderProducts(List<OrderProduct> orderProducts);
                          List<Product> findOrderProducts(int orderid);
                        } 
                
            
                
                            package springeshop.service;

                            @Service("orderService")
                            @Transactional
                            public class OrderServiceImpl implements OrderService{

                              @Autowired
                              private  OrderRepository orderRepository;

                              @Override
                              public boolean saveOrderAndIsSuccess(Order order) {
                                 boolean isSuccess = false;

                                try {
                                  orderRepository.save(order);
                                  isSuccess = true;
                                } catch (DataAccessException exception) {
                                  System.out.println(exception);
                                  isSuccess = false;
                                } 

                                return isSuccess;
                              }

                              @Override
                              public List<Order> findUserOrders(int userid);
                                 return orderRepository.findUserOrders(userid);
                               }

                        }
                
            
                
                            package springeshop.service;

                            @Service("orderProductService")
                            @Transactional
                            public class OrderProductServiceImpl implements OrderProductService{

                              @Autowired
                              private  OrderProductRepository orderProductRepository;

                              @Override
                              public void saveOrderProduct(OrderProduct orderProduct) {
                                orderProductRepository.save(orderProduct);
                              }

                              @Override
                              public List<Product> findOrderProducts(int orderid) {
                                return orderProductRepository.findOrderProducts(orderid);
                              }

                              @Override
                              public boolean saveOrderProducts(List<OrderProduct> orderProducts) {
                                 boolean isSuccess = false;

                                try {
                                  orderProductRepository.saveAll(orderProducts);
                                  isSuccess = true;
                                } catch (DataAccessException exception) {
                                  System.out.println(exception);
                                  isSuccess = false;
                                } 

                                return isSuccess;
                              }

                        }
                
            

Δημιουργούμε τoν OrderApiController στο πακέτο springeshop.controller

                
                            package springeshop.controller;

                            @RestController
                            @RequestMapping("/api")
                            public class CartApiController{
                        
                               @Autowired
                               private  OrderService orderService;
    
                               @Autowired
                               private  OrderProductService orderProductService;

                               @Autowired
                               private  ProductService productService;
    
                               @Autowired
                               private  UserService userService;

                               @Autowired
                               private  ShippingInfoService shippingInfoService;
    
                               @Autowired
                               private  BillingInfoService billingInfoService;

                               @Autowired
                               private  BillingInfoService billingInfoService;
                        
                                ...
                
            

Προσθέτουμε τη μέθοδο createOrder() στον OrderApiController, με την οποία προσθέτουμε μια παραγγελία. O client στέλνει ένα OrderDetails αντικείμενο, που περιέχει το καλάθι, το email του χρήστης, τις πληροφορίες χρέωσης και αποστολής. Προσθέτουμε την παραγγελία και τα προϊόντα στους πίνακες και στέλνουμε ένα email με τα στοιχεία της παραγγελίας στο χρήστη.

                
                           @RequestMapping(value = "/orders", method = RequestMethod.POST)
                           public ResponseEntity<?> createCartProduct(@Valid @RequestBody() OrderDetails orderDetails{

                             boolean isAnonymous = principal == null ? true : false;

                             if(isAnonymous && orderDetails.getEmail() == null){
                               return new ResponseEntity<>(new ErrorMessage("Email was not provided" , HttpStatus.BAD_REQUEST);
                             }

                             if(shippingInfoService.saveShippingInfoAndIsSuccess(orderDetails.getShipping_info()) && 
                             billingInfoService.saveBillingInfoAndIsSuccess(orderDetails.getBilling_info())){

                               Order order = new Order();

                               if(!isAnonymous){
                                 User user = userService.findByUsername(principal.getName());
                                 order.setUser(user);
                               }
                    
                               order.setEmail(orderDetails.getEmail());
                               order.setStatus("Created");
                               Timestamp currentDate = new Timestamp(System.currentTimeMillis());
                               order.setOrder_date(currentDate);
                               order.setShippingInfo(orderDetails.getShipping_info());
                               order.setBillingInfo(orderDetails.getBilling_info());

                               if(orderService.saveOrderAndIsSuccess(order)){

                                 List<OrderProduct> orderProducts = new ArrayList<>();
                                 for(CartProduct cartProduct : orderDetails.getCartProducts()){
                                   OrderProduct orderProduct = new OrderProduct();
                                   OrderProductPrimaryKey id = new OrderProductPrimaryKey(order.getId(), cartProduct.getProductid());
                                   orderProduct.setId(id);
                                   orderProduct.setOrder(order);
                                   orderProduct.setProduct(productService.findById(cartProduct.getProductid()));
                                   orderProduct.setQuantity(cartProduct.getQuantity());
                                   orderProducts.add(orderProduct);
                                 }

                                 if(orderProductService.saveOrderProducts(orderProducts)){
                                   emailService.sendEmail(order, orderDetails.getCartProducts());
                                   return new ResponseEntity<Order>(order, HttpStatus.CREATED);
                                 }
                               }
                             }  

                             return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
                           }               
                
            
Angular

Δημιουργούμε το component checkout-page και το service checkout.

                
                        ng generate component checkout-page
                
            
                
                        ng generate service checkout
                
            

Δημιουργούμε τις κλάσεις BillingInfo, ShippingInfo, Order, OrderDetails

BillingInfo Shipping Order Order Details

checkout.service.ts

Checkout Service

Όταν ο χρήστης πατήσει το κουμπί Ολοκλήρωση αγοράς, καλείται η μέθοδος onSubmit(), η οποία καλεί τη μέθοδο addOrder(), ώστε να καταχωρηθεί η παραγγελία στο Server.

checkout-page.component.ts

Checkout Page Ts

checkout-page.component.html

Checkout Page Html

checkout-page.component.css

Checkout Page Css

Εμφάνιση σελίδας

Cart Page Appearnce Checkout Page Appearnce