4 minute read

회원 도메인 개발

구현 기능

  • 회원 등록
  • 회원 목록 조회


회원 리포지토리 개발

@Repository
public class MemberRepository{
    @persistenceContext
    private EntityManger em;

    public void save(Member member){
        em.persist(member)
    }

    public Member findOne(Long id){
        return em.find(Member.class, id);
    }

    public List<Member> findAll(){
        return em.createQuery("select m from Member m", Member.class)
        .getResultlist;
    }

    public List<Member> findByName(String name){
        return em.createQuery("select m from Member m where m.name = :name", Member.class)
        .setParameter("name",name)
        .getResultList();
        }
    }


회원 서비스 코드

@Service
@Transactional(readOnly = true)
@requiredArgsConstructor
public class MemberService{

    private final MemberRepository memberRepository;

    @Transactional
    public Long join(Member member){
        validateDuplicateMember(member);
        memberRepository.save(member);
        return member.getId();
    }

    private void validateDuplicateMember(Member member){
        List<Member> findMembers= memberRepository.findByName(member.getName());
        if(!findMembers.isEmpty()){
            throw new IllegalStateExeption("이미 존재하는 회원");
        }
    }

    public List<Member> findMembers(){
        return memberRepository.findAll();
    }

    public Member findOne(Long memberId){
        return memberRepository.findOne(memberId);
    }
}


회원 기능 테스트


@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class MemberServiceTest{
    @Autowired
    MemberService memberService;

    @Autowired
    MemberRepository memberRepository;

    @Test
    public void 회원가입() throws Exception{
        Member member = new Member();
        member.setName("Kim");

        Long saveId = memberService.join(member);

        assertEquals(member, memberRepository.findOne(saveId));
    }

    @Test(expected = IllgalStateException.class)
    public void 중복_회원_예외() throws Exception{

        Member member1 = new Member();
        member1.setName("kim");

        Member member2 = new Member();
        member2.setName("kim");

        memberService.join(member1);

        memberService.join(member2);

        fail("예외발생");     
    }
}


상품 도메인 개발


//==상품 엔티티에 비즈니스 로직 추가==//

public void addStock(int quantity) {
        this.stockQuantity += quantity;
    }

    public void removeStock(int quantity) {
        int restStock = this.stockQuantity - quantity;
        if (restStock < 0) {
            throw new NotEnoughStockException("need more stock");
        }
        this.stockQuantity = restStock;
    }

    //예외 추가 클래스//

      public class NotEnoughStockException extends RuntimeException {
        
      public NotEnoughStockException() {
      }
      public NotEnoughStockException(String message) {
          super(message);
}
      public NotEnoughStockException(String message, Throwable cause) {
          super(message, cause);
}
      public NotEnoughStockException(Throwable cause) {
          super(cause);
} 
}


상품 리포지토리 코드

@Repository
@RequiredConstructor
public class ItemRepository{
    private final EntityManager em;

    public void save(Item item){
        if (item.getId()== null){
            em.persist(item);
        } else{
            em.merge(item);
        }
    }

    public Item findOne(Long id){
        return em.find(Item.class,id);
    }

    public List<Item> findAll(){
        return em.createQuery("select i from Item i",Item.class)
        .getResultList();
    }
}


상품 서비스 코드

@Service
@Transactional(readOnly = true)  
@RequiredArgsConstructor
public class ItemService{
    private final ItemRepository itemRepository;

    @Transactional
    public void saveItem(Item item){
        itemRepository.save(item);
    }

    public List<Item> findItems(){
        return itemRepository.findAll();
    }

    public Item findOne(Long itemId){
        retrun itemRepository.findOne(itemId);
    }
}


주문 도메인


// 주문 엔티티 생성 메서드 추가 // 
public static Order createOrder(Member member, Delivery delivery, OrderItem...orderItems){
    Order order = new Order();
    order.setMember(member);
    order.setDelivery(delivery);
    for (OrderItem orderItem : orderItems){
        order.addOrderItem(orderItem);
    }
    order.setStatus(OrderStatus.ORDER);
    order.setOrderDate(LocalDateTime.now());
    return order;
}

//비즈니스 로직 추가//
public void cancel(){
    if(delivery.getStatus()== DeliveryStatus.COMP){
        throw new IllgalStateException("이미 배송된 상품은 취소 불가능");
    }

    this.setStatus(OrderStatus.CANCEL);
    for(OrderItem orderItem : orderItems){
        orderItem.cancel();
    }
}

public int getTotalPrice(){
    int totalPrice = 0;
    for(Orderitem orderItem : orderItems){
        totalprice += orderItem.getTotalPrice();
    }
    return totalPrice;
}

//주문상품 생성 메서드 추가 //
public static OrderItem createOrderItem(Item item, int orderPrice, int
  count) {
          OrderItem orderItem = new OrderItem();
          orderItem.setItem(item);
          orderItem.setOrderPrice(orderPrice);
          orderItem.setCount(count);
          item.removeStock(count);
          return orderItem;
      }
//비즈니스 로직 추가//
public void cancel(){
    getItem().addStock(count);
}

public int getTotalPrice(){
        return getOrderPrice()*getCount();
    }


주문 리포지토리 개발


@Repository
@RequiredArgsConstructor
public class OrderRepository{
    private final EntityManger em;

    public void save(Order order){
        em.persist(order);
    }

    public Order findOne(Long id){
        return em.find(Order.class, id);
    }

    //JPQL//
   public List<Order> findAllByString(OrderSearch orderSearch) {
      String jpql = "select o From Order o join o.member m";
      boolean isFirstCondition = true;
//주문 상태 검색
if (orderSearch.getOrderStatus() != null) {
          if (isFirstCondition) {
              jpql += " where";
              isFirstCondition = false;
          } else {
              jpql += " and";
}
          jpql += " o.status = :status";
      }
//회원 이름 검색
if (StringUtils.hasText(orderSearch.getMemberName())) {
          if (isFirstCondition) {
              jpql += " where";
              isFirstCondition = false;
          } else {
              jpql += " and";
}
          jpql += " m.name like :name";
      }
 TypedQuery<Order> query = em.createQuery(jpql, Order.class) .setMaxResults(1000); //최대 1000건
      if (orderSearch.getOrderStatus() != null) {
          query = query.setParameter("status", orderSearch.getOrderStatus());
      }
      if (StringUtils.hasText(orderSearch.getMemberName())) {
          query = query.setParameter("name", orderSearch.getMemberName());
      }
      return query.getResultList();
  }

    //JPA Criteria//
 public List<Order> findAllByCriteria(OrderSearch orderSearch) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Order> cq = cb.createQuery(Order.class);
Root<Order> o = cq.from(Order.class);
Join<Order, Member> m = o.join("member", JoinType.INNER); //회원과 조인
      List<Predicate> criteria = new ArrayList<>();
//주문 상태 검색
if (orderSearch.getOrderStatus() != null) {
          Predicate status = cb.equal(o.get("status"),
  orderSearch.getOrderStatus());
          criteria.add(status);
      }
//회원 이름 검색
if (StringUtils.hasText(orderSearch.getMemberName())) {
          Predicate name =
                  cb.like(m.<String>get("name"), "%" +
  orderSearch.getMemberName() + "%");
          criteria.add(name);
           }
        cq.where(cb.and(criteria.toArray(new Predicate[criteria.size()])));
TypedQuery<Order> query = em.createQuery(cq).setMaxResults(1000); //최대 1000건
        return query.getResultList();
    }
 

    // 검색 조건 파라미터//
    public class OrderSearch{
        private String memberName;
        private OrderStatus orderStatus;
    }
}

주문 서비스 개발


@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class OrderService{
    private final MemberRepository memberRepository;
    private final OrderRepository orderRepository;
    private final ItemRepository itemRepository;

    @Transactional
    public Long order(Long memberId, Long ItemId, int count){
        Member member = memberRepository.findOne(memberId);
        Item item = itemRepository.findOne(itemId);

        Delivery delivery = new Delivery();
        delivery.setAddress(member.getAddress());
        delivery.setStatus(DeliveryStatus.READY);

        OrderItem orderItem = OrderItem.createOrderItem(item, item.getPrice(),int count);

        Order order = Order.createOrder(member, delivery, orderItem);

        orderRepository.save(order)
        return order.getId();
    }

    @Transactional
    public void cancelOrder(Long orderId){
        Order order = orderRepository.findOne(orderId);
        order.cancel();
    }

    public List<Order> findOrders(OrderSearch orderSearch){
        return orderRepository.findAll(orderSearch);
    }
}



주문 기능 테스트

@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class OrderServiceTest {
    @PersistenceContext
    EntityManager em;
    @Autowired OrderService orderService;
    @Autowired OrderRepository orderRepository;

    @Test
    public void 상품주문() throws Exception{

        Member member = createMember();
        Item item = createBook("JPA",10000,10);
        int orderCount = 2;

        Long orderId = orderService.order(member.getId(), item.getId(),orderCount);

        Order getOrder = orderRepository.findOne(orderId);

        assertEquals("상품 주문시 상태는 ORDER",OrderStatus.ORDER,
getOrder.getStatus());

assertEquals("주문한 상품 종류 수가 정확해야 한다.",1,
getOrder.getOrderItems().size());

assertEquals("주문 가격은 가격 * 수량이다.", 10000 * 2,
getOrder.getTotalPrice());
assertEquals("주문 수량만큼 재고가 줄어야 한다.",8, item.getStockQuantity());
}

@Test(expected = NotEnoughStockException.class) public void 상품주문_재고수량초과() throws Exception {
//Given
Member member = createMember();
Item item = createBook("시골 JPA", 10000, 10); //이름, 가격, 재고
int orderCount = 11; //재고보다 많은 수량 //When
      orderService.order(member.getId(), item.getId(), orderCount);
      //Then
fail("재고 수량 부족 예외가 발생해야 한다."); }

@Test
public void 주문취소() {
//Given
Member member = createMember();
Item item = createBook("시골 JPA", 10000, 10); //이름, 가격, 재고
      int orderCount = 2;
      Long orderId = orderService.order(member.getId(), item.getId(),
  orderCount);
//When
      orderService.cancelOrder(orderId);
      //Then
Order getOrder = orderRepository.findOne(orderId); assertEquals("주문 취소시 상태는 CANCEL 이다.",OrderStatus.CANCEL,
getOrder.getStatus());
assertEquals("주문이 취소된 상품은 그만큼 재고가 증가해야 한다.", 10,
  item.getStockQuantity());
  }

  private Member createMember() {
Member member = new Member();
member.setName("회원1");
member.setAddress(new Address("서울", "강가", "123-123")); em.persist(member);
          return member;
      }
private Book createBook(String name, int price, int stockQuantity) {
          Book book = new Book();
          book.setName(name);
          book.setStockQuantity(stockQuantity);
          book.setPrice(price);
          em.persist(book);
          return book;
} }

댓글남기기