[2022.11.16.수] 국내도서, 장바구니
1. 국내도서 리스트, 상세정보
1) sample_board_books 테이블, sample_board_book_cart_items 테이블 추가
CREATE TABLE "SAMPLE_BOARD_BOOKS"
( "BOOK_NO" NUMBER(6,0) PRIMARY KEY,
"BOOK_TITLE" VARCHAR2(255) NOT NULL,
"BOOK_AUTHOR" VARCHAR2(255) NOT NULL,
"BOOK_PUBLISHER" VARCHAR2(255) NOT NULL,
"BOOK_DESCRIPTION" VARCHAR2(2000),
"BOOK_IMAGE" VARCHAR2(100),
"BOOK_PRICE" NUMBER(10,0),
"BOOK_DISCOUNT_PRICE" NUMBER(10,0),
"BOOK_STOCK" NUMBER(10,0),
"BOOK_ON_SELL" CHAR(1) DEFAULT 'Y',
"BOOK_CREATED_DATE" DATE DEFAULT SYSDATE,
"BOOK_UPDATED_DATE" DATE DEFAULT SYSDATE
);
CREATE TABLE SAMPLE_BOARD_BOOK_CART_ITEMS (
ITEM_NO NUMBER(6) PRIMARY KEY,
BOOK_NO NUMBER(6) REFERENCES SAMPLE_BOARD_BOOKS (BOOK_NO),
USER_ID VARCHAR2(20) REFERENCES SAMPLE_BOARD_USERS (USER_ID),
ITEM_AMOUNT NUMBER(3) DEFAULT 1,
ITEM_CREATED_DATE DATE DEFAULT SYSDATE,
ITEM_UPDATED_DATE DATE DEFAULT SYSDATE
);
2) Book 객체, Dao, xml 추가
- books.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="books">
<select id="getBooks" parameterClass="com.sample.util.Pagination" resultClass="com.sample.vo.Book">
select
book_no as no,
book_title as title,
book_author as author,
book_publisher as publisher,
book_description as description,
book_image as image,
book_price as price,
book_discount_price as discount,
book_stock as stock,
book_on_sell as onSell,
book_created_date as createdDate,
book_updated_date as updatedDate
from
(select row_number() over(order by book_no desc) row_numbers,
book_no, book_title, book_author, book_publisher, book_description, book_image,
book_price, book_discount_price, book_stock, book_on_sell, book_created_date, book_updated_date
from sample_board_books)
where
row_numbers between #begin# and #end#
</select>
<select id="getTotalRows" resultClass="int">
select
count(*)
from
sample_board_books
</select>
<select id="getBookByNo" parameterClass="int" resultClass="com.sample.vo.Book">
select
book_no as no,
book_title as title,
book_author as author,
book_publisher as publisher,
book_description as description,
book_image as image,
book_price as price,
book_discount_price as discount,
book_stock as stock,
book_on_sell as onSell,
book_created_date as createdDate,
book_updated_date as updatedDate
from
sample_board_books
where
book_no = #value#
</select>
</sqlMap>
- bookDao
package com.sample.dao;
import java.util.List;
import com.sample.util.Pagination;
import com.sample.util.SqlMapper;
import com.sample.vo.Book;
public class BookDao {
@SuppressWarnings("unchecked")
public List<Book> getBooks(Pagination pagination){
return (List<Book>) SqlMapper.selectList("books.getBooks", pagination);
}
public int getTotalRows() {
return (Integer)SqlMapper.selectOne("books.getTotalRows");
}
public Book getBookByNo(int no) {
return (Book) SqlMapper.selectOne("books.getBookByNo",no);
}
}
* 겹치는 SQL 방지 -> namespace 설정
1) ibatis-config.xml 맨 첫 줄에 네임스페이스 사용 활성화
<!-- SQL 구문에 네임스페이스 사용을 활성화한다. -->
<settings useStatementNamespaces="true" />
2) 겹치는 SQL이 있는 모든 xml
<sqlMap namespace="books">
<sqlMap namespace="boards">
<sqlMap namespace="reviews">
<sqlMap namespace="users">
3) 모든 dao의 모든 메소드의 "id" 입력 부분에
"books.getBooks"
"books.getTotalRows"
"books.getBookByNo"
"boards.getBoards"
....
3) 페이징처리
* 아예 util에 Pagination 객체를 만들어놓기
- Pagination
package com.sample.util;
public class Pagination {
private int rows; // 한 화면에 표시되는 데이터 개수
private int pages; // 한 화면에 표시되는 페이지번호 개수
private int currentPage; // 요청한 페이지 번호
private int totalRows; // 전체 데이터 개수
/**
* 요청한 페이지번호, 전체 데이터 개수를 전달받아서 Pagination객체를 초기화한다.
* <p>한 화면에 표시되는 데이터 개수는 10개다.
* <p>한 화면에 표시되는 페이지번호 개수는 5개다.
* @param currentPage 요청한 페이지 번호
* @param totalRows 전체 데이터 개수
*/
public Pagination(int currentPage, int totalRows) {
this(currentPage, totalRows, 10, 5);
}
/**
* 요청한 페이지번호, 전체 데이터 개수, 한 화면에 표시할 행의 개수를 전달받아서 Pagination객체를 초기화한다.
* <p>한 화면에 표시되는 페이지번호 개수는 5개다.
* @param currentPage 요청한 페이지 번호
* @param totalRows 전체 데이터 개수
* @param rows 한 화면에 표시되는 행의 개수
*/
public Pagination(int currentPage, int totalRows, int rows) {
this(currentPage, totalRows, rows, 5);
}
/**
* 요청한 페이지번호, 전체 데이터 개수, 한 화면에 표시할 행의 개수, 한 화면에 표시할 페이지번호 개수를 전달받아서 Pagination객체를 초기화한다.
* @param currentPage 요청한 페이지 번호
* @param totalRows 전체 데이터 개수
* @param rows 한 화면에 표시되는 행의 개수
* @param pages 한 화면에 표시되는 페이지번호 개수
*/
public Pagination(int currentPage, int totalRows, int rows, int pages) {
this.currentPage = currentPage;
this.totalRows = totalRows;
this.rows = rows;
this.pages = pages;
}
/**
* 요청한 페이지번호의 조회 시작번호를 반환한다.
* @return
*/
public int getBegin() {
return (currentPage - 1)*rows + 1;
}
/**
* 요청한 페이지번호의 조회 끝번호를 반환한다.
* @return
*/
public int getEnd() {
return currentPage*rows;
}
/**
* 총 페이지 개수를 반환한다.
* @return
*/
public int getTotalPages() {
return (int) Math.ceil((double) totalRows/rows);
}
/**
* 총 페이지 블록 개수를 반환한다.
* @return
*/
public int getTotalBlocks() {
return (int) Math.ceil((double) getTotalPages()/pages);
}
/**
* 요청한 페이지번호가 속한 페이지 블록 번호를 반환한다.
* @return
*/
public int getCurrentPageBlock() {
return (int) Math.ceil((double) currentPage/pages);
}
/**
* 요청한 페이지번호가 속한 페이지 블록의 시작 페이지 번호를 반환한다.
* @return
*/
public int getBeginPage() {
return (getCurrentPageBlock() - 1)*pages + 1;
}
/**
* 요청한 페이지번호가 속한 페이지 블록의 끝 페이지 번호를 반환한다.
* @return
*/
public int getEndPage() {
return getCurrentPageBlock() == getTotalBlocks() ? getTotalPages() : getCurrentPageBlock()*pages;
}
/**
* 첫 페이지인지 여부를 반환한다.
* @return 첫 페이지이면 true 반환
*/
public boolean isFirst() {
return currentPage <= 1;
}
/**
* 끝 페이지인지 여부를 반환한다.
* @return 끝 페이지이면 true 반환
*/
public boolean isLast() {
return currentPage >= getTotalPages();
}
/**
* 이전 페이지 번호를 반환한다.
* @return
*/
public int getPrevPage() {
return currentPage - 1;
}
/**
* 다음 페이지 번호를 반환한다.
* @return
*/
public int getNextPage() {
return currentPage + 1;
}
}
- book / list.jsp 에서 페이징 처리
<%@page import="com.sample.util.Pagination"%>
<%@page import="com.sample.vo.Book"%>
<%@page import="java.util.List"%>
<%@page import="com.sample.dao.BookDao"%>
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@page import="com.sample.util.StringUtils"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"></script>
<title>익명 게시판</title>
<style type="text/css">
img.img-thumbnail {width: 53px; height: 68px;}
</style>
</head>
<body>
<jsp:include page="../common/header.jsp">
<jsp:param name="menu" value="book"/>
</jsp:include>
<div class="container my-3">
<h1 class="mb-3 fs-4 border p-2 bg-light">도서 리스트</h1>
<p>도서 목록을 확인하세요.</p>
<%
// 요청파라미터에서 요청한 페이지번호를 조회한다.
int currentPage = StringUtils.stringToInt(request.getParameter("page"), 1);
// BookDao 객체 생성
BookDao bookDao = new BookDao();
// 총 데이터 개수 조회
int totalRows = bookDao.getTotalRows();
// 페이징처리에 필요한 정보를 제공하는 Pagination객체 생성 (한 페이지에 5행, 5페이지씩 표시)
Pagination pagination = new Pagination(currentPage, totalRows, 5, 5);
// 요청한 페이지 범위에 해당하는 책목록을 조회한다.
List<Book> bookList = bookDao.getBooks(pagination);
%>
<table class="table">
<colgroup>
<col width="10%">
<col width="*">
<col width="12%">
<col width="15%">
<col width="10%">
<col width="10%">
</colgroup>
<thead>
<tr>
<th></th>
<th>제목</th>
<th>저자</th>
<th>출판사</th>
<th>가격</th>
<th>재고수량</th>
</tr>
</thead>
<tbody>
<%
if(bookList.isEmpty()){
%>
<tr>
<td colspan="6" class="text-center">등록된 도서가 없습니다.</td>
</tr>
<%
} else {
for(Book book : bookList){
%>
<tr class="align-middle">
<td><img src="../resources/images/<%=book.getImage() %>" class="img-thumbnail"></td>
<td><a href="detail.jsp?no=<%=book.getNo() %>" class="text-decoration-none"><%=book.getTitle() %></a></td>
<td><%=book.getAuthor() %></td>
<td><%=book.getPublisher() %></td>
<td><%=book.getPrice() %> 원</td>
<td><%=book.getStock() %> 권</td>
</tr>
<%
}
}
%>
</tbody>
</table>
<%
if (totalRows >= 0) {
%>
<div aria-label="navigation">
<ul class="pagination justify-content-center">
<li class="page-item">
<a class="page-link <%=pagination.isFirst() ? "disabled" : "" %>" href="list.jsp?page=<%=pagination.getPrevPage()%>">이전</a>
</li>
<%
for (int number = pagination.getBeginPage(); number <= pagination.getEndPage(); number++) {
%>
<li class="page-item"><a class="page-link <%=currentPage == number ? "active" : "" %>" href="list.jsp?page=<%=number %>"><%=number %></a></li>
<%
}
%>
<li class="page-item">
<a class="page-link <%=pagination.isLast() ? "disabled" : "" %>" href="list.jsp?page=<%=pagination.getNextPage() %>">다음</a>
</li>
</ul>
</div>
<%
}
%>
</div>
</body>
</html>
4) 도서상세
- book / detail.jsp
* book / list.jsp 의 책 제목으로부터 요청받은 no를 조회
-> 책 번호에 해당하는 책 조회
<%@page import="com.sample.vo.Book"%>
<%@page import="com.sample.dao.BookDao"%>
<%@page import="com.sample.vo.User"%>
<%@page import="com.sample.vo.Review"%>
<%@page import="com.sample.dao.ReviewDao"%>
<%@page import="java.util.List"%>
<%@page import="com.sample.vo.Board"%>
<%@page import="com.sample.dao.BoardDao"%>
<%@page import="com.sample.util.StringUtils"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"></script>
<title>익명 게시판</title>
<style>
textarea {
resize: none;
}
</style>
</head>
<body>
<jsp:include page="../common/header.jsp">
<jsp:param name="menu" value="book"/>
</jsp:include>
<div class="container my-3">
<h1 class="mb-3 fs-4 border p-2 bg-light">도서 상세정보</h1>
<%
int bookNo = StringUtils.stringToInt(request.getParameter("no"));
BookDao bookDao = new BookDao();
Book book = bookDao.getBookByNo(bookNo);
%>
<p>도서 상세정보를 확인하세요</p>
<div class="row mb-3 p-2">
<div class="col-4">
<img src="../resources/images/<%=book.getImage() %>" class="img-thumbnail"/>
</div>
<div class="offset-1 col-7">
<table class="table">
<colgroup>
<col width="15%">
<col width="35%">
<col width="15%">
<col width="35%">
</colgroup>
<tbody>
<tr>
<th>도서번호</th>
<td><%=book.getNo() %></td>
<th>등록일</th>
<td><%=StringUtils.dateToText(book.getCreatedDate()) %></td>
</tr>
<tr>
<th>제목</th>
<td colspan="3"><%=book.getTitle() %></td>
</tr>
<tr>
<th>저자</th>
<td><%=book.getAuthor() %></td>
<th>출판사</th>
<td><%=book.getPublisher() %></td>
</tr>
<tr>
<th>할인가격</th>
<td><strong class="text-danger"><%=StringUtils.numberToText(book.getDiscount()) %></strong> 원</td>
<th>가격</th>
<td><strong><%=StringUtils.numberToText(book.getPrice()) %></strong> 원</td>
</tr>
<tr>
<th>재고수량</th>
<td><%=book.getStock() %> 권</td>
<th>판매여부</th>
<td><%="Y".equals(book.getOnSell()) ? "판매중" : "재고없음" %></td>
</tr>
<tr>
<th>소개</th>
<td colspan="3"><%=book.getDescription() %></td>
</tr>
</tbody>
</table>
<div class="d-grid gap-2">
<!--
현재 URL : http://localhost/web-board/book/detail.jsp?no=10021
요청 URL : http://localhost/web-board/cart/addItem.jsp?bookNo=10021
요청 URL : http://localhost/web-board/order/orderform.jsp?bookNo=10021
기준 URL : http://localhost/web-board/book/
상대경로 : ../cart/addItem.jsp?bookNo=100121
상대경로 : ../order/orderform.jsp?bookNo=100121
-->
<a href="../cart/addItem.jsp?bookNo=<%=book.getNo() %>" class="btn btn-outline-dark fw-bold" type="button">장바구니</a>
<a href="../order/orderform.jsp?bookNo=<%=book.getNo() %>" class="btn btn-outline-primary fw-bold" type="button">바로구매</a>
</div>
</div>
</div>
<hr />
<div class="mb-3">
<!--
현재 URL : http://localhost/web-board/book/detail.jsp?no=10021
요청 URL : http://localhost/web-board/book/list.jsp
기준 URL : http://localhost/web-board/book/
상대 경로 : list.jsp
-->
<a href="list.jsp" class="btn btn-outline-primary float-end">목록</a>
</div>
</div>
</body>
</html>
* 주소표기법
- 절대경로
- 경로가 "/"로 시작하는 경로
- url 주소에서 "http://localhost" 다음부터의 전체 경로를 작성하는 것
- 절대경로는 현재 페이지의 URL 주소와 상관없이 요청 URL의 주소를 작성하는 것
* 모든 페이지에 공통으로 포함되는 내비바의 주소는 절대경로로 지정한다. - 요청 URL : http://localhost/web-board/home.jsp
<a href="/web-board/home.jsp">홈</a> - 요청 URL : http://localhost/web-board/book/list.jsp
<a href="/web-board/book/list.jsp">국내도서</a>
- 상대경로
- 경로가 "/"로 시작하지 않는 경로
- 상대경로는 현재 페이지의 URL 주소를 기준으로 요청 URL의 주소를 작성하는 것
- 현재 페이지의 URL : http://localhost/web-board/home.jsp
- 요청 URL : http://localhost/web-board/about.jsp
* 절대경로 : <a href="/web-board/about.jsp">소개</a>
* 상대경로 : <a href="about.jsp">소개</a> - 맨 마지막 / 까지가 기준
현재 URL : http://localhost/web-board/home.jsp
요청 URL : http://localhost/web-board/about.jsp
기준 : http://localhost/web-board/ + "about.jsp"
<a href="about.jsp"> - 현재 URL : http://localhost/web-board/home.jsp
요청 URL : http://localhost/web-board/board/list.js
기준 : http://localhost/web-board/ + "board/list.jsp"
<a href="board/list.jsp"> - 현재 URL : http://localhost/web-board/board/list.jsp
요청 URL : http://localhost/web-board/board/detail.jsp?no=100
기준 : http://localhost/web-board/ + "detail.jsp?no=100"
<a href="detail.jsp?no=100"> - 현재 URL : http://localhost/web-board/board/list.jsp
요청 URL : http://localhost/web-board/home.jsp
기준 : http://localhost/web-board/board/ + "../home.jsp"
=> http://localhost/web-board/ + "home.jsp"
<a href="../home.jsp">
2. 장바구니 담기
1) 장바구니 (CartItem) 객체, carts.xml, CartItemDao 생성
- CartItem
package com.sample.vo;
import java.util.Date;
public class CartItem {
private int no;
private int bookNo;
private String userId;
private int amount;
private Date createdDate;
private Date updatedDate;
public CartItem() {}
public CartItem(int bookNo, String userId) {
this.bookNo = bookNo;
this.userId = userId;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public int getBookNo() {
return bookNo;
}
public void setBookNo(int bookNo) {
this.bookNo = bookNo;
}
public String getUserid() {
return userId;
}
public void setUserid(String userid) {
this.userId = userid;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
public Date getUpdatedDate() {
return updatedDate;
}
public void setUpdatedDate(Date updatedDate) {
this.updatedDate = updatedDate;
}
}
- carts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="carts">
<insert id="insertCartItem" parameterClass="com.sample.vo.CartItem">
insert into sample_board_book_cart_items
(item_no, book_no, user_id)
values
(sample_carts_seq.nextval, #bookNo#, #userId#)
</insert>
<select id="getCartItemsByUserId" parameterClass="string" resultClass="com.sample.dto.CartItemDto">
select
A.item_no as itemNo,
A.book_no as bookNo,
A.user_id as userId,
B.book_title as title,
B.book_image as image,
A.item_amount as amount,
B.book_price as price,
B.book_discount_price as discountPrice,
A.item_created_date as createdDate,
A.item_updated_date as updatedDate
from
sample_board_book_cart_items A, sample_board_books B
where
A.book_no = B.book_no
and A.user_id = #value#
</select>
</sqlMap>
- CartItemDao
package com.sample.dao;
import java.util.List;
import com.sample.dto.CartItemDto;
import com.sample.util.SqlMapper;
import com.sample.vo.CartItem;
public class CartItemDao {
public void insertCartItem(CartItem cartItem) {
SqlMapper.insert("carts.insertCartItem", cartItem);
}
@SuppressWarnings("unchecked")
public List<CartItemDto> getCartItemsByUserId(String userId){
return (List<CartItemDto>) SqlMapper.selectList("carts.getCartItemsByUserId", userId);
}
}
2) 장바구니에 담기
- addItem.jstp
* 로그인한 사용자만 장바구니 담기 가능
장바구니에 담을 책정보 + 사용자아이디 필요
<%@page import="com.sample.dao.CartItemDao"%>
<%@page import="com.sample.vo.CartItem"%>
<%@page import="com.sample.util.StringUtils"%>
<%@page import="com.sample.vo.User"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
// 장바구니 아이템정보를 저장하기 위해서 책번호(요청 파라미터에서 획득),
// 사용자아이디(세션에 저장된 사용자정보에서 획득)가 필요함
// HttpSession 객체에 "loginedUser"라는 이름으로 저장된 사용자 정보를 조회한다. (user/login.jsp에서 저장해둔 것)
User user = (User) session.getAttribute("loginedUser");
if(user == null){
/*
현재 URL : http://localhost/web-board/cart/addItem.jsp?no=10021
요청 URL : http://localhost/web-board/user/loginform.jsp?error=deny
기준 URL : http://localhost/web-board/cart/
상대경로 : ../user/loginform.jsp?error=deny
*/
response.sendRedirect("../user/loginform.jsp?errer=deny");
return;
}
// 요청파라미터에서 책번호 조회
int bookNo = StringUtils.stringToInt(request.getParameter("bookNo"));
// 사용자 아이디 조회
String userId = user.getId();
// CartItem 객체를 생성하고, 책번호와 사용자아이디를 저장한다. (생성자)
CartItem cartItem = new CartItem(bookNo, userId);
// CartItemDao 객체를 생성하고, addCartItem(CartItem cartItem) 메소드를 실행해서 장바구니 아이템을 저장시킨다.
CartItemDao cartItemDao = new CartItemDao();
cartItemDao.insertCartItem(cartItem);
// 재요청 URL을 응답으로 보낸다.
/*
현재 URL : cart/addItem.jsp
요청 URL : cart/list.jsp
기준 URL : cart/
상대경로 : list.jsp
*/
response.sendRedirect("list.jsp");
%>
3) 장바구니 리스트 조회하기
- 장바구니 리스트에는
장바구니 상품 번호 (cart_items), 책 번호(cart_items), 사용자 아이디 (cart_items), 책 제목 (books), 이미지 (books), 수량 (cart_items), 가격 (books), 할인가격 (books), 등록 날짜(cart_items), 수정 날짜(cart_items)가 필요
- cart_items와 books 테이블 조인하기 위해 새로운 CartItemDto 객체 생성
- cart / list.jsp (장바구니 리스트) 요청 -> 장바구니 리스트 조회
* carts.xml 에서 사용자 아이디로 장바구니 리스트 조회하는 SQL -> 테이블 조인
cartItemDao 에서 사용자 아이디로 장바구니 리스트 조회하는 메소드
* 요청객체에서 책번호만 전달
* 사용자아이디는 세션 객체에서 획득
<%@page import="com.sample.util.StringUtils"%>
<%@page import="com.sample.dto.CartItemDto"%>
<%@page import="java.util.List"%>
<%@page import="com.sample.dao.CartItemDao"%>
<%@page import="com.sample.vo.User"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
// 인증된 사용자 정보를 조회하고, 없으면 로그인폼 재요청, 있으면 -> 사용자아이디로 장바구니 목록 조회 가능
User user = (User) session.getAttribute("loginedUser");
if (user == null) {
response.sendRedirect("../user/loginform.jsp?error=deny");
return;
}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"></script>
<title>익명 게시판</title>
<style type="text/css">
img.img-thumbnail {width: 53px; height: 68px;}
</style>
</head>
<body>
<jsp:include page="../common/header.jsp">
<jsp:param name="menu" value="cart"/>
</jsp:include>
<div class="container my-3">
<h1 class="mb-3 fs-4 border p-2 bg-light">장바구니 리스트</h1>
<%
// CartItemDao 객체를 생성하고, getCartItemsByUserId(String userId) 메소드를 실행해서 장바구니 아이템 목록을 조회한다.
CartItemDao cartItemDao = new CartItemDao();
List<CartItemDto> dtoList = cartItemDao.getCartItemsByUserId(user.getId());
%>
<p>장바구니 목록을 확인하세요.</p>
<table class="table">
<colgroup>
<col width="5%">
<col width="10%">
<col width="*">
<col width="10%">
<col width="15%">
<col width="15%">
<col width="10%">
</colgroup>
<thead>
<tr>
<th><input type="checkbox"></th>
<th></th>
<th>제목</th>
<th>수량</th>
<th>가격</th>
<th>구매가격</th>
<th></th>
</tr>
</thead>
<tbody>
<%
if (dtoList.isEmpty()) {
%>
<tr>
<td colspan="7" class="text-center">장바구니에 저장된 도서정보가 없습니다.</td>
</tr>
<%
} else {
for (CartItemDto dto : dtoList) {
%>
<tr class="align-middle">
<td><input type="checkbox" name="itemNo" value="<%=dto.getItemNo() %>" /></td>
<td><img src="../resources/images/<%=dto.getImage() %>" class="img-thumbnail"></td>
<td><a href="../book/detail.jsp?no=<%=dto.getBookNo() %>" class="text-decoration-none"><%=dto.getTitle() %></a></td>
<td><%=dto.getAmount() %> 권</td>
<td>
<strong class="text-danger"><%=StringUtils.numberToText(dto.getDiscountPrice()) %> 원</strong>
<small>(<%=StringUtils.numberToText(dto.getPrice()) %> 원)</small>
</td>
<td><strong class="text-danger"><%=StringUtils.numberToText(dto.getAmount()*dto.getDiscountPrice()) %> 원</strong></td>
<td>
<a href="deleteItem.jsp?itemNo=<%=dto.getItemNo() %>" class="btn btn-secondary btn-sm">삭제</a>
<a href="" class="btn btn-primary btn-sm">구매</a>
</td>
</tr>
<%
}
}
%>
</tbody>
</table>
</div>
</body>
</html>