1. 상품등록 만들기
0. 화면부터 보자!

1. store/save-form.mustache로 가자!
- input 태그의 name 속성의 값은 db 상의 컬럼명과 일치하는 게 아니라 모델링한 것과 일치해야하므로 Store.java를 확인해야 한다.
save-form.mustache

Store.java

2. 이제 StoreContoller로 가자!
- controller에서 값 잘 받고 응답 받는거 확인한다.
- Cursor에서는 매개변수에 @RequestParam("") 붙여주기
- controller의 책임은 끝났으니까 service로 넘긴다.
- 의존성 주입!

@PostMapping("/store/save")
public String save(@RequestParam("name")String name, @RequestParam("stock")int stock, @RequestParam("price")int price) {
storeService.상품등록(name,stock,price);
return "redirect:/";
}3. StoreService로 가자!
- 상품등록은 write(insert)이고 write는 commit이 적용되어야 하니까 @Transactional 붙여주기
- service의 책임은 끝났으니까 repository로 넘긴다.
- 의존성 주입!

@Transactional // import 주의 jakarta 아님!
public void 상품등록(String name, int stock, int price){
storeRepository.save(name, stock, price);
}4. StoreRepository로 가자!
- db로부터 return 받는게 없으니까 오브젝트 매핑 없어도 된다!
- 의존성 주입!

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();
}5. Repository → Service → Controller
- respository에서 return하는게 없으므로 service에서도 받는게 없다.
- service에서도 return하는게 없으므로 controller에서도 받는게 없다.
2. 상품목록 만들기
0. 화면부터 보자!

1. StoreContoller로 가자!
- 일단 controller의 책임은 끝났으니까 service로 넘긴다.
@GetMapping("/")
public String list() {
storeService.상품목록();
return "store/list";
}2. StoreService로 가자!
- 일단 service의 책임은 끝났으니까 repository로 넘긴다.
public void 상품목록(){
storeRepository.findAll();
}3. StoreRepository로 가자!
- select문을 통해 db로부터 리턴 받으므로 오브젝트 매핑을 위해 Store.class를 추가해준다.
- select * ⇒ 여러 개의 행을 리턴하므로 getResultList()
- Store 객체들을 list로 리턴하니까 리턴 타입은 List<Store>가 된다.
- 여기서 움직이는 데이터는 List<Store>이므로 List<Store>가 model이 된다.
// model = List<Store>
public List<Store> findAll() {
// 조건 : 오브젝트 매핑은 @Entity가 붙어있어야지만 가능하다. (디폴트 생성자를 호출)
// reflection을 통한 setter 호출
Query query = em.createNativeQuery("select * from store_tb order by id desc", Store.class);
return query.getResultList();
}4. 다시 StoreService로 돌아오자!
- storeRepository.findAll()의 리턴 타입이 List<Store>이므로 List<Store> storeList로 받는다.
- Repository로부터 받은 List<Store>를 다시 Controller로 리턴해줘야 하므로 메서드의 리턴 타입은 List<Store>로 수정하고 storeList를 리턴한다.
- 여기서 움직이는 데이터는 List<Store>이므로 List<Store>가 model이 된다.
// model = List<Store> (움직이는 데이터)
public List<Store> 상품목록(){
List<Store> storeList = storeRepository.findAll();
return storeList;
}5. 다시 StoreController로 돌아오자!
- storeService.상품목록()로부터 List<Store> storeList를 받는다.
- 리턴 받은 Object를 request에 담아서 View인 store/list.mustache로 보내줘야 한다.
- request.setAttribute(”key”,value)
// 동적 페이지
@GetMapping("/")
public String list(HttpServletRequest request) { // MVC
List<Store> storeList = storeService.상품목록();
request.setAttribute("models", storeList); // Object = List의 Store 타입
return "store/list";
}6. store/list.mustache로 가자!
- List<Store> storeList인 models를 돌면서 id와 name을 받아올 수 있도록 조건문을 사용하자

3. 상품상세보기 만들기
0. 화면부터 보자!

1. StoreContoller로 가자!
- 일단 controller의 책임은 끝났으니까 service로 넘긴다.
- 특정 id의 상품에 대해서 상세보기 하는 것이므로 id를 service로 넘겨야 한다.
@GetMapping("/store/{id}")
public String detail(@PathVariable("id") int id) {
storeService.상품상세보기(id)
return "store/detail";
}2. StoreService로 가자!
- 일단 service의 책임은 끝났으니까 repository로 넘긴다.
- id를 repository에도 넘긴다
public void 상품상세보기(int id) {
storeRepository.findById(id);
}3. StoreRepository로 가자!
- select문을 통해 db로부터 리턴 받으므로 오브젝트 매핑을 위해 Store.class를 추가해준다.
- where id = ?을 통해 1개의 행을 리턴하므로 getSingleResult()
- getSingleResult()는 리턴 타입이 Object이므로 다운캐스팅이 필요하다!
- Store 객체를 하나만 리턴하니까 리턴 타입은 Store가 된다.
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();
}4. 다시 StoreService로 돌아오자!
- storeRepository.findById의 리턴 타입이 Store 이므로 Store store로 받는다.
- Repository로부터 받은Store 를 다시 Controller로 리턴해줘야 하므로 메서드의 리턴 타입은 Store 로 수정하고 store를 리턴한다.
public Store 상품상세보기(int id) {
Store store = storeRepository.findById(id);
return store;
}5. 다시 StoreController로 돌아오자!
- storeService.상품상세보기(id)로부터 Store store를 받는다.
- 리턴 받은 Object를 request에 담아서 View인 store/detail.mustache로 보내줘야 한다.
- request.setAttribute(”key”,value)
- 상품목록에서 설정한 key는 리스트이므로 models로 했고 여기서는 한 개만 담아서 보내기 때문에 model로 하자
@GetMapping("/store/{id}")
public String detail(@PathVariable("id") int id, HttpServletRequest request) {
Store store = storeService.상품상세보기(id);
request.setAttribute("model", store);
return "store/detail";
}6. store/detail.mustache로 가자!
- 템플릿 엔진 mustache의 데이터 전달 문법과, key값인 model에 맞춰서 detail.mustache를 수정한다.

4. 상품 삭제하기 만들기
0. 화면부터 보자!

1. store/detail.mustache로 가자!
- 확인하고 controller로~

2. StoreContoller로 가자!
- controller의 책임은 끝났으니까 service로 넘긴다.
- 특정 id의 상품에 대해서 삭제하는 것이므로 id를 service로 넘겨야 한다.
@PostMapping("/store/{id}/delete")
public String delete(@PathVariable("id") int id) {
storeService.상품삭제(id);
return "redirect:/";
}3. StoreService로 가자!
- 삭제를 할 때에는 상품이 있는지 먼저 확인하고 (1) 있을 경우 삭제하도록(2) 비지니스 로직을 구성한다.
- 상품삭제는 write(delete)이고 write는 commit이 적용되어야 하니까 @Transactional 붙여주기
- service의 책임은 끝났으니까 repository로 넘긴다.
- id도 repository로 넘긴다.
@Transactional // insert, delete, update시에 사용 : 함수 종료시 commit됨
public void 상품삭제(int id) {
// 1. 상품 있는지 확인하고
Store store = storeRepository.findById(id);
// 2. 삭제하기
if (store == null) {
throw new RuntimeException("상품이 없는데 왜 삭제를 ㅠㅠ");
}
storeRepository.deleteById(id);
}4. StoreRepository로 가자!
- db로부터 return 받는게 없으니까 오브젝트 매핑 없어도 된다!
public void deleteById(int id){
Query query = em.createNativeQuery("delete from store_tb where id = ?");
query.setParameter(1, id);
query.executeUpdate();
}5. Repository → Service → Controller
- respository에서 deleteById()에 대해서 return하는게 없으므로 service에서도 받는게 없다.
- service에서도 return하는게 없으므로 controller에서도 받는게 없다.
5. 상품수정 만들기
- 일단 화면에 값을 뿌려야 한다!

1. update-form.mustache부터 가서 보자!
- value 속성 설정을 통해 값을 미리 입력해둔 상태기 때문에 상품상세보기를 참고해서 id에 대한 상품 정보를 가져와야 한다.
- 일단 화면에 값을 뿌려야 한다!

Controller
@GetMapping("/store/{id}/update-form")
public String updateForm(@PathVariable("id") int id, HttpServletRequest request) {
Store store = storeService.상품상세보기(id);
request.setAttribute("model", store);
return "store/update-form";
}
여기는 수정하기 버튼에 대해서 만든거
2. 이제 StoreContoller로 가자!
- controller에서 값 잘 받고 응답 받는거 확인한다.
- Cursor에서는 매개변수에 @RequestParam("") 붙여주기
- sout으로 확인해보기

@PostMapping("/store/{id}/update")
public String update(@PathVariable("id") int id, @RequestParam("name")String name, @RequestParam("stock")int stock, @RequestParam("price")int price) {
storeService.상품수정(id, name, stock, price);
return "redirect:/store/" + id;
}Service
- write니까 @Transaction을 먼저 걸자!
@Transactional
public void 상품수정(int id, String name, int stock, int price) {
// 1. 상품 있는지 확인하고
Store store = storeRepository.findById(id);
// 2. 수정하기
if (store == null){
throw new RuntimeException("상품이 없는데 왜 수정을 ㅠㅠ");
}
storeRepository.updateById(id, name, stock, price);
}Repository
public void updateById(int id, String name, int stock, int price) {
Query query = em.createNativeQuery("update store_tb set name = ?, stock = ?, price = ? where id = ?");
query.setParameter(1, name);
query.setParameter(2, stock);
query.setParameter(3, price);
query.setParameter(4, id);
query.executeUpdate();
}Share article