기획의도:
유의사항:
가독성을 위해 String으로 format된 숫자 값을 프론트에 출력하되,
정상적인 연산 위해서는 int값 그대로 전달하도록 input/type=hidden 태그에 감싸서 같이 포함시킬 것.
1, Vo
@Data
public class CartVo {
private String cartid;
private String uid; // 사용자 id
private String username; // 당시 로그인 id (관리자 포함)
private String product_code;
private String pname;
private String pimgStr;
private int pstock;
private int pquantity;
//연산 시 int 사용, 표시는 fmt 사용
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 {
//uid별 전체 cart 보기
@Select ("select cartid, uid as username, c.product_code, pquantity, "
+ "pname, pprice, pdelifee, pimgStr, pstock "
+ "from cart c join products p on c.product_code = p.product_code "
+ "where uid=#{username} "
+ "order by cartid desc")
List<CartVo> cart (CartVo vo);
@Delete ("delete from cart where cartid=#{cartid}")
void delCart(CartVo vo);
}
3, Service
@Service
public class CartSvc {
@Autowired
CartMapper cartMapper;
(@Transactional)
public List<CartVo> cart (CartVo vo) {
return cartMapper.cart(vo); //uid별 cart 보기
}
public void delCart(CartVo vo) {
cartMapper.delCart(vo);
}
}
4, Ctrl
연산은 프론트에서 진행하기에 여기선 생략
@RequestMapping("/cart/")
@Controller
public class CartCtrl {
@Autowired
CartSvc cartSvc;
@Autowired
HttpSession session;
@GetMapping("cart")
public String cart(Model model, CartVo vo) {
System.out.println("uid/username별 cart 보기");
String username=(String) session.getAttribute("username");
vo.setUsername(username); //프론트에 username만 전달됨. uid=null
List<CartVo> li = cartSvc.cart(vo);
//해당 선언 있어야 lisize 계산됨 (혹은 session.user별 cart.size로 대체 가능)
model.addAttribute("li", li);
model.addAttribute("lisize", li.size());
System.out.println("cart username: " + vo.getUid());
return "cart/cart";
}
@GetMapping("delCart")
public String delCart(CartVo vo) {
System.out.println("delCart id: " + vo.getCartid());
cartSvc.delCart(vo);
String username = (String) session.getAttribute("username");
vo.setUid(username);
return "redirect:cart?uid=" + vo.getUid();
}
}
5, html
<h1 th:text="'cart (' + ${lisize} + '건)'"></h1>
<form action="" method="post">
<input type="hidden" name="uid" value="${session.username}">
<div class="allCart" style="width: 800px; display: flex; flex-direction: column; align-items: center;">
<div style="width: 100%; display: flex; justify-content: flex-end; margin-bottom: 10px;">
<input type="hidden" name="totalPay" id="totalPayInput" th:value="${totalPay}"><!-- totalPay값 입력 받을 영역 -->
<span id="totalPayText"></span><!-- totalPay값, 즉 예상결제액 표시할 영역 -->
 
<input type="submit" value="주문하기" class=button>
</div>
</div>
<!-- table은 추후 갤러리 식으로 바꿀까 -->
<table width=800>
<tr class="tr_color">
<th>no</th>
<th>pname</th>
<th>pimg</th>
<th>pprice</th>
<th>pquantity</th>
<th>pdelifee</th>
<th>hab</th>
<th>del</th>
</tr>
<tr th:each="m, stat : ${li}" class="tr_color">
<td th:text="${stat.count}">
<input type="hidden" name="cartid" th:value="${m.cartid}">
</td>
<td>
<a th:href="@{/prd/viewPrd(product_code=${m.product_code})}"
th:text="${m.pname}" target="_blank">
</a>
</td>
<td>
<a th:href="@{/prd/viewPrd(product_code=${m.product_code})}" target="_blank">
<img th:src="@{/img/}+${m.pimgStr}" width="100" />
</a>
</td>
<td>
<input type="hidden" name="pprice" th:value="${m.pprice}">
<span th:text="${m.fmtPprice + '원'}">0</span>
</td>
<td>
<input type="number" name="pquantity" class="quantity-input"
th:value="${m.pquantity}" th:text="' / '+${m.pstock}" min="1" th:max="${m.pstock}">
<!-- class="quantity-input" 통해 입력된 주문량을 js에 전달 -->
</td>
<td>
<input type="hidden" name="pdelifee" th:value="${m.pdelifee}">
<span th:text="${m.pdelifee == 0 ? '무료배송❗' : m.fmtPdelifee + '원'}">0</span>
</td>
<td th:text="${m.pprice * m.pquantity + m.pdelifee}">합계</td>
<td>
<a th:href="@{/cart/delCart(cartid=${m.cartid})}" >✖️</a>
</td>
</tr>
</table>
</form>
6, script
<script>
document.addEventListener('DOMContentLoaded', function() {
const quantityInputs = document.querySelectorAll('.quantity-input');
const totalPayInput = document.getElementById('totalPayInput');
const totalPayText = document.getElementById('totalPayText');
// 천원단위에 콤마 찍기
function formatNumber(number) {
return number.toLocaleString();
}
//계산하기
function updateTotals() {
let totalPay = 0;
quantityInputs.forEach(input => {
const row = input.closest('tr');
const price = parseFloat(row.querySelector('input[name="pprice"]').value);
const quantity = parseInt(input.value, 10);
const deliveryFee = parseFloat(row.querySelector('input[name="pdelifee"]').value);
const itemTotal = (price * quantity) + deliveryFee;
row.querySelector('td:nth-child(7)').textContent = formatNumber(itemTotal) + '원'; // cart별 hab 업데이트
totalPay += itemTotal;
});
totalPayInput.value = totalPay;
totalPayText.innerHTML = '예상결제액: <strong>' + formatNumber(totalPay) + '원</strong>'; // totalPay 업데이트
}
quantityInputs.forEach(input => {
input.addEventListener('input', updateTotals); // 주문량 변경 시마다 각각 업데이트
});
updateTotals(); // 내장 계산기
});
</script>