[스프링부트] 20. 상점 v1 최종(Log)

백하림's avatar
Mar 21, 2025
[스프링부트] 20. 상점 v1 최종(Log)

Log 엔티티

package com.metacoding.storev1.log; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; import lombok.Getter; import lombok.NoArgsConstructor; @Getter @NoArgsConstructor // JPA가 ObjectMapping을 위해 new할 때 필요 @Table(name = "log_tb") // 실제 테이블명을 log_tb로 지정 @Entity // JPA 엔티티 선언 public class Log { @Id // PK(Primary Key) 설정 @GeneratedValue(strategy = GenerationType.IDENTITY) // AUTO_INCREMENT 설정 private Integer id; private Integer storeId; // store_tb의 id를 참조하는 FK (상품 ID) private Integer qty; // 구매 개수 private Integer totalPrice; // 총 가격 (qty * store(price)) private String buyer; // 구매자 이름 }
💡

핵심 요약

  1. JPA 엔티티 매핑
      • @Entity: JPA가 관리하는 객체임을 선언.
      • @Table(name = "log_tb"): 실제 테이블명을 log_tb로 지정.
      • @Id: id를 기본 키(PK)로 설정.
      • @GeneratedValue(strategy = GenerationType.IDENTITY): DB에서 자동 증가(AUTO_INCREMENT).
  1. JPA에서 기본 생성자 필수
      • @NoArgsConstructor: JPA가 내부적으로 리플렉션을 사용할 때 기본 생성자가 필요하므로 추가.
  1. Getter 제공
      • @Getter: 필드 값을 읽을 수 있도록 Lombok을 사용하여 자동 생성.

LogController

package com.metacoding.storev1.log; import java.util.List; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import jakarta.servlet.http.HttpServletRequest; @Controller public class LogController { private LogService logService; public LogController(LogService logService) { this.logService = logService; } @PostMapping("/log/save") public String save(@RequestParam("storeId") int storeId, @RequestParam("buyer") String buyer, @RequestParam("qty") int qty){ logService.구매하기(storeId,buyer,qty); return "redirect:/log"; } @GetMapping("/log") public String list(HttpServletRequest request) { List<LogResponse.ListPage> listPage = logService.구매목록(); request.setAttribute("models", listPage); return "log/list"; } }
💡

핵심 요약

  1. /log로 GET 요청이 오면 구매 목록을 가져옴.
  1. 데이터를 request.setAttribute("models", listPage);로 저장.
  1. log/list.mustache 템플릿으로 데이터를 전달하여 화면 출력.

LogService

package com.metacoding.storev1.store; import java.util.List; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class StoreService { private StoreRepository storeRepository; public StoreService(StoreRepository storeRepository) { this.storeRepository = storeRepository; } // 3번 : board 프로젝트의 BoardService 참고 @Transactional // insert, delete, update시에 사용 : 함수 종료시 commit 됨 public void 상품삭제(int id) { // 1. 상품 있어? Store store = storeRepository.findById(id); if (store == null) throw new RuntimeException("상품없어"); // 3. 삭제 storeRepository.deleteByid(id); // write (DML = insert, delete, update) } @Transactional public void 상품등록(String name, int stock, int price) { storeRepository.save(name, stock, price); } public List<Store> 상품목록() { List<Store> storeList = storeRepository.findAll(); return storeList; } public Store 상세보기(int id) { Store store = storeRepository.findById(id); return store; } @Transactional public void 상품수정(int id, String name, int stock, int price) { // 1. 상품 조회 Store store = storeRepository.findById(id); // 2. 없으면 예외 터트리기 if (store == null) throw new RuntimeException("상품없어"); // 3. 상품 수정 storeRepository.updateById(id, name, stock, price); } }
💡

핵심 요약

  1. @Service를 사용해 비즈니스 로직을 처리하는 서비스 계층을 정의.
  1. LogRepository를 주입받아 데이터 조회 기능을 수행.
  1. 구매목록() 메서드를 호출하면 logRepository.findAllJoinStore()를 통해 데이터베이스에서 구매 목록을 조회하여 반환.

LogRepository

package com.metacoding.storev1.log; import java.util.ArrayList; import java.util.List; import org.springframework.stereotype.Repository; import jakarta.persistence.EntityManager; import jakarta.persistence.Query; @Repository public class LogRepository { private EntityManager em; // DI public LogRepository (EntityManager em){ this.em = em; } public List<LogResponse.ListPage> findAllJoinStore() { List<LogResponse.ListPage> logList = new ArrayList<>(); String q = "SELECT lt.id, st.name, lt.qty, lt.total_price, lt.buyer FROM log_tb lt INNER JOIN store_tb st ON lt.store_id = st.id ORDER BY lt.id DESC"; Query query = em.createNativeQuery(q); List<Object[]> obsList = (List<Object[]>) query.getResultList(); // Object[] -> ROW // ObjectMapping for (Object[] obs : obsList) { LogResponse.ListPage log = new LogResponse.ListPage( (int) obs[0], (String) obs[1], (int) obs[2], (int) obs[3], (String) obs[4]); logList.add(log); } return logList; } public void save(int storeId, int qty, int totalPrice, String buyer) { Query query = em.createNativeQuery("insert into log_tb(store_id, qty, total_price, buyer) values(?,?,?,?)"); query.setParameter(1, storeId); query.setParameter(2, qty); query.setParameter(3, totalPrice); query.setParameter(4, buyer); query.executeUpdate(); } }
💡

핵심 요약

  1. @Repository를 사용해 데이터 액세스 계층(DAO)으로 등록.
  1. EntityManager를 사용해 네이티브 SQL 실행.
  1. log_tbstore_tbJOIN하여 필요한 데이터를 가져옴.
  1. Object[] 형태의 결과를 LogResponse.ListPage DTO 리스트로 변환.

LogResponse

package com.metacoding.storev1.log; import lombok.Data; // DTO : Data Transfer Object -> 화면에 필요한 데이터만 있는 오브젝트 public class LogResponse { @Data // getter, setter, toString 자동 생성 public static class ListPage { private int id; private String name; private int qty; private int totalPrice; private String buyer; public ListPage(int id, String name, int qty, int totalPrice, String buyer) { this.id = id; this.name = name; this.qty = qty; this.totalPrice = totalPrice; this.buyer = buyer; } @Override public String toString() { return "ListPage [id=" + id + ", name=" + name + ", qty=" + qty + ", totalPrice=" + totalPrice + ", buyer=" + buyer + "]"; } } }
💡

핵심 요약

  1. DTO의 역할
      • DTO는 데이터베이스 엔티티(Log)와 다르게 화면에서 필요한 데이터만 전달하는 역할을 수행.
      • Log 엔티티에는 storeId가 있지만, 화면에서는 과일 이름(name)을 표시해야 하므로 DTO를 따로 사용.
  1. ListPage 내부 클래스의 역할
      • ListPage 클래스는 구매 목록을 화면에 전달하기 위한 DTO.
      • 구매 이력(log_tb)과 가게 정보(store_tb)를 조인하여 name(과일 이름)을 포함하는 DTO.
      • LogRepository에서 findAllJoinStore() 메서드에서 List<Object[]>를 변환하여 사용.
  1. Lombok @Data 활용
      • @Data 어노테이션을 사용하여 getter, setter, toString() 자동 생성.
      • 하지만 toString()이 직접 구현되어 있어서, Lombok의 @Data에 포함된 toString() 기능은 사용되지 않음.
 
Share article

harimmon