![[Spring Boot] 17. 상점 만들기 (store_v1)](https://image.inblog.dev?url=https%3A%2F%2Finblog.ai%2Fapi%2Fog%3Ftitle%3D%255BSpring%2520Boot%255D%252017.%2520%25EC%2583%2581%25EC%25A0%2590%2520%25EB%25A7%258C%25EB%2593%25A4%25EA%25B8%25B0%2520%28store_v1%29%26logoUrl%3Dhttps%253A%252F%252Finblog.ai%252Finblog_logo.png%26blogTitle%3Dgunwoo&w=3840&q=75)
Contents
1. 컨트롤러 매핑 확인2. 그림 그리기/log/list 페이지/store/list 페이지/store/detail 페이지/store/save-form 페이지/store/update-form 페이지3. 테이블 생성 4. 더미데이터 세팅StoreController6. 새로운 상품 등록하기7. Store list 8. Store detail9. Store delete조인 쿼리 작성log list 만들기Log.javaLogController.javaLogRepository.javaLogResponse.javaLogService.javaLogRepositoryTestlist.mustache1. 컨트롤러 매핑 확인
HelloController 클래스에서 정의된 URL 요청을 처리합니다
package com.metacoding.storev1;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HelloController {
@GetMapping("/log/list")
public String t1() {
return "log/list";
}
@GetMapping("/store/list")
public String t2() {
return "store/list";
}
@GetMapping("/store/detail")
public String t3() {
return "store/detail";
}
@GetMapping("/store/save-form")
public String t4() {
return "store/save-form";
}
@GetMapping("/store/update-form")
public String t5() {
return "store/update-form";
}
}URL 요청 처리 흐름
- 브라우저에서 특정 URL을 입력하면 해당 요청을 HelloController가 받음.
- @GetMapping 어노테이션에 매핑된 뷰 파일(.mustache)을 반환함.
- src/main/resources/templates/ 폴더 안에 있는 .mustache 파일을 찾아서 렌더링함.
2. 그림 그리기
웹 페이지 네비게이션 바
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>blog</title>
</head>
<body>
<nav>
<ul>
<li>
<a href="#">상품목록</a>
</li>
<li>
<a href="#">상품등록</a>
</li>
<li>
<a href="#">구매목록</a>
</li>
</ul>
</nav>
<hr>구매 목록(주문 내역) 페이지
{{>layout/header}}
<section>
<table border="1">
<tr>
<th>주문번호</th>
<th>상품명(조인)</th>
<th>구매개수</th>
<th>총가격</th>
<th>구매자이름</th>
</tr>
<tr>
<td>1</td>
<td>바나나</td>
<td>5개</td>
<td>15000원</td>
<td>ssar</td>
</tr>
<tr>
<td>2</td>
<td>바나나</td>
<td>5개</td>
<td>15000원</td>
<td>ssar</td>
</tr>
<tr>
<td>3</td>
<td>딸기</td>
<td>5개</td>
<td>10000원</td>
<td>cos</td>
</tr>
</table>
</section>
</body>
</html>상품 상세 페이지
특정 상품의 정보를 보여주고 구매 또는 삭제 기능 제공
{{> layout/header}}
<section>
<a href="#">수정화면가기</a>
<form action="#">
<button type="submit">삭제</button>
</form>
<div>
번호 : 1 <br>
상품명 : 바나나 <br>
상품가격 : 3000원 <br>
상품재고 : 100개 <br>
</div>
<form action="#">
<input type="hidden" value="1">
<input type="text" placeholder="당신은 누구인가요?">
<input type="text" placeholder="Enter 개수">
<button type="submit">구매</button>
</form>
</section>
</body>
</html>상품 목록 페이지
사용자가 등록된 상품 확인 및 각 상품의 상세 페이지로 이동
{{>layout/header}}
<section>
<table border="1">
<tr>
<th>번호</th>
<th>상품명</th>
<th></th>
</tr>
<tr>
<td>1</td>
<td>바나나</td>
<td><a href="#">상세보기</a></td>
</tr>
<tr>
<td>2</td>
<td>딸기</td>
<td><a href="#">상세보기</a></td>
</tr>
</table>
</section>
</body>
</html>상품 등록 페이지
사용자가 새로운 상품을 추가할 수 있도록 입력 폼 제공
{{> layout/header}}
<section>
<form action="#">
<input type="text" placeholder="상품명"><br>
<input type="text" placeholder="수량"><br>
<input type="text" placeholder="가격"><br>
<button type="submit">상품등록</button>
</form>
</section>
</body>
</html>상품 수정 페이지
사용자가 기존 상품 정보를 수정하고 저장할 수 있도록 입력 폼 제공
{{> layout/header}}
<section>
<form action="#">
<input type="text" value="바나나"><br>
<input type="text" value="100"><br>
<input type="text" value="3000"><br>
<button type="submit">상품수정</button>
</form>
</section>
</body>
</html>/log/list 요청 → log/list.mustache 렌더링
- 사용자가 /log/list URL에 접속
- HelloController의 t1() 메서드 실행
- return "log/list"; → templates/log/list.mustache 파일을 찾아 화면을 렌더링
/log/list 페이지

/store/list 페이지

/store/detail 페이지

/store/save-form 페이지

/store/update-form 페이지

3. 테이블 생성
Store.java
: 상품 데이터를 DB의 store_db 테이블에 매핑하여 처리할 수 있도록 도와줌
EX) 상품 목록을 조회 하거나, 새 상품을 추가하거나, 기존 상품을 수정
package com.metacoding.storev1.store;
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 = "store_tb") // 테이블 설정
@Entity // 설정파일에서 테이블을 생성해준다.
public class Store {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private Integer stock; // 재고
private Integer price;
}Log.java
: 구매로그 정보를 데이터베이스에 저장하고 관리
EX) 상품 구매가 일어난 후 구매 로그를 DB에 저장하는데 사용
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") // 테이블 설정
@Entity // 설정파일에서 테이블을 생성해준다.
public class Log {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Integer storeId; // 상품 ID (FK)
private Integer qty; // 구매 개수
private Integer totalPrice; // qty * store(price)
private String buyer; // 구매자 이름
}README.md
store_tb**와 log_tb 두 개의 테이블을 생성하는 DDL(Data Definition Language) 문
# Table Setting
## store_tb
```sql
create table store_tb (
id integer generated by default as identity,
price integer,
stock integer,
name varchar(255),
primary key (id)
);
```
## log_tb
```sql
create table log_tb (
id integer generated by default as identity,
qty integer,
store_id integer,
total_price integer,
buyer varchar(255),
primary key (id)
);
```테이블 간 관계
- store_tb 테이블은 상품에 대한 정보를 저장하고, log_tb 테이블은 구매 로그에 대한 정보를 저장합니다.
- log_tb.store_id 필드는 **store_tb.id*와 **외래 키 관계(Foreign Key)**를 가집니다. 즉, 구매 로그는 어떤 상품이 구매되었는지를 추적하는 역할을 합니다.
4. 더미데이터 세팅
더미는 일관성 있게 만들어야한다
data.sql
insert into store_tb(name, stock, price) values ('바나나', 40, 3000);
insert into store_tb(name, stock, price) values ('딸기', 45, 2000);
insert into log_tb(store_id, qty, total_price, buyer) values (1, 5, 15000, 'ssar');
insert into log_tb(store_id, qty, total_price, buyer) values (1, 5, 15000, 'ssar');
insert into log_tb(store_id, qty, total_price, buyer) values (2, 5, 10000, 'cos');store_tb와 log_tb 테이블에 데이터를 삽입하는 명령입니다.
application.properties
# vscode console highlight
spring.output.ansi.enabled=always
# utf-8
server.servlet.encoding.charset=utf-8
server.servlet.encoding.force=true
# DB
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:test
spring.datasource.username=sa
spring.datasource.password=
spring.h2.console.enabled=true
# JPA table create or none
spring.jpa.hibernate.ddl-auto=create
# query log
spring.jpa.show-sql=true
# dummy data
spring.sql.init.data-locations=classpath:db/data.sql
# create dummy data after ddl-auto create
spring.jpa.defer-datasource-initialization=true
# mustache request expose
spring.mustache.servlet.expose-request-attributes=true
# sql formatter
spring.jpa.properties.hibernate.format_sql=true

5. 화면 연결하기
StoreController
반환하는 값의 주소를 잘 적어줘야 한다.
삭제, 추가 메서드는 홈 페이지(”/”)로 리다이렉트 하기
package com.metacoding.storev1.store;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@Controller // loC (제어의 역전) =>HashSet
public class StoreController {
@GetMapping("/")
public String list() {
return "store/list";
}
@GetMapping("/store/save-form")
public String saveForm() {
return "store/save-form";
}
@GetMapping("/store/{id}")
public String detail(@PathVariable("id") Integer id) {
return "store/detail";
}
@GetMapping("/store/{id}/update-form")
public String updateForm(@PathVariable("id") Integer id) {
return "store/update-form";
}
@PostMapping("/store/{id}/delete")
public String delete(@PathVariable("id") Integer id) {
return "redirect:/";
}
@PostMapping("/store/save")
public String save() {
return "redirect:/";
}
@PostMapping("/store/{id}/update")
public String update(@PathVariable("id") Integer id) {
return "redirect:/store/" + id;
}
}웹 페이지 네비게이션 바
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>blog</title>
</head>
<body>
<nav>
<ul>
<li>
<a href="/">상품목록</a>
</li>
<li>
<a href="/store/save-form">상품등록</a>
</li>
<li>
<a href="/log">구매목록</a>
</li>
</ul>
</nav>
<hr>


상품 상세 페이지
특정 상품의 정보를 보여주고 구매 또는 삭제 기능 제공
{{> layout/header}}
<section>
<a href="/store/1/update-form">수정화면가기</a>
<form action="/store/1/delete" method="POST">
<button type="submit">삭제</button>
</form>
<div>
번호 : 1 <br>
상품명 : 바나나 <br>
상품가격 : 3000원 <br>
상품재고 : 100개 <br>
</div>
<form action="#">
<input type="hidden" value="1">
<input type="text" placeholder="당신은 누구인가요?">
<input type="text" placeholder="Enter 개수">
<button type="submit">구매</button>
</form>
</section>
</body>
</html>

상품 목록 페이지
사용자가 등록된 상품 확인 및 각 상품의 상세 페이지로 이동
{{>layout/header}}
<section>
<table border="1">
<tr>
<th>번호</th>
<th>상품명</th>
<th></th>
</tr>
<tr>
<td>1</td>
<td>바나나</td>
<td><a href="/store/1">상세보기</a></td>
</tr>
<tr>
<td>2</td>
<td>딸기</td>
<td><a href="/store/2">상세보기</a></td>
</tr>
</table>
</section>
</body>
</html>

상품 등록 페이지
사용자가 새로운 상품을 추가할 수 있도록 입력 폼 제공
{{> layout/header}}
<section>
<form action="/store/save" method="POST">
<input type="text" placeholder="상품명"><br>
<input type="text" placeholder="수량"><br>
<input type="text" placeholder="가격"><br>
<button type="submit">상품등록</button>
</form>
</section>
</body>
</html>

상품 수정 페이지
사용자가 기존 상품 정보를 수정하고 저장할 수 있도록 입력 폼 제공
{{> layout/header}}
<section>
<form action="/store/{{id}}/update" method="POST">
<input type="text" value="바나나"><br>
<input type="text" value="100"><br>
<input type="text" value="3000"><br>
<button type="submit">상품수정</button>
</form>
</section>
</body>
</html>
6. 새로운 상품 등록하기
StoreRepository
: 상품 정보를 데이터베이스에 저장하는 기능을 담당하는 클래스
package com.metacoding.storev1.store;
import org.springframework.stereotype.Repository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
@Repository
public class StoreRepository {
private EntityManager em;
public StoreRepository(EntityManager em) {
this.em = em;
}
public void save(String name, int stock, int price) {
Query query = em.createNativeQuery("insert into store_tb(name, stock, price) values (?,?,?)");
query.setParameter(1, name);
query.setParameter(2, stock);
query.setParameter(3, price);
query.executeUpdate();
}
} 상품 데이터 저장 (save 메서드)
- createNativeQuery(...) : SQL 문을 직접 실행하는 방식 (네이티브 쿼리).
- setParameter(...) : ?에 해당하는 값을 설정.
- executeUpdate() : INSERT, UPDATE, DELETE와 같은 DML 쿼리를 실행.
StoerService
: 비즈니스 로직을 담당하는 서비스 계층
package com.metacoding.storev1.store;
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;
}
@Transactional
public void 상품등록(String name, int stock, int price) {
storeRepository.save(name, stock, price);
}
}저장소(Repository) 의존성 주입
- StoreRepository를 주입받아 사용합니다.
- 이 저장소를 통해 데이터베이스에 상품을 저장할 수 있습니다.
StoreController
package com.metacoding.storev1.store;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller // loC (제어의 역전) =>HashSet
public class StoreController {
private StoreService storeService;
public StoreController(StoreService storeService) {
this.storeService = storeService;
}
@GetMapping("/")
public String list() {
return "store/list";
}
@GetMapping("/store/save-form")
public String saveForm() {
return "store/save-form";
}
@GetMapping("/store/{id}")
public String detail(@PathVariable("id") Integer id) {
return "store/detail";
}
@GetMapping("/store/{id}/update-form")
public String updateForm(@PathVariable("id") Integer id) {
return "store/update-form";
}
@PostMapping("/store/{id}/delete")
public String delete(@PathVariable("id") Integer id) {
return "redirect:/";
}
@PostMapping("/store/save")
public String save(@RequestParam("name") String name, @RequestParam("stock") int stock,
@RequestParam("price") int price) {
storeService.상품등록(name, stock, price);
return "redirect:/";
}
@PostMapping("/store/{id}/update")
public String update(@PathVariable("id") Integer id) {
return "redirect:/store/" + id;
}
}private StoreService storeService;
public StoreController(StoreService storeService) {
this.storeService = storeService;
}StoreService를 주입받아 비즈니스 로직을 호출할 수 있도록 합니다.
상품 등록 페이지
사용자가 새로운 상품을 추가할 수 있도록 입력 폼 제공
사용자가 상품 정보를 입력한 후 상품등록 버튼을 클릭하면 /store/save로 데이터를 전송합니다.
{{> layout/header}}
<section>
<form action="/store/save" method="POST">
<input type="text" placeholder="상품명" name = "name" value="바나나"><br>
<input type="text" placeholder="수량" name = "stock" value="50"><br>
<input type="text" placeholder="가격" name = "price" value="3000"><br>
<button type="submit">상품등록</button>
</form>
</section>
</body>
</html>
localhost:8080/h2-console 들어가서 확인해보기

7. Store list
StoreController
package com.metacoding.storev1.store;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import jakarta.servlet.http.HttpServletRequest;
@Controller // loC (제어의 역전) =>HashSet
public class StoreController {
@@ -16,7 +19,9 @@ public StoreController(StoreService storeService) {
}
@GetMapping("/")
public String list() {
public String list(HttpServletRequest request) { // MVC
List<Store> storeList = storeService.상품목록();
request.setAttribute("models", storeList);
return "store/list";
}package com.metacoding.storev1.store;
import java.util.List;
import org.springframework.stereotype.Repository;
import jakarta.persistence.EntityManager;
public StoreRepository(EntityManager em) {
}
public void save(String name, int stock, int price) {
Query query = em.createNativeQuery("insert into store_tb(name, stock, price) values (?,?,?)");
Query query = em.createNativeQuery("insert into store_tb(name, stock, price) values(?,?,?)");
query.setParameter(1, name);
query.setParameter(2, stock);
query.setParameter(3, price);
query.executeUpdate();
}
public List<Store> findAll() {
// 조건 : 오브젝트 매핑은 @Entity가 붙어야지만 가능하다. (디폴트 생성자를 호출)
Query query = em.createNativeQuery("select * from store_tb order by id desc", Store.class);
return query.getResultList();
}
}StoerService
: 비즈니스 로직을 담당하는 서비스 계층
package com.metacoding.storev1.store;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
public StoreService(StoreRepository storeRepository) {
public void 상품등록(String name, int stock, int price) {
storeRepository.save(name, stock, price);
}
public List<Store> 상품목록() {
List<Store> storeList = storeRepository.findAll();
return storeList;
}
}{{#models}}
<tr>
<td>{{id}}</td>
<td>{{name}}</td>
<td><a href="/store/{{id}}">상세보기</a></td>
</tr>
{{/models}}
8. Store detail
{{> layout/header}}
<section>
<a href="/store/{{model.id}}/update-form">수정화면가기</a>
<form action="/store/{{model.id}}/delete" method="post">
<button type="submit">삭제</button>
</form>
<div>
번호 : {{model.id}} <br>
상품명 : {{model.name}} <br>
상품가격 : {{model.price}}원 <br>
상품재고 : {{model.stock}}개 <br>
</div>
<form action="#">
<input type="hidden" value="{{model.id}}">
<input type="text" placeholder="당신은 누구인가요?">
<input type="text" placeholder="Enter 개수">
<button type="submit">구매</button>
</form>
</section>
</body>
</html> // TODO: 상세보기 1
public Store findById(int id) {
Query query = em.createNativeQuery("select * from store_tb where id = ?", Store.class);
query.setParameter(1, id);
return (Store) query.getSingleResult();
}// TODO: 상세보기 2
@GetMapping("/store/{id}")
public String detail(@PathVariable("id") int id, HttpServletRequest request) {
Store store = storeService.상세보기(id);
request.setAttribute("model", store);
return "store/detail";
}// TODO: 상세보기 3
public Store 상세보기(int id) {
Store store = storeRepository.findById(id);
return store;
}
9. Store delete
// 1번
public void deleteById(int id) {
Query query = em.createNativeQuery("delete from store_tb where id = ?");
query.setParameter(1, id);
query.executeUpdate();
}// 2번
@PostMapping("/store/{id}/delete")
public String delete(@PathVariable("id") Integer id) {
storeService.상품삭제(id);
return "redirect:/";
}// 3번
@Transactional // insert, delete, uptate시에 사용 : 함수 종료시 commit 됨.
public void 상품삭제(int id) {
storeRepository.deleteById(id);
}

조인 쿼리 작성

log list 만들기

Log.java
: 상품 구매 기록을 저장하는 역할을 하며, 구매 내역을 추적하는 데 사용
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") // 테이블 설정
@Entity // 설정파일에서 테이블을 생성해준다.
public class Log {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Integer storeId; // 상품 ID (FK)
private Integer qty; // 구매 개수
private Integer totalPrice; // qty * store(price)
private String buyer; // 구매자 이름
}
LogController.java
: 구매기록을 조회하여 화면(view)에 데이터를 전달하는 기능
package com.metacoding.storev1.log;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import jakarta.servlet.http.HttpServletRequest;
@Controller
public class LogController {
private LogService logService;
public LogController(LogService logService) {
this.logService = logService;
}
@GetMapping("/log")
public String list(HttpServletRequest request) {
List<LogResponse.ListPage> listpage = logService.구매목록();
request.setAttribute("models", listpage);
return "log/list";
}
}@GetMapping("/log") : /log URL로 GET 요청이 오면 해당 메서드가 실행됩니다.
logService.구매목록() : LogService를 호출하여 구매 내역을 조회합니다.
request.setAttribute("models", listpage); : 조회한 데이터를 request 객체에 저장하여 View로 전달합니다.
return "log/list"; : log/list.jsp 또는 log/list.html 뷰 페이지로 이동합니다.
LogRepository.java
: 구매내역을 조회
: 로그 테이블과 상품 테이블을 조인하여 구매기록을 가져옴
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 // loC
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;
}
}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";
: log_tb(로그 테이블)과 store_tb(상품 테이블)을 조인(join) 하여 데이터를 조회합니다.
Query query = em.createNativeQuery(q);
: EntityManager를 사용하여 네이티브 SQL 쿼리를 실행합니다.
List<Object[]> obsList = (List<Object[]>) query.getResultList();
: 조회 결과를 리스트(Object 배열) 형태로 가져옵니다.
for (Object[] obs : obsList) { ... }
: 조회된 데이터를 LogResponse.ListPage 객체로 변환하여 logList에 추가합니다.
LogResponse.java
DTO 사용 이유
: 데이터 보호, 코드 가독성 향상, API 응답 최적화
: 코드 분석 및 역할정리
package com.metacoding.storev1.log;
import lombok.AllArgsConstructor;
import lombok.Data;
// DTO : Data Transfer Object - 화면에 필요한 데이터만 있는 오브젝트
public class LogResponse {
@AllArgsConstructor
@Data // getter, setter, toString
public static class ListPage {
private int Id;
private String name;
private int qty;
private int totalPrice;
private String buyer;
// @Override
// public String toString() {
// return "ListPage [Id=" + Id + ", name=" + name + ", qty=" + qty + ",
// totalPrice=" + totalPrice + ", buyer="
// + buyer + "]";
// }
}
}- DTO (Data Transfer Object) 역할을 하는 클래스
- 데이터베이스에서 가져온 데이터를 가공하여 화면(View)으로 전달하는 역할
- 불필요한 필드를 제거하고, 필요한 데이터만 포함
- Getter, Setter, toString 자동 생성 (@Data 사용)
LogService.java
: Controller와 Repository를 연결하는 중간 역할
: 비즈니스 로직을 담당
package com.metacoding.storev1.log;
import java.util.List;
import org.springframework.stereotype.Service;
import com.metacoding.storev1.log.LogResponse.ListPage;
@Service
public class LogService {
private LogRepository logRepository;
public LogService(LogRepository logRepository) {
this.logRepository = logRepository;
}
public List<ListPage> 구매목록() {
return logRepository.findAllJoinStore();
}
}LogRepositoryTest
: H2 같은 내장 DB에서 실행되어 실제 DB를 변경하지 않고 테스트 가능
package com.metacoding.storev1.log;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;
import com.metacoding.storev1.log.LogResponse.ListPage;
@Import(LogRepository.class)
@DataJpaTest // em loC 등록
public class LogRepositoryTest {
@Autowired // di 하는 어노테이션 새로운 방법
private LogRepository logRepository;
@Test
public void findAllJoinstore_test() { // 매개변수에 아무것도 적을 수 없다
List<LogResponse.ListPage> logList = logRepository.findAllJoinStore();
for (ListPage listpage : logList) {
System.out.println(listpage);
}
}
}
list.mustache
주문 목록을 테이블로 출력하는 코드
{{>layout/header}}
<section>
<table border="1">
<tr>
<th>주문번호</th>
<th>상품명(조인)</th>
<th>구매개수</th>
<th>총가격</th>
<th>구매자이름</th>
</tr>
{{#models}}
<tr>
<td>{{id}}</td>
<td>{{name}}</td>
<td>{{qty}}개</td>
<td>{{totalPrice}}원</td>
<td>{{buyer}}</td>
</tr>
{{/models}}
</table>
</section>
</body>
</html> {{#models}} ... {{/models}}
: 반복문 시작 (models 리스트의 각 요소를 순회)
Share article