본문 바로가기
스프링

[스프링 부트와 JPA 활용] 웹 애플리케이션 개발

by moonstal 2022. 6. 22.

도메인 분석 설계

    //Member
    @OneToMany(mappedBy = "member")//mappedBy 연관관계주인 아님
    private List<Order> orders = new ArrayList<>();

    //Order
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "member_id")
    private Member member; //주문 회원

    //==연관관계 메서드==//
    public void setMember(Member member) {
        this.member = member;
        member.getOrders().add(this);
    }
    public void addOrderItem(OrderItem orderItem) {
        orderItems.add(orderItem);
        orderItem.setOrder(this);
    }

    public void setDelivery(Delivery delivery) {
        this.delivery = delivery;
        delivery.setOrder(this);
    }


    //abstract class Item
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn(name = "dtype")

    //Book extends Item
    @DiscriminatorValue("B")

    //Category
    @ManyToMany
    @JoinTable(name = "category_item",
        joinColumns = @JoinColumn(name = "category_id"),
        inverseJoinColumns = @JoinColumn(name = "item_id"))
    private List<Item> items = new ArrayList<>();

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    private Category parent;

    @OneToMany(mappedBy = "parent")
    private List<Category> child = new ArrayList<>();

    //==연관관계 메서드==//
    public void addChildCategory(Category child) {
        this.child.add(child);
        child.setParent(this);
    }

    //Address
    @Embeddable
    protected Address() {} //값 타입은 변경 불가능하게 설계
    public Address(String city, String street, String zipcode)
  • 엔티티 설계시 주의점
    • Setter 사용하지 x
    • @XToOne 지연로딩으로 설정: N+1 문제
    • 컬렉션은 필드에서 초기화 : null 문제, 영속화->내장 컬렉션으로 변경
    • //private List orders = new ArrayList<>();
  • 테이블, 컬럼명 생성 전략
    • 논리명(_): spring.jpa.hibernate.naming.implicit-strategy
    • 물리명(필드명): spring.jpa.hibernate.naming.physical-strategy

회원 도메인 개발

    //Repository
    @PersistenceContext
    private EntityManager em;

    //Service
    @Transactional(readOnly = true) //공통

    //MemberService
    @Transactional  //변경
    join-> validateDuplicateMember-> findByName-> isEmpty
    -> save / IllegalStateException-> Id반환 //회원명 컬럼에 유니크

상품 도메인 개발

    //Item
    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;
    }

    // NotEnoughStockException extends RuntimeException

주문 도메인 개발

    //Order
    //생성메서드
    createOrder(Member member, Delivery delivery, OrderItem... orderItems)

    //주문 취소
    cancel(): COMP?->IllegalStateException/ CANCEL, orderItem.cancel()

    //전체 주문 가격 조회
    getTotalPrice(): totalPrice += orderItem.getTotalPrice();


    //OrderItem
    //생성메서드
    createOrderItem(Item item, int orderPrice, intcount): set->item.removeStock(count);

    //주문 취소 
    cancel(): getItem().addStock(count);

    //주문상품 전체 가격 조회
    getTotalPrice(): getOrderPrice() * getCount();

    //OrderService
    //주문
    order(Long memberId, Long itemId, int count):
    엔티티 조회->배송정보 생성->주문상품 생성(OrderItem.createOrderItem)
    ->주문 생성(Order.createOrder)->주문 저장

    // 주문 취소
    cancelOrder(Long orderId){
        //주문 엔티티 조회
        Order order = orderRepository.findOne(orderId);
        //주문 취소
        order.cancel();
    }
  • 검색

      //OrderSearch: memberName, orderStatus
    
      //OrderRepository
      List<Order> findAll(OrderSearch orderSearch)
      : JPQL / JPA Criteria / **Querydsl** 동적쿼리

웹 계층 개발

  • 상품수정: 준영속상태(영속성 컨텍스트가 더는 관리하지 않는 엔티티) 변경감지x

  • 변경 감지 기능 / 병합(merge)

      @PostMapping(value = "/items/{itemId}/edit")
      public String updateItem(@ModelAttribute("form") BookForm form){
          //준영속상태
          Book book = new Book();
          ~~~set~~~
          itemService.saveItem(book);
    
          //권장 코드
          itemService.updateItem(form.getId(), form.getName(), form.getPrice());
      }
    
      //변경 감지: 영속성 컨텍스트에서 엔티티를 다시 조회
      Item findItem = em.find(Item.class, itemParam.getId());
      Item item = itemRepository.findOne(id);-> set 더티체킹o
    
      //병합: 준영속 상태의 엔티티를 영속 상태로 변경(위험)
      Item mergeItem = em.merge(item);
  • 상품 주문

      //OrderController
      //주문
      @PostMapping(value = "/order")
      public String order(@RequestParam("memberId") Long memberId,
          @RequestParam("itemId") Long itemId, @RequestParam("count") int count) {
    
          orderService.order(memberId, itemId, count);
          return "redirect:/orders";
      }
    
      //검색
      orderList(@ModelAttribute("orderSearch") OrderSearch orderSearch, Model model)

쿼리 파라미터 로그 남기기
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6'

링크

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-JPA-%ED%99%9C%EC%9A%A9-1

'스프링' 카테고리의 다른 글

[스프링 부트와 JPA 활용] API 개발과 성능 최적화  (0) 2022.07.03
파일 업로드  (0) 2022.06.21
타입 컨버터  (0) 2022.06.20
예외 처리  (0) 2022.06.19
로그인  (0) 2022.06.18