接著來完成購物車區塊,先建立Cart entity,包含id、購物車是誰的、買了哪些東西、總價是多少、買了幾個。
@Entity
public class Cart {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne
@JoinColumn(name = "user_id", nullable = false)
private User user;
@OneToMany(mappedBy = "cart", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<CartItem> cartItems = new HashSet<>();
private Integer totalPrice;
private Integer totalQuantity;
public Cart() {
}
public Cart(Long id, User user, Set<CartItem> cartItems, Integer totalPrice, Integer totalQuantity) {
this.id = id;
this.user = user;
this.cartItems = cartItems;
this.totalPrice = totalPrice;
this.totalQuantity = totalQuantity;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Set<CartItem> getCartItems() {
return cartItems;
}
public void setCartItems(Set<CartItem> cartItems) {
this.cartItems = cartItems;
}
public Integer getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(Integer totalPrice) {
this.totalPrice = totalPrice;
}
public Integer getTotalQuantity() {
return totalQuantity;
}
public void setTotalQuantity(Integer totalQuantity) {
this.totalQuantity = totalQuantity;
}
}
這邊出現一些新的annotation,從user的部分開始介紹
下一個是cartItems
@OneToMany代表一對多的關係,因為一個購物車裡面可以有很多物品。
表示cart這邊不去處理與CartItem間的關聯,而是交給CartItem處理關聯。
因此,cart資料表不會出現cartItem_id的欄位。
表示對Cart entity的任何操作都會傳播到CartItem entity。
目的是清空購物車時,購物車中的物品也一併刪除。
如果我們在cart刪除購物車物品,那麼cartItem的內容也會被刪除。
建立CartItem entity,內容有id、購物車、商品、價格、數量。
@Entity
public class CartItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JsonIgnore
private Cart cart;
@ManyToOne
private Product product;
private Integer price;
private Integer quantity;
public CartItem() {
}
public CartItem(Long id, Cart cart, Product product, Integer price, Integer quantity) {
this.id = id;
this.cart = cart;
this.product = product;
this.price = price;
this.quantity = quantity;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Cart getCart() {
return cart;
}
public void setCart(Cart cart) {
this.cart = cart;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
}
表示多對一的關係
表示不會在JSON輸出中看到這部分的內容。
CartRepository提供根據用戶的id找尋用戶的購物車的功能,需要自行編寫SQL語句,Spring Data JPA無法產生我們需要的程式碼。
public interface CartRepository extends JpaRepository<Cart, Long> {
@Query("SELECT c FROM Cart c WHERE c.user.id = :userId")
public Cart findCartByUserId(@Param("userId") Long userId);
}
CartItemRepository可以查看購物車,是否已經有同樣的商品了,可以避免重複加入。
public interface CartItemRepository extends JpaRepository<CartItem, Long> {
@Query("SELECT ci FROM CartItem ci WHERE ci.cart = :cart AND ci.product = :product")
public CartItem isCartItemInCart(@Param("cart") Cart cart, @Param("product") Product product);
}
CartService.java由以下幾個部分組成
public Cart createCart(User user) {
Cart cart = new Cart();
cart.setUser(user);
return cartRepository.save(cart);
}
修改AuthController.java,在建立用戶時,同時也建立新用戶專屬的購物車。
@PostMapping("/signup")
public ResponseEntity<AuthResponse> createUserHandler(@RequestBody User user) throws Exception {
...
Cart cart = cartService.createCart(userService.findUserByEmail(user.getEmail()));
return new ResponseEntity<>(authResponse, HttpStatus.CREATED);
}
public void addToCart(Long userId, AddItemRequest req) throws Exception{
Cart cart = cartRepository.findCartByUserId(userId);
Product product = productService.getProductById(req.getProductId());
CartItem isPresent = cartItemService.isCartItemInCart(cart, product);
if(isPresent == null) {
CartItem cartItem = new CartItem();
cartItem.setCart(cart);
cartItem.setProduct(product);
cartItem.setQuantity(req.getQuantity());
cartItem.setPrice(req.getQuantity() * product.getPrice());
CartItem createdCartItem = cartItemService.createCartItem(cartItem);
cart.getCartItems().add(createdCartItem);
calcCartTotal(userId);
}
}
我們定義了加入購物車的請求的格式,新增AddItemRequest.java
public class AddItemRequest {
private Long productId;
private Integer quantity;
public AddItemRequest(){
}
public AddItemRequest(Long productId, Integer quantity) {
this.productId = productId;
this.quantity = quantity;
}
public Long getProductId() {
return productId;
}
public void setProductId(Long productId) {
this.productId = productId;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
}
public Cart calcCartTotal(Long userId) {
Cart cart = cartRepository.findCartByUserId(userId);
int totalPrice = 0, totalQuantity = 0;
for(CartItem cartItem : cart.getCartItems()) {
totalPrice += cartItem.getPrice();
totalQuantity += cartItem.getQuantity();
}
cart.setTotalPrice(totalPrice);
cart.setTotalQuantity(totalQuantity);
return cartRepository.save(cart);
}
public Integer clearCart(Long userId) throws Exception {
Cart cart = cartRepository.findCartByUserId(userId);
Integer totalPrice = cart.getTotalPrice();
Iterator<CartItem> iterator = cart.getCartItems().iterator();
while (iterator.hasNext()) {
CartItem cartItem = iterator.next();
cartItemService.removeCartItem(userId, cartItem.getId());
iterator.remove();
}
cart.setTotalPrice(0);
cart.setTotalQuantity(0);
cartRepository.save(cart);
return totalPrice;
}
CartItemService有這幾種功能
public CartItem isCartItemInCart(Cart cart, Product product) {
return cartItemRepository.isCartItemInCart(cart, product);
}
public CartItem createCartItem(CartItem cartItem) {
cartItem.setQuantity(Math.max(cartItem.getQuantity(), 1));
cartItem.setPrice(cartItem.getProduct().getPrice() * cartItem.getQuantity());
return cartItemRepository.save(cartItem);
}
public CartItem updateCartItem(Long userId, Long id, CartItem cartItem) throws Exception {
CartItem item = findCartItemById(id);
User user = userService.findUserById(item.getCart().getUser().getId());
if(user.getId().equals(userId)) {
item.setQuantity(cartItem.getQuantity());
item.setPrice(item.getQuantity() * item.getProduct().getPrice());
}
return cartItemRepository.save(item);
}
在UserService.java,新增以下程式碼,這樣才能用id查詢用戶。
public User findUserById(Long id) throws Exception{
Optional<User> opt = userRepository.findById(id);
if(opt.isPresent()){
return opt.get();
}
throw new Exception("Error: User not found with id: " + id);
}
public CartItem findCartItemById(Long id) throws Exception {
Optional<CartItem> optionalCartItem = cartItemRepository.findById(id);
if(optionalCartItem.isPresent()) {
return optionalCartItem.get();
}
throw new Exception("CartItem not found with id : " + id);
}
public void removeCartItem(Long userId, Long id) throws Exception {
CartItem item = findCartItemById(id);
User user = userService.findUserById(item.getCart().getUser().getId());
User reqUser = userService.findUserById(userId);
if(user.getId().equals(reqUser.getId())) {
cartItemRepository.deleteById(id);
return;
}
throw new Exception("Can't remove another users item");
}
CartController有兩個作用
第一個是取得購物車的內容。
@GetMapping("/")
public ResponseEntity<Cart> findUserCart(@RequestHeader("Authorization") String jwt) throws Exception {
User user = userService.findUserByJWT(jwt);
Cart cart = cartService.calcCartTotal(user.getId());
return new ResponseEntity<>(cart, HttpStatus.OK);
}
第二個是點擊加入購物車時,將商品加入購物車。
@PutMapping("/add")
public ResponseEntity<String> addItemToCart(@RequestBody AddItemRequest req, @RequestHeader("Authorization") String jwt) throws Exception{
User user = userService.findUserByJWT(jwt);
cartService.addToCart(user.getId(), req);
return new ResponseEntity<>("Item added to cart",HttpStatus.OK);
}
CartItemController提供
@PutMapping("/{cartItemId}")
public ResponseEntity<String> updateCartItem(@PathVariable("cartItemId") Long id,
@RequestBody CartItem cartItem,
@RequestHeader("Authorization") String jwt) throws Exception {
User user = userService.findUserByJWT(jwt);
cartItemService.updateCartItem(user.getId(), id, cartItem);
return new ResponseEntity<>("Cart item updated successfully", HttpStatus.OK);
}
@DeleteMapping("/{cartItemId}")
public ResponseEntity<String> deleteCartItem(@PathVariable("cartItemId") Long id,
@RequestHeader("Authorization") String jwt) throws Exception{
User user = userService.findUserByJWT(jwt);
cartItemService.removeCartItem(user.getId(), id);
return new ResponseEntity<>("CartItem deleted successfully", HttpStatus.OK);
}
購物車的商品真的變成1919個了