Skip to content
This repository has been archived by the owner on Aug 13, 2022. It is now read-only.

[#26] 장바구니 도메인 추가 #44

Open
wants to merge 6 commits into
base: feature/39
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/main/java/me/jjeda/mall/cart/configs/RedisConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package me.jjeda.mall.cart.configs;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@EnableRedisRepositories
public class RedisConfig {
@Value("${spring.redis.host}")
private String redisHost;

@Value("${spring.redis.port}")
private int redisPort;

@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisHost, redisPort);
}

@Bean
public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory redisConnectionFactory, ObjectMapper objectMapper) {
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer(objectMapper);
RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>();

redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(serializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(serializer);

return redisTemplate;
}
}
47 changes: 47 additions & 0 deletions src/main/java/me/jjeda/mall/cart/controller/CartController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package me.jjeda.mall.cart.controller;

import lombok.RequiredArgsConstructor;
import me.jjeda.mall.accounts.dto.AccountDto;
import me.jjeda.mall.cart.domain.CartItem;
import me.jjeda.mall.cart.domain.CartModifyType;
import me.jjeda.mall.cart.service.CartService;
import me.jjeda.mall.common.CurrentUser;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
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 java.util.Objects;

@Controller
@RequiredArgsConstructor
@RequestMapping("/api/carts")
public class CartController {
private final CartService cartService;

@GetMapping
public ResponseEntity getCart(@CurrentUser AccountDto accountDto) {
return ResponseEntity.ok(cartService.getCart(String.valueOf(accountDto.getEmail())));
}

@PutMapping
public ResponseEntity modifyCart(@CurrentUser AccountDto accountDto, @RequestBody CartItem cartItem,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런식으로 나누기보다는 /carts/items 이런식의 도메인구조면 더 역할나누기가 수월할 것 같습니다~

@RequestParam CartModifyType cartModifyType) {

if(Objects.equals(cartModifyType,CartModifyType.ADD)) {
return ResponseEntity.ok(cartService.addItem(String.valueOf(accountDto.getEmail()), cartItem));
} else {
return ResponseEntity.ok(cartService.removeItem(String.valueOf(accountDto.getEmail()), cartItem));
}
}
@DeleteMapping
public ResponseEntity deleteCart(@CurrentUser AccountDto accountDto) {
cartService.deleteCart(String.valueOf(accountDto.getId()));
return ResponseEntity.ok().build();
}
}
34 changes: 34 additions & 0 deletions src/main/java/me/jjeda/mall/cart/domain/Cart.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package me.jjeda.mall.cart.domain;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;

import java.util.ArrayList;
import java.util.List;

@Getter
@Builder
@RedisHash("cart")
@NoArgsConstructor(access = AccessLevel.PACKAGE)
@AllArgsConstructor(access = AccessLevel.PACKAGE)
public class Cart {

@Id
private String id;

private List<CartItem> cartItemList;

private Cart(String id) {
this.id = id;
this.cartItemList = new ArrayList<>();
}

public static Cart of(String id) {
return new Cart(id);
}
}
18 changes: 18 additions & 0 deletions src/main/java/me/jjeda/mall/cart/domain/CartItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package me.jjeda.mall.cart.domain;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import me.jjeda.mall.items.domain.Item;

@Getter
@EqualsAndHashCode
@Builder
@AllArgsConstructor(access = AccessLevel.PACKAGE)
public class CartItem {
private Item item;
private int price;
private int quantity;
}
5 changes: 5 additions & 0 deletions src/main/java/me/jjeda/mall/cart/domain/CartModifyType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package me.jjeda.mall.cart.domain;

public enum CartModifyType {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요청의 내용을 TYPE으로 분기하게 되면 API의 설계가 잘못됐을 가능성도 생각해볼 수 있습니다. 위의 리뷰를 참고하셔서 수정해보시면 좋을 것 같습니다~

ADD, REMOVE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package me.jjeda.mall.cart.repository;

import me.jjeda.mall.cart.domain.Cart;
import org.springframework.data.repository.CrudRepository;

public interface CartRedisRepository extends CrudRepository<Cart, String> {
}
51 changes: 51 additions & 0 deletions src/main/java/me/jjeda/mall/cart/service/CartService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package me.jjeda.mall.cart.service;

import lombok.RequiredArgsConstructor;
import me.jjeda.mall.cart.domain.Cart;
import me.jjeda.mall.cart.domain.CartItem;
import me.jjeda.mall.cart.repository.CartRedisRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityNotFoundException;
import java.util.List;

@Service
@RequiredArgsConstructor
public class CartService {
private final CartRedisRepository cartRedisRepository;

@Transactional(readOnly = true)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SQL이 1개만 나가게되는데 트랜잭션을 걸어준 이유가 있을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

트랜잭션에 대한 이해가 부족했네요..ㅎㅎ

public Cart getCart(String id) {
return cartRedisRepository.findById(id).orElseThrow(EntityNotFoundException::new);
}

@Transactional
public Cart addItem(String id, CartItem cartItem) {
final Cart cart;

if (!cartRedisRepository.existsById(id)) {
cart = Cart.of(id);
} else {
cart = getCart(id);
}

List<CartItem> cartItemList = cart.getCartItemList();
cartItemList.add(cartItem);
return cartRedisRepository.save(cart);
}

@Transactional
public Cart removeItem(String id, CartItem cartItem) {
final Cart cart = getCart(id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

final을 걸어주는건 괜찮지만 이 변수에만 걸어준 이유가 있을까요? 컨벤션은 일관적이면 좋을 것 같아서요~

Copy link
Collaborator Author

@jjeda jjeda Dec 31, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addItem 메서드 수정하다가 기계적으로 바꿨네요..
여기서는 동시성 문제가 없는 듯하여 일괄적인 컨벤션을 위해 삭제하겠습니다!

List<CartItem> cartItemList = cart.getCartItemList();
cartItemList.remove(cartItem);

return cartRedisRepository.save(cart);
}

@Transactional
public void deleteCart(String id) {
cartRedisRepository.delete(getCart(id));
}
}
2 changes: 2 additions & 0 deletions src/main/java/me/jjeda/mall/items/domain/Item.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
Expand All @@ -22,6 +23,7 @@
@Entity
@Getter @Setter
@Builder
@EqualsAndHashCode
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class Item {
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
spring.redis.port=6379
spring.redis.host=localhost

Loading