방법1 - 본인이 생각했던 로직
- 동일 사용자가 동일 상품 몇 번 담았는지 확인, 즉 해당 (uid, product_code) 존재하는 cart건수 카운트
1.1. 동일 상품 담은 기록 없으면 새 cart 삽입
1.2.1. 동일 상품 담은 기록 있으면 해당건의 cartid 찾기
1.2.2. 조회된 cartid의 레코드에 대해 장바구니에 담은 수량 변경
소스코드:
1, Vo
@Data
public class CartVo {
private String cartid;
private String uid;
private String username;
private String product_code;
private String pname;
private String pimgStr;
...
private int pstock;
private int pquantity;
private int camount;
private int pprice;
private int pdelifee;
// 통화 변환. 천단위 콤마 표시
public String getFmtPprice() {
NumberFormat numberFormat =
NumberFormat.getNumberInstance(Locale.getDefault());
return numberFormat.format(pprice);
}
public String getFmtPdelifee() {
NumberFormat numberFormat =
NumberFormat.getNumberInstance(Locale.getDefault());
return numberFormat.format(pdelifee);
}
}
2, Mapper
@Mapper
public interface CartMapper {
//장바구니 담기
//1. 해당 사용자가 해당 상품 몇 번 담았는지, 즉 (uid, product_code) 존재 cart건수 카운트
@Select ("select count(*) from cart "
+ "WHERE uid=#{username} "
+ "and product_code = #{product_code}")
int countCart (@Param("username") String username,
@Param("product_code") String product_code);
//1.1. 동일 상품 담은 기록 없으면 cart에 새 데이터 삽입
@Insert ("insert into cart (uid, product_code, pquantity) "
+ "values (#{uid}, #{product_code}, #{pquantity})")
void addCart (CartVo vo);
//1.2.1. 동일 상품 담은 기록 있으면 해당건의 cartid 찾기
@Select ("select cartid from cart "
+ "WHERE uid=#{username} "
+ "and product_code = #{product_code}")
String resultCartid(@Param("username") String username,
@Param("product_code") String product_code);
//1.2.2. 조회된 cartid의 레코드에 대해 장바구니에 담은 수량 업뎃
@Update ("update cart set pquantity=pquantity + #{pquantity} "
+ "where cartid=#{cartid}")
void updatePquantity (CartVo vo);
//장바구니 담기 끝
}
3, Service
@Service
public class CartSvc {
@Autowired
CartMapper cartMapper;
public void addCart(CartVo vo) {
cartMapper.addCart(vo); //장바구니에 담기
}
public int countCart (String username, String product_code) {
return cartMapper.countCart(username, product_code);
/*
해당 사용자가 해당 상품 몇 번 담았는지, 즉 (uid, product_code) 중복된 cart건수 카운트
countCart: 카운트 메서드
*/
}
public String resultCartid(String username, String product_code) {
return cartMapper.resultCartid(username, product_code); //장바구니 담은 기록 있는 cartid 추출
}
public void updatePquantity(CartVo vo) {
cartMapper.updatePquantity(vo); //장바구니에 담은 수량 업뎃
}
}
4, Ctrl
@RequestMapping("/cart/")
@Controller
public class CartCtrl {
@Autowired
CartSvc cartSvc;
@Autowired
HttpSession session;
@PostMapping("addCart")
String addCart (Model model, CartVo vo) {
System.out.println("addCart");
String username=(String) session.getAttribute("username");
vo.setUid(username); //redirect 경로 잡기 위해 db의 uid에 username값 대입
String product_code = vo.getProduct_code();
int countC = cartSvc.countCart(username, product_code);
if (countC == 0) { //해당 사용자가 해당 상품 최초 담으면 (담은 기록 없으면) cart에 새 레코드 생성
cartSvc.addCart(vo);
} else { //countC > 0
String cartid = cartSvc.resultCartid(username, product_code);
//(select cartid from cart WHERE uid=? and product_code=?) 통해 cartid 찾기
vo.setCartid(cartid); //해당 레코드의 cartid 지정
cartSvc.updatePquantity(vo); //해당 cartid의 레코드에서 해당 상품의 수량만 변경
}
System.out.println("addCart uid/username: "+vo.getUid());
return "redirect:cart?uid="+vo.getUid();
}
}
5, 제품 상세보기 > 주문 양식
<form action="/cart/addCart" method="post">
<input type="hidden" name="product_code" th:value="${m.product_code}">
<div>
<strong th:text="${m.pname}"></strong>
</div>
<div th:text="'판매가: ' + ${m.fmtPprice} + '원'"></div>
<div th:text="${m.pdelifee == 0 ? '무료배송❗' : '배송비: ' + m.fmtPdelifee + '원'}"></div>
<div th:text="'주문가능 수량: ' + ${m.pstock} + '개'"></div>
주문수량: <input type="number" name="pquantity" value="1" min="1" th:max="${m.pstock}">
<br><br>
<div>
<input type="submit" value="바로 구매" class=button>
<!-- 실제 장바구니 이동 -->
 
<input type="button" value="장바구니에 담기" class=subbtn>
<!-- 장바구니 이동 안 하고 추가만 함 -->
</div>
</form>
6, 장바구니 (초본, 미연산)
<h1 th:text="'cart (' + ${lisize} + '건)'"></h1>
<form action="" method="post">
<input type="hidden" name="uid" value="${session.username}">
<table>
<tr class="tr_color">
<th>no</th>
<th>cartid</th>
<th>pname</th>
<th>pimg</th>
<th>pprice</th>
<th>pquantity</th>
<th>pdelifee</th>
</tr>
<tr th:each="m, stat : ${li}" class="tr_color">
<td th:text="${stat.count}"></td>
<td th:text="${m.cartid}"/>
<td>
<a th:href="@{/prd/viewPrd(product_code=${m.product_code})}"
th:text="${m.pname}">
</a>
</td>
<td>
<a th:href="@{/prd/viewPrd(product_code=${m.product_code})}">
<img th:src="@{/img/}+${m.pimgStr}" width="100" />
</a>
</td>
<td>
<input type="text" name="pprice" th:value="${m.fmtPprice} + '원'" readonly>
</td>
<td>
<input type="number" name="pquantity" th:value="${m.pquantity}" min="1" th:max="${m.pstock}">
</td>
<td>
<input type="text" name="pdelifee" th:value="${m.fmtPdelifee} + '원'" readonly>
</td>
</tr>
</table>
</form>
방법2 - chat gpt에게 추천 받은 바
위보다 더 효율적인 로직 있는지 물어보니 아래와 같은 답변 받았다.
1, 단일 쿼리로 처리:
기존 로직에서는 상품을 담은 기록을 찾기 위해 두 번의 쿼리 (countCart, resultCartid)를 사용합니다. 이를 하나의 쿼리로 통합하여 처리할 수 있습니다. COUNT 쿼리 대신, cartid를 직접 조회하고 그 결과로 새 레코드를 삽입할지, 수량을 업데이트할지 결정할 수 있습니다.
2, 트랜잭션 사용:
장바구니 작업은 다단계 작업이기 때문에, 특히 여러 쿼리를 수행할 때 데이터 무결성을 보장하기 위해 트랜잭션을 사용하는 것이 좋습니다. 트랜잭션을 사용하면 모든 작업이 성공적으로 완료되었을 때만 데이터베이스에 반영되고, 그렇지 않으면 롤백됩니다.
1, Mapper
@Mapper
public interface CartMapper {
//1. 사용자가 동일 제품 담은 레코드 조회
@Select("SELECT cartid FROM cart "
+ "WHERE uid = #{uid} "
+ "AND product_code = #{product_code}")
String findCartidByUidAndProductCode(@Param("uid") String uid,
@Param("product_code") String product_code);
//2. 동일 건 없으면 새 레코드 삽입
@Insert("INSERT INTO cart (uid, product_code, pquantity) "
+ "VALUES (#{uid}, #{product_code}, #{pquantity})")
void addCart(CartVo vo);
//3. 동일 건 있으면 해당 건의 주문수량 변경
@Update("UPDATE cart SET pquantity = pquantity + #{pquantity} "
+ "WHERE cartid = #{cartid}")
void updatePquantity(CartVo vo);
}
2, Svc
@Service
public class CartSvc {
@Autowired
CartMapper cartMapper;
@Transactional
public void addOrUpdateCart(CartVo vo) {
//1. 사용자가 동일 제품 담은 레코드 조회 결과의 cartid 가져오기
String cartid = cartMapper.findCartidByUidAndProductCode(vo.getUid(), vo.getProduct_code());
//2. 동일 건 없으면 새 레코드 삽입
if (cartid == null) {
cartMapper.addCart(vo);
//3. 동일 건 있으면 해당 건의 주문수량 변경
} else {
vo.setCartid(cartid);
cartMapper.updatePquantity(vo);
}
}
}
3, Ctrl
@RequestMapping("/cart/")
@Controller
public class CartCtrl {
@Autowired
CartSvc cartSvc;
@Autowired
HttpSession session;
@PostMapping("addCart")
public String addCart(Model model, CartVo vo) {
String username = (String) session.getAttribute("username");
vo.setUid(username);
cartSvc.addOrUpdateCart(vo);
return "redirect:cart?uid=" + vo.getUid();
}
}
코드가 너무 깔끔해져서 감동..
chat gpt에게 추가로 물어보기 잘했다.
어쩌면 나 기기보다 더 기기 같은걸..
괜찮다. 초중보자니까 🥹